This commit introduces a new JavaScript function to open a document editing popup, enhancing user interaction with documentation links. The CSS has been updated to improve the layout and styling of the documentation panel, including adjustments to padding and font sizes for better readability. Additionally, new PHP functions have been added to generate edit links for documentation, integrating them into the header actions for improved accessibility. The version code has been incremented to 4.72.641.
429 lines
15 KiB
PHP
429 lines
15 KiB
PHP
<?php
|
|
|
|
/**
|
|
* Éditeur documentation MS1 (pop-up) — module doc_page FR/EN, toutes les pages d'un module.
|
|
*/
|
|
|
|
require_once('inc_start_time.php');
|
|
require_once('inc_fonctions.php');
|
|
require_once('inc_fx_messages.php');
|
|
|
|
if (!fxAdminCanUseTextEditTools()) {
|
|
header('HTTP/1.1 403 Forbidden');
|
|
echo 'Accès refusé.';
|
|
exit;
|
|
}
|
|
|
|
function docEdEsc($str) {
|
|
return htmlspecialchars((string)$str, ENT_QUOTES, 'UTF-8');
|
|
}
|
|
|
|
function docEdFieldAttrs($strChamp, $strRowKey, $strLang) {
|
|
$id = 'doc_' . preg_replace('/[^a-z0-9_]/i', '_', $strRowKey) . '_' . $strLang . '_' . $strChamp;
|
|
return 'id="' . docEdEsc($id) . '" name="pages[' . docEdEsc($strRowKey) . '][' . docEdEsc($strLang) . '][' . docEdEsc($strChamp) . ']"';
|
|
}
|
|
|
|
function docEdLoadModulePages($modClef, $prg) {
|
|
global $objDatabase;
|
|
|
|
$sql = "SELECT *
|
|
FROM doc_page
|
|
WHERE doc_mod_clef = '" . $objDatabase->fxEscape($modClef) . "'
|
|
AND doc_prg IN ('" . $objDatabase->fxEscape($prg) . "', 'global')
|
|
ORDER BY doc_tri, doc_page_clef, doc_langue DESC";
|
|
$rows = $objDatabase->fxGetResults($sql);
|
|
|
|
$grouped = array();
|
|
if (!is_array($rows)) {
|
|
return $grouped;
|
|
}
|
|
|
|
for ($i = 1; $i <= count($rows); $i++) {
|
|
$row = $rows[$i];
|
|
$pageClef = $row['doc_page_clef'] ?? '';
|
|
if ($pageClef === '') {
|
|
continue;
|
|
}
|
|
if (!isset($grouped[$pageClef])) {
|
|
$grouped[$pageClef] = array(
|
|
'doc_page_clef' => $pageClef,
|
|
'doc_tri' => (int)($row['doc_tri'] ?? 0),
|
|
'fr' => null,
|
|
'en' => null,
|
|
);
|
|
}
|
|
$lang = $row['doc_langue'] ?? 'fr';
|
|
if ($lang === 'fr' || $lang === 'en') {
|
|
$grouped[$pageClef][$lang] = $row;
|
|
}
|
|
}
|
|
|
|
uasort($grouped, function ($a, $b) {
|
|
if ($a['doc_tri'] === $b['doc_tri']) {
|
|
return strcmp($a['doc_page_clef'], $b['doc_page_clef']);
|
|
}
|
|
return $a['doc_tri'] <=> $b['doc_tri'];
|
|
});
|
|
|
|
return $grouped;
|
|
}
|
|
|
|
$anchor = trim($_GET['anchor'] ?? $_POST['anchor'] ?? '');
|
|
$modClef = trim($_GET['mod'] ?? $_POST['mod'] ?? '');
|
|
$prg = trim($_GET['prg'] ?? $_POST['prg'] ?? 'compte.php');
|
|
$page = trim($_GET['page'] ?? $_POST['page'] ?? '');
|
|
$bd = trim(strtolower($_GET['bd'] ?? $_POST['bd'] ?? 'client'));
|
|
$blnSaved = false;
|
|
|
|
if ($modClef === '' && $anchor !== '') {
|
|
$modClef = fxDocResolveModClef($anchor, 0);
|
|
}
|
|
if ($anchor === '' && $modClef !== '') {
|
|
$anchor = $modClef;
|
|
}
|
|
|
|
if (isset($_POST['btn_mod']) && !empty($_POST['pages']) && is_array($_POST['pages'])) {
|
|
foreach ($_POST['pages'] as $pageClef => $langs) {
|
|
if (!is_array($langs)) {
|
|
continue;
|
|
}
|
|
foreach ($langs as $lang => $tabPosted) {
|
|
if (!is_array($tabPosted) || empty($tabPosted['doc_langue'])) {
|
|
continue;
|
|
}
|
|
$tabPosted['doc_page_clef'] = $pageClef;
|
|
$tabPosted['doc_mod_clef'] = $modClef;
|
|
$tabPosted['doc_prg'] = $prg;
|
|
if (!empty($tabPosted['pk_doc_page'])) {
|
|
fxSetDocPage('mod', $tabPosted, $tabPosted['pk_doc_page']);
|
|
} else {
|
|
fxSetDocPage('add', $tabPosted);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!empty($_POST['doc_mod']) && is_array($_POST['doc_mod']) && !empty($_POST['doc_mod']['pk_doc_mod'])) {
|
|
fxSetDocMod('mod', $_POST['doc_mod'], $_POST['doc_mod']['pk_doc_mod']);
|
|
}
|
|
|
|
$blnSaved = true;
|
|
}
|
|
|
|
$sqlMod = "SELECT * FROM doc_mod
|
|
WHERE doc_mod_clef = '" . $objDatabase->fxEscape($modClef) . "'
|
|
AND doc_mod_prg IN ('" . $objDatabase->fxEscape($prg) . "', 'global')
|
|
ORDER BY FIELD(doc_mod_prg, '" . $objDatabase->fxEscape($prg) . "', 'global')
|
|
LIMIT 1";
|
|
$tabMod = $objDatabase->fxGetRow($sqlMod);
|
|
|
|
$tabPages = docEdLoadModulePages($modClef, $prg);
|
|
|
|
$tabLangMeta = array(
|
|
'fr' => 'Français',
|
|
'en' => 'English',
|
|
);
|
|
|
|
?><!DOCTYPE html>
|
|
<html lang="fr">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title>Documentation — <?php echo docEdEsc($modClef); ?></title>
|
|
<style>
|
|
*, *::before, *::after { box-sizing: border-box; }
|
|
body {
|
|
margin: 0;
|
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, sans-serif;
|
|
font-size: 14px;
|
|
line-height: 1.45;
|
|
color: #212529;
|
|
background: #f1f3f5;
|
|
}
|
|
.doced-page {
|
|
max-width: 1080px;
|
|
margin: 0 auto;
|
|
padding: 20px 16px 32px;
|
|
}
|
|
.doced-card {
|
|
background: #fff;
|
|
border: 1px solid #dee2e6;
|
|
border-radius: 8px;
|
|
overflow: hidden;
|
|
}
|
|
.doced-card-header {
|
|
padding: 14px 18px;
|
|
background: #2f5fd0;
|
|
color: #fff;
|
|
}
|
|
.doced-card-header h1 {
|
|
margin: 0 0 4px;
|
|
font-size: 18px;
|
|
font-weight: 700;
|
|
}
|
|
.doced-card-header .doced-key {
|
|
font-size: 12px;
|
|
opacity: .9;
|
|
word-break: break-all;
|
|
}
|
|
.doced-meta {
|
|
display: grid;
|
|
grid-template-columns: repeat(4, 1fr);
|
|
gap: 10px;
|
|
padding: 12px 18px;
|
|
background: #f8f9fa;
|
|
border-bottom: 1px solid #e9ecef;
|
|
}
|
|
.doced-meta dt {
|
|
margin: 0;
|
|
font-size: 11px;
|
|
text-transform: uppercase;
|
|
letter-spacing: .04em;
|
|
color: #6c757d;
|
|
}
|
|
.doced-meta dd {
|
|
margin: 2px 0 0;
|
|
font-weight: 600;
|
|
word-break: break-all;
|
|
}
|
|
.doced-alert {
|
|
margin: 14px 18px 0;
|
|
padding: 10px 12px;
|
|
border-radius: 6px;
|
|
background: #d1e7dd;
|
|
color: #0f5132;
|
|
border: 1px solid #badbcc;
|
|
}
|
|
.doced-mod-field {
|
|
padding: 14px 18px;
|
|
border-bottom: 1px solid #e9ecef;
|
|
}
|
|
.doced-mod-field label {
|
|
display: block;
|
|
margin-bottom: 4px;
|
|
font-size: 12px;
|
|
font-weight: 600;
|
|
}
|
|
.doced-mod-field input {
|
|
width: 100%;
|
|
max-width: 480px;
|
|
padding: 8px 10px;
|
|
border: 1px solid #ced4da;
|
|
border-radius: 4px;
|
|
font: inherit;
|
|
}
|
|
.doced-page-block {
|
|
border-bottom: 1px solid #e9ecef;
|
|
padding: 16px 18px;
|
|
}
|
|
.doced-page-block:last-of-type {
|
|
border-bottom: none;
|
|
}
|
|
.doced-page-head {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 12px;
|
|
margin-bottom: 12px;
|
|
}
|
|
.doced-page-head h2 {
|
|
margin: 0;
|
|
font-size: 15px;
|
|
font-weight: 700;
|
|
color: #2f5fd0;
|
|
}
|
|
.doced-page-head .doced-page-clef {
|
|
font-size: 12px;
|
|
color: #6c757d;
|
|
}
|
|
.doced-page-head input[type="number"] {
|
|
width: 72px;
|
|
padding: 4px 8px;
|
|
border: 1px solid #ced4da;
|
|
border-radius: 4px;
|
|
}
|
|
.doced-lang-grid {
|
|
display: grid;
|
|
grid-template-columns: 1fr 1fr;
|
|
gap: 16px;
|
|
}
|
|
@media (max-width: 900px) {
|
|
.doced-lang-grid { grid-template-columns: 1fr; }
|
|
.doced-meta { grid-template-columns: 1fr 1fr; }
|
|
}
|
|
.doced-lang-panel {
|
|
border: 1px solid #dee2e6;
|
|
border-radius: 6px;
|
|
padding: 12px;
|
|
}
|
|
.doced-lang-panel h3 {
|
|
margin: 0 0 10px;
|
|
font-size: 13px;
|
|
font-weight: 700;
|
|
}
|
|
.doced-field {
|
|
margin-bottom: 10px;
|
|
}
|
|
.doced-field:last-child {
|
|
margin-bottom: 0;
|
|
}
|
|
.doced-field label {
|
|
display: block;
|
|
margin-bottom: 4px;
|
|
font-size: 12px;
|
|
font-weight: 600;
|
|
color: #495057;
|
|
}
|
|
.doced-field .doced-hint {
|
|
font-weight: 400;
|
|
color: #868e96;
|
|
}
|
|
.doced-field input[type="text"],
|
|
.doced-field textarea {
|
|
width: 100%;
|
|
padding: 8px 10px;
|
|
border: 1px solid #ced4da;
|
|
border-radius: 4px;
|
|
font: inherit;
|
|
color: #212529;
|
|
}
|
|
.doced-field textarea.doced-html {
|
|
min-height: 200px;
|
|
font-family: Consolas, "Courier New", monospace;
|
|
font-size: 12px;
|
|
line-height: 1.45;
|
|
}
|
|
.doced-actions {
|
|
padding: 16px 18px;
|
|
}
|
|
.doced-btn-save {
|
|
padding: 10px 24px;
|
|
border: none;
|
|
border-radius: 4px;
|
|
background: #28a745;
|
|
color: #fff;
|
|
font: inherit;
|
|
font-weight: 600;
|
|
cursor: pointer;
|
|
}
|
|
.doced-btn-save:hover {
|
|
background: #218838;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="doced-page">
|
|
<form action="<?php echo docEdEsc($vDomaine); ?>/php/doc_edition.php" method="post" id="frm_doc_edition">
|
|
<input type="hidden" name="anchor" value="<?php echo docEdEsc($anchor); ?>">
|
|
<input type="hidden" name="mod" value="<?php echo docEdEsc($modClef); ?>">
|
|
<input type="hidden" name="prg" value="<?php echo docEdEsc($prg); ?>">
|
|
<input type="hidden" name="page" value="<?php echo docEdEsc($page); ?>">
|
|
<input type="hidden" name="bd" value="<?php echo docEdEsc($bd); ?>">
|
|
|
|
<div class="doced-card">
|
|
<div class="doced-card-header">
|
|
<h1>Guide documentation</h1>
|
|
<div class="doced-key">Module <?php echo docEdEsc($modClef); ?> · ancre <?php echo docEdEsc($anchor); ?></div>
|
|
</div>
|
|
|
|
<dl class="doced-meta">
|
|
<div>
|
|
<dt>Programme</dt>
|
|
<dd><?php echo docEdEsc($prg); ?></dd>
|
|
</div>
|
|
<div>
|
|
<dt>Ancre UI</dt>
|
|
<dd><?php echo docEdEsc($anchor); ?></dd>
|
|
</div>
|
|
<div>
|
|
<dt>Pages</dt>
|
|
<dd><?php echo count($tabPages); ?></dd>
|
|
</div>
|
|
<div>
|
|
<dt>Base</dt>
|
|
<dd><?php echo docEdEsc($bd); ?></dd>
|
|
</div>
|
|
</dl>
|
|
|
|
<?php if ($blnSaved) { ?>
|
|
<div class="doced-alert">Enregistré. Fermez cette fenêtre pour recharger l'écran principal.</div>
|
|
<?php } ?>
|
|
|
|
<?php if (is_array($tabMod) && !empty($tabMod['pk_doc_mod'])) { ?>
|
|
<div class="doced-mod-field">
|
|
<label for="doc_mod_titre">Titre du module (doc_mod)</label>
|
|
<input type="hidden" name="doc_mod[pk_doc_mod]" value="<?php echo (int)$tabMod['pk_doc_mod']; ?>">
|
|
<input type="hidden" name="doc_mod[doc_mod_clef]" value="<?php echo docEdEsc($tabMod['doc_mod_clef']); ?>">
|
|
<input type="hidden" name="doc_mod[doc_mod_prg]" value="<?php echo docEdEsc($tabMod['doc_mod_prg']); ?>">
|
|
<input type="text" id="doc_mod_titre" name="doc_mod[doc_mod_titre]"
|
|
value="<?php echo docEdEsc($tabMod['doc_mod_titre'] ?? ''); ?>" maxlength="255">
|
|
</div>
|
|
<?php } ?>
|
|
|
|
<?php
|
|
$intPageNum = 0;
|
|
foreach ($tabPages as $pageClef => $tabPageGroup) {
|
|
$intPageNum++;
|
|
$tri = (int)$tabPageGroup['doc_tri'];
|
|
?>
|
|
<section class="doced-page-block">
|
|
<div class="doced-page-head">
|
|
<h2>Page <?php echo (int)$intPageNum; ?></h2>
|
|
<span class="doced-page-clef"><?php echo docEdEsc($pageClef); ?></span>
|
|
</div>
|
|
|
|
<div class="doced-lang-grid">
|
|
<?php foreach ($tabLangMeta as $strLang => $strLangLabel) {
|
|
$tabRow = $tabPageGroup[$strLang];
|
|
$isMod = is_array($tabRow) && !empty($tabRow['pk_doc_page']);
|
|
?>
|
|
<div class="doced-lang-panel">
|
|
<h3><?php echo docEdEsc($strLangLabel); ?></h3>
|
|
|
|
<input type="hidden" <?php echo docEdFieldAttrs('pk_doc_page', $pageClef, $strLang); ?>
|
|
value="<?php echo $isMod ? (int)$tabRow['pk_doc_page'] : ''; ?>">
|
|
<input type="hidden" <?php echo docEdFieldAttrs('doc_langue', $pageClef, $strLang); ?>
|
|
value="<?php echo docEdEsc($strLang); ?>">
|
|
<input type="hidden" <?php echo docEdFieldAttrs('doc_tri', $pageClef, $strLang); ?>
|
|
value="<?php echo $isMod ? (int)$tabRow['doc_tri'] : $tri; ?>">
|
|
<input type="hidden" <?php echo docEdFieldAttrs('doc_actif', $pageClef, $strLang); ?>
|
|
value="1">
|
|
|
|
<div class="doced-field">
|
|
<label>Titre overlay</label>
|
|
<input type="text" maxlength="255"
|
|
<?php echo docEdFieldAttrs('doc_titre', $pageClef, $strLang); ?>
|
|
value="<?php echo docEdEsc($isMod ? ($tabRow['doc_titre'] ?? '') : ''); ?>">
|
|
</div>
|
|
<div class="doced-field">
|
|
<label>Sous-titre</label>
|
|
<input type="text" maxlength="255"
|
|
<?php echo docEdFieldAttrs('doc_sous_titre', $pageClef, $strLang); ?>
|
|
value="<?php echo docEdEsc($isMod ? ($tabRow['doc_sous_titre'] ?? '') : ''); ?>">
|
|
</div>
|
|
<div class="doced-field">
|
|
<label>Contenu HTML <span class="doced-hint">(doc_html)</span></label>
|
|
<textarea class="doced-html" <?php echo docEdFieldAttrs('doc_html', $pageClef, $strLang); ?>><?php
|
|
echo docEdEsc($isMod ? ($tabRow['doc_html'] ?? '') : '');
|
|
?></textarea>
|
|
</div>
|
|
</div>
|
|
<?php } ?>
|
|
</div>
|
|
</section>
|
|
<?php } ?>
|
|
|
|
<?php if (empty($tabPages)) { ?>
|
|
<div class="doced-page-block">
|
|
<p>Aucune page pour ce module. Vérifiez que <code>doc_page</code> est peuplé pour
|
|
<strong><?php echo docEdEsc($modClef); ?></strong>.</p>
|
|
</div>
|
|
<?php } ?>
|
|
|
|
<div class="doced-actions">
|
|
<button type="submit" name="btn_mod" value="save" class="doced-btn-save">Enregistrer tout le guide</button>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</body>
|
|
</html>
|