|
|
@@ -18,111 +18,30 @@
|
|
|
* along with SingleFile. If not, see <http://www.gnu.org/licenses/>.
|
|
|
*/
|
|
|
|
|
|
-/* global window, addEventListener, dispatchEvent, CustomEvent, document, HTMLDocument */
|
|
|
+/* global history, dispatchEvent, CustomEvent, document, HTMLDocument */
|
|
|
|
|
|
this.hooks = this.hooks || (() => {
|
|
|
|
|
|
- const NEW_FONT_FACE_EVENT = "single-file-new-font-face";
|
|
|
- const fontFaces = [];
|
|
|
-
|
|
|
if (document instanceof HTMLDocument) {
|
|
|
const scriptElement = document.createElement("script");
|
|
|
- scriptElement.textContent = `(${hook.toString()})()`;
|
|
|
+ scriptElement.textContent = `(${hookPushState.toString()})()`;
|
|
|
document.documentElement.appendChild(scriptElement);
|
|
|
scriptElement.remove();
|
|
|
- addEventListener(NEW_FONT_FACE_EVENT, event => fontFaces.push(event.detail));
|
|
|
}
|
|
|
|
|
|
- return {
|
|
|
- getFontsData: () => fontFaces
|
|
|
- };
|
|
|
-
|
|
|
- function hook() {
|
|
|
- const NEW_FONT_FACE_EVENT = "single-file-new-font-face";
|
|
|
- const FONT_STYLE_PROPERTIES = {
|
|
|
- family: "font-family",
|
|
|
- style: "font-style",
|
|
|
- weight: "font-weight",
|
|
|
- stretch: "font-stretch",
|
|
|
- unicodeRange: "unicode-range",
|
|
|
- variant: "font-variant",
|
|
|
- featureSettings: "font-feature-settings"
|
|
|
- };
|
|
|
+ return true;
|
|
|
|
|
|
- const FontFace = window.FontFace;
|
|
|
- let warningFontFaceDisplayed;
|
|
|
- window.__defineGetter__("FontFace", () => new Proxy(FontFace, {
|
|
|
- construct(FontFace, argumentsList) {
|
|
|
- if (!warningFontFaceDisplayed) {
|
|
|
- console.warn("SingleFile is hooking the FontFace constructor to get font URLs."); // eslint-disable-line no-console
|
|
|
- }
|
|
|
- const detail = {};
|
|
|
- detail["font-family"] = argumentsList[0];
|
|
|
- detail.src = argumentsList[1];
|
|
|
- const descriptors = argumentsList[2];
|
|
|
- if (descriptors) {
|
|
|
- Object.keys(descriptors).forEach(descriptor => detail[FONT_STYLE_PROPERTIES[descriptor]] = descriptors[descriptor]);
|
|
|
- }
|
|
|
- dispatchEvent(new CustomEvent(NEW_FONT_FACE_EVENT, { detail }));
|
|
|
- return new FontFace(...argumentsList);
|
|
|
+ function hookPushState() {
|
|
|
+ const pushState = history.pushState;
|
|
|
+ let warningDisplayed;
|
|
|
+ history.pushState = function (state, title, url) {
|
|
|
+ if (!warningDisplayed) {
|
|
|
+ warningDisplayed = true;
|
|
|
+ console.warn("SingleFile is hooking the history.pushState API to detect navigation."); // eslint-disable-line no-console
|
|
|
}
|
|
|
- }));
|
|
|
-
|
|
|
- const LOAD_OBSERVED_ELEMENTS_EVENT = "single-file-load-observed-elements";
|
|
|
-
|
|
|
- const IntersectionObserver = window.IntersectionObserver;
|
|
|
- const observeIntersection = IntersectionObserver.prototype.observe;
|
|
|
- const unobserveIntersection = IntersectionObserver.prototype.unobserve;
|
|
|
- const observedElements = new Map();
|
|
|
- const observers = new Map();
|
|
|
- let warningIntersectionObserverDisplayed;
|
|
|
- window.__defineGetter__("IntersectionObserver", () => new Proxy(IntersectionObserver, {
|
|
|
- construct(IntersectionObserver, argumentsList) {
|
|
|
- if (!warningIntersectionObserverDisplayed) {
|
|
|
- console.warn("SingleFile is hooking the IntersectionObserver API to detect and load deferred images."); // eslint-disable-line no-console
|
|
|
- }
|
|
|
- const intersectionObserver = new IntersectionObserver(...argumentsList);
|
|
|
- const callback = argumentsList[0];
|
|
|
- const options = argumentsList[1];
|
|
|
- intersectionObserver.observe = function (targetElement) {
|
|
|
- let targetElements = observedElements.get(intersectionObserver);
|
|
|
- if (!targetElements) {
|
|
|
- targetElements = [];
|
|
|
- observedElements.set(intersectionObserver, targetElements);
|
|
|
- }
|
|
|
- targetElements.push(targetElement);
|
|
|
- return observeIntersection.call(intersectionObserver, targetElement);
|
|
|
- };
|
|
|
- intersectionObserver.unobserve = function (targetElement) {
|
|
|
- let targetElements = observedElements.get(intersectionObserver);
|
|
|
- if (targetElements) {
|
|
|
- targetElements = targetElements.filter(element => element <= targetElement);
|
|
|
- if (targetElements.length) {
|
|
|
- observedElements.set(intersectionObserver, targetElements);
|
|
|
- } else {
|
|
|
- observedElements.delete(intersectionObserver);
|
|
|
- }
|
|
|
- }
|
|
|
- return unobserveIntersection.call(intersectionObserver, targetElement);
|
|
|
- };
|
|
|
- observers.set(intersectionObserver, { callback, options });
|
|
|
- return intersectionObserver;
|
|
|
- }
|
|
|
- }));
|
|
|
- window.__defineSetter__("IntersectionObserver", () => { });
|
|
|
- addEventListener(LOAD_OBSERVED_ELEMENTS_EVENT, () => {
|
|
|
- Array.from(observers).forEach(([intersectionObserver, observer]) => {
|
|
|
- observer.callback(observedElements.get(intersectionObserver).map(target => {
|
|
|
- const boundingClientRect = target.getBoundingClientRect();
|
|
|
- const intersectionRect = target.getBoundingClientRect();
|
|
|
- const isIntersecting = true;
|
|
|
- const intersectionRatio = 1;
|
|
|
- const rootBounds = observer.options && observer.options.root ? observer.options.root.getBoundingClientRect() : document.documentElement.getBoundingClientRect();
|
|
|
- const time = 0;
|
|
|
- return { target, intersectionRatio, boundingClientRect, intersectionRect, isIntersecting, rootBounds, time };
|
|
|
- }), intersectionObserver);
|
|
|
- });
|
|
|
- }, false);
|
|
|
+ dispatchEvent(new CustomEvent("single-file-push-state", { detail: { state, title, url } }));
|
|
|
+ pushState.call(history, state, title, url);
|
|
|
+ };
|
|
|
}
|
|
|
|
|
|
})();
|