diff options
| author | toasted-nutbread <toasted-nutbread@users.noreply.github.com> | 2020-12-29 00:06:51 -0500 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-12-29 00:06:51 -0500 | 
| commit | 2cd429fdfd718ae6e92cf5c221568f95d46b73c9 (patch) | |
| tree | 26bf60d4ef1b6e253e1cc1889a029209b494c11d /ext | |
| parent | 5c970fc404e1e057749ce642ea5fb5530c88c4f9 (diff) | |
Rename PopupElement to PanelElement; split classes into separate files (#1173)
Diffstat (limited to 'ext')
| -rw-r--r-- | ext/bg/js/settings/modal.js | 80 | ||||
| -rw-r--r-- | ext/bg/js/settings/popup-elements.js | 227 | ||||
| -rw-r--r-- | ext/bg/js/settings/status-footer.js | 84 | ||||
| -rw-r--r-- | ext/bg/settings2.html | 4 | ||||
| -rw-r--r-- | ext/bg/welcome.html | 4 | ||||
| -rw-r--r-- | ext/mixed/js/panel-element.js | 103 | 
6 files changed, 273 insertions, 229 deletions
| diff --git a/ext/bg/js/settings/modal.js b/ext/bg/js/settings/modal.js new file mode 100644 index 00000000..e87ed2d9 --- /dev/null +++ b/ext/bg/js/settings/modal.js @@ -0,0 +1,80 @@ +/* + * Copyright (C) 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/>. + */ + +/* global + * PanelElement + */ + +class Modal extends PanelElement { +    constructor(node) { +        super({ +            node, +            closingAnimationDuration: 375 // Milliseconds; includes buffer +        }); +        this._contentNode = null; +        this._canCloseOnClick = false; +    } + +    prepare() { +        const node = this.node; +        this._contentNode = node.querySelector('.modal-content'); +        let dimmerNode = node.querySelector('.modal-content-dimmer'); +        if (dimmerNode === null) { dimmerNode = node; } +        dimmerNode.addEventListener('mousedown', this._onModalContainerMouseDown.bind(this), false); +        dimmerNode.addEventListener('mouseup', this._onModalContainerMouseUp.bind(this), false); +        dimmerNode.addEventListener('click', this._onModalContainerClick.bind(this), false); + +        for (const actionNode of node.querySelectorAll('[data-modal-action]')) { +            actionNode.addEventListener('click', this._onActionNodeClick.bind(this), false); +        } +    } + +    // Private + +    _onModalContainerMouseDown(e) { +        this._canCloseOnClick = (e.currentTarget === e.target); +    } + +    _onModalContainerMouseUp(e) { +        if (!this._canCloseOnClick) { return; } +        this._canCloseOnClick = (e.currentTarget === e.target); +    } + +    _onModalContainerClick(e) { +        if (!this._canCloseOnClick) { return; } +        this._canCloseOnClick = false; +        if (e.currentTarget !== e.target) { return; } +        this.setVisible(false); +    } + +    _onActionNodeClick(e) { +        const {modalAction} = e.currentTarget.dataset; +        switch (modalAction) { +            case 'expand': +                this._setExpanded(true); +                break; +            case 'collapse': +                this._setExpanded(false); +                break; +        } +    } + +    _setExpanded(expanded) { +        if (this._contentNode === null) { return; } +        this._contentNode.classList.toggle('modal-content-full', expanded); +    } +} diff --git a/ext/bg/js/settings/popup-elements.js b/ext/bg/js/settings/popup-elements.js deleted file mode 100644 index 21a557bb..00000000 --- a/ext/bg/js/settings/popup-elements.js +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Copyright (C) 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 PopupElement extends EventDispatcher { -    constructor({node, closingAnimationDuration}) { -        super(); -        this._node = node; -        this._closingAnimationDuration = closingAnimationDuration; -        this._hiddenAnimatingClass = 'hidden-animating'; -        this._mutationObserver = null; -        this._visible = false; -        this._closeTimer = null; -    } - -    get node() { -        return this._node; -    } - -    isVisible() { -        return !this._node.hidden; -    } - -    setVisible(value, animate=true) { -        value = !!value; -        if (this.isVisible() === value) { return; } - -        if (this._closeTimer !== null) { -            clearTimeout(this._closeTimer); -            this._completeClose(true); -        } - -        const node = this._node; -        const {classList} = node; -        if (value) { -            if (animate) { classList.add(this._hiddenAnimatingClass); } -            getComputedStyle(node).getPropertyValue('display'); // Force update of CSS display property, allowing animation -            classList.remove(this._hiddenAnimatingClass); -            node.hidden = false; -            node.focus(); -        } else { -            if (animate) { classList.add(this._hiddenAnimatingClass); } -            node.hidden = true; -            if (animate) { -                this._closeTimer = setTimeout(() => this._completeClose(false), this._closingAnimationDuration); -            } -        } -    } - -    on(eventName, callback) { -        if (eventName === 'visibilityChanged') { -            if (this._mutationObserver === null) { -                this._visible = this.isVisible(); -                this._mutationObserver = new MutationObserver(this._onMutation.bind(this)); -                this._mutationObserver.observe(this._node, { -                    attributes: true, -                    attributeFilter: ['hidden'], -                    attributeOldValue: true -                }); -            } -        } -        return super.on(eventName, callback); -    } - -    off(eventName, callback) { -        const result = super.off(eventName, callback); -        if (eventName === 'visibilityChanged' && !this.hasListeners(eventName)) { -            if (this._mutationObserver !== null) { -                this._mutationObserver.disconnect(); -                this._mutationObserver = null; -            } -        } -        return result; -    } - -    // Private - -    _onMutation() { -        const visible = this.isVisible(); -        if (this._visible === visible) { return; } -        this._visible = visible; -        this.trigger('visibilityChanged', {visible}); -    } - -    _completeClose(reopening) { -        this._closeTimer = null; -        this._node.classList.remove(this._hiddenAnimatingClass); -        this.trigger('closeCompleted', {reopening}); -    } -} - -class Modal extends PopupElement { -    constructor(node) { -        super({ -            node, -            closingAnimationDuration: 375 // Milliseconds; includes buffer -        }); -        this._contentNode = null; -        this._canCloseOnClick = false; -    } - -    prepare() { -        const node = this.node; -        this._contentNode = node.querySelector('.modal-content'); -        let dimmerNode = node.querySelector('.modal-content-dimmer'); -        if (dimmerNode === null) { dimmerNode = node; } -        dimmerNode.addEventListener('mousedown', this._onModalContainerMouseDown.bind(this), false); -        dimmerNode.addEventListener('mouseup', this._onModalContainerMouseUp.bind(this), false); -        dimmerNode.addEventListener('click', this._onModalContainerClick.bind(this), false); - -        for (const actionNode of node.querySelectorAll('[data-modal-action]')) { -            actionNode.addEventListener('click', this._onActionNodeClick.bind(this), false); -        } -    } - -    // Private - -    _onModalContainerMouseDown(e) { -        this._canCloseOnClick = (e.currentTarget === e.target); -    } - -    _onModalContainerMouseUp(e) { -        if (!this._canCloseOnClick) { return; } -        this._canCloseOnClick = (e.currentTarget === e.target); -    } - -    _onModalContainerClick(e) { -        if (!this._canCloseOnClick) { return; } -        this._canCloseOnClick = false; -        if (e.currentTarget !== e.target) { return; } -        this.setVisible(false); -    } - -    _onActionNodeClick(e) { -        const {modalAction} = e.currentTarget.dataset; -        switch (modalAction) { -            case 'expand': -                this._setExpanded(true); -                break; -            case 'collapse': -                this._setExpanded(false); -                break; -        } -    } - -    _setExpanded(expanded) { -        if (this._contentNode === null) { return; } -        this._contentNode.classList.toggle('modal-content-full', expanded); -    } -} - -class StatusFooter extends PopupElement { -    constructor(node) { -        super({ -            node, -            closingAnimationDuration: 375 // Milliseconds; includes buffer -        }); -        this._body = node.querySelector('.status-footer'); -    } - -    prepare() { -        this.on('closeCompleted', this._onCloseCompleted.bind(this), false); -        this._body.querySelector('.status-footer-header-close').addEventListener('click', this._onCloseClick.bind(this), false); -    } - -    getTaskContainer(selector) { -        return this._body.querySelector(selector); -    } - -    isTaskActive(selector) { -        const target = this.getTaskContainer(selector); -        return (target !== null && target.dataset.active); -    } - -    setTaskActive(selector, active) { -        const target = this.getTaskContainer(selector); -        if (target === null) { return; } - -        const activeElements = new Set(); -        for (const element of this._body.querySelectorAll('.status-footer-item')) { -            if (element.dataset.active) { -                activeElements.add(element); -            } -        } - -        if (active) { -            target.dataset.active = 'true'; -            if (!this.isVisible()) { -                this.setVisible(true); -            } -            target.hidden = false; -        } else { -            delete target.dataset.active; -            if (activeElements.size <= 1) { -                this.setVisible(false); -            } -        } -    } - -    // Private - -    _onCloseClick(e) { -        e.preventDefault(); -        this.setVisible(false); -    } - -    _onCloseCompleted() { -        for (const element of this._body.querySelectorAll('.status-footer-item')) { -            if (!element.dataset.active) { -                element.hidden = true; -            } -        } -    } -} diff --git a/ext/bg/js/settings/status-footer.js b/ext/bg/js/settings/status-footer.js new file mode 100644 index 00000000..391ad445 --- /dev/null +++ b/ext/bg/js/settings/status-footer.js @@ -0,0 +1,84 @@ +/* + * Copyright (C) 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/>. + */ + +/* global + * PanelElement + */ + +class StatusFooter extends PanelElement { +    constructor(node) { +        super({ +            node, +            closingAnimationDuration: 375 // Milliseconds; includes buffer +        }); +        this._body = node.querySelector('.status-footer'); +    } + +    prepare() { +        this.on('closeCompleted', this._onCloseCompleted.bind(this), false); +        this._body.querySelector('.status-footer-header-close').addEventListener('click', this._onCloseClick.bind(this), false); +    } + +    getTaskContainer(selector) { +        return this._body.querySelector(selector); +    } + +    isTaskActive(selector) { +        const target = this.getTaskContainer(selector); +        return (target !== null && target.dataset.active); +    } + +    setTaskActive(selector, active) { +        const target = this.getTaskContainer(selector); +        if (target === null) { return; } + +        const activeElements = new Set(); +        for (const element of this._body.querySelectorAll('.status-footer-item')) { +            if (element.dataset.active) { +                activeElements.add(element); +            } +        } + +        if (active) { +            target.dataset.active = 'true'; +            if (!this.isVisible()) { +                this.setVisible(true); +            } +            target.hidden = false; +        } else { +            delete target.dataset.active; +            if (activeElements.size <= 1) { +                this.setVisible(false); +            } +        } +    } + +    // Private + +    _onCloseClick(e) { +        e.preventDefault(); +        this.setVisible(false); +    } + +    _onCloseCompleted() { +        for (const element of this._body.querySelectorAll('.status-footer-item')) { +            if (!element.dataset.active) { +                element.hidden = true; +            } +        } +    } +} diff --git a/ext/bg/settings2.html b/ext/bg/settings2.html index a11383b5..0a8a98c2 100644 --- a/ext/bg/settings2.html +++ b/ext/bg/settings2.html @@ -2559,6 +2559,7 @@  <script src="/mixed/js/dom-data-binder.js"></script>  <script src="/mixed/js/html-template-collection.js"></script>  <script src="/mixed/js/object-property-accessor.js"></script> +<script src="/mixed/js/panel-element.js"></script>  <script src="/mixed/js/selector-observer.js"></script>  <script src="/mixed/js/task-accumulator.js"></script>  <script src="/mixed/js/text-to-speech-audio.js"></script> @@ -2574,7 +2575,6 @@  <script src="/bg/js/template-renderer-proxy.js"></script>  <script src="/bg/js/settings/keyboard-mouse-input-field.js"></script> -<script src="/bg/js/settings/popup-elements.js"></script>  <script src="/bg/js/settings/profile-conditions-ui.js"></script>  <script src="/bg/js/settings/anki-controller.js"></script> @@ -2585,6 +2585,7 @@  <script src="/bg/js/settings/dictionary-controller.js"></script>  <script src="/bg/js/settings/dictionary-import-controller.js"></script>  <script src="/bg/js/settings/generic-setting-controller.js"></script> +<script src="/bg/js/settings/modal.js"></script>  <script src="/bg/js/settings/modal-controller.js"></script>  <script src="/bg/js/settings/popup-menu.js"></script>  <script src="/bg/js/settings/popup-preview-controller.js"></script> @@ -2592,6 +2593,7 @@  <script src="/bg/js/settings/scan-inputs-controller.js"></script>  <script src="/bg/js/settings/scan-inputs-simple-controller.js"></script>  <script src="/bg/js/settings/settings-controller.js"></script> +<script src="/bg/js/settings/status-footer.js"></script>  <script src="/bg/js/settings/storage-controller.js"></script>  <script src="/bg/js/settings2/nested-popups-controller.js"></script> diff --git a/ext/bg/welcome.html b/ext/bg/welcome.html index 6aebb356..52cf981a 100644 --- a/ext/bg/welcome.html +++ b/ext/bg/welcome.html @@ -339,6 +339,7 @@  <script src="/mixed/js/dom-data-binder.js"></script>  <script src="/mixed/js/html-template-collection.js"></script>  <script src="/mixed/js/object-property-accessor.js"></script> +<script src="/mixed/js/panel-element.js"></script>  <script src="/mixed/js/selector-observer.js"></script>  <script src="/mixed/js/task-accumulator.js"></script> @@ -351,11 +352,12 @@  <script src="/bg/js/settings/dictionary-controller.js"></script>  <script src="/bg/js/settings/dictionary-import-controller.js"></script>  <script src="/bg/js/settings/generic-setting-controller.js"></script> +<script src="/bg/js/settings/modal.js"></script>  <script src="/bg/js/settings/modal-controller.js"></script> -<script src="/bg/js/settings/popup-elements.js"></script>  <script src="/bg/js/settings/popup-menu.js"></script>  <script src="/bg/js/settings/scan-inputs-simple-controller.js"></script>  <script src="/bg/js/settings/settings-controller.js"></script> +<script src="/bg/js/settings/status-footer.js"></script>  <script src="/bg/js/settings2/settings-display-controller.js"></script> diff --git a/ext/mixed/js/panel-element.js b/ext/mixed/js/panel-element.js new file mode 100644 index 00000000..6a2c4526 --- /dev/null +++ b/ext/mixed/js/panel-element.js @@ -0,0 +1,103 @@ +/* + * Copyright (C) 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 PanelElement extends EventDispatcher { +    constructor({node, closingAnimationDuration}) { +        super(); +        this._node = node; +        this._closingAnimationDuration = closingAnimationDuration; +        this._hiddenAnimatingClass = 'hidden-animating'; +        this._mutationObserver = null; +        this._visible = false; +        this._closeTimer = null; +    } + +    get node() { +        return this._node; +    } + +    isVisible() { +        return !this._node.hidden; +    } + +    setVisible(value, animate=true) { +        value = !!value; +        if (this.isVisible() === value) { return; } + +        if (this._closeTimer !== null) { +            clearTimeout(this._closeTimer); +            this._completeClose(true); +        } + +        const node = this._node; +        const {classList} = node; +        if (value) { +            if (animate) { classList.add(this._hiddenAnimatingClass); } +            getComputedStyle(node).getPropertyValue('display'); // Force update of CSS display property, allowing animation +            classList.remove(this._hiddenAnimatingClass); +            node.hidden = false; +            node.focus(); +        } else { +            if (animate) { classList.add(this._hiddenAnimatingClass); } +            node.hidden = true; +            if (animate) { +                this._closeTimer = setTimeout(() => this._completeClose(false), this._closingAnimationDuration); +            } +        } +    } + +    on(eventName, callback) { +        if (eventName === 'visibilityChanged') { +            if (this._mutationObserver === null) { +                this._visible = this.isVisible(); +                this._mutationObserver = new MutationObserver(this._onMutation.bind(this)); +                this._mutationObserver.observe(this._node, { +                    attributes: true, +                    attributeFilter: ['hidden'], +                    attributeOldValue: true +                }); +            } +        } +        return super.on(eventName, callback); +    } + +    off(eventName, callback) { +        const result = super.off(eventName, callback); +        if (eventName === 'visibilityChanged' && !this.hasListeners(eventName)) { +            if (this._mutationObserver !== null) { +                this._mutationObserver.disconnect(); +                this._mutationObserver = null; +            } +        } +        return result; +    } + +    // Private + +    _onMutation() { +        const visible = this.isVisible(); +        if (this._visible === visible) { return; } +        this._visible = visible; +        this.trigger('visibilityChanged', {visible}); +    } + +    _completeClose(reopening) { +        this._closeTimer = null; +        this._node.classList.remove(this._hiddenAnimatingClass); +        this.trigger('closeCompleted', {reopening}); +    } +} |