tester343 commited on
Commit
1484b82
·
verified ·
1 Parent(s): 95bb0e0

Update app_enhanced.py

Browse files
Files changed (1) hide show
  1. app_enhanced.py +85 -64
app_enhanced.py CHANGED
@@ -344,7 +344,7 @@ INDEX_HTML = '''
344
  /* HANDLES FOR DRAGGING */
345
  .handle {
346
  position: absolute;
347
- /* UPDATED: 30px HANDLES */
348
  width: 30px; height: 30px;
349
  background: #ff4757;
350
  border: 3px solid white;
@@ -378,6 +378,9 @@ INDEX_HTML = '''
378
  top: 0; left: 0;
379
  transform-origin: 0 0;
380
  cursor: grab;
 
 
 
381
  }
382
  .panel img.panning { cursor: grabbing; }
383
 
@@ -645,12 +648,11 @@ INDEX_HTML = '''
645
 
646
  const panData = page.panels[i] || { src: '' };
647
  const img = document.createElement('img');
 
648
  img.onload = () => fitImageToPanel(img, pDiv, panData);
649
  img.src = panData.src.includes('?') ? panData.src : panData.src + `?sid=${sid}`;
650
- img.onmousedown = (e) => startPan(e, img);
651
 
652
  pDiv.appendChild(img);
653
- pDiv.onclick = (e) => { e.stopPropagation(); selectPanel(pDiv); };
654
  div.appendChild(pDiv);
655
  }
656
 
@@ -664,7 +666,6 @@ INDEX_HTML = '''
664
  const hDiv = document.createElement('div');
665
  hDiv.className = `handle ${h.cls||''}`; hDiv.id = `${pageId}-${h.id}`;
666
  hDiv.dataset.role = h.id;
667
- hDiv.onmousedown = (e) => startDragHandle(e, pageId, h.id);
668
  div.appendChild(hDiv);
669
  });
670
 
@@ -672,13 +673,6 @@ INDEX_HTML = '''
672
  page.pageBubbles.forEach(bData => div.appendChild(createBubbleHTML(bData)));
673
  }
674
 
675
- div.onclick = (e) => {
676
- if(e.target === div || e.target.classList.contains('comic-page')) {
677
- if(selectedBubble) selectedBubble.classList.remove('selected'); selectedBubble = null;
678
- if(selectedPanel) selectedPanel.classList.remove('selected'); selectedPanel = null;
679
- }
680
- };
681
-
682
  pageWrapper.appendChild(div);
683
  con.appendChild(pageWrapper);
684
 
@@ -723,55 +717,78 @@ INDEX_HTML = '''
723
  setH('h-tier', w/2, ty);
724
  }
725
 
726
- // --- UNIFIED DRAG HANDLERS ---
727
 
728
- function startDragHandle(e, pageId, handleRole) {
729
- e.stopPropagation(); e.preventDefault();
730
- dragMode = 'layout';
731
- dragData = { handle: handleRole, pageId: pageId };
732
- }
733
-
734
- function startBubbleDrag(e, bubble) {
735
- if(e.target.classList.contains('resize-handle')) return;
736
- e.stopPropagation(); e.preventDefault();
737
- selectBubble(bubble);
738
- dragMode = 'bubble';
739
- dragData = {
740
- el: bubble,
741
- startX: e.clientX, startY: e.clientY,
742
- initX: bubble.offsetLeft, initY: bubble.offsetTop
743
- };
744
- }
745
-
746
- function startResize(e, dir) {
747
- e.stopPropagation(); e.preventDefault();
748
- dragMode = 'resize-bubble';
749
- const rect = selectedBubble.getBoundingClientRect();
750
- dragData = {
751
- el: selectedBubble, dir: dir,
752
- startX: e.clientX, startY: e.clientY,
753
- startW: rect.width, startH: rect.height
754
- };
755
- }
756
-
757
- function startPan(e, img) {
758
- e.preventDefault();
759
- selectPanel(img.closest('.panel'));
760
- dragMode = 'pan';
761
- dragData = {
762
- el: img,
763
- startX: e.clientX, startY: e.clientY,
764
- startTx: parseFloat(img.dataset.translateX || 0),
765
- startTy: parseFloat(img.dataset.translateY || 0)
766
- };
767
- img.classList.add('panning');
768
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
769
 
770
- // --- UNIFIED MOUSE MOVE ---
771
  document.addEventListener('mousemove', (e) => {
772
  if(!dragMode) return;
773
-
774
- e.preventDefault(); // Prevent selection/scrolling while dragging
775
 
776
  if(dragMode === 'layout') {
777
  const pageEl = document.getElementById(dragData.pageId);
@@ -845,9 +862,7 @@ INDEX_HTML = '''
845
  const iW = img.naturalWidth || img.width;
846
  const iH = img.naturalHeight || img.height;
847
 
848
- // CONTAIN LOGIC: Ensure WHOLE image fits
849
  const scale = Math.min(pW / iW, pH / iH);
850
-
851
  const tx = (pW - iW * scale) / 2;
852
  const ty = (pH - iH * scale) / 2;
853
 
@@ -883,13 +898,8 @@ INDEX_HTML = '''
883
  if(data.tailPos) b.style.setProperty('--tail-pos', data.tailPos);
884
  const textSpan = document.createElement('span'); textSpan.className = 'bubble-text'; textSpan.textContent = data.text || ''; b.appendChild(textSpan);
885
  if(type === 'thought') { for(let i=1; i<=2; i++){ const d = document.createElement('div'); d.className = `thought-dot thought-dot-${i}`; b.appendChild(d); } }
886
- ['nw', 'ne', 'sw', 'se'].forEach(dir => { const handle = document.createElement('div'); handle.className = `resize-handle ${dir}`; handle.onmousedown = (e) => startResize(e, dir); b.appendChild(handle); });
887
-
888
- // BUBBLE DRAG HANDLER
889
- b.onmousedown = (e) => startBubbleDrag(e, b);
890
 
891
- b.onclick = (e) => { e.stopPropagation(); };
892
- b.ondblclick = (e) => { e.stopPropagation(); editBubbleText(b); };
893
  return b;
894
  }
895
 
@@ -915,6 +925,17 @@ INDEX_HTML = '''
915
  handles.forEach(h=>h.style.display='block');
916
  }
917
  function goBackToUpload() { if(confirm('Go home? Unsaved changes will be lost.')) { document.getElementById('editor-container').style.display = 'none'; document.getElementById('upload-container').style.display = 'flex'; document.getElementById('loading-view').style.display = 'none'; } }
 
 
 
 
 
 
 
 
 
 
 
918
  </script>
919
  </body> </html> '''
920
 
 
344
  /* HANDLES FOR DRAGGING */
345
  .handle {
346
  position: absolute;
347
+ /* UPDATED: MUCH LARGER HANDLES (30px) */
348
  width: 30px; height: 30px;
349
  background: #ff4757;
350
  border: 3px solid white;
 
378
  top: 0; left: 0;
379
  transform-origin: 0 0;
380
  cursor: grab;
381
+ /* CRITICAL FOR PANNING: Prevent ghost image */
382
+ user-select: none;
383
+ -webkit-user-drag: none;
384
  }
385
  .panel img.panning { cursor: grabbing; }
386
 
 
648
 
649
  const panData = page.panels[i] || { src: '' };
650
  const img = document.createElement('img');
651
+ img.setAttribute('draggable', 'false'); // STOP BROWSER DRAG
652
  img.onload = () => fitImageToPanel(img, pDiv, panData);
653
  img.src = panData.src.includes('?') ? panData.src : panData.src + `?sid=${sid}`;
 
654
 
655
  pDiv.appendChild(img);
 
656
  div.appendChild(pDiv);
657
  }
658
 
 
666
  const hDiv = document.createElement('div');
667
  hDiv.className = `handle ${h.cls||''}`; hDiv.id = `${pageId}-${h.id}`;
668
  hDiv.dataset.role = h.id;
 
669
  div.appendChild(hDiv);
670
  });
671
 
 
673
  page.pageBubbles.forEach(bData => div.appendChild(createBubbleHTML(bData)));
674
  }
675
 
 
 
 
 
 
 
 
676
  pageWrapper.appendChild(div);
677
  con.appendChild(pageWrapper);
678
 
 
717
  setH('h-tier', w/2, ty);
718
  }
719
 
720
+ // --- GLOBAL EVENT DELEGATION FOR RELIABILITY ---
721
 
722
+ document.addEventListener('mousedown', (e) => {
723
+ const target = e.target;
724
+
725
+ // 1. HANDLES
726
+ if (target.classList.contains('handle')) {
727
+ e.preventDefault(); e.stopPropagation();
728
+ dragMode = 'layout';
729
+ dragData = { handle: target.dataset.role, pageId: target.closest('.comic-page').id };
730
+ return;
731
+ }
732
+
733
+ // 2. RESIZE HANDLES (Bubble corner)
734
+ if (target.classList.contains('resize-handle')) {
735
+ e.preventDefault(); e.stopPropagation();
736
+ dragMode = 'resize-bubble';
737
+ const bubble = target.closest('.speech-bubble');
738
+ const rect = bubble.getBoundingClientRect();
739
+ let dir = 'se'; // default
740
+ if(target.classList.contains('sw')) dir = 'sw';
741
+ if(target.classList.contains('ne')) dir = 'ne';
742
+ if(target.classList.contains('nw')) dir = 'nw';
743
+
744
+ dragData = {
745
+ el: bubble, dir: dir,
746
+ startX: e.clientX, startY: e.clientY,
747
+ startW: rect.width, startH: rect.height
748
+ };
749
+ return;
750
+ }
751
+
752
+ // 3. BUBBLES
753
+ const bubble = target.closest('.speech-bubble');
754
+ if (bubble) {
755
+ e.preventDefault(); e.stopPropagation();
756
+ selectBubble(bubble);
757
+ dragMode = 'bubble';
758
+ dragData = {
759
+ el: bubble,
760
+ startX: e.clientX, startY: e.clientY,
761
+ initX: bubble.offsetLeft, initY: bubble.offsetTop
762
+ };
763
+ return;
764
+ }
765
+
766
+ // 4. PANELS/IMAGES
767
+ if (target.tagName === 'IMG' && target.closest('.panel')) {
768
+ e.preventDefault(); e.stopPropagation();
769
+ const panel = target.closest('.panel');
770
+ selectPanel(panel);
771
+ dragMode = 'pan';
772
+ dragData = {
773
+ el: target,
774
+ startX: e.clientX, startY: e.clientY,
775
+ startTx: parseFloat(target.dataset.translateX || 0),
776
+ startTy: parseFloat(target.dataset.translateY || 0)
777
+ };
778
+ target.classList.add('panning');
779
+ return;
780
+ }
781
+
782
+ // 5. CLICK OFF (Deselect)
783
+ if (!target.closest('.edit-controls') && !target.closest('.modal-content')) {
784
+ if(selectedBubble) selectedBubble.classList.remove('selected'); selectedBubble = null;
785
+ if(selectedPanel) selectedPanel.classList.remove('selected'); selectedPanel = null;
786
+ }
787
+ });
788
 
 
789
  document.addEventListener('mousemove', (e) => {
790
  if(!dragMode) return;
791
+ e.preventDefault(); // Stop text selection
 
792
 
793
  if(dragMode === 'layout') {
794
  const pageEl = document.getElementById(dragData.pageId);
 
862
  const iW = img.naturalWidth || img.width;
863
  const iH = img.naturalHeight || img.height;
864
 
 
865
  const scale = Math.min(pW / iW, pH / iH);
 
866
  const tx = (pW - iW * scale) / 2;
867
  const ty = (pH - iH * scale) / 2;
868
 
 
898
  if(data.tailPos) b.style.setProperty('--tail-pos', data.tailPos);
899
  const textSpan = document.createElement('span'); textSpan.className = 'bubble-text'; textSpan.textContent = data.text || ''; b.appendChild(textSpan);
900
  if(type === 'thought') { for(let i=1; i<=2; i++){ const d = document.createElement('div'); d.className = `thought-dot thought-dot-${i}`; b.appendChild(d); } }
901
+ ['nw', 'ne', 'sw', 'se'].forEach(dir => { const handle = document.createElement('div'); handle.className = `resize-handle ${dir}`; b.appendChild(handle); });
 
 
 
902
 
 
 
903
  return b;
904
  }
905
 
 
925
  handles.forEach(h=>h.style.display='block');
926
  }
927
  function goBackToUpload() { if(confirm('Go home? Unsaved changes will be lost.')) { document.getElementById('editor-container').style.display = 'none'; document.getElementById('upload-container').style.display = 'flex'; document.getElementById('loading-view').style.display = 'none'; } }
928
+
929
+ // Select panel helper
930
+ function selectPanel(el) {
931
+ if(selectedPanel) selectedPanel.classList.remove('selected');
932
+ if(selectedBubble) { selectedBubble.classList.remove('selected'); selectedBubble = null; }
933
+ selectedPanel = el; el.classList.add('selected');
934
+ document.getElementById('zoom-slider').disabled = false;
935
+ const img = el.querySelector('img');
936
+ if(img) document.getElementById('zoom-slider').value = img.dataset.zoom || 100;
937
+ document.getElementById('bubble-type-select').disabled = true; document.getElementById('font-select').disabled = true;
938
+ }
939
  </script>
940
  </body> </html> '''
941