Skip to content

Commit

Permalink
docs: fix demo hack for html-include
Browse files Browse the repository at this point in the history
  • Loading branch information
bennypowers committed Mar 28, 2022
1 parent e546170 commit d7c110c
Showing 1 changed file with 80 additions and 84 deletions.
164 changes: 80 additions & 84 deletions docs/demo/demo.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { HTMLIncludeElement } from 'html-include-element';
import 'html-include-element';
import 'api-viewer-element';
import '@vaadin/split-layout';

Expand Down Expand Up @@ -47,97 +47,89 @@ async function onLoad(element: string, base: 'core' | 'elements', location: Loca
include.classList.remove('loading');
componentHeader.classList.remove('loading');
onContextChange();
window.removeEventListener('unhandledrejection', handleBadLoad);
}

async function patchHTMLIncludes() {
/* eslint-disable no-console */
/**
* quick hack to avoid page load errors if subresources are missing from demo files
* @see https://github.com/justinfagnani/html-include-element/pull/21
*/
if (!HTMLIncludeElement.prototype.attributeChangedCallback.toString().includes('await Promise.all([...this.shadowRoot.querySelectorAll')) {
console.info('No need to patch <html-include>');
} else {
console.info('Patching <html-include>');
await customElements.whenDefined('html-include');
const isLinkAlreadyLoaded = (link: HTMLLinkElement) => {
try {
return !!(link.sheet && link.sheet.cssRules);
} catch (error) {
if (error.name === 'InvalidAccessError' || error.name === 'SecurityError') {
return false;
} else {
throw error;
}
/* eslint-disable no-console */
/**
* quick hack to avoid page load errors if subresources are missing from demo files
* @see https://github.com/justinfagnani/html-include-element/pull/21
*/
async function handleBadLoad() {
await loadPartial.call(document.querySelector('html-include'));
}

const isLinkAlreadyLoaded = (link: HTMLLinkElement) => {
try {
return !!(link.sheet && link.sheet.cssRules);
} catch (error) {
if (error.name === 'InvalidAccessError' || error.name === 'SecurityError') {
return false;
} else {
throw error;
}
}
};

const linkLoaded = async function linkLoaded(link: HTMLLinkElement) {
return new Promise((resolve, reject) => {
if (!('onload' in HTMLLinkElement.prototype)) {
resolve(null);
} else if (isLinkAlreadyLoaded(link)) {
resolve(link.sheet);
} else {
link.addEventListener('load', () => resolve(link.sheet), { once: true });
link.addEventListener('error', () => reject({ link }), { once: true });
}
});
};

/** @this {import('html-include-element').HTMLIncludeElement} */
async function loadPartial() {
let text = '';
try {
const mode = this.mode || 'cors';
const response = await fetch(this.getAttribute('src'), { mode });
if (!response.ok) {
throw new Error(`html-include fetch failed: ${response.statusText}`);
}
text = await response.text();
} catch (e) {
console.error(e);
}
// Don't destroy the light DOM if we're using shadow DOM, so that slotted content is respected
if (this.noShadow) {
this.innerHTML = text;
}

this.shadowRoot.innerHTML = `
<style>
:host {
display: block;
}
};

const linkLoaded = async function linkLoaded(link: HTMLLinkElement) {
return new Promise((resolve, reject) => {
if (!('onload' in HTMLLinkElement.prototype)) {
resolve(null);
} else if (isLinkAlreadyLoaded(link)) {
resolve(link.sheet);
} else {
link.addEventListener('load', () => resolve(link.sheet), { once: true });
link.addEventListener('error', () => reject({ link }), { once: true });
}
});
};

HTMLIncludeElement.prototype.attributeChangedCallback = async function attributeChangedCallback(name: string, _: string, newValue: string) {
if (name === 'src') {
let text = '';
try {
const mode = this.mode || 'cors';
const response = await fetch(newValue, { mode });
if (!response.ok) {
throw new Error(`html-include fetch failed: ${response.statusText}`);
}
text = await response.text();
if (this.src !== newValue) {
// the src attribute was changed before we got the response, so bail
return;
}
} catch (e) {
console.error(e);
}
// Don't destroy the light DOM if we're using shadow DOM, so that slotted content is respected
if (this.noShadow) {
this.innerHTML = text;
}
this.shadowRoot.innerHTML = `
<style>
:host {
display: block;
}
</style>
${this.noShadow ? '<slot></slot>' : text}
`;

// If we're not using shadow DOM, then the consuming root
// is responsible to load its own resources
if (!this.noShadow) {
const results = await Promise.allSettled([...this.shadowRoot.querySelectorAll('link')].map(linkLoaded));
for (const result of results) {
if (result.status === 'rejected') {
const { link } = result.reason;
const message = `Could not load ${link.href}`;
console.error(message);
}
}
}

this.dispatchEvent(new Event('load'));
</style>
${this.noShadow ? '<slot></slot>' : text}
`;

// If we're not using shadow DOM, then the consuming root
// is responsible to load its own resources
if (!this.noShadow) {
const results = await Promise.allSettled([...this.shadowRoot.querySelectorAll('link')].map(linkLoaded));
for (const result of results) {
if (result.status === 'rejected') {
const { link } = result.reason;
const message = `Could not load ${link.href}`;
console.error(message);
}
};
}
}
/* eslint-enable no-console */

this.dispatchEvent(new Event('load'));
}
/* eslint-enable no-console */

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

if (element) {
Expand All @@ -146,7 +138,11 @@ async function go(location = window.location) {
componentHeader.classList.add('loading');
include.addEventListener('load', onLoad.bind(include, element, base, location), { once: true });
include.setAttribute('data-demo', element);
include.src = `/${base}/${element}/demo/${element}.html`;

window.addEventListener('unhandledrejection', handleBadLoad, { once: true });

include.setAttribute('src', `/${base}/${element}/demo/${element}.html`);

viewer.src = `/${base}/${element}/custom-elements.json`;
viewer.hidden = false;
document.title = `${pretty(element)} | PatternFly Elements`;
Expand Down

0 comments on commit d7c110c

Please sign in to comment.