v5.2: Edit-Button für Bestellzeilen, Dialog vereinfacht
- Edit-Button (Stift-Icon) an jeder Bestellzeile statt Touch-Events - Abbrechen-Button aus Line-Edit-Dialog entfernt (nur Löschen/Speichern) - Status-Typ-Vergleich für Entwurfs-Erkennung korrigiert - Cache-Busting für zuverlässige PWA-Updates (v=60) - Service Worker v6.0 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
707d7f50a0
commit
08221a660d
7 changed files with 57 additions and 33 deletions
12
ChangeLog.md
12
ChangeLog.md
|
|
@ -27,6 +27,18 @@
|
|||
- **Kompakterer Scan-Button**: Mehr Platz für Tool-Buttons
|
||||
- **Service Worker v5.3**: Aktualisiertes Caching mit JsBarcode-Library
|
||||
|
||||
## 5.2
|
||||
|
||||
### Bestellzeilen-Bearbeitung
|
||||
- **Edit-Button**: Stift-Icon an jeder Bestellzeile für zuverlässiges Öffnen des Bearbeitungsdialogs
|
||||
- **Touch-Kompatibilität**: Button funktioniert zuverlässig auf allen Touch-Geräten
|
||||
- **Dialog vereinfacht**: Abbrechen-Button entfernt, nur noch Löschen und Speichern
|
||||
- **Typ-Fix**: Status-Vergleich für Entwurfs-Erkennung korrigiert
|
||||
|
||||
### Caching
|
||||
- **Cache-Busting**: CSS/JS URLs mit Versionsparameter für zuverlässige PWA-Updates
|
||||
- **Service Worker v6.0**: Optimiertes Caching-Verhalten
|
||||
|
||||
## 5.1
|
||||
|
||||
### Bestellungen verwalten
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ echo json_encode([
|
|||
'id' => $order->id,
|
||||
'ref' => $order->ref,
|
||||
'ref_supplier' => $order->ref_supplier,
|
||||
'status' => $order->statut,
|
||||
'status' => (int) $order->statut,
|
||||
'supplier_name' => $order->thirdparty->name ?? '',
|
||||
'total_ht' => (float) $order->total_ht
|
||||
],
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ class modHandyBarcodeScanner extends DolibarrModules
|
|||
$this->editor_squarred_logo = ''; // Must be image filename into the module/img directory followed with @modulename. Example: 'myimage.png@handybarcodescanner'
|
||||
|
||||
// Possible values for version are: 'development', 'experimental', 'dolibarr', 'dolibarr_deprecated', 'experimental_deprecated' or a version string like 'x.y.z'
|
||||
$this->version = '5.4';
|
||||
$this->version = '6.0';
|
||||
// Url to the file with your last numberversion of this module
|
||||
//$this->url_last_version = 'http://www.example.com/versionmodule.txt';
|
||||
|
||||
|
|
|
|||
|
|
@ -1075,16 +1075,10 @@
|
|||
border: 1px solid var(--colorborder, #2b2c2e);
|
||||
border-radius: 6px;
|
||||
margin-bottom: 8px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
color: var(--colortext, #dcdcdc);
|
||||
}
|
||||
|
||||
.order-line:hover {
|
||||
background: var(--colorbacktitle, #3b3c3e);
|
||||
border-color: var(--butactionbg, #ad8c4f);
|
||||
}
|
||||
|
||||
.order-line-info {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
|
|
@ -1112,6 +1106,29 @@
|
|||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.order-line-edit-btn {
|
||||
background: transparent;
|
||||
border: none;
|
||||
padding: 8px;
|
||||
margin-left: 8px;
|
||||
cursor: pointer;
|
||||
color: var(--colortextmuted, #888);
|
||||
border-radius: 6px;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.order-line-edit-btn:hover,
|
||||
.order-line-edit-btn:active {
|
||||
background: var(--colorbacktitle, #3b3c3e);
|
||||
color: var(--butactionbg, #0077b3);
|
||||
}
|
||||
|
||||
.order-line-edit-btn svg {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* Line edit dialog */
|
||||
.line-edit-dialog {
|
||||
position: fixed;
|
||||
|
|
|
|||
|
|
@ -1184,30 +1184,32 @@
|
|||
return;
|
||||
}
|
||||
|
||||
const canEdit = order.status === 0;
|
||||
const canEdit = order.status == 0;
|
||||
|
||||
content.innerHTML = lines.map(line => `
|
||||
<div class="order-line ${canEdit ? 'editable' : ''}" data-line-id="${line.id}" data-order-id="${orderId}" data-is-freetext="${line.is_freetext ? '1' : '0'}">
|
||||
<div class="order-line" data-line-id="${line.id}" data-order-id="${orderId}" data-is-freetext="${line.is_freetext ? '1' : '0'}">
|
||||
<div class="order-line-info">
|
||||
<div class="order-line-label">${escapeHtml(line.product_label)}</div>
|
||||
<div class="order-line-ref">${line.product_ref ? 'Ref: ' + escapeHtml(line.product_ref) : ''} ${line.is_freetext ? '(Freitext)' : (line.stock > 0 ? '| Lager: ' + line.stock : '')}</div>
|
||||
</div>
|
||||
<div class="order-line-qty">${line.qty}x</div>
|
||||
${canEdit ? `<button type="button" class="order-line-edit-btn" data-line-id="${line.id}" title="Bearbeiten">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7"/><path d="M18.5 2.5a2.121 2.121 0 013 3L12 15l-4 1 1-4 9.5-9.5z"/></svg>
|
||||
</button>` : ''}
|
||||
</div>
|
||||
`).join('');
|
||||
|
||||
if (canEdit) {
|
||||
content.querySelectorAll('.order-line').forEach(lineEl => {
|
||||
lineEl.addEventListener('click', function() {
|
||||
const lineId = parseInt(this.dataset.lineId);
|
||||
const oId = parseInt(this.dataset.orderId);
|
||||
const line = currentModalLines.find(l => l.id === lineId);
|
||||
if (line) {
|
||||
showLineEditDialogInModal(line, oId);
|
||||
}
|
||||
});
|
||||
// Edit-Button Events
|
||||
content.querySelectorAll('.order-line-edit-btn').forEach(btn => {
|
||||
btn.addEventListener('click', function(e) {
|
||||
e.stopPropagation();
|
||||
const lineId = parseInt(this.dataset.lineId);
|
||||
const line = currentModalLines.find(l => l.id === lineId);
|
||||
if (line) {
|
||||
showLineEditDialogInModal(line, orderId);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function showLineEditDialogInModal(line, orderId) {
|
||||
|
|
@ -1237,7 +1239,6 @@
|
|||
</div>
|
||||
<div class="line-edit-buttons">
|
||||
<button type="button" class="action-btn btn-danger" id="line-delete">Löschen</button>
|
||||
<button type="button" class="action-btn btn-secondary" id="line-cancel">Abbrechen</button>
|
||||
<button type="button" class="action-btn btn-primary" id="line-save">Speichern</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -1249,8 +1250,6 @@
|
|||
resumeScanner();
|
||||
}
|
||||
|
||||
document.getElementById('line-cancel').addEventListener('click', closeDialog);
|
||||
|
||||
document.getElementById('line-save').addEventListener('click', () => {
|
||||
const newQty = parseFloat(document.getElementById('line-qty-input').value) || 1;
|
||||
const descInput = document.getElementById('line-desc-input');
|
||||
|
|
@ -1483,7 +1482,7 @@
|
|||
return;
|
||||
}
|
||||
|
||||
const canEdit = order.status === 0; // Only draft orders can be edited
|
||||
const canEdit = order.status == 0; // Only draft orders can be edited
|
||||
|
||||
content.innerHTML = lines.map(line => `
|
||||
<div class="order-line ${canEdit ? 'editable' : ''}" data-line-id="${line.id}" data-order-id="${order.id}">
|
||||
|
|
@ -1537,7 +1536,6 @@
|
|||
</div>
|
||||
<div class="line-edit-buttons">
|
||||
<button type="button" class="action-btn btn-danger" id="line-delete">Löschen</button>
|
||||
<button type="button" class="action-btn btn-secondary" id="line-cancel">Abbrechen</button>
|
||||
<button type="button" class="action-btn btn-primary" id="line-save">Speichern</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -1549,8 +1547,6 @@
|
|||
resumeScanner();
|
||||
}
|
||||
|
||||
document.getElementById('line-cancel').addEventListener('click', closeDialog);
|
||||
|
||||
document.getElementById('line-save').addEventListener('click', () => {
|
||||
const newQty = parseFloat(document.getElementById('line-qty-input').value) || 1;
|
||||
const descInput = document.getElementById('line-desc-input');
|
||||
|
|
|
|||
4
pwa.php
4
pwa.php
|
|
@ -53,7 +53,7 @@ $colormain = getDolGlobalString('THEME_ELDY_TOPMENU_BACK1', '#0077b3');
|
|||
<title>Barcode Scanner</title>
|
||||
<link rel="manifest" href="manifest.json">
|
||||
<link rel="apple-touch-icon" href="img/icon-192.png">
|
||||
<link rel="stylesheet" href="css/scanner.css">
|
||||
<link rel="stylesheet" href="css/scanner.css?v=60">
|
||||
<style>
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
|
|
@ -1280,6 +1280,6 @@ $colormain = getDolGlobalString('THEME_ELDY_TOPMENU_BACK1', '#0077b3');
|
|||
</script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@ericblade/quagga2@1.8.4/dist/quagga.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/jsbarcode@3.11.6/dist/JsBarcode.all.min.js"></script>
|
||||
<script src="<?php echo dol_buildpath('/handybarcodescanner/js/scanner.js', 1); ?>"></script>
|
||||
<script src="<?php echo dol_buildpath('/handybarcodescanner/js/scanner.js', 1); ?>?v=60"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
5
sw.js
5
sw.js
|
|
@ -1,5 +1,5 @@
|
|||
// Service Worker for HandyBarcodeScanner PWA
|
||||
const CACHE_NAME = 'scanner-v5.5';
|
||||
const CACHE_NAME = 'scanner-v6.0';
|
||||
const ASSETS = [
|
||||
'pwa.php',
|
||||
'css/scanner.css',
|
||||
|
|
@ -36,7 +36,7 @@ self.addEventListener('activate', event => {
|
|||
self.addEventListener('fetch', event => {
|
||||
const url = new URL(event.request.url);
|
||||
|
||||
// Always fetch AJAX requests from network (include PWA auth endpoints)
|
||||
// Always fetch AJAX requests from network
|
||||
if (url.pathname.includes('/ajax/')) {
|
||||
event.respondWith(
|
||||
fetch(event.request).catch(err => {
|
||||
|
|
@ -64,7 +64,6 @@ self.addEventListener('fetch', event => {
|
|||
event.respondWith(
|
||||
caches.match(event.request).then(cached => {
|
||||
return cached || fetch(event.request).then(response => {
|
||||
// Cache successful responses
|
||||
if (response.ok) {
|
||||
const clone = response.clone();
|
||||
caches.open(CACHE_NAME).then(cache => cache.put(event.request, clone));
|
||||
|
|
|
|||
Loading…
Reference in a new issue