stable-diffusion-webui
130 строк · 4.1 Кб
1// allows drag-dropping files into gradio image elements, and also pasting images from clipboard
2
3function isValidImageList(files) {4return files && files?.length === 1 && ['image/png', 'image/gif', 'image/jpeg'].includes(files[0].type);5}
6
7function dropReplaceImage(imgWrap, files) {8if (!isValidImageList(files)) {9return;10}11
12const tmpFile = files[0];13
14imgWrap.querySelector('.modify-upload button + button, .touch-none + div button + button')?.click();15const callback = () => {16const fileInput = imgWrap.querySelector('input[type="file"]');17if (fileInput) {18if (files.length === 0) {19files = new DataTransfer();20files.items.add(tmpFile);21fileInput.files = files.files;22} else {23fileInput.files = files;24}25fileInput.dispatchEvent(new Event('change'));26}27};28
29if (imgWrap.closest('#pnginfo_image')) {30// special treatment for PNG Info tab, wait for fetch request to finish31const oldFetch = window.fetch;32window.fetch = async(input, options) => {33const response = await oldFetch(input, options);34if ('api/predict/' === input) {35const content = await response.text();36window.fetch = oldFetch;37window.requestAnimationFrame(() => callback());38return new Response(content, {39status: response.status,40statusText: response.statusText,41headers: response.headers42});43}44return response;45};46} else {47window.requestAnimationFrame(() => callback());48}49}
50
51function eventHasFiles(e) {52if (!e.dataTransfer || !e.dataTransfer.files) return false;53if (e.dataTransfer.files.length > 0) return true;54if (e.dataTransfer.items.length > 0 && e.dataTransfer.items[0].kind == "file") return true;55
56return false;57}
58
59function dragDropTargetIsPrompt(target) {60if (target?.placeholder && target?.placeholder.indexOf("Prompt") >= 0) return true;61if (target?.parentNode?.parentNode?.className?.indexOf("prompt") > 0) return true;62return false;63}
64
65window.document.addEventListener('dragover', e => {66const target = e.composedPath()[0];67if (!eventHasFiles(e)) return;68
69var targetImage = target.closest('[data-testid="image"]');70if (!dragDropTargetIsPrompt(target) && !targetImage) return;71
72e.stopPropagation();73e.preventDefault();74e.dataTransfer.dropEffect = 'copy';75});76
77window.document.addEventListener('drop', e => {78const target = e.composedPath()[0];79if (!eventHasFiles(e)) return;80
81if (dragDropTargetIsPrompt(target)) {82e.stopPropagation();83e.preventDefault();84
85let prompt_target = get_tab_index('tabs') == 1 ? "img2img_prompt_image" : "txt2img_prompt_image";86
87const imgParent = gradioApp().getElementById(prompt_target);88const files = e.dataTransfer.files;89const fileInput = imgParent.querySelector('input[type="file"]');90if (fileInput) {91fileInput.files = files;92fileInput.dispatchEvent(new Event('change'));93}94}95
96var targetImage = target.closest('[data-testid="image"]');97if (targetImage) {98e.stopPropagation();99e.preventDefault();100const files = e.dataTransfer.files;101dropReplaceImage(targetImage, files);102return;103}104});105
106window.addEventListener('paste', e => {107const files = e.clipboardData.files;108if (!isValidImageList(files)) {109return;110}111
112const visibleImageFields = [...gradioApp().querySelectorAll('[data-testid="image"]')]113.filter(el => uiElementIsVisible(el))114.sort((a, b) => uiElementInSight(b) - uiElementInSight(a));115
116
117if (!visibleImageFields.length) {118return;119}120
121const firstFreeImageField = visibleImageFields122.filter(el => !el.querySelector('img'))?.[0];123
124dropReplaceImage(125firstFreeImageField ?126firstFreeImageField :127visibleImageFields[visibleImageFields.length - 1]128, files129);130});131