Skip to content

Commit 3e7bd2a

Browse files
add drop-to-replace functionality for image prompt drop zone (#1341)
* refactor per comments * make outline larger * remove utility function and keep existing file reader code * remove unnecessary event checkers
1 parent 899cbaf commit 3e7bd2a

File tree

2 files changed

+82
-18
lines changed

2 files changed

+82
-18
lines changed

src/wwwroot/css/genpage.css

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1082,6 +1082,7 @@ body {
10821082
position: relative;
10831083
background-color: color-mix(in srgb, transparent 80%, var(--background));
10841084
transition: background-color 0.2s ease-out;
1085+
margin: 0 2px;
10851086
}
10861087
.alt-prompt-image {
10871088
max-height: 128px;
@@ -1118,6 +1119,10 @@ body {
11181119
border: 1px solid black;
11191120
cursor: pointer;
11201121
}
1122+
.alt-prompt-image-container.image-drop-replace-target .alt-prompt-image {
1123+
outline: 4px solid var(--emphasis);
1124+
border-radius: 5px;
1125+
}
11211126
.image-clear-button {
11221127
vertical-align: middle;
11231128
display: inline-block;

src/wwwroot/js/genpage/main.js

Lines changed: 77 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -525,30 +525,70 @@ function autoRevealRevision() {
525525
}
526526
}
527527

528+
let promptImageReplaceTarget = null;
529+
530+
function setPromptImageReplaceTarget(target) {
531+
if (promptImageReplaceTarget) {
532+
promptImageReplaceTarget.classList.remove('image-drop-replace-target');
533+
}
534+
promptImageReplaceTarget = target;
535+
if (promptImageReplaceTarget) {
536+
promptImageReplaceTarget.classList.add('image-drop-replace-target');
537+
}
538+
}
539+
540+
function getPromptImageDropReplaceTarget(e) {
541+
if (uiImprover.getFileList(e.dataTransfer, e).length == 0) {
542+
return null;
543+
}
544+
let target = e.target.closest('.alt-prompt-image-container');
545+
if (!target || !target.querySelector('.alt-prompt-image')) {
546+
return null;
547+
}
548+
return target;
549+
}
550+
528551
function imagePromptAddImage(file) {
529-
let clearButton = getRequiredElementById('alt_prompt_image_clear_button');
530-
let promptImageArea = getRequiredElementById('alt_prompt_image_area');
552+
let replaceTarget = promptImageReplaceTarget;
553+
setPromptImageReplaceTarget(null);
554+
let existingImage = replaceTarget ? replaceTarget.querySelector('.alt-prompt-image') : null;
555+
if (replaceTarget && !existingImage) {
556+
replaceTarget = null;
557+
}
531558
let reader = new FileReader();
532559
reader.onload = (e) => {
533560
let data = e.target.result;
534-
let imageContainer = createDiv(null, 'alt-prompt-image-container');
535-
let imageRemoveButton = createSpan(null, 'alt-prompt-image-container-remove-button', '×');
536-
imageRemoveButton.addEventListener('click', (e) => {
537-
imageContainer.remove();
538-
autoRevealRevision();
539-
genTabLayout.altPromptSizeHandle();
540-
});
541-
imageRemoveButton.title = 'Remove this image';
542-
imageContainer.appendChild(imageRemoveButton);
543-
let imageObject = new Image();
544-
imageObject.src = data;
545-
imageObject.height = 128;
546-
imageObject.className = 'alt-prompt-image';
547-
imageObject.dataset.filedata = data;
548-
imageContainer.appendChild(imageObject);
561+
if (replaceTarget && !replaceTarget.isConnected) {
562+
imagePromptAddImage(file);
563+
return;
564+
}
565+
if (existingImage) {
566+
existingImage.src = data;
567+
existingImage.height = 128;
568+
existingImage.dataset.filedata = data;
569+
}
570+
else {
571+
let promptImageArea = getRequiredElementById('alt_prompt_image_area');
572+
let imageContainer = createDiv(null, 'alt-prompt-image-container');
573+
let imageRemoveButton = createSpan(null, 'alt-prompt-image-container-remove-button', '×');
574+
imageRemoveButton.addEventListener('click', () => {
575+
imageContainer.remove();
576+
autoRevealRevision();
577+
genTabLayout.altPromptSizeHandle();
578+
});
579+
imageRemoveButton.title = 'Remove this image';
580+
imageContainer.appendChild(imageRemoveButton);
581+
let imageObject = new Image();
582+
imageObject.src = data;
583+
imageObject.height = 128;
584+
imageObject.className = 'alt-prompt-image';
585+
imageObject.dataset.filedata = data;
586+
imageContainer.appendChild(imageObject);
587+
promptImageArea.appendChild(imageContainer);
588+
}
589+
let clearButton = getRequiredElementById('alt_prompt_image_clear_button');
549590
clearButton.style.display = '';
550591
showRevisionInputs(true);
551-
promptImageArea.appendChild(imageContainer);
552592
genTabLayout.altPromptSizeHandle();
553593
};
554594
reader.readAsDataURL(file);
@@ -575,6 +615,25 @@ function imagePromptInputHandler() {
575615
}
576616
}
577617
});
618+
let updateReplaceTarget = (e) => {
619+
setPromptImageReplaceTarget(getPromptImageDropReplaceTarget(e));
620+
};
621+
dragArea.addEventListener('dragenter', updateReplaceTarget, true);
622+
dragArea.addEventListener('dragover', updateReplaceTarget, true);
623+
dragArea.addEventListener('dragleave', (e) => {
624+
if (!dragArea.contains(e.relatedTarget)) {
625+
setPromptImageReplaceTarget(null);
626+
}
627+
}, true);
628+
dragArea.addEventListener('drop', (e) => {
629+
setPromptImageReplaceTarget(getPromptImageDropReplaceTarget(e));
630+
}, true);
631+
document.addEventListener('drop', () => {
632+
setPromptImageReplaceTarget(null);
633+
}, true);
634+
document.addEventListener('dragend', () => {
635+
setPromptImageReplaceTarget(null);
636+
}, true);
578637
}
579638
imagePromptInputHandler();
580639

0 commit comments

Comments
 (0)