let state = "free" let oldGradio let galleryItemName onUiLoaded(image_browser_start) function image_browser_delay(ms){return new Promise(resolve => setTimeout(resolve, ms))} async function image_browser_lock(reason) { // Wait until lock removed let i = 0 while (state != "free") { await image_browser_delay(200) i = i + 1 if (i === 150) { throw new Error("Still locked after 30 seconds. Please Reload UI.") } } // Lock state = reason } async function image_browser_unlock() { state = "free" } function isVersionSmaller(version1, version2) { let v1 = version1.split('.').map(Number) let v2 = version2.split('.').map(Number) for (let i = 0; i < Math.max(v1.length, v2.length); i++) { if ((v1[i] || 0) < (v2[i] || 0)) return true if ((v1[i] || 0) > (v2[i] || 0)) return false } return false } const image_browser_click_image = async function() { await image_browser_lock("image_browser_click_image") const gallery_items = image_browser_get_parent_by_tagname(this, "DIV").querySelectorAll(galleryItemNameDot) const index = Array.from(gallery_items).indexOf(this) const gallery = image_browser_get_parent_by_class(this, "image_browser_container") const set_btn = gallery.querySelector(".image_browser_set_index") const curr_idx = set_btn.getAttribute("img_index") if (curr_idx != index) { set_btn.setAttribute("img_index", index) } set_btn.click() await image_browser_unlock() } function image_browser_get_parent_by_class(item, class_name) { let parent = item.parentElement while(!parent.classList.contains(class_name)){ parent = parent.parentElement } return parent } function image_browser_get_parent_by_tagname(item, tagname) { let parent = item.parentElement tagname = tagname.toUpperCase() while(parent.tagName != tagname){ parent = parent.parentElement } return parent } function image_browser_run_after_preview_load(tab_base_tag, func) { ob = new MutationObserver(async (mutationList, observer) => { elem = mutationList[0].target if (elem.classList.contains("hide")) { func() observer.disconnect() } }) ob.observe( gradioApp().querySelectorAll(`#${tab_base_tag}_image_browser_gallery .svelte-gjihhp`)[0], { attributes: true } ) } async function image_browser_get_current_img(tab_base_tag, img_index, page_index, filenames, turn_page_switch, image_gallery) { await image_browser_lock("image_browser_get_current_img") img_index = gradioApp().getElementById(tab_base_tag + '_image_browser_set_index').getAttribute("img_index") image_browser_hide_loading_animation(true) gradioApp().dispatchEvent(new Event("image_browser_get_current_img")) image_browser_run_after_preview_load(tab_base_tag,() => image_browser_hide_loading_animation(false)) await image_browser_unlock() return [ tab_base_tag, img_index, page_index, filenames, turn_page_switch, image_gallery ] } function image_browser_hide_loading_animation(hidden) { if (hidden === true) { gradioApp().querySelectorAll("div[id^='image_browser_tab'][id$='image_browser_gallery']:not(.hide_loading)").forEach((elem) => { elem.classList.add("hide_loading") }) } else { gradioApp().querySelectorAll("div[id^='image_browser_tab'][id$='image_browser_gallery'].hide_loading").forEach((elem) => { elem.classList.remove("hide_loading") }) } } async function image_browser_refresh_current_page_preview(wait_time = 200) { await image_browser_delay(wait_time) const preview_div = gradioApp().querySelector('.preview') if (preview_div === null) return const tab_base_tag = image_browser_current_tab() const gallery = gradioApp().querySelector(`#${tab_base_tag}_image_browser`) const set_btn = gallery.querySelector(".image_browser_set_index") const curr_idx = parseInt(set_btn.getAttribute("img_index")) // no loading animation, so click immediately const gallery_items = gallery.querySelectorAll(galleryItemNameDot) const curr_image = gallery_items[curr_idx] curr_image.click() } async function image_browser_refresh_preview(wait_time = 200) { await image_browser_delay(wait_time) const preview_div = gradioApp().querySelector('.preview') if (preview_div === null) return const tab_base_tag = image_browser_current_tab() const gallery = gradioApp().querySelector(`#${tab_base_tag}_image_browser`) const set_btn = gallery.querySelector(".image_browser_set_index") const curr_idx = set_btn.getAttribute("img_index") // wait for page loading... image_browser_run_after_preview_load(tab_base_tag, () => { const gallery_items = gallery.querySelectorAll(galleryItemNameDot) const curr_image = gallery_items[curr_idx] curr_image.click() }) } async function image_browser_select_image(tab_base_tag, img_index) { await image_browser_lock("image_browser_select_image") const del_img_btn = gradioApp().getElementById(tab_base_tag + "_image_browser_del_img_btn") del_img_btn.style.pointerEvents = "none" del_img_btn.style.cursor = "not-allowed" del_img_btn.style.opacity = "0.65" const gallery = gradioApp().getElementById(tab_base_tag + "_image_browser_gallery") const gallery_items = gallery.querySelectorAll(galleryItemNameDot) if (img_index >= gallery_items.length || gallery_items.length == 0) { const refreshBtn = gradioApp().getElementById(tab_base_tag + "_image_browser_renew_page") refreshBtn.dispatchEvent(new Event("click")) } else { const curr_image = gallery_items[img_index] curr_image.click() } await image_browser_unlock() // Prevent delete button spam const image_browser_get_current_img_handler = () => { del_img_btn.style.pointerEvents = "auto" del_img_btn.style.cursor = "default" del_img_btn.style.opacity = "1" } gradioApp().removeEventListener("image_browser_get_current_img", image_browser_get_current_img_handler) gradioApp().addEventListener("image_browser_get_current_img", image_browser_get_current_img_handler) } async function image_browser_turnpage(tab_base_tag) { await image_browser_lock("image_browser_turnpage") const gallery_items = gradioApp().getElementById(tab_base_tag + '_image_browser').querySelectorAll(galleryItemNameDot) gallery_items.forEach(function(elem) { elem.style.display = 'block' }) await image_browser_unlock() } function image_browser_gototab(tabname, tabsId = "tabs") { Array.from( gradioApp().querySelectorAll(`#${tabsId} > div:first-child button`) ).forEach((button) => { if (button.textContent.trim() === tabname) { button.click() } }) } async function image_browser_get_image_for_ext(tab_base_tag, image_index) { const image_browser_image = gradioApp().querySelectorAll(`#${tab_base_tag}_image_browser_gallery ${galleryItemNameDot}`)[image_index] const canvas = document.createElement("canvas") const image = document.createElement("img") image.src = image_browser_image.querySelector("img").src await image.decode() canvas.width = image.width canvas.height = image.height canvas.getContext("2d").drawImage(image, 0, 0) return canvas.toDataURL() } function image_browser_openoutpaint_send(tab_base_tag, image_index, image_browser_prompt, image_browser_neg_prompt, name = "WebUI Resource") { image_browser_get_image_for_ext(tab_base_tag, image_index) .then((dataURL) => { // Send to openOutpaint openoutpaint_send_image(dataURL, name) // Send prompt to openOutpaint const tab = get_uiCurrentTabContent().id const prompt = image_browser_prompt const negPrompt = image_browser_neg_prompt openoutpaint.frame.contentWindow.postMessage({ key: openoutpaint.key, type: "openoutpaint/set-prompt", prompt, negPrompt, }) // Change Tab image_browser_gototab("openOutpaint") }) } async function image_browser_controlnet_send(toTab, tab_base_tag, image_index, controlnetNum) { const dataURL = await image_browser_get_image_for_ext(tab_base_tag, image_index) const blob = await (await fetch(dataURL)).blob() const dt = new DataTransfer() dt.items.add(new File([blob], "ImageBrowser.png", { type: blob.type })) const container = gradioApp().querySelector( toTab === "txt2img" ? "#txt2img_script_container" : "#img2img_script_container" ) const accordion = container.querySelector("#controlnet .transition") if (accordion.classList.contains("rotate-90")) accordion.click() const tab = container.querySelectorAll( "#controlnet > div:nth-child(2) > .tabs > .tabitem, #controlnet > div:nth-child(2) > div:not(.tabs)" )[controlnetNum] if (tab.classList.contains("tabitem")) tab.parentElement.firstElementChild.querySelector(`:nth-child(${Number(controlnetNum) + 1})`).click() const input = tab.querySelector("input[type='file']") try { input.previousElementSibling.previousElementSibling.querySelector("button[aria-label='Clear']").click() } catch (e) {} input.value = "" input.files = dt.files input.dispatchEvent(new Event("change", { bubbles: true, composed: true })) image_browser_gototab(toTab) } function image_browser_controlnet_send_txt2img(tab_base_tag, image_index, controlnetNum) { image_browser_controlnet_send("txt2img", tab_base_tag, image_index, controlnetNum) } function image_browser_controlnet_send_img2img(tab_base_tag, image_index, controlnetNum) { image_browser_controlnet_send("img2img", tab_base_tag, image_index, controlnetNum) } function image_browser_class_add(tab_base_tag) { gradioApp().getElementById(tab_base_tag + '_image_browser').classList.add("image_browser_container") gradioApp().getElementById(tab_base_tag + '_image_browser_set_index').classList.add("image_browser_set_index") gradioApp().getElementById(tab_base_tag + '_image_browser_del_img_btn').classList.add("image_browser_del_img_btn") gradioApp().getElementById(tab_base_tag + '_image_browser_gallery').classList.add("image_browser_gallery") } function btnClickHandler(tab_base_tag, btn) { const tabs_box = gradioApp().getElementById("image_browser_tabs_container") if (!tabs_box.classList.contains(tab_base_tag)) { gradioApp().getElementById(tab_base_tag + "_image_browser_renew_page").click() tabs_box.classList.add(tab_base_tag) } } function image_browser_init() { const GradioVersion = gradioApp().getElementById("image_browser_gradio_version").querySelector("textarea").value if (isVersionSmaller(GradioVersion, "3.17")) { oldGradio = true galleryItemName = "gallery-item" } else { oldGradio = false galleryItemName = "thumbnail-item" } galleryItemNameDot = "." + galleryItemName const tab_base_tags = gradioApp().getElementById("image_browser_tab_base_tags_list") if (tab_base_tags) { const image_browser_tab_base_tags_list = tab_base_tags.querySelector("textarea").value.split(",") image_browser_tab_base_tags_list.forEach(function(tab_base_tag) { image_browser_class_add(tab_base_tag) }) const tab_btns = gradioApp().getElementById("image_browser_tabs_container").querySelector("div").querySelectorAll("button") tab_btns.forEach(function(btn, i) { const tab_base_tag = image_browser_tab_base_tags_list[i] btn.setAttribute("tab_base_tag", tab_base_tag) btn.removeEventListener('click', () => btnClickHandler(tab_base_tag, btn)) btn.addEventListener('click', () => btnClickHandler(tab_base_tag, btn)) }) //preload if (gradioApp().getElementById("image_browser_preload").querySelector("input").checked) { setTimeout(function(){tab_btns[0].click()}, 100) } } image_browser_keydown() } async function image_browser_wait_for_gallery_btn(tab_base_tag){ await image_browser_delay(100) while (!gradioApp().getElementById(image_browser_current_tab() + "_image_browser_gallery").getElementsByClassName(galleryItemName)) { await image_browser_delay(200) } } function image_browser_renew_page(tab_base_tag) { gradioApp().getElementById(tab_base_tag + '_image_browser_renew_page').click() } function image_browser_start() { image_browser_init() const mutationObserver = new MutationObserver(function(mutationsList) { const tab_base_tags = gradioApp().getElementById("image_browser_tab_base_tags_list") if (tab_base_tags) { const image_browser_tab_base_tags_list = tab_base_tags.querySelector("textarea").value.split(",") image_browser_tab_base_tags_list.forEach(function(tab_base_tag) { image_browser_class_add(tab_base_tag) const tab_gallery_items = gradioApp().querySelectorAll('#' + tab_base_tag + '_image_browser ' + galleryItemNameDot) tab_gallery_items.forEach(function(gallery_item) { gallery_item.removeEventListener('click', image_browser_click_image, true) gallery_item.addEventListener('click', image_browser_click_image, true) document.onkeyup = async function(e) { if (!image_browser_active()) { return } const current_tab = image_browser_current_tab() image_browser_wait_for_gallery_btn(current_tab).then(() => { let gallery_btn if (oldGradio) { gallery_btn = gradioApp().getElementById(current_tab + "_image_browser_gallery").getElementsByClassName(galleryItemName + ' !flex-none !h-9 !w-9 transition-all duration-75 !ring-2 !ring-orange-500 hover:!ring-orange-500 svelte-1g9btlg') } else { gallery_btn = gradioApp().getElementById(current_tab + "_image_browser_gallery").querySelector(galleryItemNameDot + ' .selected') } gallery_btn = gallery_btn && gallery_btn.length > 0 ? gallery_btn[0] : null if (gallery_btn) { image_browser_click_image.call(gallery_btn) } }) } }) const cls_btn = gradioApp().getElementById(tab_base_tag + '_image_browser_gallery').querySelector("svg") if (cls_btn) { cls_btn.removeEventListener('click', () => image_browser_renew_page(tab_base_tag), false) cls_btn.addEventListener('click', () => image_browser_renew_page(tab_base_tag), false) } }) } }) mutationObserver.observe(gradioApp(), { childList:true, subtree:true }) } function image_browser_current_tab() { const tabs = gradioApp().getElementById("image_browser_tabs_container").querySelectorAll('[id$="_image_browser_container"]') const tab_base_tags = gradioApp().getElementById("image_browser_tab_base_tags_list") const image_browser_tab_base_tags_list = tab_base_tags.querySelector("textarea").value.split(",") for (const element of tabs) { if (element.style.display === "block") { const id = element.id const tab_base_tag = image_browser_tab_base_tags_list.find(element => id.startsWith(element)) || null return tab_base_tag } } } function image_browser_active() { const ext_active = gradioApp().getElementById("tab_image_browser") return ext_active && ext_active.style.display !== "none" } function image_browser_keydown() { gradioApp().addEventListener("keydown", function(event) { // If we are not on the Image Browser Extension, dont listen for keypresses if (!image_browser_active()) { return } // If the user is typing in an input field, dont listen for keypresses let target if (!event.composed) { // We shouldn't get here as the Shadow DOM is always active, but just in case target = event.target } else { target = event.composedPath()[0] } if (!target || target.nodeName === "INPUT" || target.nodeName === "TEXTAREA") { return } const tab_base_tag = image_browser_current_tab() // Listens for keypresses 0-5 and updates the corresponding ranking (0 is the last option, None) if (event.code >= "Digit0" && event.code <= "Digit5") { const selectedValue = event.code.charAt(event.code.length - 1) const radioInputs = gradioApp().getElementById(tab_base_tag + "_image_browser_ranking").getElementsByTagName("input") for (const input of radioInputs) { if (input.value === selectedValue || (selectedValue === '0' && input === radioInputs[radioInputs.length - 1])) { input.checked = true input.dispatchEvent(new Event("change")) break } } } const mod_keys = gradioApp().querySelector(`#${tab_base_tag}_image_browser_mod_keys textarea`).value let modifiers_pressed = false if (mod_keys.indexOf("C") !== -1 && mod_keys.indexOf("S") !== -1) { if (event.ctrlKey && event.shiftKey) { modifiers_pressed = true } } else if (mod_keys.indexOf("S") !== -1) { if (!event.ctrlKey && event.shiftKey) { modifiers_pressed = true } } else { if (event.ctrlKey && !event.shiftKey) { modifiers_pressed = true } } let modifiers_none = false if (!event.ctrlKey && !event.shiftKey && !event.altKey && !event.metaKey) { modifiers_none = true } if (event.code == "KeyF" && modifiers_none) { if (tab_base_tag == "image_browser_tab_favorites") { return } const favoriteBtn = gradioApp().getElementById(tab_base_tag + "_image_browser_favorites_btn") favoriteBtn.dispatchEvent(new Event("click")) } if (event.code == "KeyR" && modifiers_none) { const refreshBtn = gradioApp().getElementById(tab_base_tag + "_image_browser_renew_page") refreshBtn.dispatchEvent(new Event("click")) } if (event.code == "Delete" && modifiers_none) { const deleteBtn = gradioApp().getElementById(tab_base_tag + "_image_browser_del_img_btn") deleteBtn.dispatchEvent(new Event("click")) } if (event.code == "ArrowLeft" && modifiers_pressed) { const prevBtn = gradioApp().getElementById(tab_base_tag + "_image_browser_prev_page") prevBtn.dispatchEvent(new Event("click")) } if (event.code == "ArrowLeft" && modifiers_none) { const tab_base_tag = image_browser_current_tab() const set_btn = gradioApp().querySelector(`#${tab_base_tag}_image_browser .image_browser_set_index`) const curr_idx = parseInt(set_btn.getAttribute("img_index")) set_btn.setAttribute("img_index", curr_idx - 1) image_browser_refresh_current_page_preview() } if (event.code == "ArrowRight" && modifiers_pressed) { const nextBtn = gradioApp().getElementById(tab_base_tag + "_image_browser_next_page") nextBtn.dispatchEvent(new Event("click")) } if (event.code == "ArrowRight" && modifiers_none) { const tab_base_tag = image_browser_current_tab() const set_btn = gradioApp().querySelector(`#${tab_base_tag}_image_browser .image_browser_set_index`) const curr_idx = parseInt(set_btn.getAttribute("img_index")) set_btn.setAttribute("img_index", curr_idx + 1) image_browser_refresh_current_page_preview() } }) }