diff --git a/javascript/dragdrop.js b/javascript/dragdrop.js
index eca83496..2e6f20b9 100644
--- a/javascript/dragdrop.js
+++ b/javascript/dragdrop.js
@@ -1,25 +1,16 @@
-// allows drag-dropping files into gradio image elements, and also pasting images from clipboard
+// allows drag-and-drop files into prompt fields, and also pasting images from clipboard
function isValidImageList(files) {
- return (
- files &&
- files?.length === 1 &&
- ["image/png", "image/gif", "image/jpeg"].includes(files[0].type)
- );
+ return files != null && files.length === 1 && files[0].type.startsWith("image");
}
function dropReplaceImage(imgWrap, files) {
- if (!isValidImageList(files)) {
- return;
- }
+ if (!isValidImageList(files)) return;
const tmpFile = files[0];
- imgWrap
- .querySelector(
- ".modify-upload button + button, .touch-none + div button + button",
- )
- ?.click();
+ imgWrap.querySelector(".modify-upload button + button, .touch-none + div button + button")?.click();
+
const callback = () => {
const fileInput = imgWrap.querySelector('input[type="file"]');
if (fileInput) {
@@ -40,8 +31,7 @@ function dropReplaceImage(imgWrap, files) {
function eventHasFiles(e) {
if (!e.dataTransfer || !e.dataTransfer.files) return false;
if (e.dataTransfer.files.length > 0) return true;
- if (e.dataTransfer.items.length > 0 && e.dataTransfer.items[0].kind == "file")
- return true;
+ if (e.dataTransfer.items.length > 0 && e.dataTransfer.items[0].kind == "file") return true;
return false;
}
@@ -56,10 +46,8 @@ function isURL(url) {
}
function dragDropTargetIsPrompt(target) {
- if (target?.placeholder && target?.placeholder.indexOf("Prompt") >= 0)
- return true;
- if (target?.parentNode?.parentNode?.className?.indexOf("prompt") > 0)
- return true;
+ if (target?.placeholder && target?.placeholder.indexOf("Prompt") >= 0) return true;
+ if (target?.parentNode?.parentNode?.className?.indexOf("prompt") > 0) return true;
return false;
}
@@ -67,7 +55,7 @@ window.document.addEventListener("dragover", (e) => {
const target = e.composedPath()[0];
if (!eventHasFiles(e)) return;
- let targetImage = target.closest('[data-testid="image"]');
+ const targetImage = target.closest('[data-testid="image"]');
if (!dragDropTargetIsPrompt(target) && !targetImage) return;
e.stopPropagation();
@@ -77,9 +65,7 @@ window.document.addEventListener("dragover", (e) => {
window.document.addEventListener("drop", async (e) => {
const target = e.composedPath()[0];
- const url =
- e.dataTransfer.getData("text/uri-list") ||
- e.dataTransfer.getData("text/plain");
+ const url = e.dataTransfer.getData("text/uri-list") || e.dataTransfer.getData("text/plain");
if (!eventHasFiles(e) && !isURL(url)) return;
if (dragDropTargetIsPrompt(target)) {
@@ -87,9 +73,7 @@ window.document.addEventListener("drop", async (e) => {
e.preventDefault();
const isImg2img = get_tab_index("tabs") == 1;
- let prompt_image_target = isImg2img
- ? "img2img_prompt_image"
- : "txt2img_prompt_image";
+ const prompt_image_target = isImg2img ? "img2img_prompt_image" : "txt2img_prompt_image";
const imgParent = gradioApp().getElementById(prompt_image_target);
const files = e.dataTransfer.files;
@@ -115,7 +99,7 @@ window.document.addEventListener("drop", async (e) => {
}
}
- let targetImage = target.closest('[data-testid="image"]');
+ const targetImage = target.closest('[data-testid="image"]');
if (targetImage) {
e.stopPropagation();
e.preventDefault();
@@ -127,28 +111,18 @@ window.document.addEventListener("drop", async (e) => {
window.addEventListener("paste", (e) => {
const files = e.clipboardData.files;
- if (!isValidImageList(files)) {
- return;
- }
+ if (!isValidImageList(files)) return;
- const visibleImageFields = [
- ...gradioApp().querySelectorAll('[data-testid="image"]'),
- ]
+ const visibleImageFields = [...gradioApp().querySelectorAll('[data-testid="image"]')]
.filter((el) => uiElementIsVisible(el))
.sort((a, b) => uiElementInSight(b) - uiElementInSight(a));
- if (!visibleImageFields.length) {
- return;
- }
+ if (!visibleImageFields.length) return;
- const firstFreeImageField = visibleImageFields.filter(
- (el) => !el.querySelector("img"),
- )?.[0];
+ const firstFreeImageField = visibleImageFields.filter((el) => !el.querySelector("img"))?.[0];
dropReplaceImage(
- firstFreeImageField
- ? firstFreeImageField
- : visibleImageFields[visibleImageFields.length - 1],
+ firstFreeImageField ? firstFreeImageField : visibleImageFields[visibleImageFields.length - 1],
files,
);
});
diff --git a/javascript/imageDragAndDrop.js b/javascript/imageDragAndDrop.js
index f8b3f51d..4338286a 100644
--- a/javascript/imageDragAndDrop.js
+++ b/javascript/imageDragAndDrop.js
@@ -1,55 +1,27 @@
(function () {
- function extractImageFromHTML(html) {
- if (!html) return null;
- const match = html.match(/
]+src="([^">]+)"/i);
- return match ? match[1] : null;
- }
-
/** @param {HTMLDivElement} gradioImage */
function patchDragAndDrop(gradioImage) {
- let isDroppingImage = false;
-
gradioImage.addEventListener("dragover", (e) => {
const dt = e.dataTransfer;
- isDroppingImage = dt.types.includes("text/uri-list") || dt.types.includes("text/html");
- if (isDroppingImage) e.preventDefault();
- });
-
- gradioImage.addEventListener("drop", async (e) => {
+ const isDroppingImage = dt.types.includes("text/uri-list") || dt.types.includes("text/html");
if (!isDroppingImage) return;
- const dt = e.dataTransfer;
-
- const url = dt.getData("text/uri-list") || extractImageFromHTML(dt.getData("text/html"));
- if (!url) return;
-
- e.preventDefault();
-
- try {
- const closeButton = gradioImage.querySelector('button[aria-label="Remove Image"]');
- closeButton.click();
-
- const res = await fetch(url);
- const blob = await res.blob();
-
- const file = new File([blob], "dropped-image", {
- type: blob.type || "image/png",
- });
-
- const newDT = new DataTransfer();
- newDT.items.add(file);
-
- const fileInput = gradioImage.querySelector('input[type="file"]');
- fileInput.files = newDT.files;
-
- fileInput.dispatchEvent(new Event("change", { bubbles: true }));
- } catch {
- console.log("Failed to replace image...");
- }
+ const closeButton = gradioImage.querySelector('button[aria-label="Remove Image"]');
+ if (closeButton) closeButton.click();
});
}
+ function setup() {
+ if (opts.remove_image_on_hover === false) return;
+ if (opts.remove_image_on_hover === undefined) {
+ setTimeout(setup, 50);
+ return;
+ }
+
+ for (const id of ["extras_image", "pnginfo_image"]) patchDragAndDrop(document.getElementById(id));
+ }
+
onUiLoaded(() => {
- for (const id of ["extras_image", "pnginfo_image"]) patchDragAndDrop(document.getElementById(id));
+ setTimeout(setup, 100);
});
})();
diff --git a/modules/shared_options.py b/modules/shared_options.py
index b6b966c7..b3f47dc6 100644
--- a/modules/shared_options.py
+++ b/modules/shared_options.py
@@ -425,6 +425,7 @@ options_templates.update(
"ctrl_enter_interrupt": OptionInfo(False, "Revert [Ctrl + Enter] to only interrupt the generation").info('the current "intended" behavior is to interrupt the current generation then immediately start a new one'),
"quicksettings_accordion": OptionInfo(False, "Place the Quicksettings under an Accordion").needs_reload_ui(),
"quicksettings_accordion_starts_closed": OptionInfo(False, "Close the Accordion on startup").info("for the above option").needs_reload_ui(),
+ "remove_image_on_hover": OptionInfo(True, "For image inputs in Extras and PNG Info, remove the current image when dragging another image over it").info("allow you to drag-and-drop images onto the input similar to AUTOMATIC1111 behavior").needs_reload_ui(),
"forbidden_knowledge": OptionInfo(False, "Forbidden Knowledge").info('replace "DPM++ 2s a RF" with "Flux Realistic"').needs_restart(),
"div_prompt": OptionDiv(),
"prompt_box_style": OptionInfo("Default", "Prompt Layout", gr.Radio, {"choices": ("Default", "Compact", "Scrollable", "Accordion")}).html(f"""