diff --git a/.eslintrc.json b/.eslintrc.json index 7a730c1c2..7f4c9f27f 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -87,6 +87,7 @@ "get_tab_index": "readonly", "create_submit_args": "readonly", "restartReload": "readonly", + "markSelectedCards": "readonly", "updateInput": "readonly", "toggleCompact": "readonly", "setFontSize": "readonly", diff --git a/CHANGELOG.md b/CHANGELOG.md index fe3ec541c..87b1568a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,7 +35,8 @@ - redesign *settings -> user interface* - gallery bypass browser cache for thumbnails - gallery safer delete operation - - more css optimizations and styling + - networks display indicator for currently active items + styles, loras - *hint*: card layout card layout is used by networks, gallery, civitai search, etc. you can change card size in *settings -> user interface* diff --git a/javascript/extraNetworks.js b/javascript/extraNetworks.js index 244f7c428..29b97005f 100644 --- a/javascript/extraNetworks.js +++ b/javascript/extraNetworks.js @@ -239,14 +239,31 @@ function refreshENInput(tabname) { gradioApp().querySelector(`#${tabname}_extra_networks textarea`)?.dispatchEvent(new Event('input')); } -function cardClicked(textToAdd, allowNegativePrompt) { - // log('cardClicked', textToAdd, allowNegativePrompt); +async function markSelectedCards(selected, page = '') { + log('markSelectedCards', selected, page); + gradioApp().querySelectorAll('.extra-network-cards .card').forEach((el) => { + if (page.length > 0 && el.dataset.page !== page) return; // filter by page + if (selected.includes(el.dataset.name) || selected.includes(el.dataset.short)) el.classList.add('card-selected'); + else el.classList.remove('card-selected'); + }); +} + +function extractLoraNames(prompt) { + const regex = /]+)(?::[\d.]+)?>/g; + const names = []; + let match; + while ((match = regex.exec(prompt)) !== null) names.push(match[1]); // eslint-disable-line no-cond-assign + return names; +} + +function cardClicked(textToAdd) { const tabname = getENActiveTab(); log('cardClicked', tabname, textToAdd); - const textarea = allowNegativePrompt ? activePromptTextarea[tabname] : gradioApp().querySelector(`#${tabname}_prompt > label > textarea`); + const textarea = activePromptTextarea[tabname]; if (textarea.value.indexOf(textToAdd) !== -1) textarea.value = textarea.value.replace(textToAdd, ''); else textarea.value += textToAdd; updateInput(textarea); + markSelectedCards(extractLoraNames(textarea.value), 'lora'); } function extraNetworksSearchButton(event) { @@ -278,10 +295,7 @@ function applyStyles(styles) { const index = newStyles.indexOf(desiredStyle); if (index > -1) newStyles.splice(index, 1); else newStyles.push(desiredStyle); - gradioApp().querySelectorAll('.extra-network-cards .card').forEach((el) => { - if (newStyles.includes(el.getAttribute('data-name'))) el.classList.add('card-selected'); - else el.classList.remove('card-selected'); - }); + markSelectedCards(newStyles, 'style'); return newStyles.join('|'); } diff --git a/javascript/ui.js b/javascript/ui.js index a499dc32d..e6885a80e 100644 --- a/javascript/ui.js +++ b/javascript/ui.js @@ -484,20 +484,23 @@ function selectCheckpoint(name) { const isRefiner = btnModel && btnModel.classList.contains('toolbutton-selected'); if (isRefiner) gradioApp().getElementById('change_refiner').click(); else gradioApp().getElementById('change_checkpoint').click(); - log(`Change ${isRefiner ? 'refiner' : 'model'}: ${desiredCheckpointName}`); + log(`selectCheckpoint ${isRefiner ? 'refiner' : 'model'}: ${desiredCheckpointName}`); + markSelectedCards([desiredCheckpointName], 'model'); } let desiredVAEName = null; function selectVAE(name) { desiredVAEName = name; gradioApp().getElementById('change_vae').click(); - log(`Change VAE: ${desiredVAEName}`); + log(`selectVAE: ${desiredVAEName}`); + markSelectedCards([desiredVAEName], 'vae'); } function selectReference(name) { - log(`Select reference: ${name}`); + log(`selectReference: ${name}`); desiredCheckpointName = name; gradioApp().getElementById('change_reference').click(); + markSelectedCards([desiredCheckpointName], 'model'); } function currentImageResolutionimg2img(_a, _b, scaleBy) { diff --git a/modules/ui_extra_networks.py b/modules/ui_extra_networks.py index 6882cf616..46b002abe 100644 --- a/modules/ui_extra_networks.py +++ b/modules/ui_extra_networks.py @@ -27,7 +27,7 @@ extra_pages = shared.extra_networks debug = shared.log.trace if os.environ.get('SD_EN_DEBUG', None) is not None else lambda *args, **kwargs: None debug('Trace: EN') card_full = ''' -
+
{title}
@@ -41,7 +41,7 @@ card_full = '''
''' card_list = ''' -
+
🛈 
{title}  @@ -311,12 +311,14 @@ class ExtraNetworksPage: return '#{:02x}{:02x}{:02x}'.format(r, g, b) # pylint: disable=consider-using-f-string try: + onclick = f'cardClicked({item.get("prompt", None)})' args = { - "tabname": tabname, + # "tabname": tabname, "page": self.name, "name": item.get('name', ''), "title": os.path.basename(item["name"].replace('_', ' ')), "filename": item.get('filename', ''), + "short": os.path.splitext(os.path.basename(item.get('filename', '')))[0], "tags": '|'.join([item.get('tags')] if isinstance(item.get('tags', {}), str) else list(item.get('tags', {}).keys())), "preview": html.escape(item.get('preview', None) or self.link_preview('html/card-no-preview.png')), "width": 'var(--card-size)', @@ -325,7 +327,7 @@ class ExtraNetworksPage: "prompt": item.get("prompt", None), "search": item.get("search_term", ""), "description": item.get("description") or "", - "card_click": item.get("onclick", '"' + html.escape(f'return cardClicked({item.get("prompt", None)}, {"true" if self.allow_negative_prompt else "false"})') + '"'), + "card_click": item.get("onclick", '"' + html.escape(onclick) + '"'), "mtime": item.get("mtime", 0), "size": item.get("size", 0), "version": item.get("version", ''), diff --git a/modules/ui_extra_networks_checkpoints.py b/modules/ui_extra_networks_checkpoints.py index 3eab7fd41..15efb0e5c 100644 --- a/modules/ui_extra_networks_checkpoints.py +++ b/modules/ui_extra_networks_checkpoints.py @@ -33,7 +33,7 @@ class ExtraNetworksPageCheckpoints(ui_extra_networks.ExtraNetworksPage): "filename": url, "preview": self.find_preview(os.path.join(reference_dir, preview)), "local_preview": self.find_preview_file(os.path.join(reference_dir, preview)), - "onclick": '"' + html.escape(f"""return selectReference({json.dumps(url)})""") + '"', + "onclick": '"' + html.escape(f"selectReference({json.dumps(url)})") + '"', "hash": None, "mtime": 0, "size": 0, @@ -54,7 +54,7 @@ class ExtraNetworksPageCheckpoints(ui_extra_networks.ExtraNetworksPage): "filename": checkpoint.filename, "hash": checkpoint.shorthash, "metadata": checkpoint.metadata, - "onclick": '"' + html.escape(f"""return selectCheckpoint({json.dumps(name)})""") + '"', + "onclick": '"' + html.escape(f"selectCheckpoint({json.dumps(name)})") + '"', "mtime": os.path.getmtime(checkpoint.filename) if exists else 0, "size": os.path.getsize(checkpoint.filename) if exists else 0, }