@tiba-spark/client-shared-lib 26.3.0-74 → 26.3.0-80
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { sanitizeHtmlValue } from '../services/html-sanitizer.service';
|
|
2
1
|
export function findParentElement(elementRef, className) {
|
|
3
2
|
let element = elementRef.nativeElement;
|
|
4
3
|
while (element && !element.classList?.contains(className)) {
|
|
@@ -17,26 +16,53 @@ export function findParentElementDimensions(elementRef, className) {
|
|
|
17
16
|
};
|
|
18
17
|
}
|
|
19
18
|
export async function loadHTMLContent(pathContent, id) {
|
|
20
|
-
let isSuccess = true;
|
|
21
19
|
try {
|
|
22
20
|
const response = await fetch(pathContent);
|
|
23
|
-
if (response.ok) {
|
|
24
|
-
const htmlContent = sanitizeHtmlValue(await response.text());
|
|
25
|
-
const contentDiv = document.getElementById(`${id}`);
|
|
26
|
-
if (contentDiv) {
|
|
27
|
-
const parsedDocument = new DOMParser().parseFromString(htmlContent, 'text/html');
|
|
28
|
-
contentDiv.replaceChildren(...Array.from(parsedDocument.body.childNodes));
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
else {
|
|
21
|
+
if (!response.ok) {
|
|
32
22
|
console.error(`HTTP Error: ${response.status} ${response.statusText}`);
|
|
33
|
-
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
// Render the trusted What's New document as-is (HTML + CSS + JS) into a sandboxed
|
|
26
|
+
// iframe via srcdoc. srcdoc paints the fetched bytes directly, avoiding a second
|
|
27
|
+
// navigation the browser would blank when the source sends X-Frame-Options.
|
|
28
|
+
const target = document.getElementById(`${id}`);
|
|
29
|
+
if (!(target instanceof HTMLIFrameElement)) {
|
|
30
|
+
console.error(`loadHTMLContent: target #${id} is missing or is not an <iframe>`);
|
|
31
|
+
return false;
|
|
34
32
|
}
|
|
33
|
+
target.srcdoc = injectIframeHead(await response.text(), pathContent);
|
|
34
|
+
return true;
|
|
35
35
|
}
|
|
36
36
|
catch (error) {
|
|
37
37
|
console.error('Error loading HTML:', error);
|
|
38
|
-
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
// The app's custom scrollbar — the srcdoc is an isolated document, so global app
|
|
42
|
+
// styles do not reach it; inject them so its scrollbar matches the rest of the app.
|
|
43
|
+
const IFRAME_SCROLLBAR_STYLE = '<style>' +
|
|
44
|
+
'::-webkit-scrollbar{width:5px;height:5px;border-radius:5px;background-color:transparent;}' +
|
|
45
|
+
'::-webkit-scrollbar-track{border-radius:5px;background-color:transparent;}' +
|
|
46
|
+
'::-webkit-scrollbar-thumb{border-radius:5px;background-color:#dee2e6;}' +
|
|
47
|
+
'::-webkit-scrollbar-thumb:hover{background-color:#919eab;}' +
|
|
48
|
+
'html{scrollbar-width:thin;scrollbar-color:#dee2e6 transparent;}' +
|
|
49
|
+
'</style>';
|
|
50
|
+
// Inject a <base> (so relative asset URLs resolve against the source) plus the app
|
|
51
|
+
// scrollbar style into the document head, without otherwise altering the content.
|
|
52
|
+
function injectIframeHead(html, sourceUrl) {
|
|
53
|
+
const baseHref = sourceUrl.slice(0, sourceUrl.lastIndexOf('/') + 1);
|
|
54
|
+
const injected = (baseHref ? `<base href="${encodeURI(baseHref)}">` : '') + IFRAME_SCROLLBAR_STYLE;
|
|
55
|
+
// Existing <head> → inject inside it. The (?=[\s>]) delimiter stops <head> from
|
|
56
|
+
// also matching <header …> (which would inject <base>/style outside any real head).
|
|
57
|
+
if (/<head(?=[\s>])[^>]*>/i.test(html)) {
|
|
58
|
+
return html.replace(/<head(?=[\s>])[^>]*>/i, (head) => `${head}${injected}`);
|
|
59
|
+
}
|
|
60
|
+
// Full document without a <head> → create one right after <html …> so the
|
|
61
|
+
// injected markup never precedes the doctype (which would force quirks mode).
|
|
62
|
+
if (/<html(?=[\s>])[^>]*>/i.test(html)) {
|
|
63
|
+
return html.replace(/<html(?=[\s>])[^>]*>/i, (htmlTag) => `${htmlTag}<head>${injected}</head>`);
|
|
39
64
|
}
|
|
40
|
-
|
|
65
|
+
// Bare fragment (no doctype/<html>) → safe to prepend.
|
|
66
|
+
return `${injected}${html}`;
|
|
41
67
|
}
|
|
42
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
68
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZWxlbWVudC51dGlsLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvY2xpZW50LXNoYXJlZC1saWIvc3JjL2xpYnJhcmllcy91dGlscy9lbGVtZW50LnV0aWwudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBT0EsTUFBTSxVQUFVLGlCQUFpQixDQUFDLFVBQXNCLEVBQUUsU0FBaUI7SUFDekUsSUFBSSxPQUFPLEdBQUcsVUFBVSxDQUFDLGFBQWEsQ0FBQztJQUN2QyxPQUFPLE9BQU8sSUFBSSxDQUFDLE9BQU8sQ0FBQyxTQUFTLEVBQUUsUUFBUSxDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUM7UUFDMUQsT0FBTyxHQUFHLE9BQU8sQ0FBQyxhQUFhLENBQUM7SUFDbEMsQ0FBQztJQUNELE9BQU8sT0FBTyxDQUFDO0FBQ2pCLENBQUM7QUFFRCxNQUFNLFVBQVUsMkJBQTJCLENBQUMsVUFBc0IsRUFBRSxTQUFpQjtJQUNuRixJQUFJLE9BQU8sR0FBRyxVQUFVLENBQUMsYUFBYSxDQUFDO0lBQ3ZDLE9BQU8sT0FBTyxJQUFJLENBQUMsT0FBTyxDQUFDLFlBQVksS0FBSyxDQUFDLElBQUksT0FBTyxDQUFDLFlBQVksS0FBSyxTQUFTLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxTQUFTLEVBQUUsUUFBUSxDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUM7UUFDaEksT0FBTyxHQUFHLE9BQU8sQ0FBQyxhQUFhLENBQUM7SUFDbEMsQ0FBQztJQUVELE9BQU87UUFDTCxNQUFNLEVBQUUsT0FBTyxFQUFFLFlBQVksSUFBSSxDQUFDO1FBQ2xDLEtBQUssRUFBRSxPQUFPLEVBQUUsV0FBVyxJQUFJLENBQUM7S0FDWixDQUFDO0FBQ3pCLENBQUM7QUFFRCxNQUFNLENBQUMsS0FBSyxVQUFVLGVBQWUsQ0FBQyxXQUFtQixFQUFFLEVBQVU7SUFDbkUsSUFBSSxDQUFDO1FBQ0gsTUFBTSxRQUFRLEdBQUcsTUFBTSxLQUFLLENBQUMsV0FBVyxDQUFDLENBQUM7UUFDMUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxFQUFFLEVBQUUsQ0FBQztZQUNqQixPQUFPLENBQUMsS0FBSyxDQUFDLGVBQWUsUUFBUSxDQUFDLE1BQU0sSUFBSSxRQUFRLENBQUMsVUFBVSxFQUFFLENBQUMsQ0FBQztZQUN2RSxPQUFPLEtBQUssQ0FBQztRQUNmLENBQUM7UUFFRCxrRkFBa0Y7UUFDbEYsaUZBQWlGO1FBQ2pGLDRFQUE0RTtRQUM1RSxNQUFNLE1BQU0sR0FBRyxRQUFRLENBQUMsY0FBYyxDQUFDLEdBQUcsRUFBRSxFQUFFLENBQUMsQ0FBQztRQUNoRCxJQUFJLENBQUMsQ0FBQyxNQUFNLFlBQVksaUJBQWlCLENBQUMsRUFBRSxDQUFDO1lBQzNDLE9BQU8sQ0FBQyxLQUFLLENBQUMsNEJBQTRCLEVBQUUsbUNBQW1DLENBQUMsQ0FBQztZQUNqRixPQUFPLEtBQUssQ0FBQztRQUNmLENBQUM7UUFDRCxNQUFNLENBQUMsTUFBTSxHQUFHLGdCQUFnQixDQUFDLE1BQU0sUUFBUSxDQUFDLElBQUksRUFBRSxFQUFFLFdBQVcsQ0FBQyxDQUFDO1FBRXJFLE9BQU8sSUFBSSxDQUFDO0lBQ2QsQ0FBQztJQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7UUFDZixPQUFPLENBQUMsS0FBSyxDQUFDLHFCQUFxQixFQUFFLEtBQUssQ0FBQyxDQUFDO1FBQzVDLE9BQU8sS0FBSyxDQUFDO0lBQ2YsQ0FBQztBQUNILENBQUM7QUFFRCxpRkFBaUY7QUFDakYsb0ZBQW9GO0FBQ3BGLE1BQU0sc0JBQXNCLEdBQzFCLFNBQVM7SUFDVCwyRkFBMkY7SUFDM0YsNEVBQTRFO0lBQzVFLHdFQUF3RTtJQUN4RSw0REFBNEQ7SUFDNUQsaUVBQWlFO0lBQ2pFLFVBQVUsQ0FBQztBQUViLG1GQUFtRjtBQUNuRixrRkFBa0Y7QUFDbEYsU0FBUyxnQkFBZ0IsQ0FBQyxJQUFZLEVBQUUsU0FBaUI7SUFDdkQsTUFBTSxRQUFRLEdBQUcsU0FBUyxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsU0FBUyxDQUFDLFdBQVcsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztJQUNwRSxNQUFNLFFBQVEsR0FBRyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsZUFBZSxTQUFTLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEdBQUcsc0JBQXNCLENBQUM7SUFFbkcsZ0ZBQWdGO0lBQ2hGLG9GQUFvRjtJQUNwRixJQUFJLHVCQUF1QixDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO1FBQ3ZDLE9BQU8sSUFBSSxDQUFDLE9BQU8sQ0FBQyx1QkFBdUIsRUFBRSxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsR0FBRyxJQUFJLEdBQUcsUUFBUSxFQUFFLENBQUMsQ0FBQztJQUMvRSxDQUFDO0lBQ0QsMEVBQTBFO0lBQzFFLDhFQUE4RTtJQUM5RSxJQUFJLHVCQUF1QixDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO1FBQ3ZDLE9BQU8sSUFBSSxDQUFDLE9BQU8sQ0FBQyx1QkFBdUIsRUFBRSxDQUFDLE9BQU8sRUFBRSxFQUFFLENBQUMsR0FBRyxPQUFPLFNBQVMsUUFBUSxTQUFTLENBQUMsQ0FBQztJQUNsRyxDQUFDO0lBQ0QsdURBQXVEO0lBQ3ZELE9BQU8sR0FBRyxRQUFRLEdBQUcsSUFBSSxFQUFFLENBQUM7QUFDOUIsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEVsZW1lbnRSZWYgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcblxuZXhwb3J0IGludGVyZmFjZSBFbGVtZW50RGltZW5zaW9ucyB7XG4gIGhlaWdodDogbnVtYmVyO1xuICB3aWR0aDogbnVtYmVyO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZmluZFBhcmVudEVsZW1lbnQoZWxlbWVudFJlZjogRWxlbWVudFJlZiwgY2xhc3NOYW1lOiBzdHJpbmcpIHtcbiAgbGV0IGVsZW1lbnQgPSBlbGVtZW50UmVmLm5hdGl2ZUVsZW1lbnQ7XG4gIHdoaWxlIChlbGVtZW50ICYmICFlbGVtZW50LmNsYXNzTGlzdD8uY29udGFpbnMoY2xhc3NOYW1lKSkge1xuICAgIGVsZW1lbnQgPSBlbGVtZW50LnBhcmVudEVsZW1lbnQ7XG4gIH1cbiAgcmV0dXJuIGVsZW1lbnQ7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBmaW5kUGFyZW50RWxlbWVudERpbWVuc2lvbnMoZWxlbWVudFJlZjogRWxlbWVudFJlZiwgY2xhc3NOYW1lOiBzdHJpbmcpOiBFbGVtZW50RGltZW5zaW9ucyB7XG4gIGxldCBlbGVtZW50ID0gZWxlbWVudFJlZi5uYXRpdmVFbGVtZW50O1xuICB3aGlsZSAoZWxlbWVudCAmJiAoZWxlbWVudC5vZmZzZXRIZWlnaHQgPT09IDAgfHwgZWxlbWVudC5vZmZzZXRIZWlnaHQgPT09IHVuZGVmaW5lZCkgJiYgIWVsZW1lbnQuY2xhc3NMaXN0Py5jb250YWlucyhjbGFzc05hbWUpKSB7XG4gICAgZWxlbWVudCA9IGVsZW1lbnQucGFyZW50RWxlbWVudDtcbiAgfVxuXG4gIHJldHVybiB7XG4gICAgaGVpZ2h0OiBlbGVtZW50Py5vZmZzZXRIZWlnaHQgPz8gMCxcbiAgICB3aWR0aDogZWxlbWVudD8ub2Zmc2V0V2lkdGggPz8gMCxcbiAgfSBhcyBFbGVtZW50RGltZW5zaW9ucztcbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGxvYWRIVE1MQ29udGVudChwYXRoQ29udGVudDogc3RyaW5nLCBpZDogc3RyaW5nKTogUHJvbWlzZTxib29sZWFuPiB7XG4gIHRyeSB7XG4gICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBmZXRjaChwYXRoQ29udGVudCk7XG4gICAgaWYgKCFyZXNwb25zZS5vaykge1xuICAgICAgY29uc29sZS5lcnJvcihgSFRUUCBFcnJvcjogJHtyZXNwb25zZS5zdGF0dXN9ICR7cmVzcG9uc2Uuc3RhdHVzVGV4dH1gKTtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICAvLyBSZW5kZXIgdGhlIHRydXN0ZWQgV2hhdCdzIE5ldyBkb2N1bWVudCBhcy1pcyAoSFRNTCArIENTUyArIEpTKSBpbnRvIGEgc2FuZGJveGVkXG4gICAgLy8gaWZyYW1lIHZpYSBzcmNkb2MuIHNyY2RvYyBwYWludHMgdGhlIGZldGNoZWQgYnl0ZXMgZGlyZWN0bHksIGF2b2lkaW5nIGEgc2Vjb25kXG4gICAgLy8gbmF2aWdhdGlvbiB0aGUgYnJvd3NlciB3b3VsZCBibGFuayB3aGVuIHRoZSBzb3VyY2Ugc2VuZHMgWC1GcmFtZS1PcHRpb25zLlxuICAgIGNvbnN0IHRhcmdldCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKGAke2lkfWApO1xuICAgIGlmICghKHRhcmdldCBpbnN0YW5jZW9mIEhUTUxJRnJhbWVFbGVtZW50KSkge1xuICAgICAgY29uc29sZS5lcnJvcihgbG9hZEhUTUxDb250ZW50OiB0YXJnZXQgIyR7aWR9IGlzIG1pc3Npbmcgb3IgaXMgbm90IGFuIDxpZnJhbWU+YCk7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIHRhcmdldC5zcmNkb2MgPSBpbmplY3RJZnJhbWVIZWFkKGF3YWl0IHJlc3BvbnNlLnRleHQoKSwgcGF0aENvbnRlbnQpO1xuXG4gICAgcmV0dXJuIHRydWU7XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgY29uc29sZS5lcnJvcignRXJyb3IgbG9hZGluZyBIVE1MOicsIGVycm9yKTtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cbn1cblxuLy8gVGhlIGFwcCdzIGN1c3RvbSBzY3JvbGxiYXIg4oCUIHRoZSBzcmNkb2MgaXMgYW4gaXNvbGF0ZWQgZG9jdW1lbnQsIHNvIGdsb2JhbCBhcHBcbi8vIHN0eWxlcyBkbyBub3QgcmVhY2ggaXQ7IGluamVjdCB0aGVtIHNvIGl0cyBzY3JvbGxiYXIgbWF0Y2hlcyB0aGUgcmVzdCBvZiB0aGUgYXBwLlxuY29uc3QgSUZSQU1FX1NDUk9MTEJBUl9TVFlMRSA9XG4gICc8c3R5bGU+JyArXG4gICc6Oi13ZWJraXQtc2Nyb2xsYmFye3dpZHRoOjVweDtoZWlnaHQ6NXB4O2JvcmRlci1yYWRpdXM6NXB4O2JhY2tncm91bmQtY29sb3I6dHJhbnNwYXJlbnQ7fScgK1xuICAnOjotd2Via2l0LXNjcm9sbGJhci10cmFja3tib3JkZXItcmFkaXVzOjVweDtiYWNrZ3JvdW5kLWNvbG9yOnRyYW5zcGFyZW50O30nICtcbiAgJzo6LXdlYmtpdC1zY3JvbGxiYXItdGh1bWJ7Ym9yZGVyLXJhZGl1czo1cHg7YmFja2dyb3VuZC1jb2xvcjojZGVlMmU2O30nICtcbiAgJzo6LXdlYmtpdC1zY3JvbGxiYXItdGh1bWI6aG92ZXJ7YmFja2dyb3VuZC1jb2xvcjojOTE5ZWFiO30nICtcbiAgJ2h0bWx7c2Nyb2xsYmFyLXdpZHRoOnRoaW47c2Nyb2xsYmFyLWNvbG9yOiNkZWUyZTYgdHJhbnNwYXJlbnQ7fScgK1xuICAnPC9zdHlsZT4nO1xuXG4vLyBJbmplY3QgYSA8YmFzZT4gKHNvIHJlbGF0aXZlIGFzc2V0IFVSTHMgcmVzb2x2ZSBhZ2FpbnN0IHRoZSBzb3VyY2UpIHBsdXMgdGhlIGFwcFxuLy8gc2Nyb2xsYmFyIHN0eWxlIGludG8gdGhlIGRvY3VtZW50IGhlYWQsIHdpdGhvdXQgb3RoZXJ3aXNlIGFsdGVyaW5nIHRoZSBjb250ZW50LlxuZnVuY3Rpb24gaW5qZWN0SWZyYW1lSGVhZChodG1sOiBzdHJpbmcsIHNvdXJjZVVybDogc3RyaW5nKTogc3RyaW5nIHtcbiAgY29uc3QgYmFzZUhyZWYgPSBzb3VyY2VVcmwuc2xpY2UoMCwgc291cmNlVXJsLmxhc3RJbmRleE9mKCcvJykgKyAxKTtcbiAgY29uc3QgaW5qZWN0ZWQgPSAoYmFzZUhyZWYgPyBgPGJhc2UgaHJlZj1cIiR7ZW5jb2RlVVJJKGJhc2VIcmVmKX1cIj5gIDogJycpICsgSUZSQU1FX1NDUk9MTEJBUl9TVFlMRTtcblxuICAvLyBFeGlzdGluZyA8aGVhZD4g4oaSIGluamVjdCBpbnNpZGUgaXQuIFRoZSAoPz1bXFxzPl0pIGRlbGltaXRlciBzdG9wcyA8aGVhZD4gZnJvbVxuICAvLyBhbHNvIG1hdGNoaW5nIDxoZWFkZXIg4oCmPiAod2hpY2ggd291bGQgaW5qZWN0IDxiYXNlPi9zdHlsZSBvdXRzaWRlIGFueSByZWFsIGhlYWQpLlxuICBpZiAoLzxoZWFkKD89W1xccz5dKVtePl0qPi9pLnRlc3QoaHRtbCkpIHtcbiAgICByZXR1cm4gaHRtbC5yZXBsYWNlKC88aGVhZCg/PVtcXHM+XSlbXj5dKj4vaSwgKGhlYWQpID0+IGAke2hlYWR9JHtpbmplY3RlZH1gKTtcbiAgfVxuICAvLyBGdWxsIGRvY3VtZW50IHdpdGhvdXQgYSA8aGVhZD4g4oaSIGNyZWF0ZSBvbmUgcmlnaHQgYWZ0ZXIgPGh0bWwg4oCmPiBzbyB0aGVcbiAgLy8gaW5qZWN0ZWQgbWFya3VwIG5ldmVyIHByZWNlZGVzIHRoZSBkb2N0eXBlICh3aGljaCB3b3VsZCBmb3JjZSBxdWlya3MgbW9kZSkuXG4gIGlmICgvPGh0bWwoPz1bXFxzPl0pW14+XSo+L2kudGVzdChodG1sKSkge1xuICAgIHJldHVybiBodG1sLnJlcGxhY2UoLzxodG1sKD89W1xccz5dKVtePl0qPi9pLCAoaHRtbFRhZykgPT4gYCR7aHRtbFRhZ308aGVhZD4ke2luamVjdGVkfTwvaGVhZD5gKTtcbiAgfVxuICAvLyBCYXJlIGZyYWdtZW50IChubyBkb2N0eXBlLzxodG1sPikg4oaSIHNhZmUgdG8gcHJlcGVuZC5cbiAgcmV0dXJuIGAke2luamVjdGVkfSR7aHRtbH1gO1xufVxuIl19
|
|
@@ -385,27 +385,54 @@ function findParentElementDimensions(elementRef, className) {
|
|
|
385
385
|
};
|
|
386
386
|
}
|
|
387
387
|
async function loadHTMLContent(pathContent, id) {
|
|
388
|
-
let isSuccess = true;
|
|
389
388
|
try {
|
|
390
389
|
const response = await fetch(pathContent);
|
|
391
|
-
if (response.ok) {
|
|
392
|
-
const htmlContent = sanitizeHtmlValue(await response.text());
|
|
393
|
-
const contentDiv = document.getElementById(`${id}`);
|
|
394
|
-
if (contentDiv) {
|
|
395
|
-
const parsedDocument = new DOMParser().parseFromString(htmlContent, 'text/html');
|
|
396
|
-
contentDiv.replaceChildren(...Array.from(parsedDocument.body.childNodes));
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
else {
|
|
390
|
+
if (!response.ok) {
|
|
400
391
|
console.error(`HTTP Error: ${response.status} ${response.statusText}`);
|
|
401
|
-
|
|
392
|
+
return false;
|
|
402
393
|
}
|
|
394
|
+
// Render the trusted What's New document as-is (HTML + CSS + JS) into a sandboxed
|
|
395
|
+
// iframe via srcdoc. srcdoc paints the fetched bytes directly, avoiding a second
|
|
396
|
+
// navigation the browser would blank when the source sends X-Frame-Options.
|
|
397
|
+
const target = document.getElementById(`${id}`);
|
|
398
|
+
if (!(target instanceof HTMLIFrameElement)) {
|
|
399
|
+
console.error(`loadHTMLContent: target #${id} is missing or is not an <iframe>`);
|
|
400
|
+
return false;
|
|
401
|
+
}
|
|
402
|
+
target.srcdoc = injectIframeHead(await response.text(), pathContent);
|
|
403
|
+
return true;
|
|
403
404
|
}
|
|
404
405
|
catch (error) {
|
|
405
406
|
console.error('Error loading HTML:', error);
|
|
406
|
-
|
|
407
|
+
return false;
|
|
407
408
|
}
|
|
408
|
-
|
|
409
|
+
}
|
|
410
|
+
// The app's custom scrollbar — the srcdoc is an isolated document, so global app
|
|
411
|
+
// styles do not reach it; inject them so its scrollbar matches the rest of the app.
|
|
412
|
+
const IFRAME_SCROLLBAR_STYLE = '<style>' +
|
|
413
|
+
'::-webkit-scrollbar{width:5px;height:5px;border-radius:5px;background-color:transparent;}' +
|
|
414
|
+
'::-webkit-scrollbar-track{border-radius:5px;background-color:transparent;}' +
|
|
415
|
+
'::-webkit-scrollbar-thumb{border-radius:5px;background-color:#dee2e6;}' +
|
|
416
|
+
'::-webkit-scrollbar-thumb:hover{background-color:#919eab;}' +
|
|
417
|
+
'html{scrollbar-width:thin;scrollbar-color:#dee2e6 transparent;}' +
|
|
418
|
+
'</style>';
|
|
419
|
+
// Inject a <base> (so relative asset URLs resolve against the source) plus the app
|
|
420
|
+
// scrollbar style into the document head, without otherwise altering the content.
|
|
421
|
+
function injectIframeHead(html, sourceUrl) {
|
|
422
|
+
const baseHref = sourceUrl.slice(0, sourceUrl.lastIndexOf('/') + 1);
|
|
423
|
+
const injected = (baseHref ? `<base href="${encodeURI(baseHref)}">` : '') + IFRAME_SCROLLBAR_STYLE;
|
|
424
|
+
// Existing <head> → inject inside it. The (?=[\s>]) delimiter stops <head> from
|
|
425
|
+
// also matching <header …> (which would inject <base>/style outside any real head).
|
|
426
|
+
if (/<head(?=[\s>])[^>]*>/i.test(html)) {
|
|
427
|
+
return html.replace(/<head(?=[\s>])[^>]*>/i, (head) => `${head}${injected}`);
|
|
428
|
+
}
|
|
429
|
+
// Full document without a <head> → create one right after <html …> so the
|
|
430
|
+
// injected markup never precedes the doctype (which would force quirks mode).
|
|
431
|
+
if (/<html(?=[\s>])[^>]*>/i.test(html)) {
|
|
432
|
+
return html.replace(/<html(?=[\s>])[^>]*>/i, (htmlTag) => `${htmlTag}<head>${injected}</head>`);
|
|
433
|
+
}
|
|
434
|
+
// Bare fragment (no doctype/<html>) → safe to prepend.
|
|
435
|
+
return `${injected}${html}`;
|
|
409
436
|
}
|
|
410
437
|
|
|
411
438
|
class MatHintErrorDirective {
|