diff options
Diffstat (limited to 'ext')
| -rw-r--r-- | ext/mixed/js/display.js | 228 | 
1 files changed, 112 insertions, 116 deletions
| diff --git a/ext/mixed/js/display.js b/ext/mixed/js/display.js index cc5bc95f..5238661b 100644 --- a/ext/mixed/js/display.js +++ b/ext/mixed/js/display.js @@ -24,7 +24,6 @@ class Display {          this.definitions = [];          this.options = null;          this.context = null; -        this.sequence = 0;          this.index = 0;          this.audioPlaying = null;          this.audioFallback = null; @@ -36,6 +35,7 @@ class Display {          this.interactive = false;          this.eventListenersActive = false;          this.clickScanPrevent = false; +        this.setContentToken = null;          this.displayGenerator = new DisplayGenerator();          this.windowScroll = new WindowScroll(); @@ -322,131 +322,136 @@ class Display {          }      } -    setContent(type, details) { -        switch (type) { -            case 'terms': -                return this.setContentTerms(details.definitions, details.context); -            case 'kanji': -                return this.setContentKanji(details.definitions, details.context); -            case 'orphaned': -                return this.setContentOrphaned(); -            default: -                return Promise.resolve(); +    async setContent(type, details) { +        const token = {}; // Unique identifier token +        this.setContentToken = token; +        try { +            switch (type) { +                case 'terms': +                    await this.setContentTerms(details.definitions, details.context, token); +                    break; +                case 'kanji': +                    await this.setContentKanji(details.definitions, details.context, token); +                    break; +                case 'orphaned': +                    this.setContentOrphaned(); +                    break; +            } +        } catch (e) { +            this.onError(e); +        } finally { +            if (this.setContentToken === token) { +                this.setContentToken = null; +            }          }      } -    async setContentTerms(definitions, context) { +    async setContentTerms(definitions, context, token) {          if (!context) { throw new Error('Context expected'); }          if (!this.isInitialized()) { return; } -        try { -            const options = this.options; +        this.setEventListenersActive(false); -            this.setEventListenersActive(false); - -            if (context.focus !== false) { -                window.focus(); -            } +        if (context.focus !== false) { +            window.focus(); +        } -            this.definitions = definitions; -            if (context.disableHistory) { -                delete context.disableHistory; -                this.context = new DisplayContext('terms', definitions, context); -            } else { -                this.context = DisplayContext.push(this.context, 'terms', definitions, context); -            } +        this.definitions = definitions; +        if (context.disableHistory) { +            delete context.disableHistory; +            this.context = new DisplayContext('terms', definitions, context); +        } else { +            this.context = DisplayContext.push(this.context, 'terms', definitions, context); +        } -            const sequence = ++this.sequence; +        for (const definition of definitions) { +            definition.cloze = Display.clozeBuild(context.sentence, definition.source); +            definition.url = context.url; +        } -            for (const definition of definitions) { -                definition.cloze = Display.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 fragment = document.createDocumentFragment(); +        for (const definition of definitions) { +            fragment.appendChild(this.displayGenerator.createTermEntry(definition)); +        } -            const fragment = document.createDocumentFragment(); -            for (const definition of definitions) { -                fragment.appendChild(this.displayGenerator.createTermEntry(definition)); -            } +        await Promise.resolve(); // Delay to help avoid forced reflow warnings in Chrome +        if (this.setContentToken !== token) { return; } -            await Promise.resolve(); // Delay to help avoid forced reflow warnings in Chrome +        this.container.textContent = ''; +        this.container.appendChild(fragment); -            this.container.textContent = ''; -            this.container.appendChild(fragment); +        const {index, scroll, disableScroll} = context; +        if (!disableScroll) { +            this.entryScrollIntoView(index || 0, scroll); +        } else { +            delete context.disableScroll; +            this.entrySetCurrent(index || 0); +        } -            const {index, scroll, disableScroll} = context; -            if (!disableScroll) { -                this.entryScrollIntoView(index || 0, scroll); -            } else { -                delete context.disableScroll; -                this.entrySetCurrent(index || 0); -            } +        if (this.options.audio.enabled && this.options.audio.autoPlay) { +            this.autoPlayAudio(); +        } -            if (options.audio.enabled && options.audio.autoPlay) { -                this.autoPlayAudio(); -            } +        this.setEventListenersActive(true); -            this.setEventListenersActive(true); +        const states = await apiDefinitionsAddable(definitions, ['term-kanji', 'term-kana'], this.getOptionsContext()); +        if (this.setContentToken !== token) { return; } -            await this.adderButtonUpdate(['term-kanji', 'term-kana'], sequence); -        } catch (e) { -            this.onError(e); -        } +        this.updateAdderButtons(states);      } -    async setContentKanji(definitions, context) { +    async setContentKanji(definitions, context, token) {          if (!context) { throw new Error('Context expected'); }          if (!this.isInitialized()) { return; } -        try { -            this.setEventListenersActive(false); +        this.setEventListenersActive(false); -            if (context.focus !== false) { -                window.focus(); -            } +        if (context.focus !== false) { +            window.focus(); +        } -            this.definitions = definitions; -            if (context.disableHistory) { -                delete context.disableHistory; -                this.context = new DisplayContext('kanji', definitions, context); -            } else { -                this.context = DisplayContext.push(this.context, 'kanji', definitions, context); -            } +        this.definitions = definitions; +        if (context.disableHistory) { +            delete context.disableHistory; +            this.context = new DisplayContext('kanji', definitions, context); +        } else { +            this.context = DisplayContext.push(this.context, 'kanji', definitions, context); +        } -            const sequence = ++this.sequence; +        for (const definition of definitions) { +            definition.cloze = Display.clozeBuild(context.sentence, definition.character); +            definition.url = context.url; +        } -            for (const definition of definitions) { -                definition.cloze = Display.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 fragment = document.createDocumentFragment(); +        for (const definition of definitions) { +            fragment.appendChild(this.displayGenerator.createKanjiEntry(definition)); +        } -            const fragment = document.createDocumentFragment(); -            for (const definition of definitions) { -                fragment.appendChild(this.displayGenerator.createKanjiEntry(definition)); -            } +        await Promise.resolve(); // Delay to help avoid forced reflow warnings in Chrome +        if (this.setContentToken !== token) { return; } -            await Promise.resolve(); // Delay to help avoid forced reflow warnings in Chrome +        this.container.textContent = ''; +        this.container.appendChild(fragment); -            this.container.textContent = ''; -            this.container.appendChild(fragment); +        const {index, scroll} = context; +        this.entryScrollIntoView(index || 0, scroll); -            const {index, scroll} = context; -            this.entryScrollIntoView(index || 0, scroll); +        this.setEventListenersActive(true); -            this.setEventListenersActive(true); +        const states = await apiDefinitionsAddable(definitions, ['kanji'], this.getOptionsContext()); +        if (this.setContentToken !== token) { return; } -            await this.adderButtonUpdate(['kanji'], sequence); -        } catch (e) { -            this.onError(e); -        } +        this.updateAdderButtons(states);      } -    async setContentOrphaned() { +    setContentOrphaned() {          const definitions = document.querySelector('#definitions');          const errorOrphaned = document.querySelector('#error-orphaned'); @@ -483,35 +488,26 @@ class Display {          this.audioPlay(this.definitions[0], this.firstExpressionIndex, 0);      } -    async adderButtonUpdate(modes, sequence) { -        try { -            const states = await apiDefinitionsAddable(this.definitions, modes, this.getOptionsContext()); -            if (!states || sequence !== this.sequence) { -                return; -            } - -            for (let i = 0; i < states.length; ++i) { -                const state = states[i]; -                let noteId = null; -                for (const mode in state) { -                    const button = this.adderButtonFind(i, mode); -                    if (button === null) { -                        continue; -                    } - -                    const info = state[mode]; -                    if (!info.canAdd && noteId === null && info.noteId) { -                        noteId = info.noteId; -                    } -                    button.classList.toggle('disabled', !info.canAdd); -                    button.classList.remove('pending'); +    updateAdderButtons(states) { +        for (let i = 0; i < states.length; ++i) { +            const state = states[i]; +            let noteId = null; +            for (const mode in state) { +                const button = this.adderButtonFind(i, mode); +                if (button === null) { +                    continue;                  } -                if (noteId !== null) { -                    this.viewerButtonShow(i, noteId); + +                const info = state[mode]; +                if (!info.canAdd && noteId === null && info.noteId) { +                    noteId = info.noteId;                  } +                button.classList.toggle('disabled', !info.canAdd); +                button.classList.remove('pending'); +            } +            if (noteId !== null) { +                this.viewerButtonShow(i, noteId);              } -        } catch (e) { -            this.onError(e);          }      } |