Refactor mobile bib scanning functionality and enhance UI feedback
This commit refines the mobile bib scanning process by introducing a new capture element and updating the UI to provide clearer feedback during scanning. It removes the unused OCR interval and enhances the event handling for capture actions. Additionally, new messages are added for user guidance, and the version code is incremented to 4.72.696 to reflect these changes. The SQL file is updated to include new translation keys for improved user instructions.
This commit is contained in:
@ -2487,6 +2487,52 @@ a.ms1-trad-link.btn-aide-trad{
|
||||
color:#fff;
|
||||
}
|
||||
|
||||
.inscr-mobile-bib-scan-capture{
|
||||
position:relative;
|
||||
overflow:hidden;
|
||||
border-radius:4px;
|
||||
background:#111;
|
||||
max-height:100px;
|
||||
cursor:pointer;
|
||||
outline:none;
|
||||
}
|
||||
|
||||
.inscr-mobile-bib-scan-capture.is-ready{
|
||||
box-shadow:0 0 0 2px rgba(111,66,193,.35);
|
||||
}
|
||||
|
||||
.inscr-mobile-bib-scan-capture[aria-disabled="true"]{
|
||||
cursor:wait;
|
||||
pointer-events:none;
|
||||
}
|
||||
|
||||
.inscr-mobile-bib-scan-video{
|
||||
max-height:100px;
|
||||
}
|
||||
|
||||
.inscr-mobile-bib-scan-video video{
|
||||
display:block;
|
||||
width:100%;
|
||||
max-height:100px;
|
||||
object-fit:cover;
|
||||
pointer-events:none;
|
||||
}
|
||||
|
||||
.inscr-mobile-bib-scan-capture-label{
|
||||
position:absolute;
|
||||
left:50%;
|
||||
bottom:8px;
|
||||
transform:translateX(-50%);
|
||||
padding:4px 10px;
|
||||
border-radius:999px;
|
||||
background:rgba(0,0,0,.65);
|
||||
color:#fff;
|
||||
font-size:11px;
|
||||
font-weight:600;
|
||||
white-space:nowrap;
|
||||
pointer-events:none;
|
||||
}
|
||||
|
||||
.inscr-mobile-bib-scan-panel{
|
||||
margin-top:8px;
|
||||
}
|
||||
@ -2507,20 +2553,6 @@ a.ms1-trad-link.btn-aide-trad{
|
||||
animation:inscr-mobile-qr-pulse 1.2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.inscr-mobile-bib-scan-video{
|
||||
overflow:hidden;
|
||||
border-radius:4px;
|
||||
background:#111;
|
||||
max-height:100px;
|
||||
}
|
||||
|
||||
.inscr-mobile-bib-scan-video video{
|
||||
display:block;
|
||||
width:100%;
|
||||
max-height:100px;
|
||||
object-fit:cover;
|
||||
}
|
||||
|
||||
.inscr-mobile-bib-row input.inscr-mobile-bib--proposed{
|
||||
border-color:#6f42c1;
|
||||
box-shadow:0 0 0 2px rgba(111,66,193,.2);
|
||||
|
||||
@ -3716,7 +3716,6 @@ if ($strLangue == 'fr') {
|
||||
(function () {
|
||||
var BIB_MAX_LEN = 6;
|
||||
var OCR_MAX_WIDTH = 320;
|
||||
var OCR_INTERVAL_MS = 1200;
|
||||
var tesseractPromise = null;
|
||||
var globalOcrWorker = null;
|
||||
var globalOcrWorkerPromise = null;
|
||||
@ -3817,13 +3816,15 @@ if ($strLangue == 'fr') {
|
||||
this.panel = block.querySelector('.inscr-mobile-bib-scan-panel');
|
||||
this.toggleBtn = block.querySelector('.inscr-mobile-bib-scan-toggle');
|
||||
this.statusEl = this.panel ? this.panel.querySelector('.inscr-mobile-bib-scan-status') : null;
|
||||
this.videoWrap = this.panel ? this.panel.querySelector('.inscr-mobile-bib-scan-video') : null;
|
||||
this.captureEl = this.panel ? this.panel.querySelector('.inscr-mobile-bib-scan-capture') : null;
|
||||
this.videoWrap = this.captureEl ? this.captureEl.querySelector('.inscr-mobile-bib-scan-video') : null;
|
||||
this.captureLabel = this.captureEl ? this.captureEl.querySelector('.inscr-mobile-bib-scan-capture-label') : null;
|
||||
this.inputId = this.panel ? this.panel.getAttribute('data-bib-input-id') : '';
|
||||
this.stream = null;
|
||||
this.video = null;
|
||||
this.intervalId = null;
|
||||
this.ocrBusy = false;
|
||||
this.workerReady = false;
|
||||
this.onCaptureClick = null;
|
||||
}
|
||||
|
||||
BibScanSession.prototype.getInput = function () {
|
||||
@ -3838,11 +3839,54 @@ if ($strLangue == 'fr') {
|
||||
this.statusEl.classList.toggle('is-active', !!active);
|
||||
};
|
||||
|
||||
BibScanSession.prototype.stop = function () {
|
||||
if (this.intervalId) {
|
||||
window.clearInterval(this.intervalId);
|
||||
this.intervalId = null;
|
||||
BibScanSession.prototype.setCaptureReady = function (ready) {
|
||||
if (this.captureEl) {
|
||||
this.captureEl.classList.toggle('is-ready', !!ready);
|
||||
this.captureEl.setAttribute('aria-disabled', ready ? 'false' : 'true');
|
||||
}
|
||||
};
|
||||
|
||||
BibScanSession.prototype.showReady = function () {
|
||||
this.setStatus(this.panel.getAttribute('data-msg-ready') || '', 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;
|
||||
@ -3856,6 +3900,7 @@ if ($strLangue == 'fr') {
|
||||
}
|
||||
this.ocrBusy = false;
|
||||
this.workerReady = false;
|
||||
this.setCaptureReady(false);
|
||||
this.setStatus('');
|
||||
if (this.panel) {
|
||||
this.panel.hidden = true;
|
||||
@ -3892,6 +3937,11 @@ if ($strLangue == 'fr') {
|
||||
return;
|
||||
}
|
||||
self.ocrBusy = true;
|
||||
self.setCaptureReady(false);
|
||||
if (self.captureLabel) {
|
||||
self.captureLabel.hidden = true;
|
||||
}
|
||||
self.setStatus(self.panel.getAttribute('data-msg-scanning') || '', true);
|
||||
getGlobalOcrWorker().then(function (worker) {
|
||||
return worker.recognize(canvas);
|
||||
}).then(function (result) {
|
||||
@ -3899,9 +3949,21 @@ if ($strLangue == 'fr') {
|
||||
var strNum = extractBibNumber(rawText);
|
||||
if (strNum) {
|
||||
self.applyNumber(strNum);
|
||||
return;
|
||||
}
|
||||
self.setStatus(self.panel.getAttribute('data-msg-invalid') || '', false);
|
||||
window.setTimeout(function () {
|
||||
if (activeScan === self) {
|
||||
self.showReady();
|
||||
}
|
||||
}, 1800);
|
||||
}).catch(function () {
|
||||
/* ignore transient OCR errors */
|
||||
self.setStatus(self.panel.getAttribute('data-msg-invalid') || '', false);
|
||||
window.setTimeout(function () {
|
||||
if (activeScan === self) {
|
||||
self.showReady();
|
||||
}
|
||||
}, 1800);
|
||||
}).then(function () {
|
||||
self.ocrBusy = false;
|
||||
});
|
||||
@ -3936,7 +3998,6 @@ if ($strLangue == 'fr') {
|
||||
return;
|
||||
}
|
||||
self.workerReady = true;
|
||||
self.setStatus(self.panel.getAttribute('data-msg-scanning') || '', true);
|
||||
self.stream = results[0];
|
||||
self.video = document.createElement('video');
|
||||
self.video.setAttribute('playsinline', 'true');
|
||||
@ -3950,10 +4011,8 @@ if ($strLangue == 'fr') {
|
||||
if (activeScan !== self || !self.workerReady) {
|
||||
return;
|
||||
}
|
||||
self.runOcr();
|
||||
self.intervalId = window.setInterval(function () {
|
||||
self.runOcr();
|
||||
}, OCR_INTERVAL_MS);
|
||||
self.bindCapture();
|
||||
self.showReady();
|
||||
}).catch(function () {
|
||||
self.setStatus(self.panel.getAttribute('data-msg-camera') || '', false);
|
||||
self.stop();
|
||||
|
||||
@ -207,7 +207,9 @@ function fxInscrMobileFallbackTexte($strClef, $strLangue) {
|
||||
'inscr_mobile_qr_wrong_event' => $blnFr ? 'Ce code QR appartient à un autre événement : %s' : 'This QR code belongs to another event: %s',
|
||||
'inscr_mobile_qr_camera_error' => $blnFr ? 'Impossible d\'accéder à la caméra.' : 'Unable to access the camera.',
|
||||
'inscr_mobile_bib_scan_btn' => $blnFr ? 'Scanner le numéro' : 'Scan number',
|
||||
'inscr_mobile_bib_scan_hint' => $blnFr ? 'Cadrez un seul numéro au centre, puis maintenez stable.' : 'Frame a single number in the centre and hold steady.',
|
||||
'inscr_mobile_bib_scan_hint' => $blnFr ? 'Ouvrez la caméra, cadrez le numéro, puis touchez l\'image pour lire.' : 'Open the camera, frame the number, then tap the image to read.',
|
||||
'inscr_mobile_bib_scan_ready' => $blnFr ? 'Cadrez le numéro, puis touchez l\'image' : 'Frame the number, then tap the image',
|
||||
'inscr_mobile_bib_scan_tap' => $blnFr ? 'Toucher pour lire' : 'Tap to read',
|
||||
'inscr_mobile_bib_scan_scanning' => $blnFr ? 'Lecture en cours...' : 'Reading...',
|
||||
'inscr_mobile_bib_scan_loading' => $blnFr ? 'Initialisation (1re fois)...' : 'Initializing (first time)...',
|
||||
'inscr_mobile_bib_scan_found' => $blnFr ? 'Numéro %s détecté — validez avec OK.' : 'Number %s detected — press OK.',
|
||||
@ -958,12 +960,16 @@ function fxInscrMobileRenderBibScanBlock($strBibInputId, $strLangue) {
|
||||
echo ' data-bib-input-id="' . fxInscrMobileEsc($strBibInputId) . '"';
|
||||
echo ' data-msg-scanning="' . fxInscrMobileEsc(fxInscrMobileT('inscr_mobile_bib_scan_scanning')) . '"';
|
||||
echo ' data-msg-loading="' . fxInscrMobileEsc(fxInscrMobileT('inscr_mobile_bib_scan_loading')) . '"';
|
||||
echo ' data-msg-ready="' . fxInscrMobileEsc(fxInscrMobileT('inscr_mobile_bib_scan_ready')) . '"';
|
||||
echo ' data-msg-found="' . fxInscrMobileEsc(fxInscrMobileT('inscr_mobile_bib_scan_found')) . '"';
|
||||
echo ' data-msg-invalid="' . fxInscrMobileEsc(fxInscrMobileT('inscr_mobile_bib_scan_invalid')) . '"';
|
||||
echo ' data-msg-camera="' . fxInscrMobileEsc(fxInscrMobileT('inscr_mobile_qr_camera_error')) . '">';
|
||||
echo '<p class="inscr-mobile-bib-scan-hint text-muted small mb-1">' . fxInscrMobileEsc(fxInscrMobileT('inscr_mobile_bib_scan_hint')) . '</p>';
|
||||
echo '<div class="inscr-mobile-bib-scan-status small mb-1" aria-live="polite"></div>';
|
||||
echo '<div class="inscr-mobile-bib-scan-capture" role="button" tabindex="0">';
|
||||
echo '<div class="inscr-mobile-bib-scan-video"></div>';
|
||||
echo '<span class="inscr-mobile-bib-scan-capture-label">' . fxInscrMobileEsc(fxInscrMobileT('inscr_mobile_bib_scan_tap')) . '</span>';
|
||||
echo '</div>';
|
||||
echo '</div>';
|
||||
}
|
||||
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
* Constantes *
|
||||
*
|
||||
**************/
|
||||
define('_VERSION_CODE', '4.72.695');
|
||||
define('_VERSION_CODE', '4.72.696');
|
||||
define('_DATE_CODE', '2026-06-22');
|
||||
//MSIN-4290
|
||||
define('QR_SECRET_KEY', 'ms1_qr_2026_cle_secrete_longue_et_fixe');
|
||||
|
||||
@ -11,6 +11,8 @@ WHERE info_prg = 'compte.php'
|
||||
'inscr_mobile_qr_camera_error',
|
||||
'inscr_mobile_bib_scan_btn',
|
||||
'inscr_mobile_bib_scan_hint',
|
||||
'inscr_mobile_bib_scan_ready',
|
||||
'inscr_mobile_bib_scan_tap',
|
||||
'inscr_mobile_bib_scan_scanning',
|
||||
'inscr_mobile_bib_scan_loading',
|
||||
'inscr_mobile_bib_scan_found',
|
||||
@ -32,8 +34,12 @@ INSERT INTO info (info_clef, info_langue, info_texte, info_aide, info_prg, info_
|
||||
('inscr_mobile_qr_camera_error', 'en', 'Unable to access the camera.', '', 'compte.php', '', 0, 1, '', '', '', NOW()),
|
||||
('inscr_mobile_bib_scan_btn', 'fr', 'Scanner le numero', '', 'compte.php', '', 0, 1, '', '', '', NOW()),
|
||||
('inscr_mobile_bib_scan_btn', 'en', 'Scan number', '', 'compte.php', '', 0, 1, '', '', '', NOW()),
|
||||
('inscr_mobile_bib_scan_hint', 'fr', 'Cadrez un seul numero au centre et maintenez stable.', '', 'compte.php', '', 0, 1, '', '', '', NOW()),
|
||||
('inscr_mobile_bib_scan_hint', 'en', 'Frame a single number in the centre and hold steady.', '', 'compte.php', '', 0, 1, '', '', '', NOW()),
|
||||
('inscr_mobile_bib_scan_hint', 'fr', 'Ouvrez la camera, cadrez le numero, puis touchez l''image pour lire.', '', 'compte.php', '', 0, 1, '', '', '', NOW()),
|
||||
('inscr_mobile_bib_scan_hint', 'en', 'Open the camera, frame the number, then tap the image to read.', '', 'compte.php', '', 0, 1, '', '', '', NOW()),
|
||||
('inscr_mobile_bib_scan_ready', 'fr', 'Cadrez le numero, puis touchez l''image', '', 'compte.php', '', 0, 1, '', '', '', NOW()),
|
||||
('inscr_mobile_bib_scan_ready', 'en', 'Frame the number, then tap the image', '', 'compte.php', '', 0, 1, '', '', '', NOW()),
|
||||
('inscr_mobile_bib_scan_tap', 'fr', 'Toucher pour lire', '', 'compte.php', '', 0, 1, '', '', '', NOW()),
|
||||
('inscr_mobile_bib_scan_tap', 'en', 'Tap to read', '', 'compte.php', '', 0, 1, '', '', '', NOW()),
|
||||
('inscr_mobile_bib_scan_scanning', 'fr', 'Lecture en cours...', '', 'compte.php', '', 0, 1, '', '', '', NOW()),
|
||||
('inscr_mobile_bib_scan_scanning', 'en', 'Reading...', '', 'compte.php', '', 0, 1, '', '', '', NOW()),
|
||||
('inscr_mobile_bib_scan_loading', 'fr', 'Initialisation (1re fois)...', '', 'compte.php', '', 0, 1, '', '', '', NOW()),
|
||||
|
||||
Reference in New Issue
Block a user