1- import { HTMLIncludeElement } from 'html-include-element' ;
1+ import 'html-include-element' ;
22import 'api-viewer-element' ;
33import '@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 */
139132async 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