Wizard DXF: correzioni revisione zoom anteprime (style statico, x-show, altezza utile). Refs #113
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -514,7 +514,9 @@ function dxfRecipeWizard(taskId, csrf, msgs) {
|
||||
vFit(k) {
|
||||
const vp = this._vpEl(k), v = this.views[k];
|
||||
if (!vp || !v.w || !v.h || !vp.clientWidth) return; // nascosto o vuoto: niente
|
||||
let z = Math.min(vp.clientWidth / v.w, 240 / v.h);
|
||||
// altezza utile del viewport (senza bordo), ripiego 240; con 240 secco il contenuto sborda e compare lo scroll
|
||||
const ch = vp.clientHeight || 240;
|
||||
let z = Math.min(vp.clientWidth / v.w, ch / v.h);
|
||||
if (k === 'img') z = Math.min(8, Math.max(0.05, z));
|
||||
v.zoom = z;
|
||||
v.fit = z;
|
||||
|
||||
@@ -730,8 +730,8 @@
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 gap-3 items-start">
|
||||
<div x-show="imagePreviewUrl">
|
||||
<!-- #102: anteprima dell'immagine -->
|
||||
<!-- #113: barra zoom come quella della Prova (#104), per l'anteprima 'img' -->
|
||||
<div class="relative">
|
||||
<!-- #113: barra zoom come quella della Prova (#104), per l'anteprima 'img'; x-show sul contenitore (sul viewport :style lo pesterebbe) -->
|
||||
<div class="relative" x-show="!imageBroken">
|
||||
<div x-show="!imageBroken && views.img.w" class="absolute top-2 right-2 z-10 flex items-center gap-1 rounded px-1 py-0.5"
|
||||
style="background: rgba(0,0,0,.55); color: #fff;">
|
||||
<button type="button" class="px-1.5 text-xs rounded hover:bg-white/20" @click="vZoomBy('img', 1 / 1.25)" title="{{ _('Riduci') }}">−</button>
|
||||
@@ -740,12 +740,12 @@
|
||||
<span class="text-xs px-1" x-text="vPct('img')"></span>
|
||||
</div>
|
||||
<!-- #113: viewport fisso 240px; il wrapper (margin auto) e' largo w*zoom: centrato se piu' piccolo, scorrevole se piu' grande -->
|
||||
<div x-show="!imageBroken" x-ref="vpImg" @wheel="vWheel('img', $event)"
|
||||
<div x-ref="vpImg" @wheel="vWheel('img', $event)"
|
||||
@pointerdown="vPanDown('img', $event)" @pointermove="vPanMove('img', $event)"
|
||||
@pointerup="vPanEnd()" @pointercancel="vPanEnd()"
|
||||
class="rounded border border-[var(--border-color)]"
|
||||
:style="'overflow:auto;touch-action:none;user-select:none;display:flex;height:240px;background:var(--bg-primary);cursor:' + vCursor('img')">
|
||||
<div style="margin:auto;flex:none;" :style="views.img.w ? ('width:' + vW('img') + 'px;height:' + vH('img') + 'px') : 'width:100%;height:240px'">
|
||||
<div :style="'margin:auto;flex:none;' + (views.img.w ? ('width:' + vW('img') + 'px;height:' + vH('img') + 'px') : 'width:100%;height:240px')">{# #113: tutto in :style, Alpine con stringa sostituisce l'attributo style #}
|
||||
<img :src="imagePreviewUrl" alt="" draggable="false"
|
||||
@load="onImagePreviewLoad($event.target)" @error="onImagePreviewError()"
|
||||
class="block" style="width: 100%; height: 100%; object-fit: contain; user-select: none;">
|
||||
@@ -771,7 +771,7 @@
|
||||
@pointerup="vPanEnd()" @pointercancel="vPanEnd()"
|
||||
class="rounded border border-[var(--border-color)]"
|
||||
:style="'overflow:auto;touch-action:none;user-select:none;display:flex;height:240px;background:var(--bg-primary);cursor:' + vCursor('dxf')">
|
||||
<div style="margin:auto;flex:none;" :style="'width:' + vW('dxf') + 'px;height:' + vH('dxf') + 'px'">
|
||||
<div :style="'margin:auto;flex:none;width:' + vW('dxf') + 'px;height:' + vH('dxf') + 'px'">
|
||||
<svg x-bind:view-box.camel="dxfPreviewViewBox()" preserveAspectRatio="xMidYMid meet"
|
||||
class="block rounded" style="width: 100%; height: 100%;">
|
||||
<!-- #101: un solo path (x-for/template non funziona nel namespace SVG); view-box.camel perche' il parser HTML abbassa viewBox -->
|
||||
|
||||
@@ -23,18 +23,18 @@ const near = (a, b) => Math.abs(a - b) < 1e-9 * Math.max(1, Math.abs(b));
|
||||
// Wizard con viewport finti e $nextTick sincrono
|
||||
function make(cw) {
|
||||
const w = dxfRecipeWizard(1, () => 'tok', {});
|
||||
const vp = () => ({ clientWidth: cw, clientHeight: 240, scrollLeft: 5, scrollTop: 5 });
|
||||
const vp = () => ({ clientWidth: cw, clientHeight: 238, scrollLeft: 5, scrollTop: 5 });
|
||||
w.$refs = { vpImg: vp(), vpDxf: vp() };
|
||||
w.$nextTick = fn => fn();
|
||||
return w;
|
||||
}
|
||||
|
||||
// img: viewport 400 x 240, immagine 2856 x 2848
|
||||
// img: viewport 400 x 238 utili, immagine 2856 x 2848
|
||||
let w = make(400);
|
||||
w.vSetContent('img', 2856, 2848);
|
||||
check('#113 img: Adatta = 240/2848', near(w.views.img.zoom, 240 / 2848) && near(w.views.img.fit, 240 / 2848), String(w.views.img.zoom));
|
||||
check('#113 img: Adatta = clientHeight/2848', near(w.views.img.zoom, 238 / 2848) && near(w.views.img.fit, 238 / 2848), String(w.views.img.zoom));
|
||||
check('#113 img: scroll azzerato dopo Adatta', w.$refs.vpImg.scrollLeft === 0 && w.$refs.vpImg.scrollTop === 0);
|
||||
check('#113 img: percentuale = zoom*100', w.vPct('img') === Math.round(240 / 2848 * 100) + ' %', w.vPct('img'));
|
||||
check('#113 img: percentuale = zoom*100', w.vPct('img') === Math.round(238 / 2848 * 100) + ' %', w.vPct('img'));
|
||||
const z0 = w.views.img.zoom;
|
||||
w.vZoomBy('img', 1.25);
|
||||
check('#113 img: zoomBy moltiplica', near(w.views.img.zoom, z0 * 1.25));
|
||||
@@ -45,13 +45,17 @@ w.vZoomBy('img', 1e-9);
|
||||
check('#113 img: limite basso 0.05', w.views.img.zoom === 0.05);
|
||||
w.vFit('img');
|
||||
check('#113 img: Adatta torna al fit', near(w.views.img.zoom, z0) && w.vCanPan('img') === false);
|
||||
// clientHeight 0 (non misurabile): ripiego 240
|
||||
w = make(400); w.$refs.vpImg.clientHeight = 0; w.vSetContent('img', 2856, 2848);
|
||||
check('#113 img: clientHeight 0 usa 240', near(w.views.img.fit, 240 / 2848));
|
||||
w = make(400); w.vSetContent('img', 2856, 2848);
|
||||
check('#113 img: l\'altra vista non si muove', w.views.dxf.w === 0 && w.views.dxf.zoom === 1);
|
||||
check('#113 img: wrapper w*zoom', near(w.vW('img'), 2856 * z0) && near(w.vH('img'), 2848 * z0));
|
||||
|
||||
// dxf: viewBox 20 x 10 mm, viewport 400 x 240 -> fit = min(20, 24) = 20
|
||||
// dxf: viewBox 20 x 10 mm, viewport 400 x 238 -> fit = min(20, 23.8) = 20
|
||||
w = make(400);
|
||||
w.vSetContent('dxf', 20, 10);
|
||||
check('#113 dxf: fit = min(vpW/w, 240/h)', near(w.views.dxf.fit, 20), String(w.views.dxf.fit));
|
||||
check('#113 dxf: fit = min(vpW/w, clientHeight/h)', near(w.views.dxf.fit, 20), String(w.views.dxf.fit));
|
||||
check('#113 dxf: dopo Adatta 100 %', w.vPct('dxf') === '100 %', w.vPct('dxf'));
|
||||
w.vZoomBy('dxf', 2);
|
||||
check('#113 dxf: zoom 2x = 200 %', w.vPct('dxf') === '200 %', w.vPct('dxf'));
|
||||
@@ -66,7 +70,7 @@ w.vSetContent('img', 1000, 500);
|
||||
check('#113 clientWidth 0: nessun fit, stato invariato', w.views.img.zoom === 1 && w.views.img.fit === 1 && w.views.img.w === 1000);
|
||||
w.$refs.vpImg.clientWidth = 500;
|
||||
w.vFit('img');
|
||||
check('#113 viewport visibile: il fit parte', near(w.views.img.fit, 0.48), String(w.views.img.fit));
|
||||
check('#113 viewport visibile: il fit parte', near(w.views.img.fit, 238 / 500), String(w.views.img.fit));
|
||||
|
||||
// Reset: nuova immagine / DXF tolto
|
||||
w.vReset('img');
|
||||
|
||||
@@ -362,5 +362,11 @@ class TestPages:
|
||||
assert "vFit('img')" in html and "vFit('dxf')" in html
|
||||
assert "vZoomBy('img', 1.25)" in html and "vZoomBy('dxf', 1.25)" in html
|
||||
assert "vPanDown('img', $event)" in html and "vWheel('dxf', $event)" in html
|
||||
# #113: Alpine :style a stringa sostituisce l'attributo style: niente style statico sullo stesso tag
|
||||
assert 'style="margin:auto;flex:none;"' not in html
|
||||
assert html.count("margin:auto;flex:none;") == 2 and html.count(":style=\"'margin:auto;flex:none;") == 2
|
||||
# #113: x-show e :style (display:flex) si pestano: x-ref="vpImg" non sta sul tag con x-show
|
||||
tag = html[html.rindex("<div", 0, html.index('x-ref="vpImg"')):html.index('x-ref="vpImg"')]
|
||||
assert "x-show" not in tag
|
||||
assert "existing ? msgs.editLabel : msgs.createLabel" in html and "Modifica ricetta da DXF" in html # #105: etichetta dinamica
|
||||
assert "Pezzo scuro su fondo chiaro" in html or "Dark part on light" in html
|
||||
|
||||
Reference in New Issue
Block a user