362 lines
15 KiB
PHP
362 lines
15 KiB
PHP
<?php
|
||
/**
|
||
* MSIN-4512 — UI kit MS1 (chooser / ordre / apply-all / radios / fit).
|
||
* Rendu générique : pas de métier PDF ici. Les panneaux passent données + names.
|
||
*/
|
||
|
||
if (!function_exists('fxMs1UiEsc')) {
|
||
|
||
function fxMs1UiEsc($str) {
|
||
return htmlspecialchars((string)$str, ENT_QUOTES, 'UTF-8');
|
||
}
|
||
|
||
/**
|
||
* Marqueur kit — à poser sur le root de chaque écran migré.
|
||
* Recherche plus tard : data-ms1-ui-kit | MS1-UI-KIT | data-ms1-ui-screen
|
||
*
|
||
* @param array $tabCfg
|
||
* screen (ex. bib-dist-print) — id stable
|
||
* patterns (ex. 'P2,P3,P4' ou array)
|
||
* ticket (ex. MSIN-4512)
|
||
* class (classes CSS extra)
|
||
* @return string attributs HTML (sans balise) : class="…" data-…
|
||
*/
|
||
function fxMs1UiKitRootAttrs($tabCfg = []) {
|
||
$strScreen = trim((string)($tabCfg['screen'] ?? ''));
|
||
$strTicket = trim((string)($tabCfg['ticket'] ?? ''));
|
||
$mixPatterns = $tabCfg['patterns'] ?? '';
|
||
if (is_array($mixPatterns)) {
|
||
$strPatterns = implode(',', array_map('strval', $mixPatterns));
|
||
} else {
|
||
$strPatterns = trim((string)$mixPatterns);
|
||
}
|
||
$strExtraClass = trim((string)($tabCfg['class'] ?? ''));
|
||
$strClass = 'ms1-ui-chooser';
|
||
if ($strExtraClass !== '') {
|
||
$strClass .= ' ' . $strExtraClass;
|
||
}
|
||
|
||
$str = 'class="' . fxMs1UiEsc($strClass) . '" data-ms1-ui-kit="1"';
|
||
if ($strScreen !== '') {
|
||
$str .= ' data-ms1-ui-screen="' . fxMs1UiEsc($strScreen) . '"';
|
||
}
|
||
if ($strPatterns !== '') {
|
||
$str .= ' data-ms1-ui-patterns="' . fxMs1UiEsc($strPatterns) . '"';
|
||
}
|
||
if ($strTicket !== '') {
|
||
$str .= ' data-ms1-ui-ticket="' . fxMs1UiEsc($strTicket) . '"';
|
||
}
|
||
return $str;
|
||
}
|
||
|
||
/** Commentaire PHP à coller au-dessus du render (grep MS1-UI-KIT). */
|
||
function fxMs1UiKitPhpMarker($strScreen, $strPatterns, $strTicket = '') {
|
||
$str = '// MS1-UI-KIT — ' . $strScreen . ' — ' . $strPatterns;
|
||
if ($strTicket !== '') {
|
||
$str .= ' — ' . $strTicket;
|
||
}
|
||
return $str;
|
||
}
|
||
|
||
/**
|
||
* Bouton « Appliquer à toutes » (P4).
|
||
*
|
||
* @param array $tabCfg label, class (extra), attrs (string HTML attrs optionnel)
|
||
*/
|
||
function fxMs1UiRenderApplyAllButton($tabCfg = []) {
|
||
$strLabel = (string)($tabCfg['label'] ?? '');
|
||
$strExtra = trim((string)($tabCfg['class'] ?? ''));
|
||
$strAttrs = (string)($tabCfg['attrs'] ?? '');
|
||
$strClass = 'btn btn-outline-secondary btn-sm ms1-ui-chooser-apply-all';
|
||
if ($strExtra !== '') {
|
||
$strClass .= ' ' . $strExtra;
|
||
}
|
||
return '<button type="button" class="' . fxMs1UiEsc($strClass) . '"'
|
||
. ($strAttrs !== '' ? ' ' . $strAttrs : '')
|
||
. '>' . fxMs1UiEsc($strLabel) . '</button>';
|
||
}
|
||
|
||
/**
|
||
* Groupe de cases à cocher (P2).
|
||
*
|
||
* options[] : key, label, width (int optionnel), checked (bool), data (assoc attrs data-*)
|
||
*/
|
||
function fxMs1UiRenderChooserGroup($tabCfg = []) {
|
||
$strLabel = (string)($tabCfg['label'] ?? '');
|
||
$strLegendClass = (string)($tabCfg['legend_class'] ?? 'sr-only');
|
||
$tabOptions = $tabCfg['options'] ?? [];
|
||
if (!is_array($tabOptions)) {
|
||
$tabOptions = [];
|
||
}
|
||
|
||
ob_start();
|
||
?>
|
||
<fieldset class="ms1-ui-chooser-group">
|
||
<legend class="<?php echo fxMs1UiEsc($strLegendClass); ?>"><?php echo fxMs1UiEsc($strLabel); ?></legend>
|
||
<?php if ($strLabel !== '' && $strLegendClass === 'sr-only') { ?>
|
||
<span class="ms1-ui-chooser-group-label small text-muted d-block mb-1"><?php echo fxMs1UiEsc($strLabel); ?></span>
|
||
<?php } ?>
|
||
<ul class="ms1-ui-chooser-option-list list-unstyled mb-2">
|
||
<?php foreach ($tabOptions as $opt) {
|
||
$strKey = (string)($opt['key'] ?? '');
|
||
if ($strKey === '') {
|
||
continue;
|
||
}
|
||
$strOptLabel = (string)($opt['label'] ?? $strKey);
|
||
$intW = (int)($opt['width'] ?? 0);
|
||
$blnChecked = !empty($opt['checked']);
|
||
$tabData = is_array($opt['data'] ?? null) ? $opt['data'] : [];
|
||
?>
|
||
<li class="ms1-ui-chooser-option">
|
||
<label class="ms1-ui-chooser-option-label">
|
||
<input type="checkbox"
|
||
class="ms1-ui-chooser-cb"
|
||
value="<?php echo fxMs1UiEsc($strKey); ?>"
|
||
data-item-key="<?php echo fxMs1UiEsc($strKey); ?>"
|
||
data-item-label="<?php echo fxMs1UiEsc($strOptLabel); ?>"
|
||
<?php if ($intW > 0) { ?>data-item-width="<?php echo $intW; ?>"<?php } ?>
|
||
<?php
|
||
foreach ($tabData as $strDk => $strDv) {
|
||
echo ' data-' . fxMs1UiEsc(preg_replace('/[^a-z0-9_\-]/i', '', (string)$strDk))
|
||
. '="' . fxMs1UiEsc((string)$strDv) . '"';
|
||
}
|
||
?>
|
||
<?php echo $blnChecked ? 'checked' : ''; ?>>
|
||
<span><?php echo fxMs1UiEsc($strOptLabel); ?></span>
|
||
</label>
|
||
</li>
|
||
<?php } ?>
|
||
</ul>
|
||
</fieldset>
|
||
<?php
|
||
return ob_get_clean();
|
||
}
|
||
|
||
/**
|
||
* Liste d’ordre + ↑↓ (P3).
|
||
*
|
||
* selected[] : key, label, width ; input_name_tpl avec %s = section_id
|
||
*/
|
||
function fxMs1UiRenderChooserOrder($tabCfg = []) {
|
||
$strLabel = (string)($tabCfg['label'] ?? '');
|
||
$strEmpty = (string)($tabCfg['empty_label'] ?? '');
|
||
$strLabelUp = (string)($tabCfg['label_up'] ?? '');
|
||
$strLabelDown = (string)($tabCfg['label_down'] ?? '');
|
||
$strSectionId = (string)($tabCfg['section_id'] ?? '');
|
||
$strInputNameTpl = (string)($tabCfg['input_name_tpl'] ?? 'items[%s][]');
|
||
$tabSelected = $tabCfg['selected'] ?? [];
|
||
if (!is_array($tabSelected)) {
|
||
$tabSelected = [];
|
||
}
|
||
|
||
$strInputName = sprintf($strInputNameTpl, $strSectionId);
|
||
$blnAny = false;
|
||
|
||
ob_start();
|
||
?>
|
||
<div class="ms1-ui-chooser-order-wrap">
|
||
<?php if ($strLabel !== '') { ?>
|
||
<span class="ms1-ui-chooser-group-label small text-muted d-block mb-1"><?php echo fxMs1UiEsc($strLabel); ?></span>
|
||
<?php } ?>
|
||
<ol class="ms1-ui-chooser-order list-unstyled mb-0"
|
||
data-section-id="<?php echo fxMs1UiEsc($strSectionId); ?>"
|
||
data-input-name="<?php echo fxMs1UiEsc($strInputName); ?>">
|
||
<?php foreach ($tabSelected as $opt) {
|
||
$strKey = (string)($opt['key'] ?? '');
|
||
if ($strKey === '') {
|
||
continue;
|
||
}
|
||
$blnAny = true;
|
||
$strOptLabel = (string)($opt['label'] ?? $strKey);
|
||
$intW = (int)($opt['width'] ?? 0);
|
||
echo fxMs1UiRenderChooserOrderItem([
|
||
'key' => $strKey,
|
||
'label' => $strOptLabel,
|
||
'width' => $intW,
|
||
'input_name' => $strInputName,
|
||
'label_up' => $strLabelUp,
|
||
'label_down' => $strLabelDown,
|
||
]);
|
||
} ?>
|
||
</ol>
|
||
<p class="ms1-ui-chooser-order-empty text-muted small mb-0"<?php echo $blnAny ? ' hidden' : ''; ?>>
|
||
<?php echo fxMs1UiEsc($strEmpty); ?>
|
||
</p>
|
||
</div>
|
||
<?php
|
||
return ob_get_clean();
|
||
}
|
||
|
||
/** Une ligne d’ordre (PHP initial + miroir JS). */
|
||
function fxMs1UiRenderChooserOrderItem($tabCfg = []) {
|
||
$strKey = (string)($tabCfg['key'] ?? '');
|
||
$strLabel = (string)($tabCfg['label'] ?? $strKey);
|
||
$intW = (int)($tabCfg['width'] ?? 0);
|
||
$strInputName = (string)($tabCfg['input_name'] ?? '');
|
||
$strLabelUp = (string)($tabCfg['label_up'] ?? '');
|
||
$strLabelDown = (string)($tabCfg['label_down'] ?? '');
|
||
|
||
ob_start();
|
||
?>
|
||
<li class="ms1-ui-chooser-order-item"
|
||
data-item-key="<?php echo fxMs1UiEsc($strKey); ?>"
|
||
<?php if ($intW > 0) { ?>data-item-width="<?php echo $intW; ?>"<?php } ?>>
|
||
<span class="ms1-ui-chooser-order-label"><?php echo fxMs1UiEsc($strLabel); ?></span>
|
||
<span class="ms1-ui-chooser-order-actions">
|
||
<button type="button"
|
||
class="btn btn-link btn-sm p-0 ms1-ui-chooser-order-up"
|
||
title="<?php echo fxMs1UiEsc($strLabelUp); ?>"
|
||
aria-label="<?php echo fxMs1UiEsc($strLabelUp); ?>">
|
||
<i class="fa fa-chevron-up" aria-hidden="true"></i>
|
||
</button>
|
||
<button type="button"
|
||
class="btn btn-link btn-sm p-0 ms1-ui-chooser-order-down"
|
||
title="<?php echo fxMs1UiEsc($strLabelDown); ?>"
|
||
aria-label="<?php echo fxMs1UiEsc($strLabelDown); ?>">
|
||
<i class="fa fa-chevron-down" aria-hidden="true"></i>
|
||
</button>
|
||
</span>
|
||
<?php if ($strInputName !== '') { ?>
|
||
<input type="hidden" name="<?php echo fxMs1UiEsc($strInputName); ?>" value="<?php echo fxMs1UiEsc($strKey); ?>">
|
||
<?php } ?>
|
||
</li>
|
||
<?php
|
||
return ob_get_clean();
|
||
}
|
||
|
||
/**
|
||
* Radios exclusifs (P5) — ex. Portrait / Paysage.
|
||
*
|
||
* options[] : value, label, checked
|
||
*/
|
||
function fxMs1UiRenderRadios($tabCfg = []) {
|
||
$strName = (string)($tabCfg['name'] ?? 'ms1_ui_radio');
|
||
$strLegend = (string)($tabCfg['legend'] ?? '');
|
||
$strLegendHtml = (string)($tabCfg['legend_html'] ?? ''); // déjà échappé / aide
|
||
$strHint = (string)($tabCfg['hint'] ?? '');
|
||
$strRadioClass = trim((string)($tabCfg['radio_class'] ?? ''));
|
||
$tabOptions = $tabCfg['options'] ?? [];
|
||
if (!is_array($tabOptions)) {
|
||
$tabOptions = [];
|
||
}
|
||
|
||
ob_start();
|
||
?>
|
||
<fieldset class="ms1-ui-chooser-radios mb-3">
|
||
<legend class="ms1-ui-chooser-radios-legend">
|
||
<?php
|
||
if ($strLegendHtml !== '') {
|
||
echo $strLegendHtml;
|
||
} else {
|
||
echo fxMs1UiEsc($strLegend);
|
||
}
|
||
?>
|
||
</legend>
|
||
<?php foreach ($tabOptions as $opt) {
|
||
$strVal = (string)($opt['value'] ?? '');
|
||
$strOptLabel = (string)($opt['label'] ?? $strVal);
|
||
$blnChecked = !empty($opt['checked']);
|
||
$strCbClass = 'ms1-ui-chooser-radio';
|
||
if ($strRadioClass !== '') {
|
||
$strCbClass .= ' ' . $strRadioClass;
|
||
}
|
||
?>
|
||
<label class="ms1-ui-chooser-radios-opt mr-3">
|
||
<input type="radio"
|
||
class="<?php echo fxMs1UiEsc($strCbClass); ?>"
|
||
name="<?php echo fxMs1UiEsc($strName); ?>"
|
||
value="<?php echo fxMs1UiEsc($strVal); ?>"
|
||
<?php echo $blnChecked ? 'checked' : ''; ?>>
|
||
<span><?php echo fxMs1UiEsc($strOptLabel); ?></span>
|
||
</label>
|
||
<?php } ?>
|
||
<?php if ($strHint !== '') { ?>
|
||
<p class="text-muted small mb-1 mt-1"><?php echo fxMs1UiEsc($strHint); ?></p>
|
||
<?php } ?>
|
||
</fieldset>
|
||
<?php
|
||
return ob_get_clean();
|
||
}
|
||
|
||
/**
|
||
* Feedback contrainte budget (P6) — hint + status + warn.
|
||
*/
|
||
function fxMs1UiRenderFitFeedback($tabCfg = []) {
|
||
$strHint = (string)($tabCfg['hint'] ?? '');
|
||
$strHintTpl = (string)($tabCfg['hint_tpl'] ?? '');
|
||
$strStatusClass = 'ms1-ui-chooser-fit-status small mb-0';
|
||
$strWarnClass = 'ms1-ui-chooser-fit-warn text-danger small mb-0';
|
||
|
||
ob_start();
|
||
?>
|
||
<?php if ($strHint !== '' || $strHintTpl !== '') { ?>
|
||
<p class="ms1-ui-chooser-fit-hint text-muted small mb-0"
|
||
data-hint-tpl="<?php echo fxMs1UiEsc($strHintTpl !== '' ? $strHintTpl : $strHint); ?>">
|
||
<?php echo fxMs1UiEsc($strHint); ?>
|
||
</p>
|
||
<?php } ?>
|
||
<p class="<?php echo fxMs1UiEsc($strStatusClass); ?>" aria-live="polite"></p>
|
||
<p class="<?php echo fxMs1UiEsc($strWarnClass); ?>" hidden></p>
|
||
<?php
|
||
return ob_get_clean();
|
||
}
|
||
|
||
/**
|
||
* Section chooser complète (titre + apply-all + groupes + ordre).
|
||
*
|
||
* @param array $tabCfg
|
||
* section_id, title, title_suffix_html, apply_all (label|false),
|
||
* groups[], order{}, class (extra sur section)
|
||
*/
|
||
function fxMs1UiRenderChooserSection($tabCfg = []) {
|
||
$strSectionId = (string)($tabCfg['section_id'] ?? '');
|
||
$strTitle = (string)($tabCfg['title'] ?? '');
|
||
$strTitleSuffix = (string)($tabCfg['title_suffix_html'] ?? '');
|
||
$strExtraClass = trim((string)($tabCfg['class'] ?? ''));
|
||
$tabApply = $tabCfg['apply_all'] ?? null;
|
||
$tabGroups = $tabCfg['groups'] ?? [];
|
||
$tabOrder = $tabCfg['order'] ?? null;
|
||
$strAfterGroupsHtml = (string)($tabCfg['after_groups_html'] ?? '');
|
||
|
||
$strClass = 'ms1-ui-chooser-section';
|
||
if ($strExtraClass !== '') {
|
||
$strClass .= ' ' . $strExtraClass;
|
||
}
|
||
|
||
ob_start();
|
||
?>
|
||
<section class="<?php echo fxMs1UiEsc($strClass); ?>" data-section-id="<?php echo fxMs1UiEsc($strSectionId); ?>">
|
||
<div class="ms1-ui-chooser-section-head">
|
||
<h3 class="ms1-ui-chooser-section-title">
|
||
<?php echo fxMs1UiEsc($strTitle); ?>
|
||
<?php echo $strTitleSuffix; ?>
|
||
</h3>
|
||
<?php
|
||
if (is_array($tabApply) && !empty($tabApply['label'])) {
|
||
echo fxMs1UiRenderApplyAllButton($tabApply);
|
||
}
|
||
?>
|
||
</div>
|
||
<div class="ms1-ui-chooser-section-body">
|
||
<?php
|
||
if (is_array($tabGroups)) {
|
||
foreach ($tabGroups as $tabGroup) {
|
||
if (!is_array($tabGroup)) {
|
||
continue;
|
||
}
|
||
echo fxMs1UiRenderChooserGroup($tabGroup);
|
||
}
|
||
}
|
||
echo $strAfterGroupsHtml;
|
||
if (is_array($tabOrder)) {
|
||
$tabOrder['section_id'] = $strSectionId;
|
||
echo fxMs1UiRenderChooserOrder($tabOrder);
|
||
}
|
||
?>
|
||
</div>
|
||
</section>
|
||
<?php
|
||
return ob_get_clean();
|
||
}
|
||
}
|