Skip to content

Commit 93f9403

Browse files
committed
docs: fix demo hack for html-include
1 parent 3bce33e commit 93f9403

File tree

1 file changed

+80
-84
lines changed

1 file changed

+80
-84
lines changed

docs/demo/demo.ts

Lines changed: 80 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { HTMLIncludeElement } from 'html-include-element';
1+
import 'html-include-element';
22
import 'api-viewer-element';
33
import '@vaadin/split-layout';
44

@@ -47,97 +47,89 @@ async function onLoad(element: string, base: 'core' | 'elements', location: Loca
4747
include.classList.remove('loading');
4848
componentHeader.classList.remove('loading');
4949
onContextChange();
50+
window.removeEventListener('unhandledrejection', handleBadLoad);
5051
}
5152

52-
async function patchHTMLIncludes() {
53-
/* eslint-disable no-console */
54-
/**
55-
* quick hack to avoid page load errors if subresources are missing from demo files
56-
* @see https://github.com/justinfagnani/html-include-element/pull/21
57-
*/
58-
if (!HTMLIncludeElement.prototype.attributeChangedCallback.toString().includes('await Promise.all([...this.shadowRoot.querySelectorAll')) {
59-
console.info('No need to patch <html-include>');
60-
} else {
61-
console.info('Patching <html-include>');
62-
await customElements.whenDefined('html-include');
63-
const isLinkAlreadyLoaded = (link: HTMLLinkElement) => {
64-
try {
65-
return !!(link.sheet && link.sheet.cssRules);
66-
} catch (error) {
67-
if (error.name === 'InvalidAccessError' || error.name === 'SecurityError') {
68-
return false;
69-
} else {
70-
throw error;
71-
}
53+
/* eslint-disable no-console */
54+
/**
55+
* quick hack to avoid page load errors if subresources are missing from demo files
56+
* @see https://github.com/justinfagnani/html-include-element/pull/21
57+
*/
58+
async function handleBadLoad() {
59+
await loadPartial.call(document.querySelector('html-include'));
60+
}
61+
62+
const isLinkAlreadyLoaded = (link: HTMLLinkElement) => {
63+
try {
64+
return !!(link.sheet && link.sheet.cssRules);
65+
} catch (error) {
66+
if (error.name === 'InvalidAccessError' || error.name === 'SecurityError') {
67+
return false;
68+
} else {
69+
throw error;
70+
}
71+
}
72+
};
73+
74+
const linkLoaded = async function linkLoaded(link: HTMLLinkElement) {
75+
return new Promise((resolve, reject) => {
76+
if (!('onload' in HTMLLinkElement.prototype)) {
77+
resolve(null);
78+
} else if (isLinkAlreadyLoaded(link)) {
79+
resolve(link.sheet);
80+
} else {
81+
link.addEventListener('load', () => resolve(link.sheet), { once: true });
82+
link.addEventListener('error', () => reject({ link }), { once: true });
83+
}
84+
});
85+
};
86+
87+
/** @this {import('html-include-element').HTMLIncludeElement} */
88+
async function loadPartial() {
89+
let text = '';
90+
try {
91+
const mode = this.mode || 'cors';
92+
const response = await fetch(this.getAttribute('src'), { mode });
93+
if (!response.ok) {
94+
throw new Error(`html-include fetch failed: ${response.statusText}`);
95+
}
96+
text = await response.text();
97+
} catch (e) {
98+
console.error(e);
99+
}
100+
// Don't destroy the light DOM if we're using shadow DOM, so that slotted content is respected
101+
if (this.noShadow) {
102+
this.innerHTML = text;
103+
}
104+
105+
this.shadowRoot.innerHTML = `
106+
<style>
107+
:host {
108+
display: block;
72109
}
73-
};
74-
75-
const linkLoaded = async function linkLoaded(link: HTMLLinkElement) {
76-
return new Promise((resolve, reject) => {
77-
if (!('onload' in HTMLLinkElement.prototype)) {
78-
resolve(null);
79-
} else if (isLinkAlreadyLoaded(link)) {
80-
resolve(link.sheet);
81-
} else {
82-
link.addEventListener('load', () => resolve(link.sheet), { once: true });
83-
link.addEventListener('error', () => reject({ link }), { once: true });
84-
}
85-
});
86-
};
87-
88-
HTMLIncludeElement.prototype.attributeChangedCallback = async function attributeChangedCallback(name: string, _: string, newValue: string) {
89-
if (name === 'src') {
90-
let text = '';
91-
try {
92-
const mode = this.mode || 'cors';
93-
const response = await fetch(newValue, { mode });
94-
if (!response.ok) {
95-
throw new Error(`html-include fetch failed: ${response.statusText}`);
96-
}
97-
text = await response.text();
98-
if (this.src !== newValue) {
99-
// the src attribute was changed before we got the response, so bail
100-
return;
101-
}
102-
} catch (e) {
103-
console.error(e);
104-
}
105-
// Don't destroy the light DOM if we're using shadow DOM, so that slotted content is respected
106-
if (this.noShadow) {
107-
this.innerHTML = text;
108-
}
109-
this.shadowRoot.innerHTML = `
110-
<style>
111-
:host {
112-
display: block;
113-
}
114-
</style>
115-
${this.noShadow ? '<slot></slot>' : text}
116-
`;
117-
118-
// If we're not using shadow DOM, then the consuming root
119-
// is responsible to load its own resources
120-
if (!this.noShadow) {
121-
const results = await Promise.allSettled([...this.shadowRoot.querySelectorAll('link')].map(linkLoaded));
122-
for (const result of results) {
123-
if (result.status === 'rejected') {
124-
const { link } = result.reason;
125-
const message = `Could not load ${link.href}`;
126-
console.error(message);
127-
}
128-
}
129-
}
130-
131-
this.dispatchEvent(new Event('load'));
110+
</style>
111+
${this.noShadow ? '<slot></slot>' : text}
112+
`;
113+
114+
// If we're not using shadow DOM, then the consuming root
115+
// is responsible to load its own resources
116+
if (!this.noShadow) {
117+
const results = await Promise.allSettled([...this.shadowRoot.querySelectorAll('link')].map(linkLoaded));
118+
for (const result of results) {
119+
if (result.status === 'rejected') {
120+
const { link } = result.reason;
121+
const message = `Could not load ${link.href}`;
122+
console.error(message);
132123
}
133-
};
124+
}
134125
}
135-
/* eslint-enable no-console */
126+
127+
this.dispatchEvent(new Event('load'));
136128
}
129+
/* eslint-enable no-console */
137130

138131
/** Load up the requested element's demo in a separate shadow root */
139132
async function go(location = window.location) {
140-
await patchHTMLIncludes();
141133
const { element } = pattern.exec(location.href)?.pathname?.groups ?? {};
142134

143135
if (element) {
@@ -146,7 +138,11 @@ async function go(location = window.location) {
146138
componentHeader.classList.add('loading');
147139
include.addEventListener('load', onLoad.bind(include, element, base, location), { once: true });
148140
include.setAttribute('data-demo', element);
149-
include.src = `/${base}/${element}/demo/${element}.html`;
141+
142+
window.addEventListener('unhandledrejection', handleBadLoad, { once: true });
143+
144+
include.setAttribute('src', `/${base}/${element}/demo/${element}.html`);
145+
150146
viewer.src = `/${base}/${element}/custom-elements.json`;
151147
viewer.hidden = false;
152148
document.title = `${pretty(element)} | PatternFly Elements`;

0 commit comments

Comments
 (0)