From f388c3955391113a013e45a62b15f91e529453bb Mon Sep 17 00:00:00 2001 From: Ludwig Schubert Date: Tue, 24 Oct 2017 16:48:48 -0700 Subject: [PATCH] WIP switch to webcomponents loader async polyfills; multiple small fixes for Firefox and generally more defensive coding --- src/components/d-article.js | 4 +- src/components/d-bibliography.js | 6 ++ src/components/d-cite.js | 14 ++- src/controller.js | 4 +- src/transforms/meta.js | 5 + src/transforms/polyfills.js | 99 ++++++++++++------- src/ui/d-slider.js | 162 +++++++++++++++---------------- 7 files changed, 165 insertions(+), 129 deletions(-) diff --git a/src/components/d-article.js b/src/components/d-article.js index e8b12bd..aa9b92f 100644 --- a/src/components/d-article.js +++ b/src/components/d-article.js @@ -1,4 +1,4 @@ -import { Template } from '../mixins/template'; +// import { Template } from '../mixins/template'; import { Controller } from '../controller'; const isOnlyWhitespace = /^\s*$/; @@ -31,7 +31,7 @@ export class Article extends HTMLElement { connectedCallback() { document.onreadystatechange = function () { - console.log("onreadystatechange:"); + console.log('onreadystatechange:'); console.log(document.readyState); }; console.info('Article tag connected, we can now listen to controller events.'); diff --git a/src/components/d-bibliography.js b/src/components/d-bibliography.js index b737228..a420422 100644 --- a/src/components/d-bibliography.js +++ b/src/components/d-bibliography.js @@ -35,6 +35,12 @@ export class Bibliography extends HTMLElement { observer.observe(this, options); } + connectedCallback() { + requestAnimationFrame(() => { + this.parseIfPossible(); + }); + } + parseIfPossible() { const scriptTag = this.querySelector('script'); if (!scriptTag) return; diff --git a/src/components/d-cite.js b/src/components/d-cite.js index 13d1cc0..78f1128 100644 --- a/src/components/d-cite.js +++ b/src/components/d-cite.js @@ -49,12 +49,6 @@ export class Cite extends T(HTMLElement) { /* Lifecycle */ - // constructor() { - // super(); - // // Cite.currentId += 1; - // // this.citeId = Cite.currentId; - // } - connectedCallback() { this.outerSpan = this.root.querySelector('#citation-'); this.innerSpan = this.root.querySelector('.citation-number'); @@ -105,11 +99,15 @@ export class Cite extends T(HTMLElement) { return index == -1 ? '?' : index + 1 + ''; }); const textContent = '[' + numberStrings.join(', ') + ']'; - this.innerSpan.textContent = textContent; + if (this.innerSpan) { + this.innerSpan.textContent = textContent; + } } set entries(entries) { - this.hoverBox.innerHTML = entries.map(hover_cite).join('

'); + if (this.hoverBox) { + this.hoverBox.innerHTML = entries.map(hover_cite).join('

'); + } } } diff --git a/src/controller.js b/src/controller.js index cec5244..d715e67 100644 --- a/src/controller.js +++ b/src/controller.js @@ -38,7 +38,7 @@ export const Controller = { citeTag.entries = entries; }, - onCiteKeyChanged(event) { + onCiteKeyChanged() { // const [citeTag, keys] = event.detail; // update citations @@ -145,7 +145,7 @@ export const Controller = { return; } else { Controller.loaded = true; - console.log('Controller running DOMContentLoaded') + console.log('Controller running DOMContentLoaded'); } const frontMatterTag = document.querySelector('d-front-matter'); diff --git a/src/transforms/meta.js b/src/transforms/meta.js index a02231d..cad5c56 100644 --- a/src/transforms/meta.js +++ b/src/transforms/meta.js @@ -37,6 +37,11 @@ export default function(dom, data) { + `); + } + + if (data.updatedDate) { + appendHead(` `); } diff --git a/src/transforms/polyfills.js b/src/transforms/polyfills.js index 34ded4d..d4fb6c5 100644 --- a/src/transforms/polyfills.js +++ b/src/transforms/polyfills.js @@ -1,47 +1,74 @@ const webcomponentPath = 'https://distill.pub/third-party/polyfills/webcomponents-lite.js'; const intersectionObserverPath = 'https://distill.pub/third-party/polyfills/intersection-observer.js'; -const template = ` -if ('IntersectionObserver' in window && - 'IntersectionObserverEntry' in window && - 'intersectionRatio' in IntersectionObserverEntry.prototype) { - // Platform supports IntersectionObserver natively! :-) - if (!('isIntersecting' in IntersectionObserverEntry.prototype)) { - Object.defineProperty(IntersectionObserverEntry.prototype, - 'isIntersecting', { - get: function () { - return this.intersectionRatio > 0; - } - }); - } -} else { - // Platform does not support webcomponents--loading polyfills synchronously. - const scriptTag = document.createElement('script'); - scriptTag.src = '${intersectionObserverPath}'; - scriptTag.async = false; - document.currentScript.parentNode.insertBefore(scriptTag, document.currentScript.nextSibling); -} +// const template = ` +// if ('IntersectionObserver' in window && +// 'IntersectionObserverEntry' in window && +// 'intersectionRatio' in IntersectionObserverEntry.prototype) { +// // Platform supports IntersectionObserver natively! :-) +// if (!('isIntersecting' in IntersectionObserverEntry.prototype)) { +// Object.defineProperty(IntersectionObserverEntry.prototype, +// 'isIntersecting', { +// get: function () { +// return this.intersectionRatio > 0; +// } +// }); +// } +// } else { +// // Platform does not support webcomponents--loading polyfills synchronously. +// const scriptTag = document.createElement('script'); +// scriptTag.src = '${intersectionObserverPath}'; +// scriptTag.async = false; +// document.currentScript.parentNode.insertBefore(scriptTag, document.currentScript.nextSibling); +// } +// +// if ('registerElement' in document && +// 'import' in document.createElement('link') && +// 'content' in document.createElement('template')) { +// // Platform supports webcomponents natively! :-) +// } else { +// // Platform does not support webcomponents--loading polyfills synchronously. +// const scriptTag = document.createElement('script'); +// scriptTag.src = '${webcomponentPath}'; +// scriptTag.async = false; +// document.currentScript.parentNode.insertBefore(scriptTag, document.currentScript.nextSibling); +// } +// +// +// `; -if ('registerElement' in document && - 'import' in document.createElement('link') && - 'content' in document.createElement('template')) { - // Platform supports webcomponents natively! :-) -} else { - // Platform does not support webcomponents--loading polyfills synchronously. - const scriptTag = document.createElement('script'); - scriptTag.src = '${webcomponentPath}'; - scriptTag.async = false; - document.currentScript.parentNode.insertBefore(scriptTag, document.currentScript.nextSibling); -} + +const addBackIn = ` +window.addEventListener('WebComponentsReady', function() { + console.warn('WebComponentsReady'); + const loaderTag = document.createElement('script'); + loaderTag.src = 'http://localhost:8888/dist/template.v2.js'; + document.head.insertBefore(loaderTag, document.head.firstChild); +}); `; export default function render(dom) { + // pull out template script tag + const templateTag = dom.querySelector('script[src*="template.v2.js"]'); + templateTag.parentNode.removeChild(templateTag); + + // add loader + const loaderTag = dom.createElement('script'); + loaderTag.src = 'https://cdnjs.cloudflare.com/ajax/libs/webcomponentsjs/1.0.17/webcomponents-loader.js'; + dom.head.insertBefore(loaderTag, dom.head.firstChild); + + // add loader event listener to add tempalrte back in + const addTag = dom.createElement('script'); + addTag.innerHTML = addBackIn; + dom.head.insertBefore(addTag, dom.head.firstChild); + + // create polyfill script tag - const polyfillScriptTag = dom.createElement('script'); - polyfillScriptTag.innerHTML = template; - polyfillScriptTag.id = 'polyfills'; + // const polyfillScriptTag = dom.createElement('script'); + // polyfillScriptTag.innerHTML = template; + // polyfillScriptTag.id = 'polyfills'; // insert at appropriate position--before any other script tag - const firstScriptTag = dom.head.querySelector('script'); - dom.head.insertBefore(polyfillScriptTag, firstScriptTag); + // const firstScriptTag = dom.head.querySelector('script'); + // dom.head.insertBefore(polyfillScriptTag, firstScriptTag); } diff --git a/src/ui/d-slider.js b/src/ui/d-slider.js index 1b2b421..1cdc3d5 100644 --- a/src/ui/d-slider.js +++ b/src/ui/d-slider.js @@ -90,14 +90,14 @@ const T = Template('d-slider', ` -
-
-
-
-
-
+
+
+
+
+
+
-
+
`); @@ -121,18 +121,18 @@ export class Slider extends T(HTMLElement) { connectedCallback() { this.connected = true; - this.setAttribute("role", "slider"); + this.setAttribute('role', 'slider'); // Makes the element tab-able. - if (!this.hasAttribute("tabindex")) { this.setAttribute("tabindex", 0); } + if (!this.hasAttribute('tabindex')) { this.setAttribute('tabindex', 0); } // Keeps track of keyboard vs. mouse interactions for focus rings this.mouseEvent = false; // Handles to shadow DOM elements - this.knob = this.root.querySelector(".knob-container"); - this.background = this.root.querySelector(".background"); - this.trackFill = this.root.querySelector(".track-fill"); - this.track = this.root.querySelector(".track"); + this.knob = this.root.querySelector('.knob-container'); + this.background = this.root.querySelector('.background'); + this.trackFill = this.root.querySelector('.track-fill'); + this.track = this.root.querySelector('.track'); // Default values for attributes this.min = this.min ? this.min : 0; @@ -148,108 +148,108 @@ export class Slider extends T(HTMLElement) { this.drag = drag() .container(this.background) - .on("start", () => { + .on('start', () => { this.mouseEvent = true; - this.background.classList.add("mousedown"); + this.background.classList.add('mousedown'); this.changeValue = this.value; this.dragUpdate(); }) - .on("drag", () => { + .on('drag', () => { this.dragUpdate(); }) - .on("end", () => { + .on('end', () => { this.mouseEvent = false; - this.background.classList.remove("mousedown"); + this.background.classList.remove('mousedown'); this.dragUpdate(); if (this.changeValue !== this.value) this.dispatchChange(); this.changeValue = this.value; }); this.drag(select(this.background)); - this.addEventListener("focusin", (e) => { + this.addEventListener('focusin', () => { if(!this.mouseEvent) { - this.background.classList.add("focus"); + this.background.classList.add('focus'); } }); - this.addEventListener("focusout", (e) => { - this.background.classList.remove("focus"); + this.addEventListener('focusout', () => { + this.background.classList.remove('focus'); }); - this.addEventListener("keydown", this.onKeyDown); + this.addEventListener('keydown', this.onKeyDown); } - static get observedAttributes() {return ["min", "max", "value", "step", "ticks", "origin", "tickValues", "tickLabels"]; } + static get observedAttributes() {return ['min', 'max', 'value', 'step', 'ticks', 'origin', 'tickValues', 'tickLabels']; } attributeChangedCallback(attr, oldValue, newValue) { - if (attr == "min") { + if (attr == 'min') { this.min = +newValue; - this.setAttribute("aria-valuemin", this.min); + this.setAttribute('aria-valuemin', this.min); } - if (attr == "max") { + if (attr == 'max') { this.max = +newValue; - this.setAttribute("aria-valuemax", this.max); + this.setAttribute('aria-valuemax', this.max); } - if (attr == "value") { + if (attr == 'value') { this.update(+newValue); } - if (attr == "origin") { + if (attr == 'origin') { this.origin = +newValue; this.update(this.value); } - if (attr == "step") { + if (attr == 'step') { if (newValue > 0) { this.step = +newValue; } } - if (attr == "ticks") { - this.ticks = (newValue === "" ? true : newValue); + if (attr == 'ticks') { + this.ticks = (newValue === '' ? true : newValue); } } - onKeyDown(e) { + onKeyDown(event) { this.changeValue = this.value; let stopPropagation = false; switch (event.keyCode) { - case keyCodes.left: - case keyCodes.down: - this.update(this.value - this.step) - stopPropagation = true; - break; - case keyCodes.right: - case keyCodes.up: - this.update(this.value + this.step) - stopPropagation = true; - break; - case keyCodes.pageUp: - this.update(this.value + this.step * 10) - stopPropagation = true; - break; + case keyCodes.left: + case keyCodes.down: + this.update(this.value - this.step); + stopPropagation = true; + break; + case keyCodes.right: + case keyCodes.up: + this.update(this.value + this.step); + stopPropagation = true; + break; + case keyCodes.pageUp: + this.update(this.value + this.step * 10); + stopPropagation = true; + break; - case keyCodes.pageDown: - this.update(this.value + this.step * 10) - stopPropagation = true; - break; - case keyCodes.home: - this.update(this.min); - stopPropagation = true; - break; - case keyCodes.end: - this.update(this.max); - stopPropagation = true; - break; - default: - break; + case keyCodes.pageDown: + this.update(this.value + this.step * 10); + stopPropagation = true; + break; + case keyCodes.home: + this.update(this.min); + stopPropagation = true; + break; + case keyCodes.end: + this.update(this.max); + stopPropagation = true; + break; + default: + break; } if (stopPropagation) { - this.background.classList.add("focus"); - e.preventDefault(); - e.stopPropagation(); + this.background.classList.add('focus'); + event.preventDefault(); + event.stopPropagation(); if (this.changeValue !== this.value) this.dispatchChange(); } } validateValueRange(min, max, value) { - return Math.max(Math.min(max, value), min) + return Math.max(Math.min(max, value), min); } quantizeValue(value, step) { @@ -265,53 +265,53 @@ export class Slider extends T(HTMLElement) { update(value) { let v = value; - if (this.step !== "any") { + if (this.step !== 'any') { v = this.quantizeValue(value, this.step); } v = this.validateValueRange(this.min, this.max, v); if (this.connected) { - this.knob.style.left = this.scale(v) * 100 + "%"; - this.trackFill.style.width = this.scale(this.min + Math.abs(v - this.origin)) * 100 + "%"; - this.trackFill.style.left = this.scale(Math.min(v, this.origin)) * 100 + "%"; + this.knob.style.left = this.scale(v) * 100 + '%'; + this.trackFill.style.width = this.scale(this.min + Math.abs(v - this.origin)) * 100 + '%'; + this.trackFill.style.left = this.scale(Math.min(v, this.origin)) * 100 + '%'; } if (this.value !== v) { this.value = v; - this.setAttribute("aria-valuenow", this.value); + this.setAttribute('aria-valuenow', this.value); this.dispatchInput(); } } // Dispatches only on a committed change (basically only on mouseup). dispatchChange() { - const e = new Event("change"); + const e = new Event('change'); this.dispatchEvent(e, {}); } // Dispatches on each value change. dispatchInput() { - const e = new Event("input"); + const e = new Event('input'); this.dispatchEvent(e, {}); } renderTicks() { - const ticksContainer = this.root.querySelector(".ticks"); + const ticksContainer = this.root.querySelector('.ticks'); if (this.ticks !== false) { let tickData = []; if (this.ticks > 0) { tickData = this.scale.ticks(this.ticks); - } else if (this.step === "any") { + } else if (this.step === 'any') { tickData = this.scale.ticks(); } else { tickData = range(this.min, this.max + 1e-6, this.step); } tickData.forEach(d => { - const tick = document.createElement("div"); - tick.classList.add("tick"); - tick.style.left = this.scale(d) * 100 + "%"; - ticksContainer.appendChild(tick) + const tick = document.createElement('div'); + tick.classList.add('tick'); + tick.style.left = this.scale(d) * 100 + '%'; + ticksContainer.appendChild(tick); }); } else { - ticksContainer.style.display = "none"; + ticksContainer.style.display = 'none'; } } -} \ No newline at end of file +}