diff --git a/src/docdiff.js b/src/docdiff.js index f4944b5..21e1083 100644 --- a/src/docdiff.js +++ b/src/docdiff.js @@ -1,4 +1,3 @@ -import { ajv } from "./data-validation"; import styleSheet from "./docdiff.css"; import docdiffGeneralStyleSheet from "./docdiff.document.css"; @@ -17,7 +16,7 @@ import { EVENT_READTHEDOCS_DOCDIFF_ADDED_REMOVED_SHOW, EVENT_READTHEDOCS_DOCDIFF_HIDE, } from "./events"; -import { html, nothing, LitElement } from "lit"; +import { nothing, LitElement } from "lit"; import { default as objectPath } from "object-path"; import { hasQueryParam, docTool } from "./utils"; @@ -84,6 +83,7 @@ export class DocDiffElement extends LitElement { this.injectStyles = true; this.originalBody = null; + this.cachedRemoteContent = null; } loadConfig(config) { @@ -103,7 +103,8 @@ export class DocDiffElement extends LitElement { // Enable DocDiff if the URL parameter is present if (hasQueryParam(DOCDIFF_URL_PARAM)) { - this.enableDocDiff(); + event = new CustomEvent(EVENT_READTHEDOCS_DOCDIFF_ADDED_REMOVED_SHOW); + document.dispatchEvent(event); } } @@ -120,60 +121,87 @@ export class DocDiffElement extends LitElement { // `; } - handleClick(e) { - if (e.target.checked) { - this.enableDocDiff(); - } else { - this.disableDocDiff(); - } - } + // This code isn't used until we show a UI, + // and even then we'll want to trigger events to match state? + // handleClick(e) { + // if (e.target.checked) { + // this.enableDocDiff(); + // } else { + // this.disableDocDiff(); + // } + // } compare() { - fetch(this.config.addons.doc_diff.base_url) - .then((response) => { - if (!response.ok) { - throw new Error("Error downloading requested base URL."); - } + let promiseData; - return response.text(); - }) + if (this.cachedRemoteContent !== null) { + promiseData = Promise.resolve(this.cachedRemoteContent); + } else { + promiseData = fetch(this.config.addons.doc_diff.base_url).then( + (response) => { + if (!response.ok) { + throw new Error("Error downloading requested base URL."); + } + return response.text(); + }, + ); + } + + promiseData .then((text) => { - const parser = new DOMParser(); - const html_document = parser.parseFromString(text, "text/html"); - const old_body = html_document.documentElement.querySelector( - this.rootSelector, - ); - const new_body = document.querySelector(this.rootSelector); - - if (old_body == null || new_body == null) { - throw new Error("Element not found in both documents."); - } - - // After finding the root element, and diffing it, replace it in the DOM - // with the resulting visual diff elements instead. - const diffNode = visualDomDiff.visualDomDiff( - old_body, - new_body, - VISUAL_DIFF_OPTIONS, - ); - new_body.replaceWith(diffNode.firstElementChild); + this.cachedRemoteContent = text; + this.performDiff(text); }) .catch((error) => { console.error(error); }); } + // After finding the root element, and diffing it, replace it in the DOM + // with the resulting visual diff elements instead. + performDiff(remoteContent) { + const parser = new DOMParser(); + const html_document = parser.parseFromString(remoteContent, "text/html"); + const old_body = html_document.documentElement.querySelector( + this.rootSelector, + ); + const new_body = document.querySelector(this.rootSelector); + + if (old_body == null || new_body == null) { + throw new Error("Element not found in both documents."); + } + + const diffNode = visualDomDiff.visualDomDiff( + old_body, + new_body, + VISUAL_DIFF_OPTIONS, + ); + new_body.replaceWith(diffNode.firstElementChild); + } + enableDocDiff() { + // TODO: Unsure when this would happen? + // Perhaps when DocDiffAddon.isEnabled returns false? if (this.config === null) { return null; } + if (this.enabled) { + console.debug("Ignoring enableDocDiff: it was already enabled"); + return null; + } + this.enabled = true; this.originalBody = document.querySelector(this.rootSelector); return this.compare(); } disableDocDiff() { + if (!this.enabled) { + console.debug("Ignoring disableDocDiff: it was already disabled"); + return null; + } + this.enabled = false; document.querySelector(this.rootSelector).replaceWith(this.originalBody); } @@ -195,15 +223,20 @@ export class DocDiffElement extends LitElement { EVENT_READTHEDOCS_DOCDIFF_ADDED_REMOVED_SHOW, this._handleShowDocDiff, ); - document.addEventListener( EVENT_READTHEDOCS_DOCDIFF_HIDE, this._handleHideDocDiff, ); } - disconnectedCallback() { - document.removeEventListener("keydown", this._handleShowDocDiff); + document.removeEventListener( + EVENT_READTHEDOCS_DOCDIFF_ADDED_REMOVED_SHOW, + this._handleShowDocDiff, + ); + document.removeEventListener( + EVENT_READTHEDOCS_DOCDIFF_HIDE, + this._handleHideDocDiff, + ); super.disconnectedCallback(); } } diff --git a/src/hotkeys.js b/src/hotkeys.js index 49597a1..f6ff1e9 100644 --- a/src/hotkeys.js +++ b/src/hotkeys.js @@ -1,11 +1,9 @@ -import { ajv } from "./data-validation"; import { toString as keyboardEventToString } from "keyboard-event-to-string"; import { AddonBase } from "./utils"; -import { html, nothing, LitElement } from "lit"; +import { LitElement } from "lit"; import { EVENT_READTHEDOCS_SEARCH_SHOW, - EVENT_READTHEDOCS_SEARCH_HIDE, EVENT_READTHEDOCS_DOCDIFF_ADDED_REMOVED_SHOW, EVENT_READTHEDOCS_DOCDIFF_HIDE, } from "./events"; @@ -26,7 +24,6 @@ export class HotKeysElement extends LitElement { super(); this.config = null; - this.docDiffShow = false; } loadConfig(config) { @@ -40,7 +37,7 @@ export class HotKeysElement extends LitElement { this.config = config; this.docDiffHotKeyEnabled = this.config.addons.hotkeys.doc_diff.enabled; - this.docDiffShowed = false; + this.docDiffEnabled = false; this.searchHotKeyEnabled = this.config.addons.hotkeys.search.enabled; } @@ -51,6 +48,7 @@ export class HotKeysElement extends LitElement { // Read more about these decisions at https://github.com/readthedocs/addons/issues/80 let event; + // DocDiff if ( this.docDiffHotKeyEnabled && @@ -60,12 +58,10 @@ export class HotKeysElement extends LitElement { document.activeElement.tagName !== "TEXTAREA" && document.activeElement.tagName !== "READTHEDOCS-SEARCH" ) { - if (this.docDiffShowed) { + if (this.docDiffEnabled) { event = new CustomEvent(EVENT_READTHEDOCS_DOCDIFF_HIDE); - this.docDiffShowed = false; } else { event = new CustomEvent(EVENT_READTHEDOCS_DOCDIFF_ADDED_REMOVED_SHOW); - this.docDiffShowed = true; } } @@ -80,6 +76,7 @@ export class HotKeysElement extends LitElement { event = new CustomEvent(EVENT_READTHEDOCS_SEARCH_SHOW); } + // Send event for all keydown events if (event !== undefined) { document.dispatchEvent(event); e.preventDefault(); @@ -89,12 +86,36 @@ export class HotKeysElement extends LitElement { connectedCallback() { super.connectedCallback(); document.addEventListener("keydown", this._handleKeydown); + document.addEventListener( + EVENT_READTHEDOCS_DOCDIFF_ADDED_REMOVED_SHOW, + this._handleDocDiffShow, + ); + document.addEventListener( + EVENT_READTHEDOCS_DOCDIFF_HIDE, + this._handleDocDiffHide, + ); } disconnectedCallback() { document.removeEventListener("keydown", this._handleKeydown); + document.removeEventListener( + EVENT_READTHEDOCS_DOCDIFF_ADDED_REMOVED_SHOW, + this._handleDocDiffShow, + ); + document.removeEventListener( + EVENT_READTHEDOCS_DOCDIFF_HIDE, + this._handleDocDiffHide, + ); super.disconnectedCallback(); } + + _handleDocDiffShow = (event) => { + this.docDiffEnabled = true; + }; + + _handleDocDiffHide = (event) => { + this.docDiffEnabled = false; + }; } export class HotKeysAddon extends AddonBase {