extraNetworks.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400
  1. function toggleCss(key, css, enable) {
  2. var style = document.getElementById(key);
  3. if (enable && !style) {
  4. style = document.createElement('style');
  5. style.id = key;
  6. style.type = 'text/css';
  7. document.head.appendChild(style);
  8. }
  9. if (style && !enable) {
  10. document.head.removeChild(style);
  11. }
  12. if (style) {
  13. style.innerHTML == '';
  14. style.appendChild(document.createTextNode(css));
  15. }
  16. }
  17. function setupExtraNetworksForTab(tabname) {
  18. gradioApp().querySelector('#' + tabname + '_extra_tabs').classList.add('extra-networks');
  19. var tabs = gradioApp().querySelector('#' + tabname + '_extra_tabs > div');
  20. var searchDiv = gradioApp().getElementById(tabname + '_extra_search');
  21. var search = searchDiv.querySelector('textarea');
  22. var sort = gradioApp().getElementById(tabname + '_extra_sort');
  23. var sortOrder = gradioApp().getElementById(tabname + '_extra_sortorder');
  24. var refresh = gradioApp().getElementById(tabname + '_extra_refresh');
  25. var showDirsDiv = gradioApp().getElementById(tabname + '_extra_show_dirs');
  26. var showDirs = gradioApp().querySelector('#' + tabname + '_extra_show_dirs input');
  27. var promptContainer = gradioApp().querySelector('.prompt-container-compact#' + tabname + '_prompt_container');
  28. var negativePrompt = gradioApp().querySelector('#' + tabname + '_neg_prompt');
  29. tabs.appendChild(searchDiv);
  30. tabs.appendChild(sort);
  31. tabs.appendChild(sortOrder);
  32. tabs.appendChild(refresh);
  33. tabs.appendChild(showDirsDiv);
  34. var applyFilter = function() {
  35. var searchTerm = search.value.toLowerCase();
  36. gradioApp().querySelectorAll('#' + tabname + '_extra_tabs div.card').forEach(function(elem) {
  37. var searchOnly = elem.querySelector('.search_only');
  38. var text = elem.querySelector('.name').textContent.toLowerCase() + " " + elem.querySelector('.search_term').textContent.toLowerCase();
  39. var visible = text.indexOf(searchTerm) != -1;
  40. if (searchOnly && searchTerm.length < 4) {
  41. visible = false;
  42. }
  43. elem.style.display = visible ? "" : "none";
  44. });
  45. applySort();
  46. };
  47. var applySort = function() {
  48. var cards = gradioApp().querySelectorAll('#' + tabname + '_extra_tabs div.card');
  49. var reverse = sortOrder.classList.contains("sortReverse");
  50. var sortKey = sort.querySelector("input").value.toLowerCase().replace("sort", "").replaceAll(" ", "_").replace(/_+$/, "").trim() || "name";
  51. sortKey = "sort" + sortKey.charAt(0).toUpperCase() + sortKey.slice(1);
  52. var sortKeyStore = sortKey + "-" + (reverse ? "Descending" : "Ascending") + "-" + cards.length;
  53. if (sortKeyStore == sort.dataset.sortkey) {
  54. return;
  55. }
  56. sort.dataset.sortkey = sortKeyStore;
  57. cards.forEach(function(card) {
  58. card.originalParentElement = card.parentElement;
  59. });
  60. var sortedCards = Array.from(cards);
  61. sortedCards.sort(function(cardA, cardB) {
  62. var a = cardA.dataset[sortKey];
  63. var b = cardB.dataset[sortKey];
  64. if (!isNaN(a) && !isNaN(b)) {
  65. return parseInt(a) - parseInt(b);
  66. }
  67. return (a < b ? -1 : (a > b ? 1 : 0));
  68. });
  69. if (reverse) {
  70. sortedCards.reverse();
  71. }
  72. cards.forEach(function(card) {
  73. card.remove();
  74. });
  75. sortedCards.forEach(function(card) {
  76. card.originalParentElement.appendChild(card);
  77. });
  78. };
  79. search.addEventListener("input", applyFilter);
  80. sortOrder.addEventListener("click", function() {
  81. sortOrder.classList.toggle("sortReverse");
  82. applySort();
  83. });
  84. applyFilter();
  85. extraNetworksApplySort[tabname] = applySort;
  86. extraNetworksApplyFilter[tabname] = applyFilter;
  87. var showDirsUpdate = function() {
  88. var css = '#' + tabname + '_extra_tabs .extra-network-subdirs { display: none; }';
  89. toggleCss(tabname + '_extra_show_dirs_style', css, !showDirs.checked);
  90. localSet('extra-networks-show-dirs', showDirs.checked ? 1 : 0);
  91. };
  92. showDirs.checked = localGet('extra-networks-show-dirs', 1) == 1;
  93. showDirs.addEventListener("change", showDirsUpdate);
  94. showDirsUpdate();
  95. }
  96. function extraNetworksMovePromptToTab(tabname, id, showPrompt, showNegativePrompt) {
  97. if (!gradioApp().querySelector('.toprow-compact-tools')) return; // only applicable for compact prompt layout
  98. var promptContainer = gradioApp().getElementById(tabname + '_prompt_container');
  99. var prompt = gradioApp().getElementById(tabname + '_prompt_row');
  100. var negPrompt = gradioApp().getElementById(tabname + '_neg_prompt_row');
  101. var elem = id ? gradioApp().getElementById(id) : null;
  102. if (showNegativePrompt && elem) {
  103. elem.insertBefore(negPrompt, elem.firstChild);
  104. } else {
  105. promptContainer.insertBefore(negPrompt, promptContainer.firstChild);
  106. }
  107. if (showPrompt && elem) {
  108. elem.insertBefore(prompt, elem.firstChild);
  109. } else {
  110. promptContainer.insertBefore(prompt, promptContainer.firstChild);
  111. }
  112. if (elem) {
  113. elem.classList.toggle('extra-page-prompts-active', showNegativePrompt || showPrompt);
  114. }
  115. }
  116. function extraNetworksUrelatedTabSelected(tabname) { // called from python when user selects an unrelated tab (generate)
  117. extraNetworksMovePromptToTab(tabname, '', false, false);
  118. }
  119. function extraNetworksTabSelected(tabname, id, showPrompt, showNegativePrompt) { // called from python when user selects an extra networks tab
  120. extraNetworksMovePromptToTab(tabname, id, showPrompt, showNegativePrompt);
  121. }
  122. function applyExtraNetworkFilter(tabname) {
  123. setTimeout(extraNetworksApplyFilter[tabname], 1);
  124. }
  125. function applyExtraNetworkSort(tabname) {
  126. setTimeout(extraNetworksApplySort[tabname], 1);
  127. }
  128. var extraNetworksApplyFilter = {};
  129. var extraNetworksApplySort = {};
  130. var activePromptTextarea = {};
  131. function setupExtraNetworks() {
  132. setupExtraNetworksForTab('txt2img');
  133. setupExtraNetworksForTab('img2img');
  134. function registerPrompt(tabname, id) {
  135. var textarea = gradioApp().querySelector("#" + id + " > label > textarea");
  136. if (!activePromptTextarea[tabname]) {
  137. activePromptTextarea[tabname] = textarea;
  138. }
  139. textarea.addEventListener("focus", function() {
  140. activePromptTextarea[tabname] = textarea;
  141. });
  142. }
  143. registerPrompt('txt2img', 'txt2img_prompt');
  144. registerPrompt('txt2img', 'txt2img_neg_prompt');
  145. registerPrompt('img2img', 'img2img_prompt');
  146. registerPrompt('img2img', 'img2img_neg_prompt');
  147. }
  148. onUiLoaded(setupExtraNetworks);
  149. var re_extranet = /<([^:^>]+:[^:]+):[\d.]+>(.*)/;
  150. var re_extranet_g = /<([^:^>]+:[^:]+):[\d.]+>/g;
  151. function tryToRemoveExtraNetworkFromPrompt(textarea, text) {
  152. var m = text.match(re_extranet);
  153. var replaced = false;
  154. var newTextareaText;
  155. if (m) {
  156. var extraTextBeforeNet = opts.extra_networks_add_text_separator;
  157. var extraTextAfterNet = m[2];
  158. var partToSearch = m[1];
  159. var foundAtPosition = -1;
  160. newTextareaText = textarea.value.replaceAll(re_extranet_g, function(found, net, pos) {
  161. m = found.match(re_extranet);
  162. if (m[1] == partToSearch) {
  163. replaced = true;
  164. foundAtPosition = pos;
  165. return "";
  166. }
  167. return found;
  168. });
  169. if (foundAtPosition >= 0) {
  170. if (newTextareaText.substr(foundAtPosition, extraTextAfterNet.length) == extraTextAfterNet) {
  171. newTextareaText = newTextareaText.substr(0, foundAtPosition) + newTextareaText.substr(foundAtPosition + extraTextAfterNet.length);
  172. }
  173. if (newTextareaText.substr(foundAtPosition - extraTextBeforeNet.length, extraTextBeforeNet.length) == extraTextBeforeNet) {
  174. newTextareaText = newTextareaText.substr(0, foundAtPosition - extraTextBeforeNet.length) + newTextareaText.substr(foundAtPosition);
  175. }
  176. }
  177. } else {
  178. newTextareaText = textarea.value.replaceAll(new RegExp(text, "g"), function(found) {
  179. if (found == text) {
  180. replaced = true;
  181. return "";
  182. }
  183. return found;
  184. });
  185. }
  186. if (replaced) {
  187. textarea.value = newTextareaText;
  188. return true;
  189. }
  190. return false;
  191. }
  192. function cardClicked(tabname, textToAdd, allowNegativePrompt) {
  193. var textarea = allowNegativePrompt ? activePromptTextarea[tabname] : gradioApp().querySelector("#" + tabname + "_prompt > label > textarea");
  194. if (!tryToRemoveExtraNetworkFromPrompt(textarea, textToAdd)) {
  195. textarea.value = textarea.value + opts.extra_networks_add_text_separator + textToAdd;
  196. }
  197. updateInput(textarea);
  198. }
  199. function saveCardPreview(event, tabname, filename) {
  200. var textarea = gradioApp().querySelector("#" + tabname + '_preview_filename > label > textarea');
  201. var button = gradioApp().getElementById(tabname + '_save_preview');
  202. textarea.value = filename;
  203. updateInput(textarea);
  204. button.click();
  205. event.stopPropagation();
  206. event.preventDefault();
  207. }
  208. function extraNetworksSearchButton(tabs_id, event) {
  209. var searchTextarea = gradioApp().querySelector("#" + tabs_id + ' > label > textarea');
  210. var button = event.target;
  211. var text = button.classList.contains("search-all") ? "" : button.textContent.trim();
  212. searchTextarea.value = text;
  213. updateInput(searchTextarea);
  214. }
  215. var globalPopup = null;
  216. var globalPopupInner = null;
  217. function closePopup() {
  218. if (!globalPopup) return;
  219. globalPopup.style.display = "none";
  220. }
  221. function popup(contents) {
  222. if (!globalPopup) {
  223. globalPopup = document.createElement('div');
  224. globalPopup.classList.add('global-popup');
  225. var close = document.createElement('div');
  226. close.classList.add('global-popup-close');
  227. close.addEventListener("click", closePopup);
  228. close.title = "Close";
  229. globalPopup.appendChild(close);
  230. globalPopupInner = document.createElement('div');
  231. globalPopupInner.classList.add('global-popup-inner');
  232. globalPopup.appendChild(globalPopupInner);
  233. gradioApp().querySelector('.main').appendChild(globalPopup);
  234. }
  235. globalPopupInner.innerHTML = '';
  236. globalPopupInner.appendChild(contents);
  237. globalPopup.style.display = "flex";
  238. }
  239. var storedPopupIds = {};
  240. function popupId(id) {
  241. if (!storedPopupIds[id]) {
  242. storedPopupIds[id] = gradioApp().getElementById(id);
  243. }
  244. popup(storedPopupIds[id]);
  245. }
  246. function extraNetworksShowMetadata(text) {
  247. var elem = document.createElement('pre');
  248. elem.classList.add('popup-metadata');
  249. elem.textContent = text;
  250. popup(elem);
  251. }
  252. function requestGet(url, data, handler, errorHandler) {
  253. var xhr = new XMLHttpRequest();
  254. var args = Object.keys(data).map(function(k) {
  255. return encodeURIComponent(k) + '=' + encodeURIComponent(data[k]);
  256. }).join('&');
  257. xhr.open("GET", url + "?" + args, true);
  258. xhr.onreadystatechange = function() {
  259. if (xhr.readyState === 4) {
  260. if (xhr.status === 200) {
  261. try {
  262. var js = JSON.parse(xhr.responseText);
  263. handler(js);
  264. } catch (error) {
  265. console.error(error);
  266. errorHandler();
  267. }
  268. } else {
  269. errorHandler();
  270. }
  271. }
  272. };
  273. var js = JSON.stringify(data);
  274. xhr.send(js);
  275. }
  276. function extraNetworksRequestMetadata(event, extraPage, cardName) {
  277. var showError = function() {
  278. extraNetworksShowMetadata("there was an error getting metadata");
  279. };
  280. requestGet("./sd_extra_networks/metadata", {page: extraPage, item: cardName}, function(data) {
  281. if (data && data.metadata) {
  282. extraNetworksShowMetadata(data.metadata);
  283. } else {
  284. showError();
  285. }
  286. }, showError);
  287. event.stopPropagation();
  288. }
  289. var extraPageUserMetadataEditors = {};
  290. function extraNetworksEditUserMetadata(event, tabname, extraPage, cardName) {
  291. var id = tabname + '_' + extraPage + '_edit_user_metadata';
  292. var editor = extraPageUserMetadataEditors[id];
  293. if (!editor) {
  294. editor = {};
  295. editor.page = gradioApp().getElementById(id);
  296. editor.nameTextarea = gradioApp().querySelector("#" + id + "_name" + ' textarea');
  297. editor.button = gradioApp().querySelector("#" + id + "_button");
  298. extraPageUserMetadataEditors[id] = editor;
  299. }
  300. editor.nameTextarea.value = cardName;
  301. updateInput(editor.nameTextarea);
  302. editor.button.click();
  303. popup(editor.page);
  304. event.stopPropagation();
  305. }
  306. function extraNetworksRefreshSingleCard(page, tabname, name) {
  307. requestGet("./sd_extra_networks/get-single-card", {page: page, tabname: tabname, name: name}, function(data) {
  308. if (data && data.html) {
  309. var card = gradioApp().querySelector(`#${tabname}_${page.replace(" ", "_")}_cards > .card[data-name="${name}"]`);
  310. var newDiv = document.createElement('DIV');
  311. newDiv.innerHTML = data.html;
  312. var newCard = newDiv.firstElementChild;
  313. newCard.style.display = '';
  314. card.parentElement.insertBefore(newCard, card);
  315. card.parentElement.removeChild(card);
  316. }
  317. });
  318. }
  319. window.addEventListener("keydown", function(event) {
  320. if (event.key == "Escape") {
  321. closePopup();
  322. }
  323. });