diff options
Diffstat (limited to 'ext')
| -rw-r--r-- | ext/bg/js/search.js | 18 | ||||
| -rw-r--r-- | ext/fg/js/float.js | 20 | ||||
| -rw-r--r-- | ext/mixed/js/display.js | 531 | 
3 files changed, 287 insertions, 282 deletions
| diff --git a/ext/bg/js/search.js b/ext/bg/js/search.js index e968e8cf..e9ec2b85 100644 --- a/ext/bg/js/search.js +++ b/ext/bg/js/search.js @@ -33,10 +33,10 @@ class DisplaySearch extends Display {          this._isPrepared = false; -        this.optionsContext = { +        this.setOptionsContext({              depth: 0,              url: window.location.href -        }; +        });          this.queryParser = new QueryParser({              getOptionsContext: this.getOptionsContext.bind(this), @@ -80,12 +80,13 @@ class DisplaySearch extends Display {          await this.updateOptions();          yomichan.on('optionsUpdated', () => this.updateOptions());          await this.queryParser.prepare(); +        const options = this.getOptions();          const {queryParams: {query='', mode=''}} = parseUrl(window.location.href);          document.documentElement.dataset.searchMode = mode; -        if (this.options.general.enableWanakana === true) { +        if (options.general.enableWanakana === true) {              this.wanakanaEnable.checked = true;              wanakana.bind(this.query);          } else { @@ -96,7 +97,7 @@ class DisplaySearch extends Display {          this.onSearchQueryUpdated(this.query.value, false);          if (mode !== 'popup') { -            if (this.options.general.enableClipboardMonitor === true) { +            if (options.general.enableClipboardMonitor === true) {                  this.clipboardMonitorEnable.checked = true;                  this.clipboardMonitor.start();              } else { @@ -121,10 +122,6 @@ class DisplaySearch extends Display {          this._isPrepared = true;      } -    onError(error) { -        yomichan.logError(error); -    } -      onEscape() {          if (this.query === null) {              return; @@ -241,7 +238,7 @@ class DisplaySearch extends Display {                      url: window.location.href                  }});              } else { -                this.container.textContent = ''; +                this.clearContent();              }              this.setTitleText(query);              window.parent.postMessage('popupClose', '*'); @@ -299,7 +296,8 @@ class DisplaySearch extends Display {      async updateOptions() {          await super.updateOptions(); -        this.queryParser.setOptions(this.options); +        const options = this.getOptions(); +        this.queryParser.setOptions(options);          if (!this._isPrepared) { return; }          const query = this.query.value;          if (query) { diff --git a/ext/fg/js/float.js b/ext/fg/js/float.js index d7beb675..d86f16c3 100644 --- a/ext/fg/js/float.js +++ b/ext/fg/js/float.js @@ -31,7 +31,6 @@ class DisplayFloat extends Display {          this._secret = yomichan.generateId(16);          this._token = null; -        this._orphaned = false;          this._nestedPopupsPrepared = false;          this._onKeyDownHandlers = new Map([ @@ -59,24 +58,11 @@ class DisplayFloat extends Display {      async prepare() {          await super.prepare(); -        yomichan.on('orphaned', this.onOrphaned.bind(this));          window.addEventListener('message', this.onMessage.bind(this), false);          api.broadcastTab('popupPrepared', {secret: this._secret});      } -    onError(error) { -        if (this._orphaned) { -            this.setContent('orphaned'); -        } else { -            yomichan.logError(error); -        } -    } - -    onOrphaned() { -        this._orphaned = true; -    } -      onEscape() {          window.parent.postMessage('popupClose', '*');      } @@ -126,7 +112,7 @@ class DisplayFloat extends Display {      }      async setOptionsContext(optionsContext) { -        this.optionsContext = optionsContext; +        super.setOptionsContext(optionsContext);          await this.updateOptions();      } @@ -181,7 +167,7 @@ class DisplayFloat extends Display {      }      async _configure({messageId, frameId, popupId, optionsContext, childrenSupported, scale}) { -        this.optionsContext = optionsContext; +        this.setOptionsContext(optionsContext);          await this.updateOptions(); @@ -208,7 +194,7 @@ class DisplayFloat extends Display {          let complete = false;          const onOptionsUpdated = async () => { -            const optionsContext = this.optionsContext; +            const optionsContext = this.getOptionsContext();              const options = await api.optionsGet(optionsContext);              const maxPopupDepthExceeded = !(typeof depth === 'number' && depth < options.scanning.popupNestingMaxDepth);              if (maxPopupDepthExceeded || complete) { return; } diff --git a/ext/mixed/js/display.js b/ext/mixed/js/display.js index e7439796..c8c574f4 100644 --- a/ext/mixed/js/display.js +++ b/ext/mixed/js/display.js @@ -29,16 +29,16 @@  class Display {      constructor(spinner, container) { -        this.spinner = spinner; -        this.container = container; -        this.definitions = []; -        this.optionsContext = null; -        this.options = null; -        this.context = null; -        this.index = 0; -        this.audioPlaying = null; -        this.audioFallback = null; -        this.audioSystem = new AudioSystem({ +        this._spinner = spinner; +        this._container = container; +        this._definitions = []; +        this._optionsContext = null; +        this._options = null; +        this._context = null; +        this._index = 0; +        this._audioPlaying = null; +        this._audioFallback = null; +        this._audioSystem = new AudioSystem({              audioUriBuilder: {                  getUri: async (definition, source, details) => {                      return await api.audioGetUri(definition, source, details); @@ -46,18 +46,19 @@ class Display {              },              useCache: true          }); -        this.styleNode = null; +        this._styleNode = null; +        this._orphaned = false; -        this.eventListeners = new EventListenerCollection(); -        this.persistentEventListeners = new EventListenerCollection(); -        this.interactive = false; -        this.eventListenersActive = false; -        this.clickScanPrevent = false; -        this.setContentToken = null; +        this._eventListeners = new EventListenerCollection(); +        this._persistentEventListeners = new EventListenerCollection(); +        this._interactive = false; +        this._eventListenersActive = false; +        this._clickScanPrevent = false; +        this._setContentToken = null; -        this.mediaLoader = new MediaLoader(); -        this.displayGenerator = new DisplayGenerator({mediaLoader: this.mediaLoader}); -        this.windowScroll = new WindowScroll(); +        this._mediaLoader = new MediaLoader(); +        this._displayGenerator = new DisplayGenerator({mediaLoader: this._mediaLoader}); +        this._windowScroll = new WindowScroll();          this._onKeyDownHandlers = new Map([              ['Escape', () => { @@ -66,89 +67,89 @@ class Display {              }],              ['PageUp', (e) => {                  if (e.altKey) { -                    this.entryScrollIntoView(this.index - 3, null, true); +                    this._entryScrollIntoView(this._index - 3, null, true);                      return true;                  }                  return false;              }],              ['PageDown', (e) => {                  if (e.altKey) { -                    this.entryScrollIntoView(this.index + 3, null, true); +                    this._entryScrollIntoView(this._index + 3, null, true);                      return true;                  }                  return false;              }],              ['End', (e) => {                  if (e.altKey) { -                    this.entryScrollIntoView(this.definitions.length - 1, null, true); +                    this._entryScrollIntoView(this._definitions.length - 1, null, true);                      return true;                  }                  return false;              }],              ['Home', (e) => {                  if (e.altKey) { -                    this.entryScrollIntoView(0, null, true); +                    this._entryScrollIntoView(0, null, true);                      return true;                  }                  return false;              }],              ['ArrowUp', (e) => {                  if (e.altKey) { -                    this.entryScrollIntoView(this.index - 1, null, true); +                    this._entryScrollIntoView(this._index - 1, null, true);                      return true;                  }                  return false;              }],              ['ArrowDown', (e) => {                  if (e.altKey) { -                    this.entryScrollIntoView(this.index + 1, null, true); +                    this._entryScrollIntoView(this._index + 1, null, true);                      return true;                  }                  return false;              }],              ['B', (e) => {                  if (e.altKey) { -                    this.sourceTermView(); +                    this._sourceTermView();                      return true;                  }                  return false;              }],              ['F', (e) => {                  if (e.altKey) { -                    this.nextTermView(); +                    this._nextTermView();                      return true;                  }                  return false;              }],              ['E', (e) => {                  if (e.altKey) { -                    this.noteTryAdd('term-kanji'); +                    this._noteTryAdd('term-kanji');                      return true;                  }                  return false;              }],              ['K', (e) => {                  if (e.altKey) { -                    this.noteTryAdd('kanji'); +                    this._noteTryAdd('kanji');                      return true;                  }                  return false;              }],              ['R', (e) => {                  if (e.altKey) { -                    this.noteTryAdd('term-kana'); +                    this._noteTryAdd('term-kana');                      return true;                  }                  return false;              }],              ['P', (e) => {                  if (e.altKey) { -                    const index = this.index; -                    if (index < 0 || index >= this.definitions.length) { return; } +                    const index = this._index; +                    if (index < 0 || index >= this._definitions.length) { return; } -                    const entry = this.getEntry(index); +                    const entry = this._getEntry(index);                      if (entry !== null && entry.dataset.type === 'term') { -                        this.audioPlay(this.definitions[index], this.firstExpressionIndex, index); +                        this._audioPlay(this._definitions[index], this._getFirstExpressionIndex(), index);                      }                      return true;                  } @@ -156,52 +157,60 @@ class Display {              }],              ['V', (e) => {                  if (e.altKey) { -                    this.noteTryView(); +                    this._noteTryView();                      return true;                  }                  return false;              }]          ]); - -        this.setInteractive(true);      }      async prepare() { +        this._setInteractive(true);          await yomichan.ready(); -        await this.displayGenerator.prepare(); +        await this._displayGenerator.prepare(); +        yomichan.on('orphaned', this._onOrphaned.bind(this));      } -    onError(_error) { -        throw new Error('Override me'); +    _onOrphaned() { +        this._orphaned = true; +    } + +    onError(error) { +        if (this._orphaned) { +            this.setContent('orphaned'); +        } else { +            yomichan.logError(error); +        }      }      onEscape() {          throw new Error('Override me');      } -    onSourceTermView(e) { +    _onSourceTermView(e) {          e.preventDefault(); -        this.sourceTermView(); +        this._sourceTermView();      } -    onNextTermView(e) { +    _onNextTermView(e) {          e.preventDefault(); -        this.nextTermView(); +        this._nextTermView();      } -    async onKanjiLookup(e) { +    async _onKanjiLookup(e) {          try {              e.preventDefault(); -            if (!this.context) { return; } +            if (!this._context) { return; }              const link = e.target; -            this.context.update({ -                index: this.entryIndexFind(link), -                scroll: this.windowScroll.y +            this._context.update({ +                index: this._entryIndexFind(link), +                scroll: this._windowScroll.y              });              const context = { -                sentence: this.context.get('sentence'), -                url: this.context.get('url') +                sentence: this._context.get('sentence'), +                url: this._context.get('url')              };              const definitions = await api.kanjiFind(link.textContent, this.getOptionsContext()); @@ -211,53 +220,53 @@ class Display {          }      } -    onGlossaryMouseDown(e) { +    _onGlossaryMouseDown(e) {          if (DOM.isMouseButtonPressed(e, 'primary')) { -            this.clickScanPrevent = false; +            this._clickScanPrevent = false;          }      } -    onGlossaryMouseMove() { -        this.clickScanPrevent = true; +    _onGlossaryMouseMove() { +        this._clickScanPrevent = true;      } -    onGlossaryMouseUp(e) { -        if (!this.clickScanPrevent && DOM.isMouseButtonPressed(e, 'primary')) { -            this.onTermLookup(e); +    _onGlossaryMouseUp(e) { +        if (!this._clickScanPrevent && DOM.isMouseButtonPressed(e, 'primary')) { +            this._onTermLookup(e);          }      } -    async onTermLookup(e, {disableScroll, selectText, disableHistory}={}) { +    async _onTermLookup(e, {disableScroll, selectText, disableHistory}={}) {          try { -            if (!this.context) { return; } +            if (!this._context) { return; } -            const termLookupResults = await this.termLookup(e); +            const termLookupResults = await this._termLookup(e);              if (!termLookupResults) { return; }              const {textSource, definitions} = termLookupResults;              const scannedElement = e.target; -            const sentenceExtent = this.options.anki.sentenceExt; -            const layoutAwareScan = this.options.scanning.layoutAwareScan; +            const sentenceExtent = this._options.anki.sentenceExt; +            const layoutAwareScan = this._options.scanning.layoutAwareScan;              const sentence = docSentenceExtract(textSource, sentenceExtent, layoutAwareScan); -            this.context.update({ -                index: this.entryIndexFind(scannedElement), -                scroll: this.windowScroll.y +            this._context.update({ +                index: this._entryIndexFind(scannedElement), +                scroll: this._windowScroll.y              });              const context = {                  disableScroll,                  disableHistory,                  sentence, -                url: this.context.get('url') +                url: this._context.get('url')              };              if (disableHistory) {                  Object.assign(context, { -                    previous: this.context.previous, -                    next: this.context.next +                    previous: this._context.previous, +                    next: this._context.next                  });              } else {                  Object.assign(context, { -                    previous: this.context +                    previous: this._context                  });              } @@ -271,11 +280,11 @@ class Display {          }      } -    async termLookup(e) { +    async _termLookup(e) {          try {              e.preventDefault(); -            const {length: scanLength, deepDomScan: deepScan, layoutAwareScan} = this.options.scanning; +            const {length: scanLength, deepDomScan: deepScan, layoutAwareScan} = this._options.scanning;              const textSource = docRangeFromPoint(e.clientX, e.clientY, deepScan);              if (textSource === null) {                  return false; @@ -301,32 +310,32 @@ class Display {          }      } -    onAudioPlay(e) { +    _onAudioPlay(e) {          e.preventDefault();          const link = e.currentTarget;          const entry = link.closest('.entry'); -        const index = this.entryIndexFind(entry); -        if (index < 0 || index >= this.definitions.length) { return; } +        const index = this._entryIndexFind(entry); +        if (index < 0 || index >= this._definitions.length) { return; } -        const expressionIndex = Display.indexOf(entry.querySelectorAll('.term-expression .action-play-audio'), link); -        this.audioPlay( -            this.definitions[index], +        const expressionIndex = this._indexOf(entry.querySelectorAll('.term-expression .action-play-audio'), link); +        this._audioPlay( +            this._definitions[index],              // expressionIndex is used in audioPlay to detect result output mode -            Math.max(expressionIndex, this.options.general.resultOutputMode === 'merge' ? 0 : -1), +            Math.max(expressionIndex, this._options.general.resultOutputMode === 'merge' ? 0 : -1),              index          );      } -    onNoteAdd(e) { +    _onNoteAdd(e) {          e.preventDefault();          const link = e.currentTarget; -        const index = this.entryIndexFind(link); -        if (index < 0 || index >= this.definitions.length) { return; } +        const index = this._entryIndexFind(link); +        if (index < 0 || index >= this._definitions.length) { return; } -        this.noteAdd(this.definitions[index], link.dataset.mode); +        this._noteAdd(this._definitions[index], link.dataset.mode);      } -    onNoteView(e) { +    _onNoteView(e) {          e.preventDefault();          const link = e.currentTarget;          api.noteView(link.dataset.noteId); @@ -344,43 +353,51 @@ class Display {          return false;      } -    onWheel(e) { +    _onWheel(e) {          if (e.altKey) {              if (e.deltaY !== 0) { -                this.entryScrollIntoView(this.index + (e.deltaY > 0 ? 1 : -1), null, true); +                this._entryScrollIntoView(this._index + (e.deltaY > 0 ? 1 : -1), null, true);                  e.preventDefault();              }          } else if (e.shiftKey) { -            this.onHistoryWheel(e); +            this._onHistoryWheel(e);          }      } -    onHistoryWheel(e) { +    _onHistoryWheel(e) {          if (e.altKey) { return; }          const delta = -e.deltaX || e.deltaY;          if (delta > 0) { -            this.sourceTermView(); +            this._sourceTermView();              e.preventDefault();              e.stopPropagation();          } else if (delta < 0) { -            this.nextTermView(); +            this._nextTermView();              e.preventDefault();              e.stopPropagation();          }      } +    getOptions() { +        return this._options; +    } +      getOptionsContext() { -        return this.optionsContext; +        return this._optionsContext; +    } + +    setOptionsContext(optionsContext) { +        this._optionsContext = optionsContext;      }      async updateOptions() { -        this.options = await api.optionsGet(this.getOptionsContext()); -        this.updateDocumentOptions(this.options); -        this.updateTheme(this.options.general.popupTheme); -        this.setCustomCss(this.options.general.customPopupCss); +        this._options = await api.optionsGet(this.getOptionsContext()); +        this._updateDocumentOptions(this._options); +        this._updateTheme(this._options.general.popupTheme); +        this.setCustomCss(this._options.general.customPopupCss);      } -    updateDocumentOptions(options) { +    _updateDocumentOptions(options) {          const data = document.documentElement.dataset;          data.ankiEnabled = `${options.anki.enable}`;          data.audioEnabled = `${options.audio.enabled}`; @@ -392,227 +409,227 @@ class Display {          data.debug = `${options.general.debugInfo}`;      } -    updateTheme(themeName) { +    _updateTheme(themeName) {          document.documentElement.dataset.yomichanTheme = themeName;      }      setCustomCss(css) { -        if (this.styleNode === null) { +        if (this._styleNode === null) {              if (css.length === 0) { return; } -            this.styleNode = document.createElement('style'); +            this._styleNode = document.createElement('style');          } -        this.styleNode.textContent = css; +        this._styleNode.textContent = css;          const parent = document.head; -        if (this.styleNode.parentNode !== parent) { -            parent.appendChild(this.styleNode); +        if (this._styleNode.parentNode !== parent) { +            parent.appendChild(this._styleNode);          }      } -    setInteractive(interactive) { +    _setInteractive(interactive) {          interactive = !!interactive; -        if (this.interactive === interactive) { return; } -        this.interactive = interactive; +        if (this._interactive === interactive) { return; } +        this._interactive = interactive;          if (interactive) {              const actionPrevious = document.querySelector('.action-previous');              const actionNext = document.querySelector('.action-next');              // const navigationHeader = document.querySelector('.navigation-header'); -            this.persistentEventListeners.addEventListener(document, 'keydown', this.onKeyDown.bind(this), false); -            this.persistentEventListeners.addEventListener(document, 'wheel', this.onWheel.bind(this), {passive: false}); +            this._persistentEventListeners.addEventListener(document, 'keydown', this.onKeyDown.bind(this), false); +            this._persistentEventListeners.addEventListener(document, 'wheel', this._onWheel.bind(this), {passive: false});              if (actionPrevious !== null) { -                this.persistentEventListeners.addEventListener(actionPrevious, 'click', this.onSourceTermView.bind(this)); +                this._persistentEventListeners.addEventListener(actionPrevious, 'click', this._onSourceTermView.bind(this));              }              if (actionNext !== null) { -                this.persistentEventListeners.addEventListener(actionNext, 'click', this.onNextTermView.bind(this)); +                this._persistentEventListeners.addEventListener(actionNext, 'click', this._onNextTermView.bind(this));              }              // temporarily disabled              // if (navigationHeader !== null) {              //     this.persistentEventListeners.addEventListener(navigationHeader, 'wheel', this.onHistoryWheel.bind(this), {passive: false});              // }          } else { -            this.persistentEventListeners.removeAllEventListeners(); +            this._persistentEventListeners.removeAllEventListeners();          } -        this.setEventListenersActive(this.eventListenersActive); +        this._setEventListenersActive(this._eventListenersActive);      } -    setEventListenersActive(active) { -        active = !!active && this.interactive; -        if (this.eventListenersActive === active) { return; } -        this.eventListenersActive = active; +    _setEventListenersActive(active) { +        active = !!active && this._interactive; +        if (this._eventListenersActive === active) { return; } +        this._eventListenersActive = active;          if (active) { -            this.addMultipleEventListeners('.action-add-note', 'click', this.onNoteAdd.bind(this)); -            this.addMultipleEventListeners('.action-view-note', 'click', this.onNoteView.bind(this)); -            this.addMultipleEventListeners('.action-play-audio', 'click', this.onAudioPlay.bind(this)); -            this.addMultipleEventListeners('.kanji-link', 'click', this.onKanjiLookup.bind(this)); -            if (this.options.scanning.enablePopupSearch) { -                this.addMultipleEventListeners('.term-glossary-item, .tag', 'mouseup', this.onGlossaryMouseUp.bind(this)); -                this.addMultipleEventListeners('.term-glossary-item, .tag', 'mousedown', this.onGlossaryMouseDown.bind(this)); -                this.addMultipleEventListeners('.term-glossary-item, .tag', 'mousemove', this.onGlossaryMouseMove.bind(this)); +            this.addMultipleEventListeners('.action-add-note', 'click', this._onNoteAdd.bind(this)); +            this.addMultipleEventListeners('.action-view-note', 'click', this._onNoteView.bind(this)); +            this.addMultipleEventListeners('.action-play-audio', 'click', this._onAudioPlay.bind(this)); +            this.addMultipleEventListeners('.kanji-link', 'click', this._onKanjiLookup.bind(this)); +            if (this._options.scanning.enablePopupSearch) { +                this.addMultipleEventListeners('.term-glossary-item, .tag', 'mouseup', this._onGlossaryMouseUp.bind(this)); +                this.addMultipleEventListeners('.term-glossary-item, .tag', 'mousedown', this._onGlossaryMouseDown.bind(this)); +                this.addMultipleEventListeners('.term-glossary-item, .tag', 'mousemove', this._onGlossaryMouseMove.bind(this));              }          } else { -            this.eventListeners.removeAllEventListeners(); +            this._eventListeners.removeAllEventListeners();          }      }      addMultipleEventListeners(selector, type, listener, options) { -        for (const node of this.container.querySelectorAll(selector)) { -            this.eventListeners.addEventListener(node, type, listener, options); +        for (const node of this._container.querySelectorAll(selector)) { +            this._eventListeners.addEventListener(node, type, listener, options);          }      }      async setContent(type, details) {          const token = {}; // Unique identifier token -        this.setContentToken = token; +        this._setContentToken = token;          try { -            this.mediaLoader.unloadAll(); +            this._mediaLoader.unloadAll();              switch (type) {                  case 'terms': -                    await this.setContentTerms(details.definitions, details.context, token); +                    await this._setContentTerms(details.definitions, details.context, token);                      break;                  case 'kanji': -                    await this.setContentKanji(details.definitions, details.context, token); +                    await this._setContentKanji(details.definitions, details.context, token);                      break;                  case 'orphaned': -                    this.setContentOrphaned(); +                    this._setContentOrphaned();                      break;              }          } catch (e) {              this.onError(e);          } finally { -            if (this.setContentToken === token) { -                this.setContentToken = null; +            if (this._setContentToken === token) { +                this._setContentToken = null;              }          }      } -    async setContentTerms(definitions, context, token) { +    async _setContentTerms(definitions, context, token) {          if (!context) { throw new Error('Context expected'); } -        this.setEventListenersActive(false); +        this._setEventListenersActive(false);          if (context.focus !== false) {              window.focus();          } -        this.definitions = definitions; +        this._definitions = definitions;          if (context.disableHistory) {              delete context.disableHistory; -            this.context = new DisplayContext('terms', definitions, context); +            this._context = new DisplayContext('terms', definitions, context);          } else { -            this.context = DisplayContext.push(this.context, 'terms', definitions, context); +            this._context = DisplayContext.push(this._context, 'terms', definitions, context);          }          for (const definition of definitions) { -            definition.cloze = Display.clozeBuild(context.sentence, definition.source); +            definition.cloze = this._clozeBuild(context.sentence, definition.source);              definition.url = context.url;          } -        this.updateNavigation(this.context.previous, this.context.next); -        this.setNoContentVisible(definitions.length === 0); +        this._updateNavigation(this._context.previous, this._context.next); +        this._setNoContentVisible(definitions.length === 0); -        const container = this.container; +        const container = this._container;          container.textContent = '';          for (let i = 0, ii = definitions.length; i < ii; ++i) {              if (i > 0) {                  await promiseTimeout(1); -                if (this.setContentToken !== token) { return; } +                if (this._setContentToken !== token) { return; }              } -            const entry = this.displayGenerator.createTermEntry(definitions[i]); +            const entry = this._displayGenerator.createTermEntry(definitions[i]);              container.appendChild(entry);          }          const {index, scroll, disableScroll} = context;          if (!disableScroll) { -            this.entryScrollIntoView(index || 0, scroll); +            this._entryScrollIntoView(index || 0, scroll);          } else {              delete context.disableScroll; -            this.entrySetCurrent(index || 0); +            this._entrySetCurrent(index || 0);          } -        if (this.options.audio.enabled && this.options.audio.autoPlay) { +        if (this._options.audio.enabled && this._options.audio.autoPlay) {              this.autoPlayAudio();          } -        this.setEventListenersActive(true); +        this._setEventListenersActive(true); -        const states = await this.getDefinitionsAddable(definitions, ['term-kanji', 'term-kana']); -        if (this.setContentToken !== token) { return; } +        const states = await this._getDefinitionsAddable(definitions, ['term-kanji', 'term-kana']); +        if (this._setContentToken !== token) { return; } -        this.updateAdderButtons(states); +        this._updateAdderButtons(states);      } -    async setContentKanji(definitions, context, token) { +    async _setContentKanji(definitions, context, token) {          if (!context) { throw new Error('Context expected'); } -        this.setEventListenersActive(false); +        this._setEventListenersActive(false);          if (context.focus !== false) {              window.focus();          } -        this.definitions = definitions; +        this._definitions = definitions;          if (context.disableHistory) {              delete context.disableHistory; -            this.context = new DisplayContext('kanji', definitions, context); +            this._context = new DisplayContext('kanji', definitions, context);          } else { -            this.context = DisplayContext.push(this.context, 'kanji', definitions, context); +            this._context = DisplayContext.push(this._context, 'kanji', definitions, context);          }          for (const definition of definitions) { -            definition.cloze = Display.clozeBuild(context.sentence, definition.character); +            definition.cloze = this._clozeBuild(context.sentence, definition.character);              definition.url = context.url;          } -        this.updateNavigation(this.context.previous, this.context.next); -        this.setNoContentVisible(definitions.length === 0); +        this._updateNavigation(this._context.previous, this._context.next); +        this._setNoContentVisible(definitions.length === 0); -        const container = this.container; +        const container = this._container;          container.textContent = '';          for (let i = 0, ii = definitions.length; i < ii; ++i) {              if (i > 0) {                  await promiseTimeout(1); -                if (this.setContentToken !== token) { return; } +                if (this._setContentToken !== token) { return; }              } -            const entry = this.displayGenerator.createKanjiEntry(definitions[i]); +            const entry = this._displayGenerator.createKanjiEntry(definitions[i]);              container.appendChild(entry);          }          const {index, scroll} = context; -        this.entryScrollIntoView(index || 0, scroll); +        this._entryScrollIntoView(index || 0, scroll); -        this.setEventListenersActive(true); +        this._setEventListenersActive(true); -        const states = await this.getDefinitionsAddable(definitions, ['kanji']); -        if (this.setContentToken !== token) { return; } +        const states = await this._getDefinitionsAddable(definitions, ['kanji']); +        if (this._setContentToken !== token) { return; } -        this.updateAdderButtons(states); +        this._updateAdderButtons(states);      } -    setContentOrphaned() { +    _setContentOrphaned() {          const errorOrphaned = document.querySelector('#error-orphaned'); -        if (this.container !== null) { -            this.container.hidden = true; +        if (this._container !== null) { +            this._container.hidden = true;          }          if (errorOrphaned !== null) {              errorOrphaned.hidden = false;          } -        this.updateNavigation(null, null); -        this.setNoContentVisible(false); +        this._updateNavigation(null, null); +        this._setNoContentVisible(false);      } -    setNoContentVisible(visible) { +    _setNoContentVisible(visible) {          const noResults = document.querySelector('#no-results');          if (noResults !== null) { @@ -620,7 +637,11 @@ class Display {          }      } -    updateNavigation(previous, next) { +    clearContent() { +        this._container.textContent = ''; +    } + +    _updateNavigation(previous, next) {          const navigation = document.querySelector('#navigation-header');          if (navigation !== null) {              navigation.hidden = !(previous || next); @@ -630,16 +651,16 @@ class Display {      }      autoPlayAudio() { -        if (this.definitions.length === 0) { return; } +        if (this._definitions.length === 0) { return; } -        this.audioPlay(this.definitions[0], this.firstExpressionIndex, 0); +        this._audioPlay(this._definitions[0], this._getFirstExpressionIndex(), 0);      } -    updateAdderButtons(states) { +    _updateAdderButtons(states) {          for (let i = 0; i < states.length; ++i) {              let noteId = null;              for (const [mode, info] of Object.entries(states[i])) { -                const button = this.adderButtonFind(i, mode); +                const button = this._adderButtonFind(i, mode);                  if (button === null) {                      continue;                  } @@ -651,39 +672,39 @@ class Display {                  button.classList.remove('pending');              }              if (noteId !== null) { -                this.viewerButtonShow(i, noteId); +                this._viewerButtonShow(i, noteId);              }          }      } -    entrySetCurrent(index) { -        index = Math.min(index, this.definitions.length - 1); +    _entrySetCurrent(index) { +        index = Math.min(index, this._definitions.length - 1);          index = Math.max(index, 0); -        const entryPre = this.getEntry(this.index); +        const entryPre = this._getEntry(this._index);          if (entryPre !== null) {              entryPre.classList.remove('entry-current');          } -        const entry = this.getEntry(index); +        const entry = this._getEntry(index);          if (entry !== null) {              entry.classList.add('entry-current');          } -        this.index = index; +        this._index = index;          return entry;      } -    entryScrollIntoView(index, scroll, smooth) { -        this.windowScroll.stop(); +    _entryScrollIntoView(index, scroll, smooth) { +        this._windowScroll.stop(); -        const entry = this.entrySetCurrent(index); +        const entry = this._entrySetCurrent(index);          let target;          if (scroll !== null) {              target = scroll;          } else { -            target = this.index === 0 || entry === null ? 0 : Display.getElementTop(entry); +            target = this._index === 0 || entry === null ? 0 : this._getElementTop(entry);              const header = document.querySelector('#navigation-header');              if (header !== null) { @@ -692,19 +713,19 @@ class Display {          }          if (smooth) { -            this.windowScroll.animate(this.windowScroll.x, target, 200); +            this._windowScroll.animate(this._windowScroll.x, target, 200);          } else { -            this.windowScroll.toY(target); +            this._windowScroll.toY(target);          }      } -    sourceTermView() { -        if (!this.context || !this.context.previous) { return; } -        this.context.update({ -            index: this.index, -            scroll: this.windowScroll.y +    _sourceTermView() { +        if (!this._context || !this._context.previous) { return; } +        this._context.update({ +            index: this._index, +            scroll: this._windowScroll.y          }); -        const previousContext = this.context.previous; +        const previousContext = this._context.previous;          previousContext.set('disableHistory', true);          const details = {              definitions: previousContext.definitions, @@ -713,13 +734,13 @@ class Display {          this.setContent(previousContext.type, details);      } -    nextTermView() { -        if (!this.context || !this.context.next) { return; } -        this.context.update({ -            index: this.index, -            scroll: this.windowScroll.y +    _nextTermView() { +        if (!this._context || !this._context.next) { return; } +        this._context.update({ +            index: this._index, +            scroll: this._windowScroll.y          }); -        const nextContext = this.context.next; +        const nextContext = this._context.next;          nextContext.set('disableHistory', true);          const details = {              definitions: nextContext.definitions, @@ -728,30 +749,30 @@ class Display {          this.setContent(nextContext.type, details);      } -    noteTryAdd(mode) { -        const index = this.index; -        if (index < 0 || index >= this.definitions.length) { return; } +    _noteTryAdd(mode) { +        const index = this._index; +        if (index < 0 || index >= this._definitions.length) { return; } -        const button = this.adderButtonFind(index, mode); +        const button = this._adderButtonFind(index, mode);          if (button !== null && !button.classList.contains('disabled')) { -            this.noteAdd(this.definitions[index], mode); +            this._noteAdd(this._definitions[index], mode);          }      } -    noteTryView() { -        const button = this.viewerButtonFind(this.index); +    _noteTryView() { +        const button = this._viewerButtonFind(this._index);          if (button !== null && !button.classList.contains('disabled')) {              api.noteView(button.dataset.noteId);          }      } -    async noteAdd(definition, mode) { +    async _noteAdd(definition, mode) {          try {              this.setSpinnerVisible(true);              const details = {}; -            if (this.noteUsesScreenshot(mode)) { -                const screenshot = await this.getScreenshot(); +            if (this._noteUsesScreenshot(mode)) { +                const screenshot = await this._getScreenshot();                  if (screenshot) {                      details.screenshot = screenshot;                  } @@ -760,12 +781,12 @@ class Display {              const context = await this._getNoteContext();              const noteId = await api.definitionAdd(definition, mode, context, details, this.getOptionsContext());              if (noteId) { -                const index = this.definitions.indexOf(definition); -                const adderButton = this.adderButtonFind(index, mode); +                const index = this._definitions.indexOf(definition); +                const adderButton = this._adderButtonFind(index, mode);                  if (adderButton !== null) {                      adderButton.classList.add('disabled');                  } -                this.viewerButtonShow(index, noteId); +                this._viewerButtonShow(index, noteId);              } else {                  throw new Error('Note could not be added');              } @@ -776,7 +797,7 @@ class Display {          }      } -    async audioPlay(definition, expressionIndex, entryIndex) { +    async _audioPlay(definition, expressionIndex, entryIndex) {          try {              this.setSpinnerVisible(true); @@ -786,19 +807,19 @@ class Display {              let audio, info;              try { -                const {sources, textToSpeechVoice, customSourceUrl} = this.options.audio; +                const {sources, textToSpeechVoice, customSourceUrl} = this._options.audio;                  let index; -                ({audio, index} = await this.audioSystem.getDefinitionAudio(expression, sources, {textToSpeechVoice, customSourceUrl})); +                ({audio, index} = await this._audioSystem.getDefinitionAudio(expression, sources, {textToSpeechVoice, customSourceUrl}));                  info = `From source ${1 + index}: ${sources[index]}`;              } catch (e) { -                if (this.audioFallback === null) { -                    this.audioFallback = new Audio('/mixed/mp3/button.mp3'); +                if (this._audioFallback === null) { +                    this._audioFallback = new Audio('/mixed/mp3/button.mp3');                  } -                audio = this.audioFallback; +                audio = this._audioFallback;                  info = 'Could not find audio';              } -            const button = this.audioButtonFindImage(entryIndex, expressionIndex); +            const button = this._audioButtonFindImage(entryIndex, expressionIndex);              if (button !== null) {                  let titleDefault = button.dataset.titleDefault;                  if (!titleDefault) { @@ -810,8 +831,8 @@ class Display {              this._stopPlayingAudio(); -            const volume = Math.max(0.0, Math.min(1.0, this.options.audio.volume / 100.0)); -            this.audioPlaying = audio; +            const volume = Math.max(0.0, Math.min(1.0, this._options.audio.volume / 100.0)); +            this._audioPlaying = audio;              audio.currentTime = 0;              audio.volume = Number.isFinite(volume) ? volume : 1.0;              const playPromise = audio.play(); @@ -830,14 +851,14 @@ class Display {      }      _stopPlayingAudio() { -        if (this.audioPlaying !== null) { -            this.audioPlaying.pause(); -            this.audioPlaying = null; +        if (this._audioPlaying !== null) { +            this._audioPlaying.pause(); +            this._audioPlaying = null;          }      } -    noteUsesScreenshot(mode) { -        const optionsAnki = this.options.anki; +    _noteUsesScreenshot(mode) { +        const optionsAnki = this._options.anki;          const fields = (mode === 'kanji' ? optionsAnki.kanji : optionsAnki.terms).fields;          for (const fieldValue of Object.values(fields)) {              if (fieldValue.includes('{screenshot}')) { @@ -847,41 +868,41 @@ class Display {          return false;      } -    async getScreenshot() { +    async _getScreenshot() {          try { -            await this.setPopupVisibleOverride(false); +            await this._setPopupVisibleOverride(false);              await promiseTimeout(1); // Wait for popup to be hidden. -            const {format, quality} = this.options.anki.screenshot; +            const {format, quality} = this._options.anki.screenshot;              const dataUrl = await api.screenshotGet({format, quality});              if (!dataUrl || dataUrl.error) { return; }              return {dataUrl, format};          } finally { -            await this.setPopupVisibleOverride(null); +            await this._setPopupVisibleOverride(null);          }      } -    get firstExpressionIndex() { -        return this.options.general.resultOutputMode === 'merge' ? 0 : -1; +    _getFirstExpressionIndex() { +        return this._options.general.resultOutputMode === 'merge' ? 0 : -1;      } -    setPopupVisibleOverride(visible) { +    _setPopupVisibleOverride(visible) {          return api.broadcastTab('popupSetVisibleOverride', {visible});      }      setSpinnerVisible(visible) { -        if (this.spinner !== null) { -            this.spinner.hidden = !visible; +        if (this._spinner !== null) { +            this._spinner.hidden = !visible;          }      } -    getEntry(index) { -        const entries = this.container.querySelectorAll('.entry'); +    _getEntry(index) { +        const entries = this._container.querySelectorAll('.entry');          return index >= 0 && index < entries.length ? entries[index] : null;      } -    static clozeBuild({text, offset}, source) { +    _clozeBuild({text, offset}, source) {          return {              sentence: text.trim(),              prefix: text.substring(0, offset).trim(), @@ -890,23 +911,23 @@ class Display {          };      } -    entryIndexFind(element) { +    _entryIndexFind(element) {          const entry = element.closest('.entry'); -        return entry !== null ? Display.indexOf(this.container.querySelectorAll('.entry'), entry) : -1; +        return entry !== null ? this._indexOf(this._container.querySelectorAll('.entry'), entry) : -1;      } -    adderButtonFind(index, mode) { -        const entry = this.getEntry(index); +    _adderButtonFind(index, mode) { +        const entry = this._getEntry(index);          return entry !== null ? entry.querySelector(`.action-add-note[data-mode="${mode}"]`) : null;      } -    viewerButtonFind(index) { -        const entry = this.getEntry(index); +    _viewerButtonFind(index) { +        const entry = this._getEntry(index);          return entry !== null ? entry.querySelector('.action-view-note') : null;      } -    viewerButtonShow(index, noteId) { -        const viewerButton = this.viewerButtonFind(index); +    _viewerButtonShow(index, noteId) { +        const viewerButton = this._viewerButtonFind(index);          if (viewerButton === null) {              return;          } @@ -914,8 +935,8 @@ class Display {          viewerButton.dataset.noteId = noteId;      } -    audioButtonFindImage(index, expressionIndex) { -        const entry = this.getEntry(index); +    _audioButtonFindImage(index, expressionIndex) { +        const entry = this._getEntry(index);          if (entry === null) { return null; }          const container = ( @@ -926,7 +947,7 @@ class Display {          return container !== null ? container.querySelector('.action-play-audio>img') : null;      } -    async getDefinitionsAddable(definitions, modes) { +    async _getDefinitionsAddable(definitions, modes) {          try {              const context = await this._getNoteContext();              return await api.definitionsAddable(definitions, modes, context, this.getOptionsContext()); @@ -939,7 +960,7 @@ class Display {          return document.title;      } -    static indexOf(nodeList, node) { +    _indexOf(nodeList, node) {          for (let i = 0, ii = nodeList.length; i < ii; ++i) {              if (nodeList[i] === node) {                  return i; @@ -948,7 +969,7 @@ class Display {          return -1;      } -    static getElementTop(element) { +    _getElementTop(element) {          const elementRect = element.getBoundingClientRect();          const documentRect = document.documentElement.getBoundingClientRect();          return elementRect.top - documentRect.top; |