Fix parsing of HTML in model descriptions.

This commit is contained in:
Sj-Si 2024-05-31 11:43:37 -04:00
parent a3e9b0ce04
commit 19f2c61f4c
7 changed files with 57 additions and 4 deletions

View file

@ -3,6 +3,6 @@
{button_row}
<div class="actions">
<span class="name">{name}</span>
<span class="description">{description}</span>
<span class="description" {description_data_attributes}>{description}</span>
</div>
</div>

View file

@ -1,6 +1,6 @@
<div class="extra-network-content--dets-view-model-info">
<div class="model-info--header">
<h1>{name}</h1>
<h1 class="model-info--name">{name}</h1>
<button class="extra-network-control model-info--close" title="Close model details">
<svg class="extra-network-control--icon" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
@ -8,9 +8,9 @@
</svg>
</button>
</div>
<p>{description}</p>
<p class="model-info--description" {description_data_attributes}>{description}</p>
<h3>Model Metadata</h3>
<table>
<table class="model-info--metadata">
<tbody>{metadata_table}</tbody>
</table>
{model_specific}

View file

@ -466,6 +466,10 @@ class Clusterize {
} else {
content_elem.innerHTML = data;
}
// Parse items flagged as containing Shadow DOM entries.
convertElementShadowDOM(content_elem, "[data-parse-as-shadow-dom]");
return content_elem.innerHTML;
}

View file

@ -18,6 +18,7 @@
waitForBool,
copyToClipboard,
resizeGridSetup,
convertElementShadowDOM,
*/
/*eslint no-undef: "error"*/
@ -313,6 +314,11 @@ class ExtraNetworksTab {
(data) => {
if (data && data.html) {
this.card_list.updateHtml(elem, data.html);
// If this model's detail is displayed, update it.
const desc_elem = this.container_elem.querySelector(".model-info--name");
if (isElement(desc_elem) && desc_elem.textContent === elem.dataset.name) {
this.showDetsView(elem);
}
}
},
);
@ -927,7 +933,10 @@ class ExtraNetworksTab {
div_dets.innerHTML = "Error parsing model details.";
return;
}
div_dets.innerHTML = response.html;
convertElementShadowDOM(div_dets, "[data-parse-as-shadow-dom]");
};
_clear_details();

View file

@ -12,6 +12,7 @@
isElementLogError,
keyExistsLogError,
htmlStringToElement,
convertElementShadowDOM,
*/
/*eslint no-undef: "error"*/
@ -260,6 +261,7 @@ class ExtraNetworksClusterize extends Clusterize {
return;
}
const parsed_html = htmlStringToElement(new_html);
convertElementShadowDOM(parsed_html, "[data-parse-as-shadow-dom]");
// replace the element in DOM with our new element
elem.replaceWith(parsed_html);

View file

@ -615,6 +615,38 @@ function htmlStringToFragment(s) {
return document.createRange().createContextualFragment(s);
}
function convertInnerHtmlToShadowDOM(elem) {
/** Inplace conversion of innerHTML of an element into a Shadow DOM.
*
* If the innerHTML is not valid HTML then the innerHTML is left unchanged.
*/
const parsed_str = new DOMParser().parseFromString(elem.innerHTML, "text/html").documentElement.textContent;
const parsed_elem = htmlStringToElement(parsed_str);
if (!isNullOrUndefined(parsed_elem)) {
elem.innerHTML = "";
const shadow = elem.attachShadow({mode: "open"});
shadow.appendChild(parsed_elem);
}
}
function convertElementShadowDOM(elem, selector) {
/** Inplace conversion of Shadow DOM of all children matching the passed selector.
*
* `selector` defaults to [data-parse-as-shadow-dom] if not a valid string.
*
* NOTE: Nested Shadow DOMs are untested but will likely not work.
*/
if (!isString(selector)) {
selector = "[data-parse-as-shadow-dom]";
}
let children = Array.from(elem.querySelectorAll(selector));
children = children.filter(x => x.innerHTML !== "");
for (const child of children) {
convertInnerHtmlToShadowDOM(child);
}
}
function toggleCss(key, css, enable) {
var style = document.getElementById(key);
if (enable && !style) {

View file

@ -442,8 +442,10 @@ class ExtraNetworksPage:
if shared.opts.extra_networks_card_show_desc:
description = item.get("description", "") or ""
description_data_attributes = ""
if not shared.opts.extra_networks_card_description_is_html:
description = html.escape(description)
description_data_attributes = "data-parse-as-shadow-dom"
data_name = item.get("name", "").strip()
data_path = os.path.normpath(item.get("filename", "").strip())
@ -475,6 +477,7 @@ class ExtraNetworksPage:
background_image=background_image,
button_row=button_row,
name=html.escape(item["name"].strip()),
description_data_attributes=description_data_attributes,
description=description,
)
@ -1055,13 +1058,16 @@ class ExtraNetworksPage:
if not description:
description = ""
description_data_attributes = ""
if not shared.opts.extra_networks_card_description_is_html:
description = html.escape(description)
description_data_attributes = "data-parse-as-shadow-dom"
model_specific = self.get_model_detail_extra_html(model_name)
return self.model_details_tpl.format(
name=model_name,
description_data_attributes=description_data_attributes,
description=description,
metadata_table=tbl_metadata,
model_specific=model_specific,