diff options
Diffstat (limited to 'ext/mixed/js')
| -rw-r--r-- | ext/mixed/js/display-generator.js | 7 | ||||
| -rw-r--r-- | ext/mixed/js/display-notification.js | 90 | ||||
| -rw-r--r-- | ext/mixed/js/display.js | 26 | 
3 files changed, 123 insertions, 0 deletions
| diff --git a/ext/mixed/js/display-generator.js b/ext/mixed/js/display-generator.js index 1810000b..1ccd5941 100644 --- a/ext/mixed/js/display-generator.js +++ b/ext/mixed/js/display-generator.js @@ -117,6 +117,10 @@ class DisplayGenerator {          return node;      } +    createEmptyFooterNotification() { +        return this._templates.instantiate('footer-notification'); +    } +      // Private      _createTermExpression(details) { @@ -310,6 +314,7 @@ class DisplayGenerator {          node.title = details.notes;          inner.textContent = details.name; +        node.dataset.details = details.notes || details.name;          node.dataset.category = details.category;          if (details.redundant) { node.dataset.redundant = 'true'; } @@ -472,6 +477,7 @@ class DisplayGenerator {          node.dataset.readingIsSame = `${reading === expression}`;          node.dataset.dictionary = dictionary;          node.dataset.frequency = frequency; +        node.dataset.details = `${dictionary}: ${frequency}`;          return node;      } @@ -486,6 +492,7 @@ class DisplayGenerator {          node.dataset.character = character;          node.dataset.dictionary = dictionary;          node.dataset.frequency = frequency; +        node.dataset.details = `${dictionary}: ${frequency}`;          return node;      } diff --git a/ext/mixed/js/display-notification.js b/ext/mixed/js/display-notification.js new file mode 100644 index 00000000..2d3c50bb --- /dev/null +++ b/ext/mixed/js/display-notification.js @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2017-2020  Yomichan Authors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <https://www.gnu.org/licenses/>. + */ + +class DisplayNotification { +    constructor(container, node) { +        this._container = container; +        this._node = node; +        this._body = node.querySelector('.footer-notification-body'); +        this._closeButton = node.querySelector('.footer-notification-close-button'); +        this._eventListeners = new EventListenerCollection(); +        this._closeTimer = null; +    } + +    open() { +        if (!this.isClosed()) { return; } + +        this._clearTimer(); + +        const node = this._node; +        this._container.appendChild(node); +        const style = getComputedStyle(node); +        node.hidden = true; +        style.getPropertyValue('opacity'); // Force CSS update, allowing animation +        node.hidden = false; +        this._eventListeners.addEventListener(this._closeButton, 'click', this._onCloseButtonClick.bind(this), false); +    } + +    close(animate=false) { +        if (this.isClosed()) { return; } + +        if (animate) { +            if (this._closeTimer !== null) { return; } + +            this._node.hidden = true; +            this._closeTimer = setTimeout(this._onDelayClose.bind(this), 200); +        } else { +            this._clearTimer(); + +            this._eventListeners.removeAllEventListeners(); +            const parent = this._node.parentNode; +            if (parent !== null) { +                parent.removeChild(this._node); +            } +        } +    } + +    setContent(text) { +        this._body.textContent = text; +    } + +    isClosing() { +        return this._closeTimer !== null; +    } + +    isClosed() { +        return this._node.parentNode === null; +    } + +    // Private + +    _onCloseButtonClick() { +        this.close(true); +    } + +    _onDelayClose() { +        this._closeTimer = null; +        this.close(false); +    } + +    _clearTimer() { +        if (this._closeTimer !== null) { +            clearTimeout(this._closeTimer); +            this._closeTimer = null; +        } +    } +} diff --git a/ext/mixed/js/display.js b/ext/mixed/js/display.js index 26a05abd..77bf9649 100644 --- a/ext/mixed/js/display.js +++ b/ext/mixed/js/display.js @@ -20,6 +20,7 @@   * AudioSystem   * DisplayGenerator   * DisplayHistory + * DisplayNotification   * DocumentUtil   * FrameEndpoint   * Frontend @@ -114,6 +115,8 @@ class Display extends EventDispatcher {          this._frameResizeStartSize = null;          this._frameResizeStartOffset = null;          this._frameResizeEventListeners = new EventListenerCollection(); +        this._tagNotification = null; +        this._tagNotificationContainer = document.querySelector('#content-footer');          this.registerActions([              ['close',             () => { this.onEscape(); }], @@ -543,6 +546,7 @@ class Display extends EventDispatcher {              this._closePopups();              this._eventListeners.removeAllEventListeners();              this._mediaLoader.unloadAll(); +            this._hideTagNotification(false);              // Prepare              const urlSearchParams = new URLSearchParams(location.search); @@ -799,6 +803,27 @@ class Display extends EventDispatcher {          this._entrySetCurrent(index);      } +    _onTagClick(e) { +        const node = e.currentTarget; +        const {dataset: {details}} = node; +        this._showTagNotification(details); +    } + +    _showTagNotification(content) { +        if (this._tagNotification === null) { +            const node = this._displayGenerator.createEmptyFooterNotification(); +            this._tagNotification = new DisplayNotification(this._tagNotificationContainer, node); +        } + +        this._tagNotification.setContent(content); +        this._tagNotification.open(); +    } + +    _hideTagNotification(animate) { +        if (this._tagNotification === null) { return; } +        this._tagNotification.close(animate); +    } +      _updateDocumentOptions(options) {          const data = document.documentElement.dataset;          data.ankiEnabled = `${options.anki.enable}`; @@ -1720,6 +1745,7 @@ class Display extends EventDispatcher {          this._addMultipleEventListeners(entry, '.action-play-audio', 'click', this._onAudioPlay.bind(this));          this._addMultipleEventListeners(entry, '.kanji-link', 'click', this._onKanjiLookup.bind(this));          this._addMultipleEventListeners(entry, '.debug-log-link', 'click', this._onDebugLogClick.bind(this)); +        this._addMultipleEventListeners(entry, '.tag', 'click', this._onTagClick.bind(this));      }      _updateDefinitionTextScanner(options) { |