diff options
author | Moonchild <mcwerewolf@gmail.com> | 2018-05-16 17:10:38 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-05-16 17:10:38 +0200 |
commit | 90942a2af0cabb9345cf04fa6113e12197504fcf (patch) | |
tree | e16c71be5a1343abe0489863f84ed271b6ebd3d7 /toolkit/components/narrate/Narrator.jsm | |
parent | 819ca50f163a9113772a7dbfd617d97151893337 (diff) | |
parent | 9ef464a5ac0a17135a0f7b4fef070bb4f7fbe44c (diff) | |
download | UXP-90942a2af0cabb9345cf04fa6113e12197504fcf.tar UXP-90942a2af0cabb9345cf04fa6113e12197504fcf.tar.gz UXP-90942a2af0cabb9345cf04fa6113e12197504fcf.tar.lz UXP-90942a2af0cabb9345cf04fa6113e12197504fcf.tar.xz UXP-90942a2af0cabb9345cf04fa6113e12197504fcf.zip |
Merge pull request #367 from Ascrod/readerview
Reader and Narrator Updates
Diffstat (limited to 'toolkit/components/narrate/Narrator.jsm')
-rw-r--r-- | toolkit/components/narrate/Narrator.jsm | 78 |
1 files changed, 27 insertions, 51 deletions
diff --git a/toolkit/components/narrate/Narrator.jsm b/toolkit/components/narrate/Narrator.jsm index ade06510e..ac0b2e040 100644 --- a/toolkit/components/narrate/Narrator.jsm +++ b/toolkit/components/narrate/Narrator.jsm @@ -8,8 +8,6 @@ const { interfaces: Ci, utils: Cu } = Components; Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "LanguageDetector", - "resource:///modules/translation/LanguageDetector.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "Services", "resource://gre/modules/Services.jsm"); @@ -24,29 +22,13 @@ const kTextStylesRules = ["font-family", "font-kerning", "font-size", "line-height", "letter-spacing", "text-orientation", "text-transform", "word-spacing"]; -function Narrator(win) { +function Narrator(win, languagePromise) { this._winRef = Cu.getWeakReference(win); + this._languagePromise = languagePromise; this._inTest = Services.prefs.getBoolPref("narrate.test"); this._speechOptions = {}; this._startTime = 0; this._stopped = false; - - this.languagePromise = new Promise(resolve => { - let detect = () => { - win.document.removeEventListener("AboutReaderContentReady", detect); - let sampleText = this._doc.getElementById( - "moz-reader-content").textContent.substring(0, 60 * 1024); - LanguageDetector.detectLanguage(sampleText).then(result => { - resolve(result.confident ? result.language : null); - }); - }; - - if (win.document.body.classList.contains("loaded")) { - detect(); - } else { - win.document.addEventListener("AboutReaderContentReady", detect); - } - }); } Narrator.prototype = { @@ -71,7 +53,7 @@ Narrator.prototype = { // For example, paragraphs. But nested anchors and other elements // are not interesting since their text already appears in their // parent's textContent. - acceptNode: function(node) { + acceptNode(node) { if (this._matches.has(node.parentNode)) { // Reject sub-trees of accepted nodes. return nf.FILTER_REJECT; @@ -107,7 +89,7 @@ Narrator.prototype = { // are no other strong references, and it will be GC'ed. Instead, // we rely on the window's lifetime and use it as a weak reference. this._treeWalkerRef.set(this._win, - this._doc.createTreeWalker(this._doc.getElementById("container"), + this._doc.createTreeWalker(this._doc.querySelector(".container"), nf.SHOW_ELEMENT, filter, false)); } @@ -124,7 +106,7 @@ Narrator.prototype = { this._win.speechSynthesis.pending; }, - _getVoice: function(voiceURI) { + _getVoice(voiceURI) { if (!this._voiceMap || !this._voiceMap.has(voiceURI)) { this._voiceMap = new Map( this._win.speechSynthesis.getVoices().map(v => [v.voiceURI, v])); @@ -133,7 +115,7 @@ Narrator.prototype = { return this._voiceMap.get(voiceURI); }, - _isParagraphInView: function(paragraph) { + _isParagraphInView(paragraph) { if (!paragraph) { return false; } @@ -142,13 +124,13 @@ Narrator.prototype = { return bb.top >= 0 && bb.top < this._win.innerHeight; }, - _sendTestEvent: function(eventType, detail) { + _sendTestEvent(eventType, detail) { let win = this._win; win.dispatchEvent(new win.CustomEvent(eventType, { detail: Cu.cloneInto(detail, win.document) })); }, - _speakInner: function() { + _speakInner() { this._win.speechSynthesis.cancel(); let tw = this._treeWalker; let paragraph = tw.currentNode; @@ -238,18 +220,12 @@ Narrator.prototype = { return; } - // Match non-whitespace. This isn't perfect, but the most universal - // solution for now. - let reWordBoundary = /\S+/g; - // Match the first word from the boundary event offset. - reWordBoundary.lastIndex = e.charIndex; - let firstIndex = reWordBoundary.exec(paragraph.textContent); - if (firstIndex) { - highlighter.highlight(firstIndex.index, reWordBoundary.lastIndex); + if (e.charLength) { + highlighter.highlight(e.charIndex, e.charLength); if (this._inTest) { this._sendTestEvent("wordhighlight", { - start: firstIndex.index, - end: reWordBoundary.lastIndex + start: e.charIndex, + end: e.charIndex + e.charLength }); } } @@ -259,14 +235,14 @@ Narrator.prototype = { }); }, - start: function(speechOptions) { + start(speechOptions) { this._speechOptions = { rate: speechOptions.rate, voice: this._getVoice(speechOptions.voice) }; this._stopped = false; - return this.languagePromise.then(language => { + return this._languagePromise.then(language => { if (!this._speechOptions.voice) { this._speechOptions.lang = language; } @@ -288,32 +264,32 @@ Narrator.prototype = { }); }, - stop: function() { + stop() { this._stopped = true; this._win.speechSynthesis.cancel(); }, - skipNext: function() { + skipNext() { this._win.speechSynthesis.cancel(); }, - skipPrevious: function() { + skipPrevious() { this._goBackParagraphs(this._timeIntoParagraph < PREV_THRESHOLD ? 2 : 1); }, - setRate: function(rate) { + setRate(rate) { this._speechOptions.rate = rate; /* repeat current paragraph */ this._goBackParagraphs(1); }, - setVoice: function(voice) { + setVoice(voice) { this._speechOptions.voice = this._getVoice(voice); /* repeat current paragraph */ this._goBackParagraphs(1); }, - _goBackParagraphs: function(count) { + _goBackParagraphs(count) { let tw = this._treeWalker; for (let i = 0; i < count; i++) { if (!tw.previousNode()) { @@ -338,13 +314,13 @@ Highlighter.prototype = { * Highlight the range within offsets relative to the container. * * @param {Number} startOffset the start offset - * @param {Number} endOffset the end offset + * @param {Number} length the length in characters of the range */ - highlight: function(startOffset, endOffset) { + highlight(startOffset, length) { let containerRect = this.container.getBoundingClientRect(); - let range = this._getRange(startOffset, endOffset); + let range = this._getRange(startOffset, startOffset + length); let rangeRects = range.getClientRects(); - let win = this.container.ownerDocument.defaultView; + let win = this.container.ownerGlobal; let computedStyle = win.getComputedStyle(range.endContainer.parentNode); let nodes = this._getFreshHighlightNodes(rangeRects.length); @@ -386,7 +362,7 @@ Highlighter.prototype = { /** * Releases reference to container and removes all highlight nodes. */ - remove: function() { + remove() { for (let node of this._nodes) { node.remove(); } @@ -400,7 +376,7 @@ Highlighter.prototype = { * * @param {Number} count number of nodes needed */ - _getFreshHighlightNodes: function(count) { + _getFreshHighlightNodes(count) { let doc = this.container.ownerDocument; let nodes = Array.from(this._nodes); @@ -427,7 +403,7 @@ Highlighter.prototype = { * @param {Number} startOffset the start offset * @param {Number} endOffset the end offset */ - _getRange: function(startOffset, endOffset) { + _getRange(startOffset, endOffset) { let doc = this.container.ownerDocument; let i = 0; let treeWalker = doc.createTreeWalker( |