MSIN-4435 Add inc_v2_assets.php integration across multiple files
This commit integrates the `inc_v2_assets.php` file into several PHP scripts, including `compte.php`, `inc_footer.php`, `inc_tableau_gestion_epreuves.php`, `inc_tableau_inscriptions_gestion.php`, and `mobile.php`. Additionally, it registers new scripts for improved functionality in the `inscriptions gestion` context. The version code is incremented to reflect these updates, aiming to enhance asset management and script handling across the application.
This commit is contained in:
31
.cursor/rules/ms1-v2.mdc
Normal file
31
.cursor/rules/ms1-v2.mdc
Normal file
@ -0,0 +1,31 @@
|
||||
---
|
||||
description: MS1 modules v2 — bib v4 et gestion inscriptions (hors legacy)
|
||||
globs: js/v2/**,php/inc_v2_assets.php,inc_tableau_gestion_epreuves.php,inc_tableau_inscriptions_gestion.php,ajax_bib_range.php,ajax_inscr_gestion.php,php/inc_fx_promoteur.php,php/inc_fx_inscriptions_gestion.php
|
||||
alwaysApply: false
|
||||
---
|
||||
|
||||
# Modules v2 MS1
|
||||
|
||||
## Périmètre v2 (non prod, développement actif)
|
||||
|
||||
- **Bib assignments v4** — `#module-bib`, `fxShowBibTool4`, `ajax_bib_range.php`
|
||||
- **Gestion inscriptions v2** — `#module-inscr-gestion`, `inc_fx_inscriptions_gestion.php`, `ajax_inscr_gestion.php`
|
||||
|
||||
## Règle JS
|
||||
|
||||
- **Ne jamais** ajouter de code v2 dans `inc_footer_scripts.php`.
|
||||
- Nouveau JS v2 → `js/v2/` (fichier existant ou nouveau selon le module).
|
||||
- Enregistrer le script sur la page concernée : `fxV2RegisterScript('bib-assignments')` ou `'inscr-gestion'`.
|
||||
- Config PHP → JS : `data-*` sur le module (bib) ou `window.MS1_V2_INSCR_GESTION` (inscr).
|
||||
|
||||
## Legacy (ne pas toucher sauf pont minimal)
|
||||
|
||||
- `.btn_bib` jQuery, `fxShowBibTool2/3`, `inc_tableau_dossards.php`
|
||||
|
||||
## Fichiers de référence
|
||||
|
||||
| Rôle | Fichier |
|
||||
|------|---------|
|
||||
| Enregistrement / rendu scripts | `php/inc_v2_assets.php` |
|
||||
| Bib v4 client | `js/v2/bib-assignments.js` |
|
||||
| Inscr gestion client | `js/v2/inscr-gestion.js` |
|
||||
@ -22,6 +22,7 @@ require_once('superadm/php/inc_fx_excell.php');
|
||||
|
||||
require_once('php/inc_fx_liste_attente.php');
|
||||
require_once('php/inc_fx_inscriptions_gestion.php');
|
||||
require_once('php/inc_v2_assets.php');
|
||||
require_once('php/inc_fx_eve_acces.php');
|
||||
require_once('php/inc_fx_promoteur_hub.php');
|
||||
global $objDatabase, $vPage, $vDomaine;
|
||||
|
||||
@ -369,6 +369,10 @@ if (isset($tabEvenement) && $tabEvenement['general']['eve_commanditaires'] == "1
|
||||
</div>
|
||||
|
||||
<?php require_once 'inc_footer_scripts.php'; ?>
|
||||
<?php
|
||||
require_once __DIR__ . '/php/inc_v2_assets.php';
|
||||
fxV2RenderFooterScripts();
|
||||
?>
|
||||
|
||||
<script src="<?php echo $vDomaine; ?>/js/cookie-consent.js?version=v<?php echo _VERSION_CODE; ?>"></script>
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -4,6 +4,7 @@
|
||||
include_once("php/inc_fx_modifierinscriptions.php");
|
||||
include_once("php/inc_fx_memberships.php");
|
||||
include_once("php/inc_fx_promoteur.php");
|
||||
require_once('php/inc_v2_assets.php');
|
||||
require_once('php/inc_fx_eve_acces.php');
|
||||
require_once('superadm/php/inc_manager.php');
|
||||
|
||||
@ -63,6 +64,7 @@ if (isset($_POST['btn_cancel_event_promo'])) {
|
||||
|
||||
|
||||
<?php
|
||||
fxV2RegisterScript('bib-assignments');
|
||||
fxShowBibTool4($strBibCode, $intEveId, $strLangue);
|
||||
?>
|
||||
<link rel="stylesheet" href="<?php echo $vDomaine; ?>/libs/tippy.js-6.3.7/tippy.css">
|
||||
|
||||
@ -5,6 +5,7 @@ include_once('php/inc_fx_modifierinscriptions.php');
|
||||
include_once('php/inc_fx_memberships.php');
|
||||
include_once('php/inc_fx_promoteur.php');
|
||||
include_once('php/inc_fx_inscriptions_gestion.php');
|
||||
require_once('php/inc_v2_assets.php');
|
||||
require_once('superadm/php/inc_manager.php');
|
||||
|
||||
global $objDatabase, $vDomaine, $strLangue;
|
||||
@ -24,5 +25,6 @@ if ($intEveId === 0) {
|
||||
}
|
||||
|
||||
echo '<div class="inscr-gestion-page">';
|
||||
fxV2RegisterScript('inscr-gestion');
|
||||
fxInscrGestionRun($intEveId, $strLangue);
|
||||
echo '</div>';
|
||||
|
||||
1994
js/v2/bib-assignments.js
Normal file
1994
js/v2/bib-assignments.js
Normal file
File diff suppressed because it is too large
Load Diff
895
js/v2/inscr-gestion.js
Normal file
895
js/v2/inscr-gestion.js
Normal file
@ -0,0 +1,895 @@
|
||||
/**
|
||||
* MSIN-4435 — Gestion inscriptions v2
|
||||
* Chargé sur inc_tableau_inscriptions_gestion et mobile.php (entrée gestion).
|
||||
*/
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
var cfg = window.MS1_V2_INSCR_GESTION || {};
|
||||
|
||||
function ms1LoaderInlineHtml() {
|
||||
if (window.Ms1Loader) {
|
||||
return Ms1Loader.inlineHtml(cfg.preloaderWait || undefined);
|
||||
}
|
||||
return '<div class="inscr-gestion-muted" style="padding:10px;">…</div>';
|
||||
}
|
||||
|
||||
if (typeof jQuery !== 'undefined') {
|
||||
jQuery(function ($) {
|
||||
if ($('#frm_inscr_gestion_login').length && cfg.loginMessages) {
|
||||
$('#frm_inscr_gestion_login').validate({
|
||||
messages: {
|
||||
txt_login: cfg.loginMessages.txt_login || '',
|
||||
txt_password: cfg.loginMessages.txt_password || ''
|
||||
},
|
||||
submitHandler: function (form) {
|
||||
if (window.Ms1Loader) {
|
||||
Ms1Loader.show(cfg.preloaderWait || undefined);
|
||||
} else {
|
||||
$('#preloader').show();
|
||||
}
|
||||
form.submit();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var $body = $('body');
|
||||
var $preloader = $('#preloader');
|
||||
var $preloader_text = $('#preloader_text');
|
||||
|
||||
(function () {
|
||||
var pendingStatutXhr = null;
|
||||
var lastStatutParId = null;
|
||||
|
||||
$('.inscr-gestion-statut-select').each(function () {
|
||||
$(this).data('prev', $(this).val());
|
||||
});
|
||||
|
||||
$body.on('change', '.inscr-gestion-statut-select', function () {
|
||||
var $select = $(this);
|
||||
var $block = $select.closest('.inscr-gestion-field-block--statut');
|
||||
var intParId = $select.data('par_id');
|
||||
var strCode = $select.val();
|
||||
var strPrev = $select.data('prev');
|
||||
|
||||
if (!intParId || !strCode) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (pendingStatutXhr && lastStatutParId === intParId) {
|
||||
pendingStatutXhr.abort();
|
||||
}
|
||||
lastStatutParId = intParId;
|
||||
$block.removeClass('inscr-gestion-statut--saved inscr-gestion-statut--error');
|
||||
|
||||
$preloader_text.html(cfg.preloaderWait || '');
|
||||
$preloader.show();
|
||||
|
||||
pendingStatutXhr = $.post((cfg.domain || '') + '/ajax_inscr_gestion.php', {
|
||||
a: 'par_statut_course',
|
||||
par_id: intParId,
|
||||
par_statut_course: strCode,
|
||||
lang: cfg.lang || 'fr'
|
||||
}, function (result) {
|
||||
pendingStatutXhr = null;
|
||||
$preloader.fadeOut('slow');
|
||||
if (result && result.state === 'success') {
|
||||
$select.data('prev', strCode);
|
||||
$block.addClass('inscr-gestion-statut--saved');
|
||||
window.setTimeout(function () {
|
||||
$block.removeClass('inscr-gestion-statut--saved');
|
||||
}, 1200);
|
||||
} else {
|
||||
$select.val(strPrev);
|
||||
$block.addClass('inscr-gestion-statut--error');
|
||||
}
|
||||
}, 'json').fail(function () {
|
||||
pendingStatutXhr = null;
|
||||
$preloader.fadeOut('slow');
|
||||
$select.val(strPrev);
|
||||
$block.addClass('inscr-gestion-statut--error');
|
||||
});
|
||||
});
|
||||
})();
|
||||
|
||||
(function () {
|
||||
var refundCancelHint = cfg.refundCancelHint || '';
|
||||
|
||||
function onRefundSuccess(form, json) {
|
||||
var $form = $(form);
|
||||
|
||||
if (json && json.new_token) {
|
||||
$form.find('input[name="refund_token"]').val(json.new_token);
|
||||
}
|
||||
|
||||
var amount = parseFloat($form.find('input[name="refund_amount"]').val()) || 0;
|
||||
var $max = $('#pp_ref_max');
|
||||
var oldMax = parseFloat(String($max.text() || '0').replace(',', '.')) || 0;
|
||||
var newMax = Math.max(0, oldMax - amount);
|
||||
$max.text(newMax.toFixed(2));
|
||||
|
||||
var $amountInput = $('#pp_ref_amount');
|
||||
$amountInput.attr('max', newMax.toFixed(2));
|
||||
if (newMax <= 0) {
|
||||
$amountInput.val('0.00').prop('disabled', true);
|
||||
$form.find('button[type="submit"]').prop('disabled', true);
|
||||
} else {
|
||||
$amountInput.val(newMax.toFixed(2));
|
||||
}
|
||||
|
||||
var $cancelBtn = $('#annuler_fiche');
|
||||
if ($cancelBtn.length && $cancelBtn.is(':visible')) {
|
||||
if (!$('#inscr-gestion-refund-cancel-hint').length) {
|
||||
var $hint = $('<div id="inscr-gestion-refund-cancel-hint" style="margin-top:8px;padding:10px;border:1px solid #ffe1a6;background:#fff8e6;border-radius:8px;font-size:13px;display:flex;align-items:center;flex-wrap:wrap;gap:10px;"></div>');
|
||||
$hint.append($('<span></span>').text(refundCancelHint));
|
||||
$hint.append(
|
||||
$('<button type="button" class="btn btn-danger btn-sm rounded-0"></button>')
|
||||
.text($.trim($cancelBtn.text()))
|
||||
.on('click', function () { $cancelBtn.trigger('click'); })
|
||||
);
|
||||
$hint.insertAfter($('#inscr-gestion-refund-panel'));
|
||||
}
|
||||
$cancelBtn.addClass('d-none');
|
||||
}
|
||||
}
|
||||
|
||||
$(document).on('click', '.btn_refund_toggle', function () {
|
||||
var $btn = $(this);
|
||||
var $panel = $($btn.attr('data-refund-target') || '#inscr-gestion-refund-panel');
|
||||
if (!$panel.length) { return; }
|
||||
|
||||
if (!$panel.prop('hidden')) {
|
||||
$panel.prop('hidden', true);
|
||||
$btn.attr('aria-expanded', 'false');
|
||||
return;
|
||||
}
|
||||
|
||||
$panel.prop('hidden', false);
|
||||
$btn.attr('aria-expanded', 'true');
|
||||
|
||||
function focusRefundPanel() {
|
||||
if ($panel[0] && $panel[0].scrollIntoView) {
|
||||
$panel[0].scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||||
}
|
||||
var $amount = $panel.find('#pp_ref_amount');
|
||||
if ($amount.length && !$amount.prop('disabled')) {
|
||||
$amount.trigger('focus').trigger('select');
|
||||
}
|
||||
}
|
||||
|
||||
if ($panel.attr('data-loaded') === '1') { focusRefundPanel(); return; }
|
||||
|
||||
$panel.html(ms1LoaderInlineHtml());
|
||||
$.post((cfg.domain || '') + '/ajax_inscr_gestion.php', {
|
||||
a: 'refund_form',
|
||||
no_panier: $btn.data('no_panier'),
|
||||
eve_id: $btn.data('eve_id'),
|
||||
lang: cfg.lang || 'fr'
|
||||
}, function (result) {
|
||||
if (result && result.state === 'ok' && result.html) {
|
||||
$panel.html(result.html);
|
||||
$panel.attr('data-loaded', '1');
|
||||
focusRefundPanel();
|
||||
} else {
|
||||
$panel.html('<div style="background:#feecec;border:1px solid #f2b8b5;padding:10px;border-radius:8px;">\u26a0\ufe0f ' + ((result && result.message) || 'Erreur de chargement.') + '</div>');
|
||||
}
|
||||
}, 'json').fail(function () {
|
||||
$panel.html('<div style="background:#feecec;border:1px solid #f2b8b5;padding:10px;border-radius:8px;">\u26a0\ufe0f Erreur reseau.</div>');
|
||||
});
|
||||
});
|
||||
|
||||
$(document).on('click', '.btn_transaction_toggle', function () {
|
||||
var $btn = $(this);
|
||||
var $panel = $($btn.attr('data-transaction-target') || '#inscr-gestion-transaction-panel');
|
||||
if (!$panel.length) { return; }
|
||||
|
||||
var strShow = $btn.data('label-show');
|
||||
var strHide = $btn.data('label-hide');
|
||||
|
||||
if (!$panel.prop('hidden')) {
|
||||
$panel.prop('hidden', true);
|
||||
$btn.attr('aria-expanded', 'false');
|
||||
if (strShow) { $btn.text(strShow); }
|
||||
return;
|
||||
}
|
||||
|
||||
$panel.prop('hidden', false);
|
||||
$btn.attr('aria-expanded', 'true');
|
||||
if (strHide) { $btn.text(strHide); }
|
||||
|
||||
if ($panel.attr('data-loaded') === '1') { return; }
|
||||
|
||||
$panel.html(ms1LoaderInlineHtml());
|
||||
$.post((cfg.domain || '') + '/ajax_inscr_gestion.php', {
|
||||
a: 'transaction_resume',
|
||||
no_panier: $btn.data('no_panier'),
|
||||
lang: cfg.lang || 'fr'
|
||||
}, function (result) {
|
||||
if (result && result.state === 'ok' && result.html) {
|
||||
$panel.html(result.html);
|
||||
$panel.attr('data-loaded', '1');
|
||||
} else {
|
||||
$panel.html('<div style="background:#feecec;border:1px solid #f2b8b5;padding:10px;border-radius:8px;">\u26a0\ufe0f ' + ((result && result.message) || 'Erreur de chargement.') + '</div>');
|
||||
}
|
||||
}, 'json').fail(function () {
|
||||
$panel.html('<div style="background:#feecec;border:1px solid #f2b8b5;padding:10px;border-radius:8px;">\u26a0\ufe0f Erreur reseau.</div>');
|
||||
});
|
||||
});
|
||||
|
||||
$(document).on('submit', '#refund-form', function (e) {
|
||||
e.preventDefault();
|
||||
var form = this;
|
||||
var url = form.getAttribute('data-refund-url');
|
||||
var $msg = $('#refund-msg');
|
||||
|
||||
function showMsg(text, ok) {
|
||||
$msg.css({
|
||||
display: 'block',
|
||||
background: ok ? '#e9f8ef' : '#feecec',
|
||||
border: ok ? '1px solid #b8e3c5' : '1px solid #f2b8b5'
|
||||
}).text(text);
|
||||
}
|
||||
|
||||
showMsg('\u23f3 Traitement en cours...', false);
|
||||
if (window.Ms1Loader) {
|
||||
Ms1Loader.show(cfg.preloaderWait || undefined);
|
||||
}
|
||||
|
||||
fetch(url, { method: 'POST', body: new FormData(form) })
|
||||
.then(function (res) {
|
||||
if (!res.ok) { throw new Error('network'); }
|
||||
return res.json();
|
||||
})
|
||||
.then(function (json) {
|
||||
if (window.Ms1Loader) {
|
||||
Ms1Loader.hide();
|
||||
}
|
||||
if (json && json.success) {
|
||||
showMsg('\u2705 ' + (json.message || 'Remboursement effectue.'), true);
|
||||
onRefundSuccess(form, json);
|
||||
} else {
|
||||
showMsg('\u26a0\ufe0f ' + ((json && json.message) || 'Erreur remboursement.'), false);
|
||||
}
|
||||
})
|
||||
.catch(function () {
|
||||
if (window.Ms1Loader) {
|
||||
Ms1Loader.hide();
|
||||
}
|
||||
showMsg('\u26a0\ufe0f Erreur reseau pendant le remboursement.', false);
|
||||
});
|
||||
});
|
||||
})();
|
||||
});
|
||||
}
|
||||
(function () {
|
||||
var qrPanel = document.getElementById('inscr-gestion-qr-panel');
|
||||
if (!qrPanel) {
|
||||
return;
|
||||
}
|
||||
|
||||
var qrReaderEl = document.getElementById('inscr-gestion-qr-reader');
|
||||
var qrFeedback = document.getElementById('inscr-gestion-qr-feedback');
|
||||
var qrCamera = null;
|
||||
var qrStarting = false;
|
||||
var lastQrRaw = '';
|
||||
var qrResolvePending = false;
|
||||
var qrLibPromise = null;
|
||||
|
||||
function loadHtml5Qrcode() {
|
||||
if (window.Html5Qrcode) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
if (qrLibPromise) {
|
||||
return qrLibPromise;
|
||||
}
|
||||
qrLibPromise = new Promise(function (resolve, reject) {
|
||||
var script = document.createElement('script');
|
||||
script.src = 'https://unpkg.com/html5-qrcode@2.3.8/html5-qrcode.min.js';
|
||||
script.onload = function () { resolve(); };
|
||||
script.onerror = function () {
|
||||
qrLibPromise = null;
|
||||
reject(new Error('load'));
|
||||
};
|
||||
document.head.appendChild(script);
|
||||
});
|
||||
return qrLibPromise;
|
||||
}
|
||||
|
||||
function showQrFeedback(type, message) {
|
||||
if (!qrFeedback) {
|
||||
return;
|
||||
}
|
||||
qrFeedback.className = 'alert mb-2 alert-' + type;
|
||||
qrFeedback.textContent = message;
|
||||
qrFeedback.classList.remove('d-none');
|
||||
}
|
||||
|
||||
function hideQrFeedback() {
|
||||
if (!qrFeedback) {
|
||||
return;
|
||||
}
|
||||
qrFeedback.classList.add('d-none');
|
||||
qrFeedback.textContent = '';
|
||||
}
|
||||
|
||||
function stopQrScanner() {
|
||||
if (!qrCamera) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
var instance = qrCamera;
|
||||
qrCamera = null;
|
||||
return instance.stop().catch(function () {
|
||||
return null;
|
||||
}).then(function () {
|
||||
try {
|
||||
instance.clear();
|
||||
} catch (e) {
|
||||
/* ignore */
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function startQrScanner() {
|
||||
if (qrStarting || qrCamera || !qrReaderEl || !qrPanel.open) {
|
||||
return;
|
||||
}
|
||||
qrStarting = true;
|
||||
hideQrFeedback();
|
||||
lastQrRaw = '';
|
||||
|
||||
loadHtml5Qrcode().then(function () {
|
||||
if (!qrPanel.open) {
|
||||
qrStarting = false;
|
||||
return;
|
||||
}
|
||||
var config = window.Html5QrcodeSupportedFormats
|
||||
? {formatsToSupport: [Html5QrcodeSupportedFormats.QR_CODE]}
|
||||
: undefined;
|
||||
qrCamera = new Html5Qrcode('inscr-gestion-qr-reader', config);
|
||||
return qrCamera.start(
|
||||
{facingMode: 'environment'},
|
||||
{fps: 8, qrbox: {width: 220, height: 220}},
|
||||
onQrDecoded
|
||||
);
|
||||
}).catch(function () {
|
||||
showQrFeedback('danger', qrPanel.getAttribute('data-qr-msg-camera') || '');
|
||||
}).then(function () {
|
||||
qrStarting = false;
|
||||
});
|
||||
}
|
||||
|
||||
function onQrDecoded(decodedText) {
|
||||
if (!decodedText || decodedText === lastQrRaw || qrResolvePending) {
|
||||
return;
|
||||
}
|
||||
lastQrRaw = decodedText;
|
||||
qrResolvePending = true;
|
||||
|
||||
var resolveUrl = qrPanel.getAttribute('data-qr-resolve-url');
|
||||
var eveId = qrPanel.getAttribute('data-qr-eve-id');
|
||||
var lang = qrPanel.getAttribute('data-qr-lang') || 'fr';
|
||||
if (!resolveUrl || !eveId) {
|
||||
qrResolvePending = false;
|
||||
return;
|
||||
}
|
||||
|
||||
var body = new URLSearchParams();
|
||||
body.set('qr', decodedText);
|
||||
body.set('promoteur_eve_id', eveId);
|
||||
body.set('lang', lang);
|
||||
|
||||
fetch(resolveUrl, {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'},
|
||||
body: body.toString(),
|
||||
credentials: 'same-origin'
|
||||
}).then(function (response) {
|
||||
return response.json();
|
||||
}).then(function (data) {
|
||||
qrResolvePending = false;
|
||||
if (!data || !data.state) {
|
||||
showQrFeedback('danger', qrPanel.getAttribute('data-qr-msg-invalid') || '');
|
||||
window.setTimeout(function () { lastQrRaw = ''; }, 2000);
|
||||
return;
|
||||
}
|
||||
if (data.state === 'success' && data.pec_id) {
|
||||
stopQrScanner().then(function () {
|
||||
var url = new URL(window.location.href);
|
||||
url.searchParams.set('pec_id', String(data.pec_id));
|
||||
url.searchParams.set('from_qr', '1');
|
||||
window.location.href = url.toString();
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (data.state === 'wrong_event') {
|
||||
var wrongTpl = qrPanel.getAttribute('data-qr-msg-wrong') || '';
|
||||
showQrFeedback('warning', data.message || wrongTpl.replace('%s', data.eve_nom || ''));
|
||||
window.setTimeout(function () { lastQrRaw = ''; }, 2500);
|
||||
return;
|
||||
}
|
||||
showQrFeedback('danger', data.message || qrPanel.getAttribute('data-qr-msg-invalid') || '');
|
||||
window.setTimeout(function () { lastQrRaw = ''; }, 2000);
|
||||
}).catch(function () {
|
||||
qrResolvePending = false;
|
||||
showQrFeedback('danger', qrPanel.getAttribute('data-qr-msg-invalid') || '');
|
||||
window.setTimeout(function () { lastQrRaw = ''; }, 2000);
|
||||
});
|
||||
}
|
||||
|
||||
qrPanel.addEventListener('toggle', function () {
|
||||
if (qrPanel.open) {
|
||||
startQrScanner();
|
||||
} else {
|
||||
stopQrScanner();
|
||||
hideQrFeedback();
|
||||
lastQrRaw = '';
|
||||
qrResolvePending = false;
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
|
||||
(function () {
|
||||
var BIB_MAX_LEN = 6;
|
||||
var OCR_MAX_WIDTH = 320;
|
||||
var tesseractPromise = null;
|
||||
var globalOcrWorker = null;
|
||||
var globalOcrWorkerPromise = null;
|
||||
var activeScan = null;
|
||||
|
||||
function loadTesseract() {
|
||||
if (window.Tesseract) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
if (tesseractPromise) {
|
||||
return tesseractPromise;
|
||||
}
|
||||
tesseractPromise = new Promise(function (resolve, reject) {
|
||||
var script = document.createElement('script');
|
||||
script.src = 'https://cdn.jsdelivr.net/npm/tesseract.js@5/dist/tesseract.min.js';
|
||||
script.onload = function () { resolve(); };
|
||||
script.onerror = function () {
|
||||
tesseractPromise = null;
|
||||
reject(new Error('load'));
|
||||
};
|
||||
document.head.appendChild(script);
|
||||
});
|
||||
return tesseractPromise;
|
||||
}
|
||||
|
||||
function getGlobalOcrWorker() {
|
||||
if (globalOcrWorker) {
|
||||
return Promise.resolve(globalOcrWorker);
|
||||
}
|
||||
if (globalOcrWorkerPromise) {
|
||||
return globalOcrWorkerPromise;
|
||||
}
|
||||
globalOcrWorkerPromise = loadTesseract().then(function () {
|
||||
return Tesseract.createWorker('eng');
|
||||
}).then(function (worker) {
|
||||
globalOcrWorker = worker;
|
||||
var params = {tessedit_char_whitelist: '0123456789'};
|
||||
if (window.Tesseract && Tesseract.PSM && Tesseract.PSM.SINGLE_LINE) {
|
||||
params.tessedit_pageseg_mode = Tesseract.PSM.SINGLE_LINE;
|
||||
}
|
||||
return worker.setParameters(params).then(function () {
|
||||
return globalOcrWorker;
|
||||
});
|
||||
}).catch(function (err) {
|
||||
globalOcrWorkerPromise = null;
|
||||
throw err;
|
||||
});
|
||||
return globalOcrWorkerPromise;
|
||||
}
|
||||
|
||||
function preloadOcrWorker() {
|
||||
return getGlobalOcrWorker().catch(function () {
|
||||
/* ignore preload errors */
|
||||
});
|
||||
}
|
||||
|
||||
function extractBibNumber(raw) {
|
||||
var matches = String(raw || '').match(/\d+/g);
|
||||
if (!matches || !matches.length) {
|
||||
return '';
|
||||
}
|
||||
if (matches.length > 1) {
|
||||
return '';
|
||||
}
|
||||
var num = matches[0];
|
||||
if (num.length < 1 || num.length > BIB_MAX_LEN) {
|
||||
return '';
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
function captureCenterFrame(videoEl) {
|
||||
if (!videoEl || !videoEl.videoWidth) {
|
||||
return null;
|
||||
}
|
||||
var w = videoEl.videoWidth;
|
||||
var h = videoEl.videoHeight;
|
||||
var cropW = Math.round(w * 0.55);
|
||||
var cropH = Math.round(h * 0.3);
|
||||
var sx = Math.round((w - cropW) / 2);
|
||||
var sy = Math.round((h - cropH) / 2);
|
||||
var canvas = document.createElement('canvas');
|
||||
var outW = cropW;
|
||||
var outH = cropH;
|
||||
if (cropW > OCR_MAX_WIDTH) {
|
||||
var scale = OCR_MAX_WIDTH / cropW;
|
||||
outW = OCR_MAX_WIDTH;
|
||||
outH = Math.max(1, Math.round(cropH * scale));
|
||||
}
|
||||
canvas.width = outW;
|
||||
canvas.height = outH;
|
||||
canvas.getContext('2d').drawImage(videoEl, sx, sy, cropW, cropH, 0, 0, outW, outH);
|
||||
return canvas;
|
||||
}
|
||||
|
||||
function BibScanSession(block) {
|
||||
this.block = block;
|
||||
this.panel = block.querySelector('.inscr-gestion-bib-scan-panel');
|
||||
this.toggleBtn = block.querySelector('.inscr-gestion-bib-scan-toggle');
|
||||
this.statusEl = this.panel ? this.panel.querySelector('.inscr-gestion-bib-scan-status') : null;
|
||||
this.captureEl = this.panel ? this.panel.querySelector('.inscr-gestion-bib-scan-capture') : null;
|
||||
this.videoWrap = this.captureEl ? this.captureEl.querySelector('.inscr-gestion-bib-scan-video') : null;
|
||||
this.captureLabel = this.captureEl ? this.captureEl.querySelector('.inscr-gestion-bib-scan-capture-label') : null;
|
||||
this.inputId = this.panel ? this.panel.getAttribute('data-bib-input-id') : '';
|
||||
this.stream = null;
|
||||
this.video = null;
|
||||
this.ocrBusy = false;
|
||||
this.workerReady = false;
|
||||
this.onCaptureClick = null;
|
||||
}
|
||||
|
||||
BibScanSession.prototype.getInput = function () {
|
||||
return this.inputId ? document.getElementById(this.inputId) : null;
|
||||
};
|
||||
|
||||
BibScanSession.prototype.setStatus = function (text, active) {
|
||||
if (!this.statusEl) {
|
||||
return;
|
||||
}
|
||||
this.statusEl.textContent = text || '';
|
||||
this.statusEl.classList.toggle('is-active', !!active);
|
||||
};
|
||||
|
||||
BibScanSession.prototype.setCaptureReady = function (ready) {
|
||||
if (this.captureEl) {
|
||||
this.captureEl.classList.toggle('is-ready', !!ready);
|
||||
this.captureEl.setAttribute('aria-disabled', ready ? 'false' : 'true');
|
||||
}
|
||||
};
|
||||
|
||||
// Detecte une clef i18n brute (label absent de la table info) quel que
|
||||
// soit le prefixe (inscr_gestion_, ancien inscr_mobile_, etc.) : une vraie
|
||||
// traduction contient des espaces/accents, jamais ce motif "cle_technique".
|
||||
function isRawI18nKey(str) {
|
||||
return typeof str === 'string' && /^[a-z][a-z0-9_]*$/.test(str) && str.indexOf('_') !== -1;
|
||||
}
|
||||
|
||||
// Renvoie la valeur de l'attribut si elle est traduite, sinon le texte
|
||||
// integre (bilingue) — evite d'afficher une clef brute a l'usager.
|
||||
function scanMsg(panel, attr, frText, enText) {
|
||||
var value = panel ? panel.getAttribute(attr) : '';
|
||||
if (value && !isRawI18nKey(value)) {
|
||||
return value;
|
||||
}
|
||||
return (document.documentElement.lang === 'en') ? enText : frText;
|
||||
}
|
||||
|
||||
BibScanSession.prototype.showReady = function () {
|
||||
this.setStatus(scanMsg(this.panel, 'data-msg-ready', 'Cadrez le numéro, puis touchez l\'image', 'Frame the number, then tap the image'), false);
|
||||
this.setCaptureReady(true);
|
||||
if (this.captureLabel) {
|
||||
this.captureLabel.hidden = false;
|
||||
}
|
||||
};
|
||||
|
||||
BibScanSession.prototype.unbindCapture = function () {
|
||||
if (this.captureEl && this.onCaptureClick) {
|
||||
this.captureEl.removeEventListener('click', this.onCaptureClick);
|
||||
this.captureEl.removeEventListener('keydown', this.onCaptureKey);
|
||||
}
|
||||
this.onCaptureClick = null;
|
||||
this.onCaptureKey = null;
|
||||
};
|
||||
|
||||
BibScanSession.prototype.bindCapture = function () {
|
||||
var self = this;
|
||||
self.unbindCapture();
|
||||
if (!self.captureEl) {
|
||||
return;
|
||||
}
|
||||
self.onCaptureClick = function () {
|
||||
if (!self.workerReady || self.ocrBusy || activeScan !== self) {
|
||||
return;
|
||||
}
|
||||
self.runOcr();
|
||||
};
|
||||
self.onCaptureKey = function (e) {
|
||||
if (e.key === 'Enter' || e.key === ' ') {
|
||||
e.preventDefault();
|
||||
self.onCaptureClick();
|
||||
}
|
||||
};
|
||||
self.captureEl.addEventListener('click', self.onCaptureClick);
|
||||
self.captureEl.addEventListener('keydown', self.onCaptureKey);
|
||||
};
|
||||
|
||||
BibScanSession.prototype.stop = function () {
|
||||
this.unbindCapture();
|
||||
if (this.stream) {
|
||||
this.stream.getTracks().forEach(function (track) { track.stop(); });
|
||||
this.stream = null;
|
||||
}
|
||||
if (this.video) {
|
||||
this.video.srcObject = null;
|
||||
this.video = null;
|
||||
}
|
||||
if (this.videoWrap) {
|
||||
this.videoWrap.innerHTML = '';
|
||||
}
|
||||
this.ocrBusy = false;
|
||||
this.workerReady = false;
|
||||
this.setCaptureReady(false);
|
||||
this.setStatus('');
|
||||
if (this.panel) {
|
||||
this.panel.hidden = true;
|
||||
}
|
||||
if (this.toggleBtn) {
|
||||
this.toggleBtn.setAttribute('aria-expanded', 'false');
|
||||
this.toggleBtn.classList.remove('is-active');
|
||||
}
|
||||
if (activeScan === this) {
|
||||
activeScan = null;
|
||||
}
|
||||
};
|
||||
|
||||
BibScanSession.prototype.isSearchContext = function () {
|
||||
var form = this.block ? this.block.closest('form.inscr-gestion-form') : null;
|
||||
return !!(form && !form.closest('.inscr-gestion-fiche'));
|
||||
};
|
||||
|
||||
BibScanSession.prototype.submitSearchForm = function (form) {
|
||||
if (!form) {
|
||||
return;
|
||||
}
|
||||
var submitBtn = form.querySelector('button[type="submit"][name="btn_recherche"], input[type="submit"][name="btn_recherche"]');
|
||||
if (submitBtn) {
|
||||
submitBtn.click();
|
||||
return;
|
||||
}
|
||||
var hidden = document.createElement('input');
|
||||
hidden.type = 'hidden';
|
||||
hidden.name = 'btn_recherche';
|
||||
hidden.value = '1';
|
||||
form.appendChild(hidden);
|
||||
form.submit();
|
||||
};
|
||||
|
||||
BibScanSession.prototype.applyNumber = function (strNum) {
|
||||
var input = this.getInput();
|
||||
if (!input) {
|
||||
return;
|
||||
}
|
||||
input.value = strNum;
|
||||
input.classList.add('inscr-gestion-bib--proposed');
|
||||
var blnSearch = this.isSearchContext();
|
||||
if (blnSearch) {
|
||||
var tplSearch = scanMsg(this.panel, 'data-msg-found-search', 'Numéro %s détecté — recherche...', 'Number %s detected — searching...');
|
||||
this.setStatus(tplSearch.replace('%s', strNum), true);
|
||||
this.stop();
|
||||
var form = this.block.closest('form.inscr-gestion-form');
|
||||
window.setTimeout(function () {
|
||||
BibScanSession.prototype.submitSearchForm(form);
|
||||
}, 350);
|
||||
return;
|
||||
}
|
||||
input.focus();
|
||||
var tpl = scanMsg(this.panel, 'data-msg-found', 'Numéro %s détecté — validez avec OK.', 'Number %s detected — press OK.');
|
||||
this.setStatus(tpl.replace('%s', strNum), false);
|
||||
this.stop();
|
||||
};
|
||||
|
||||
BibScanSession.prototype.runOcr = function () {
|
||||
var self = this;
|
||||
if (self.ocrBusy || !self.video || activeScan !== self || !self.workerReady) {
|
||||
return;
|
||||
}
|
||||
var canvas = captureCenterFrame(self.video);
|
||||
if (!canvas) {
|
||||
return;
|
||||
}
|
||||
self.ocrBusy = true;
|
||||
self.setCaptureReady(false);
|
||||
if (self.captureLabel) {
|
||||
self.captureLabel.hidden = true;
|
||||
}
|
||||
self.setStatus(scanMsg(self.panel, 'data-msg-scanning', 'Lecture en cours...', 'Reading...'), true);
|
||||
getGlobalOcrWorker().then(function (worker) {
|
||||
return worker.recognize(canvas);
|
||||
}).then(function (result) {
|
||||
var rawText = result && result.data ? String(result.data.text || '') : '';
|
||||
var strNum = extractBibNumber(rawText);
|
||||
if (strNum) {
|
||||
self.applyNumber(strNum);
|
||||
return;
|
||||
}
|
||||
self.setStatus(scanMsg(self.panel, 'data-msg-invalid', 'Numéro illisible. Cadrez un seul numéro.', 'Unreadable number. Frame a single number.'), false);
|
||||
window.setTimeout(function () {
|
||||
if (activeScan === self) {
|
||||
self.showReady();
|
||||
}
|
||||
}, 1800);
|
||||
}).catch(function () {
|
||||
self.setStatus(scanMsg(self.panel, 'data-msg-invalid', 'Numéro illisible. Cadrez un seul numéro.', 'Unreadable number. Frame a single number.'), false);
|
||||
window.setTimeout(function () {
|
||||
if (activeScan === self) {
|
||||
self.showReady();
|
||||
}
|
||||
}, 1800);
|
||||
}).then(function () {
|
||||
self.ocrBusy = false;
|
||||
});
|
||||
};
|
||||
|
||||
BibScanSession.prototype.start = function () {
|
||||
var self = this;
|
||||
if (!self.panel || !navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
|
||||
self.setStatus(scanMsg(self.panel, 'data-msg-camera', 'Impossible d\'accéder à la caméra.', 'Unable to access the camera.'), false);
|
||||
return;
|
||||
}
|
||||
if (activeScan && activeScan !== self) {
|
||||
activeScan.stop();
|
||||
}
|
||||
activeScan = self;
|
||||
self.panel.hidden = false;
|
||||
if (self.toggleBtn) {
|
||||
self.toggleBtn.setAttribute('aria-expanded', 'true');
|
||||
self.toggleBtn.classList.add('is-active');
|
||||
}
|
||||
self.setStatus(scanMsg(self.panel, 'data-msg-loading', 'Initialisation (1re fois)...', 'Initializing (first time)...'), true);
|
||||
|
||||
var cameraPromise = navigator.mediaDevices.getUserMedia({
|
||||
video: {facingMode: 'environment'},
|
||||
audio: false
|
||||
});
|
||||
var workerPromise = getGlobalOcrWorker();
|
||||
|
||||
Promise.all([cameraPromise, workerPromise]).then(function (results) {
|
||||
if (activeScan !== self) {
|
||||
results[0].getTracks().forEach(function (track) { track.stop(); });
|
||||
return;
|
||||
}
|
||||
self.workerReady = true;
|
||||
self.stream = results[0];
|
||||
self.video = document.createElement('video');
|
||||
self.video.setAttribute('playsinline', 'true');
|
||||
self.video.setAttribute('autoplay', 'true');
|
||||
self.video.muted = true;
|
||||
self.video.srcObject = self.stream;
|
||||
self.videoWrap.innerHTML = '';
|
||||
self.videoWrap.appendChild(self.video);
|
||||
return self.video.play();
|
||||
}).then(function () {
|
||||
if (activeScan !== self || !self.workerReady) {
|
||||
return;
|
||||
}
|
||||
self.bindCapture();
|
||||
self.showReady();
|
||||
}).catch(function () {
|
||||
self.setStatus(scanMsg(self.panel, 'data-msg-camera', 'Impossible d\'accéder à la caméra.', 'Unable to access the camera.'), false);
|
||||
self.stop();
|
||||
});
|
||||
};
|
||||
|
||||
if (document.querySelector('.inscr-gestion-bib-scan-toggle')) {
|
||||
preloadOcrWorker();
|
||||
}
|
||||
|
||||
document.querySelectorAll('.inscr-gestion-field-block[data-inscr-field="bib"]').forEach(function (block) {
|
||||
var toggleBtn = block.querySelector('.inscr-gestion-bib-scan-toggle');
|
||||
var panel = block.querySelector('.inscr-gestion-bib-scan-panel');
|
||||
if (!toggleBtn || !panel) {
|
||||
return;
|
||||
}
|
||||
var session = new BibScanSession(block);
|
||||
toggleBtn.addEventListener('click', function () {
|
||||
if (activeScan === session && !panel.hidden) {
|
||||
session.stop();
|
||||
return;
|
||||
}
|
||||
session.start();
|
||||
});
|
||||
var input = session.getInput();
|
||||
if (input) {
|
||||
input.addEventListener('input', function () {
|
||||
input.classList.remove('inscr-gestion-bib--proposed');
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
var ficheFromQr = document.querySelector('.inscr-gestion-fiche[data-from-qr="1"]');
|
||||
if (ficheFromQr) {
|
||||
var editableSection = ficheFromQr.querySelector('.inscr-gestion-fiche-section--editable');
|
||||
if (editableSection) {
|
||||
window.setTimeout(function () {
|
||||
editableSection.scrollIntoView({behavior: 'smooth', block: 'start'});
|
||||
}, 80);
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
|
||||
(function () {
|
||||
var moduleInscr = document.getElementById('module-inscr-gestion');
|
||||
if (!moduleInscr) {
|
||||
return;
|
||||
}
|
||||
|
||||
var params = new URLSearchParams(window.location.search);
|
||||
if (params.get('pec_id')) {
|
||||
moduleInscr.scrollIntoView({block: 'start'});
|
||||
} else if (params.get('pg') && parseInt(params.get('pg'), 10) > 1) {
|
||||
var listAnchor = document.getElementById('inscr-gestion-list');
|
||||
if (listAnchor) {
|
||||
listAnchor.scrollIntoView({block: 'start'});
|
||||
}
|
||||
}
|
||||
moduleInscr.addEventListener('click', function (e) {
|
||||
var btnToggle = e.target.closest('.epr-block-toggle');
|
||||
if (!btnToggle || !moduleInscr.contains(btnToggle)) {
|
||||
return;
|
||||
}
|
||||
var block = btnToggle.closest('.epr-block');
|
||||
if (!block) {
|
||||
return;
|
||||
}
|
||||
var collapsed = block.classList.toggle('is-collapsed');
|
||||
btnToggle.setAttribute('aria-expanded', collapsed ? 'false' : 'true');
|
||||
var label = collapsed
|
||||
? (btnToggle.getAttribute('data-label-expand') || '')
|
||||
: (btnToggle.getAttribute('data-label-collapse') || '');
|
||||
if (label) {
|
||||
btnToggle.setAttribute('aria-label', label);
|
||||
btnToggle.setAttribute('title', label);
|
||||
}
|
||||
var icon = btnToggle.querySelector('.fa');
|
||||
if (icon) {
|
||||
icon.classList.toggle('fa-chevron-up', !collapsed);
|
||||
icon.classList.toggle('fa-chevron-down', collapsed);
|
||||
}
|
||||
});
|
||||
|
||||
var inscrLoaderMsg = cfg.preloaderWait || '';
|
||||
|
||||
moduleInscr.addEventListener('click', function (e) {
|
||||
var factureLink = e.target.closest('a[href*="facture.php"]');
|
||||
if (!factureLink || !moduleInscr.contains(factureLink)) {
|
||||
return;
|
||||
}
|
||||
if (window.Ms1Loader) {
|
||||
Ms1Loader.show(inscrLoaderMsg);
|
||||
window.setTimeout(function () {
|
||||
Ms1Loader.hide();
|
||||
}, 3000);
|
||||
}
|
||||
});
|
||||
|
||||
moduleInscr.addEventListener('submit', function (e) {
|
||||
var form = e.target;
|
||||
if (!form || !moduleInscr.contains(form)) {
|
||||
return;
|
||||
}
|
||||
if (!form.classList.contains('inscr-gestion-form')) {
|
||||
return;
|
||||
}
|
||||
if (window.Ms1Loader) {
|
||||
Ms1Loader.show(inscrLoaderMsg);
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
})();
|
||||
@ -8,6 +8,7 @@ require_once('php/inc_fx_messages.php');
|
||||
require_once('php/inc_fx_compte.php');
|
||||
require_once('php/inc_fx_promoteur.php');
|
||||
require_once('php/inc_fx_inscriptions_gestion.php');
|
||||
require_once('php/inc_v2_assets.php');
|
||||
|
||||
global $objDatabase, $vDomaine, $vPage, $vtexte_page;
|
||||
|
||||
@ -18,6 +19,7 @@ if (!empty($_GET['lang'])) {
|
||||
}
|
||||
|
||||
fxInscrGestionInitTextes($strLangue);
|
||||
fxV2RegisterScript('inscr-gestion');
|
||||
|
||||
$vPage = 'mobile.php';
|
||||
$strCode = 'mobile';
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
* Constantes *
|
||||
*
|
||||
**************/
|
||||
define('_VERSION_CODE', '4.72.733');
|
||||
define('_VERSION_CODE', '4.72.734');
|
||||
define('_DATE_CODE', '2026-07-07');
|
||||
//MSIN-4290
|
||||
define('QR_SECRET_KEY', 'ms1_qr_2026_cle_secrete_longue_et_fixe');
|
||||
|
||||
72
php/inc_v2_assets.php
Normal file
72
php/inc_v2_assets.php
Normal file
@ -0,0 +1,72 @@
|
||||
<?php
|
||||
/**
|
||||
* MSIN-4435 — Assets JS modules v2 (hors inc_footer_scripts.php legacy).
|
||||
* Bib v4, gestion inscriptions v2 : chargés uniquement sur leurs pages.
|
||||
*/
|
||||
|
||||
if (!function_exists('fxV2RegisterScript')) {
|
||||
|
||||
/** @param string $strName bib-assignments | inscr-gestion */
|
||||
function fxV2RegisterScript($strName) {
|
||||
global $MS1_V2_SCRIPTS;
|
||||
if (!isset($MS1_V2_SCRIPTS) || !is_array($MS1_V2_SCRIPTS)) {
|
||||
$MS1_V2_SCRIPTS = [];
|
||||
}
|
||||
if (!in_array($strName, $MS1_V2_SCRIPTS, true)) {
|
||||
$MS1_V2_SCRIPTS[] = $strName;
|
||||
}
|
||||
}
|
||||
|
||||
/** Config injectée dans window.MS1_V2_INSCR_GESTION avant inscr-gestion.js */
|
||||
function fxV2InscrGestionConfig($strLangue) {
|
||||
global $vDomaine;
|
||||
|
||||
$strLangue = ($strLangue === 'en') ? 'en' : 'fr';
|
||||
|
||||
return [
|
||||
'domain' => $vDomaine,
|
||||
'lang' => $strLangue,
|
||||
'preloaderWait' => afficheTexte('preloader_wait', 0, 0, 1),
|
||||
'refundCancelHint' => ($strLangue === 'en')
|
||||
? 'Your transaction has been refunded. If you also want to cancel it in the registration system:'
|
||||
: "Votre transaction a été remboursée. Si vous voulez aussi l'annuler dans le système d'inscription :",
|
||||
'loginMessages' => [
|
||||
'txt_login' => ($strLangue === 'fr')
|
||||
? "Veuillez entrer votre nom d'usager"
|
||||
: 'Please enter your username',
|
||||
'txt_password' => ($strLangue === 'fr')
|
||||
? 'Veuillez entrer votre mot de passe'
|
||||
: 'Please enter your password',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/** À appeler dans inc_footer.php après inc_footer_scripts.php */
|
||||
function fxV2RenderFooterScripts() {
|
||||
global $MS1_V2_SCRIPTS, $vDomaine, $strLangue;
|
||||
|
||||
if (empty($MS1_V2_SCRIPTS) || !is_array($MS1_V2_SCRIPTS)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$mapFiles = [
|
||||
'bib-assignments' => '/js/v2/bib-assignments.js',
|
||||
'inscr-gestion' => '/js/v2/inscr-gestion.js',
|
||||
];
|
||||
|
||||
if (in_array('inscr-gestion', $MS1_V2_SCRIPTS, true)) {
|
||||
$cfg = fxV2InscrGestionConfig($strLangue ?? 'fr');
|
||||
echo '<script>window.MS1_V2_INSCR_GESTION='
|
||||
. json_encode($cfg, JSON_UNESCAPED_UNICODE | JSON_HEX_TAG | JSON_HEX_AMP)
|
||||
. ';</script>' . "\n";
|
||||
}
|
||||
|
||||
foreach ($MS1_V2_SCRIPTS as $strName) {
|
||||
if (!isset($mapFiles[$strName])) {
|
||||
continue;
|
||||
}
|
||||
$strSrc = htmlspecialchars($vDomaine . $mapFiles[$strName], ENT_QUOTES, 'UTF-8');
|
||||
echo '<script src="' . $strSrc . '?v=' . htmlspecialchars(_VERSION_CODE, ENT_QUOTES, 'UTF-8') . '"></script>' . "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user