PageSourceSearch

https://www.eventeny.com/js/Components/Base/WebComponent.js?v=1790795785

js eventeny.com collected 2026-10-01 10:25:16 UTC 8,739 bytes, 198 lines download raw bytes

1
2// Polyfill for html_entities in case base-2019-06-24.js is not loaded on the page.
3// Encodes &, <, >, ", and ' to their HTML entity equivalents.
4if (typeof html_entities !== 'function') {
5    window.html_entities = function(text) {
6        if (text == null) return '';
7        return String(text)
8            .replace(/&/g, '&amp;')
9            .replace(/</g, '&lt;')
10            .replace(/>/g, '&gt;')
11            .replace(/"/g, '&quot;')
12            .replace(/'/g, '&#039;');
13    };
14}
15
16export class WebComponent extends HTMLElement {
17    shadowRoot; // Shadow DOM
18    placeHolderRoot; // Placeholder root
19    state = {}; // State object
20
21    // Per-class caches for the shadow-DOM caching helpers below. Keyed by class reference
22    // (WeakMap) so unrelated components (Button, BasicCheckbox, BasicField, ...) each get
23    // their own independent cache entry with no collisions.
24    static _templateCache = new WeakMap();   // ClassRef -> HTMLTemplateElement
25    static _styleSheetCache = new WeakMap(); // ClassRef -> CSSStyleSheet
26    static _supportsAdoptedStyleSheetsResult = null;
27
28    // Feature-detect once and memoize: constructed stylesheets (needed for adoptedStyleSheets)
29    // aren't available on every browser, so callers need a way to know whether to fall back
30    // to a plain per-instance <style> tag instead.
31    static supportsAdoptedStyleSheets() {
32        if (WebComponent._supportsAdoptedStyleSheetsResult === null) {
33            WebComponent._supportsAdoptedStyleSheetsResult = typeof CSSStyleSheet !== 'undefined'
34                && 'replaceSync' in CSSStyleSheet.prototype
35                && typeof ShadowRoot !== 'undefined'
36                && 'adoptedStyleSheets' in ShadowRoot.prototype;
37        }
38        return WebComponent._supportsAdoptedStyleSheetsResult;
39    }
40
41    // Building shadow DOM markup via a fresh innerHTML string on every instance forces the
42    // browser to re-parse that HTML on every single instantiation. With many instances of
43    // the same component on one page (e.g. dozens of cards each containing several buttons,
44    // checkboxes, and fields), that parsing cost is paid over and over for identical markup.
45    // This parses `html` into a <template> once per calling class and returns a fresh clone
46    // of its content on every call after that — cloning is far cheaper than re-parsing.
47    static getTemplateClone(ClassRef, html) {
48        let template = WebComponent._templateCache.get(ClassRef);
49        if (!template) {
50            template = document.createElement('template');
51            template.innerHTML = html;
52            WebComponent._templateCache.set(ClassRef, template);
53        }
54        return template.content.cloneNode(true);
55    }
56
57    // Same idea for CSS: parses `cssText` into a CSSStyleSheet once per calling class via
58    // replaceSync(), so it can be shared across every instance via shadowRoot.adoptedStyleSheets
59    // instead of re-parsing the same CSS text into a fresh <style> tag per instance. Returns
60    // null when constructed stylesheets aren't supported, so the caller can fall back to a
61    // plain <style> tag with the same cssText.
62    //
63    // Note: cssText must not contain @import — @import rules are silently dropped by
64    // replaceSync() per spec. Load external stylesheets (e.g. icon fonts) via a <link> in the
65    // template markup instead.
66    static getComponentStyleSheet(ClassRef, cssText) {
67        if (!WebComponent.supportsAdoptedStyleSheets()) return null;
68        let sheet = WebComponent._styleSheetCache.get(ClassRef);
69        if (!sheet) {
70            sheet = new CSSStyleSheet();
71            sheet.replaceSync(cssText);
72            WebComponent._styleSheetCache.set(ClassRef, sheet);
73        }
74        return sheet;
75    }
76
77    constructor() {
78        super();
79        this.placeHolderRoot = document.createElement('div');
80        this.shadowRoot = this.attachShadow({ mode: 'open' });
81    }
82
83    // Updates state and triggers re-render
84    setState(newState) {
85        this.state = { ...this.state, ...newState };
86        this.render();
87    }
88
89    // Lifecycle hook to trigger the initial render
90    connectedCallback() {
91        this.render();
92    }
93    
94    // Placeholder render method
95    render() {
96        // Should be implemented in derived components
97        throw new Error('Render method must be implemented in the derived component.');
98    }
99
100    setEventListeners() {
101        // Optional to be implemented in derived components
102    }
103
104    loadBaseCSS() {
105        const base2017 = document.createElement('link');
106        base2017.setAttribute('rel', 'stylesheet');
107        base2017.setAttribute('type', 'text/css');
108        base2017.setAttribute('href', '/css/base-2017-05-15.css');
109        this.placeHolderRoot.appendChild(base2017);
110        const base2018 = document.createElement('link');
111        base2018.setAttribute('rel', 'stylesheet');
112        base2018.setAttribute('type', 'text/css');
113        base2018.setAttribute('href', '/css/base-2018-11-17.css');
114        this.placeHolderRoot.appendChild(base2018);
115    }
116
117    // TODO: more discussion needed on how to handle jQuery depen
117dency for components. For now, we can load it globally in the head if not already present.
118    loadJQuery() {
119        // jQuery is a global dependency. Load it once in document head to avoid
120        // reinitializing window.$ / window.jQuery when multiple components mount.
121        if (window.jQuery && window.jQuery.fn) return;
122        if (document.querySelector('script[data-webcomponent-lib="jquery"]')) return;
123        if (document.querySelector('script[src*="/js/jquery.min.js"]')) return;
124
125        const jQuery = document.createElement('script');
126        jQuery.setAttribute('src', '/js/jquery.min.js');
127        jQuery.setAttribute('data-webcomponent-lib', 'jquery');
128        document.head.appendChild(jQuery);
129    }
130
131    loadBaseJS() {
132        // Base JS is also global; load once in head to avoid duplicate execution.
133        if (document.querySelector('script[data-webcomponent-lib="base-js"]')) return;
134        if (document.querySelector('script[src*="/js/base-2019-06-24.js"]')) return;
135
136        const baseJS = document.createElement('script');
137        baseJS.setAttribute('src', '/js/base-2019-06-24.js');
138        baseJS.setAttribute('data-webcomponent-lib', 'base-js');
139        document.head.appendChild(baseJS);
140    }
141
142    loadChartJS() {
143        return new Promise((resolve) => {
144            if (typeof Chart !== 'undefined') { resolve(); return; }
145            const existing = document.querySelector('script[src="/js/chart4.min.js"]');
146            if (existing) { existing.addEventListener('load', resolve); return; }
147            const script = document.createElement('script');
148            script.src = '/js/chart4.min.js';
149            script.onload = resolve;
150            document.head.appendChild(script);
151        });
152    }
153
154    loadD3() {
155        const loadScript = (src, check) => new Promise(resolve => {
156            if (check()) { resolve(); return; }
157            const existing = document.querySelector(`script[src="${src}"]`);
158            if (existing) { existing.addEventListener('load', resolve); return; }
159            const script = document.createElement('script');
160            script.src = src; script.onload = resolve;
161            document.head.appendChild(script);
162        });
163        return Promise.all([
164            loadScript('https://d3js.org/d3.v7.min.js',
165                       () => typeof d3 !== 'undefined'),
166            loadScript('https://cdn.jsdelivr.net/npm/topojson-client@3/dist/topojson-client.min.js',
167                       () => typeof topojson !== 'undefined'),
168        ]);
169    }
170
171    loadIcons() {
172        const icons = ['https://unicons.iconscout.com/release/v4.0.8/css/line.css', 'https://unicons.iconscout.com/release/v4.0.8/css/solid.css', 'https://unicons.iconscout.com/release/v4.0.8/css/thinline.css'];
173        return Promise.all(
174            icons.map((file) => {
175                return new Promise((resolve) => {
176                    const link = document.createElement("link");
177                    link.rel = "stylesheet";
178                    link.href = file;
179                    link.onload = () => resolve(); // Wait for CSS to load
180                    this.placeHolderRoot.appendChild(link);
181                });
182            })
183        );
184        
185    }
186
187    loadTemplate(template) {
188        const templateElement = document.createElement('template');
189        templateElement.innerHTML += this.placeHolderRoot.innerHTML;
190        templateElement.innerHTML += template;
191        this.shadowRoot.innerHTML = '';
192        this.shadowRoot.appendChild(templateElement.content.cloneNode(true));
193
194        this.setEventListeners();
195    }
196    
197}
198

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.