--- a/toolkit/modules/Finder.jsm
+++ b/toolkit/modules/Finder.jsm
@@ -128,21 +128,25 @@ Finder.prototype = {
if (!aSearchString || !Clipboard.supportsFindClipboard())
return;
ClipboardHelper.copyStringToClipboard(aSearchString,
Ci.nsIClipboard.kFindClipboard);
},
set caseSensitive(aSensitive) {
+ if (this._fastFind.caseSensitive === aSensitive)
+ return;
this._fastFind.caseSensitive = aSensitive;
this.iterator.reset();
},
set entireWord(aEntireWord) {
+ if (this._fastFind.entireWord === aEntireWord)
+ return;
this._fastFind.entireWord = aEntireWord;
this.iterator.reset();
},
get highlighter() {
if (this._highlighter)
return this._highlighter;
@@ -363,70 +367,89 @@ Finder.prototype = {
controller.scrollLine(false);
break;
case Ci.nsIDOMKeyEvent.DOM_VK_DOWN:
controller.scrollLine(true);
break;
}
},
- _notifyMatchesCount: function(result) {
+ _notifyMatchesCount: function(result = this._currentMatchesCountResult) {
+ // The `_currentFound` property is only used for internal bookkeeping.
+ delete result._currentFound;
+ if (result.total == this._currentMatchLimit)
+ result.total = -1;
+
for (let l of this._listeners) {
try {
l.onMatchesCountResult(result);
} catch (ex) {}
}
+
+ this._currentMatchesCountResult = null;
},
requestMatchesCount: function(aWord, aMatchLimit, aLinksOnly) {
if (this._lastFindResult == Ci.nsITypeAheadFind.FIND_NOTFOUND ||
this.searchString == "" || !aWord) {
this._notifyMatchesCount({
total: 0,
current: 0
});
return;
}
let window = this._getWindow();
- let result = {
+ this._currentFoundRange = this._fastFind.getFoundRange();
+ this._currentMatchLimit = aMatchLimit;
+
+ this._currentMatchesCountResult = {
total: 0,
current: 0,
_currentFound: false
};
- let foundRange = this._fastFind.getFoundRange();
this.iterator.start({
finder: this,
limit: aMatchLimit,
linksOnly: aLinksOnly,
- onRange: range => {
- ++result.total;
- if (!result._currentFound) {
- ++result.current;
- result._currentFound = (foundRange &&
- range.startContainer == foundRange.startContainer &&
- range.startOffset == foundRange.startOffset &&
- range.endContainer == foundRange.endContainer &&
- range.endOffset == foundRange.endOffset);
- }
- },
+ listener: this,
useCache: true,
word: aWord
- }).then(() => {
- // The `_currentFound` property is only used for internal bookkeeping.
- delete result._currentFound;
+ }).then(this._notifyMatchesCount.bind(this));
+ },
+
+ // Start of FinderIterator listener
+
+ onIteratorBeforeRestart() {},
+
+ onIteratorRangeFound(range) {
+ let result = this._currentMatchesCountResult;
+ if (!result)
+ return;
- if (result.total == aMatchLimit)
- result.total = -1;
+ ++result.total;
+ if (!result._currentFound) {
+ ++result.current;
+ result._currentFound = (this._currentFoundRange &&
+ range.startContainer == this._currentFoundRange.startContainer &&
+ range.startOffset == this._currentFoundRange.startOffset &&
+ range.endContainer == this._currentFoundRange.endContainer &&
+ range.endOffset == this._currentFoundRange.endOffset);
+ }
+ },
- this._notifyMatchesCount(result);
- });
+ onIteratorReset() {},
+
+ onIteratorRestart({ word, linksOnly }) {
+ this.requestMatchesCount(word, this._currentMatchLimit, linksOnly);
},
+ // END of FinderIterator listener
+
_getWindow: function () {
return this._docShell.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindow);
},
/**
* Get the bounding selection rect in CSS px relative to the origin of the
* top-level content document.
*/
--- a/toolkit/modules/FinderHighlighter.jsm
+++ b/toolkit/modules/FinderHighlighter.jsm
@@ -202,62 +202,71 @@ FinderHighlighter.prototype = {
* @param {String} word Needle to search for and highlight when found
* @param {Boolean} linksOnly Only consider nodes that are links for the search
* @yield {Promise} that resolves once the operation has finished
*/
highlight: Task.async(function* (highlight, word, linksOnly) {
let window = this.finder._getWindow();
let controller = this.finder._getSelectionController(window);
let doc = window.document;
- let found = false;
-
- this.clear();
+ this._found = false;
if (!controller || !doc || !doc.documentElement) {
// Without the selection controller,
// we are unable to (un)highlight any matches
- return found;
+ return this._found;
}
if (highlight) {
yield this.iterator.start({
linksOnly, word,
finder: this.finder,
- onRange: range => {
- this.highlightRange(range, controller, window);
- found = true;
- },
+ listener: this,
useCache: true
});
} else {
this.hide(window);
- this.clear();
- this.iterator.reset();
// Removing the highlighting always succeeds, so return true.
- found = true;
+ this._found = true;
}
- return found;
+ return this._found;
}),
+ // Start of FinderIterator listener
+
+ onIteratorBeforeRestart() {
+ this.clear();
+ },
+
+ onIteratorRangeFound(range) {
+ this.highlightRange(range);
+ this._found = true;
+ },
+
+ onIteratorReset() {
+ this.clear();
+ },
+
+ onIteratorRestart() {},
+
+ // END of FinderIterator listener
+
/**
* Add a range to the find selection, i.e. highlight it, and if it's inside an
* editable node, track it.
*
- * @param {nsIDOMRange} range Range object to be highlighted
- * @param {nsISelectionController} controller Selection controller of the
- * document that the range belongs
- * to
- * @param {nsIDOMWindow} window Window object, whose DOM tree
- * is being traversed
+ * @param {nsIDOMRange} range Range object to be highlighted
*/
- highlightRange(range, controller, window) {
+ highlightRange(range) {
let node = range.startContainer;
let editableNode = this._getEditableNode(node);
+ let window = node.ownerDocument.defaultView;
+ let controller = this.finder._getSelectionController(window);
if (editableNode) {
controller = editableNode.editor.selectionController;
}
if (this._modal) {
this._modalHighlight(range, controller, window);
} else {
let findSelection = controller.getSelection(Ci.nsISelectionController.SELECTION_FIND);
@@ -437,16 +446,18 @@ FinderHighlighter.prototype = {
/**
* When the current page is refreshed or navigated away from, the CanvasFrame
* contents is not valid anymore, i.e. all anonymous content is destroyed.
* We need to clear the references we keep, which'll make sure we redraw
* everything when the user starts to find in page again.
*/
onLocationChange() {
+ this.clear();
+
if (!this._modalHighlightOutline)
return;
if (kDebug)
this._modalHighlightOutline.remove();
try {
this.finder._getWindow().document
.removeAnonymousContent(this._modalHighlightOutline);
@@ -728,23 +739,24 @@ FinderHighlighter.prototype = {
_repaintHighlightAllMask(window, paintContent = true) {
let document = window.document;
const kMaskId = kModalIdPrefix + "-findbar-modalHighlight-outlineMask";
let maskNode = document.createElement("div");
// Make sure the dimmed mask node takes the full width and height that's available.
let {width, height} = this._getWindowDimensions(window);
+ this._lastWindowDimensions = { width, height };
maskNode.setAttribute("id", kMaskId);
maskNode.setAttribute("class", kMaskId + (kDebug ? ` ${kModalIdPrefix}-findbar-debug` : ""));
maskNode.setAttribute("style", `width: ${width}px; height: ${height}px;`);
if (this._brightText)
maskNode.setAttribute("brighttext", "true");
- if (paintContent) {
+ if (paintContent || this._modalHighlightAllMask) {
// Create a DOM node for each rectangle representing the ranges we found.
let maskContent = [];
const kRectClassName = kModalIdPrefix + "-findbar-modalHighlight-rect";
if (this._modalHighlightRectsMap) {
for (let [range, rects] of this._modalHighlightRectsMap) {
for (let rect of rects) {
maskContent.push(`<div class="${kRectClassName}" style="top: ${rect.y}px;
left: ${rect.x}px; height: ${rect.height}px; width: ${rect.width}px;"></div>`);
@@ -782,22 +794,47 @@ FinderHighlighter.prototype = {
},
/**
* Doing a full repaint each time a range is delivered by the highlight iterator
* is way too costly, thus we pipe the frequency down to every
* `kModalHighlightRepaintFreqMs` milliseconds.
*
* @param {nsIDOMWindow} window
+ * @param {Boolean} contentChanged Whether the documents' content changed
+ * in the meantime. This happens when the
+ * DOM is updated whilst the page is loaded.
*/
- _scheduleRepaintOfMask(window) {
+ _scheduleRepaintOfMask(window, contentChanged = false) {
if (this._modalRepaintScheduler)
window.clearTimeout(this._modalRepaintScheduler);
- this._modalRepaintScheduler = window.setTimeout(
- this._repaintHighlightAllMask.bind(this, window), kModalHighlightRepaintFreqMs);
+
+ // When we request to repaint unconditionally, we mean to call
+ // `_repaintHighlightAllMask()` right after the timeout.
+ if (!this._unconditionalRepaintRequested)
+ this._unconditionalRepaintRequested = !contentChanged;
+
+ this._modalRepaintScheduler = window.setTimeout(() => {
+ if (this._unconditionalRepaintRequested) {
+ this._unconditionalRepaintRequested = false;
+ this._repaintHighlightAllMask(window);
+ return;
+ }
+
+ let { width, height } = this._getWindowDimensions(window);
+ if (!this._modalHighlightRectsMap ||
+ (Math.abs(this._lastWindowDimensions.width - width) < 5 &&
+ Math.abs(this._lastWindowDimensions.height - height) < 5)) {
+ return;
+ }
+
+ this.iterator.restart(this.finder);
+ this._lastWindowDimensions = { width, height };
+ this._repaintHighlightAllMask(window);
+ }, kModalHighlightRepaintFreqMs);
},
/**
* The outline that shows/ highlights the current found range is styled and
* animated using CSS. This style can be found in `kModalStyle`, but to have it
* applied on any DOM node we insert using the AnonymousContent API we need to
* inject an agent sheet into the document.
*
@@ -826,36 +863,36 @@ FinderHighlighter.prototype = {
*
* @param {nsIDOMWindow} window
*/
_addModalHighlightListeners(window) {
if (this._highlightListeners)
return;
this._highlightListeners = [
- this._scheduleRepaintOfMask.bind(this, window),
+ this._scheduleRepaintOfMask.bind(this, window, true),
this.hide.bind(this, window, null)
];
- window.addEventListener("DOMContentLoaded", this._highlightListeners[0]);
+ let target = this.iterator._getDocShell(window).chromeEventHandler;
+ target.addEventListener("MozAfterPaint", this._highlightListeners[0]);
window.addEventListener("click", this._highlightListeners[1]);
- window.addEventListener("resize", this._highlightListeners[1]);
},
/**
* Remove event listeners from content.
*
* @param {nsIDOMWindow} window
*/
_removeModalHighlightListeners(window) {
if (!this._highlightListeners)
return;
- window.removeEventListener("DOMContentLoaded", this._highlightListeners[0]);
+ let target = this.iterator._getDocShell(window).chromeEventHandler;
+ target.removeEventListener("MozAfterPaint", this._highlightListeners[0]);
window.removeEventListener("click", this._highlightListeners[1]);
- window.removeEventListener("resize", this._highlightListeners[1]);
this._highlightListeners = null;
},
/**
* For a given node returns its editable parent or null if there is none.
* It's enough to check if node is a text node and its parent's parent is
* instance of nsIDOMNSEditableElement.
--- a/toolkit/modules/FinderIterator.jsm
+++ b/toolkit/modules/FinderIterator.jsm
@@ -37,78 +37,87 @@ this.FinderIterator = {
* Start iterating the active Finder docShell, using the options below. When
* it already started at the request of another consumer, we first yield the
* results we already collected before continuing onward to yield fresh results.
* We make sure to pause every `kIterationSizeMax` iterations to make sure we
* don't block the host process too long. In the case of a break like this, we
* yield `undefined`, instead of a range.
* Upon re-entrance after a break, we check if `stop()` was called during the
* break and if so, we stop iterating.
- * Results are also passed to the `onRange` callback method, along with a flag
- * that specifies if the result comes from the cache or is fresh. The callback
- * also adheres to the `limit` flag.
+ * Results are also passed to the `listener.onIteratorRangeFound` callback
+ * method, along with a flag that specifies if the result comes from the cache
+ * or is fresh. The callback also adheres to the `limit` flag.
* The returned promise is resolved when 1) the limit is reached, 2) when all
* the ranges have been found or 3) when `stop()` is called whilst iterating.
*
* @param {Finder} options.finder Currently active Finder instance
* @param {Number} [options.limit] Limit the amount of results to be
* passed back. Optional, defaults to no
* limit.
* @param {Boolean} [options.linksOnly] Only yield ranges that are inside a
* hyperlink (used by QuickFind).
* Optional, defaults to `false`.
- * @param {Function} options.onRange Callback invoked when a range is found
+ * @param {Object} options.listener Listener object that implements the
+ * following callback functions:
+ * - onIteratorBeforeRestart({Object} iterParams);
+ * - onIteratorRangeFound({nsIDOMRange} range);
+ * - onIteratorReset();
+ * - onIteratorRestart({Object} iterParams);
* @param {Boolean} [options.useCache] Whether to allow results already
* present in the cache or demand fresh.
* Optional, defaults to `false`.
* @param {String} options.word Word to search for
* @return {Promise}
*/
- start({ finder, limit, linksOnly, onRange, useCache, word }) {
+ start({ finder, limit, linksOnly, listener, useCache, word }) {
// Take care of default values for non-required options.
if (typeof limit != "number")
limit = -1;
if (typeof linksOnly != "boolean")
linksOnly = false;
if (typeof useCache != "boolean")
useCache = false;
// Validate the options.
if (!finder)
throw new Error("Missing required option 'finder'");
if (!word)
throw new Error("Missing required option 'word'");
- if (typeof onRange != "function")
- throw new TypeError("Missing valid, required option 'onRange'");
+ if (typeof listener != "object")
+ throw new TypeError("Missing valid, required option 'listener'");
- // Don't add the same listener twice.
- if (this._listeners.has(onRange))
- throw new Error("Already listening to iterator results");
+ // If the listener was added before, make sure the promise is resolved before
+ // we replace it with another.
+ if (this._listeners.has(listener)) {
+ let { onEnd } = this._listeners.get(listener);
+ if (onEnd)
+ onEnd();
+ }
let window = finder._getWindow();
let resolver;
let promise = new Promise(resolve => resolver = resolve);
let iterParams = { linksOnly, useCache, word };
- this._listeners.set(onRange, { limit, onEnd: resolver });
+ this._listeners.set(listener, { limit, onEnd: resolver });
// If we're not running anymore and we're requesting the previous result, use it.
if (!this.running && this._previousResultAvailable(iterParams)) {
- this._yieldPreviousResult(onRange, window);
+ this._yieldPreviousResult(listener, window);
return promise;
}
if (this.running) {
// Double-check if we're not running the iterator with a different set of
// parameters, otherwise throw an error with the most common reason.
if (!this._areParamsEqual(this._currentParams, iterParams))
throw new Error(`We're currently iterating over '${this._currentParams.word}', not '${word}'`);
// if we're still running, yield the set we have built up this far.
- this._yieldIntermediateResult(onRange, window);
+ this._yieldIntermediateResult(listener, window);
return promise;
}
// Start!
this.running = true;
this._currentParams = iterParams;
this._findAllRanges(finder, window, ++this._spawnId);
@@ -137,32 +146,54 @@ this.FinderIterator = {
this._catchingUp.clear();
this._currentParams = null;
this.ranges = [];
this.running = false;
for (let [, { onEnd }] of this._listeners)
onEnd();
- this._listeners.clear();
+ },
+
+ /**
+ * Stops the iteration that currently running, if it is, and start a new one
+ * with the exact same params as before.
+ *
+ * @param {Finder} finder Currently active Finder instance
+ */
+ restart(finder) {
+ // Capture current iterator params before we stop the show.
+ let iterParams = this.params;
+ if (!iterParams.word)
+ return;
+ this.stop();
+
+ // Restart manually.
+ this.running = true;
+ this._currentParams = iterParams;
+
+ this._notifyListeners("beforeRestart", iterParams);
+ this._findAllRanges(finder, finder._getWindow(), ++this._spawnId);
+ this._notifyListeners("restart", iterParams);
},
/**
* Reset the internal state of the iterator. Typically this would be called
* when the docShell is not active anymore, which makes the current and cached
* previous result invalid.
* If the iterator is running, it will be stopped as soon as possible.
*/
reset() {
this._catchingUp.clear();
this._currentParams = this._previousParams = null;
this._previousRanges = [];
this.ranges = [];
this.running = false;
+ this._notifyListeners("reset");
for (let [, { onEnd }] of this._listeners)
onEnd();
this._listeners.clear();
},
/**
* Check if the currently running iterator parameters are the same as the ones
* passed through the arguments. When `true`, we can keep it running as-is and
@@ -175,16 +206,34 @@ this.FinderIterator = {
*/
continueRunning({ linksOnly, word }) {
return (this.running &&
this._currentParams.linksOnly === linksOnly &&
this._currentParams.word == word);
},
/**
+ * Safely notify all registered listeners that an event has occurred.
+ *
+ * @param {String} callback Name of the callback to invoke
+ * @param {...[mixed]} params Arbitrary amount of arguments that will be
+ * passed to the callback in-order.
+ */
+ _notifyListeners(callback, ...params) {
+ callback = "onIterator" + callback.charAt(0).toUpperCase() + callback.substr(1);
+ for (let [listener] of this._listeners) {
+ try {
+ listener[callback](...params);
+ } catch (ex) {
+ Cu.reportError("FinderIterator Error: " + ex);
+ }
+ }
+ },
+
+ /**
* Internal; check if an iteration request is available in the previous result
* that we cached.
*
* @param {Boolean} options.linksOnly Whether to search for the word to be
* present in links only
* @param {Boolean} options.useCache Whether the consumer wants to use the
* cached previous result at all
* @param {String} options.word The word being searched for
@@ -211,99 +260,97 @@ this.FinderIterator = {
/**
* Internal; iterate over a predefined set of ranges that have been collected
* before.
* Also here, we make sure to pause every `kIterationSizeMax` iterations to
* make sure we don't block the host process too long. In the case of a break
* like this, we yield `undefined`, instead of a range.
*
- * @param {Function} onRange Callback invoked when a range is found
+ * @param {Object} listener Listener object
* @param {Array} rangeSource Set of ranges to iterate over
* @param {nsIDOMWindow} window The window object is only really used
* for access to `setTimeout`
* @yield {nsIDOMRange}
*/
- _yieldResult: function* (onRange, rangeSource, window) {
+ _yieldResult: function* (listener, rangeSource, window) {
// We keep track of the number of iterations to allow a short pause between
// every `kIterationSizeMax` number of iterations.
let iterCount = 0;
- let { limit, onEnd } = this._listeners.get(onRange);
+ let { limit, onEnd } = this._listeners.get(listener);
let ranges = rangeSource.slice(0, limit > -1 ? limit : undefined);
for (let range of ranges) {
try {
range.startContainer;
} catch (ex) {
// Don't yield dead objects, so use the escape hatch.
if (ex.message.includes("dead object"))
return;
}
// Pass a flag that is `true` when we're returning the result from a
// cached previous iteration.
- onRange(range, !this.running);
+ listener.onIteratorRangeFound(range, !this.running);
yield range;
if (++iterCount >= kIterationSizeMax) {
iterCount = 0;
// Make sure to save the current limit for later.
- this._listeners.set(onRange, { limit, onEnd });
+ this._listeners.set(listener, { limit, onEnd });
// Sleep for the rest of this cycle.
yield new Promise(resolve => window.setTimeout(resolve, 0));
// After a sleep, the set of ranges may have updated.
ranges = rangeSource.slice(0, limit > -1 ? limit : undefined);
}
if (limit !== -1 && --limit === 0) {
// We've reached our limit; no need to do more work.
- this._listeners.delete(onRange);
+ this._listeners.delete(listener);
onEnd();
return;
}
}
// Save the updated limit globally.
- this._listeners.set(onRange, { limit, onEnd });
+ this._listeners.set(listener, { limit, onEnd });
},
/**
* Internal; iterate over the set of previously found ranges. Meanwhile it'll
* mark the listener as 'catching up', meaning it will not receive fresh
* results from a running iterator.
*
- * @param {Function} onRange Callback invoked when a range is found
- * @param {nsIDOMWindow} window The window object is only really used
- * for access to `setTimeout`
+ * @param {Object} listener Listener object
+ * @param {nsIDOMWindow} window The window object is only really used
+ * for access to `setTimeout`
* @yield {nsIDOMRange}
*/
- _yieldPreviousResult: Task.async(function* (onRange, window) {
- this._catchingUp.add(onRange);
- yield* this._yieldResult(onRange, this._previousRanges, window);
- this._catchingUp.delete(onRange);
- let { onEnd } = this._listeners.get(onRange);
- if (onEnd) {
+ _yieldPreviousResult: Task.async(function* (listener, window) {
+ this._catchingUp.add(listener);
+ yield* this._yieldResult(listener, this._previousRanges, window);
+ this._catchingUp.delete(listener);
+ let { onEnd } = this._listeners.get(listener);
+ if (onEnd)
onEnd();
- this._listeners.delete(onRange);
- }
}),
/**
* Internal; iterate over the set of already found ranges. Meanwhile it'll
* mark the listener as 'catching up', meaning it will not receive fresh
* results from the running iterator.
*
- * @param {Function} onRange Callback invoked when a range is found
- * @param {nsIDOMWindow} window The window object is only really used
- * for access to `setTimeout`
+ * @param {Object} listener Listener object
+ * @param {nsIDOMWindow} window The window object is only really used
+ * for access to `setTimeout`
* @yield {nsIDOMRange}
*/
- _yieldIntermediateResult: Task.async(function* (onRange, window) {
- this._catchingUp.add(onRange);
- yield* this._yieldResult(onRange, this.ranges, window);
- this._catchingUp.delete(onRange);
+ _yieldIntermediateResult: Task.async(function* (listener, window) {
+ this._catchingUp.add(listener);
+ yield* this._yieldResult(listener, this.ranges, window);
+ this._catchingUp.delete(listener);
}),
/**
* Internal; see the documentation of the start() method above.
*
* @param {Finder} finder Currently active Finder instance
* @param {nsIDOMWindow} window The window to search in
* @param {Number} spawnId Since `stop()` is synchronous and this method
@@ -326,31 +373,31 @@ this.FinderIterator = {
// Deal with links-only mode here.
if (linksOnly && this._rangeStartsInLink(range))
continue;
this.ranges.push(range);
// Call each listener with the range we just found.
- for (let [onRange, { limit, onEnd }] of this._listeners) {
- if (this._catchingUp.has(onRange))
+ for (let [listener, { limit, onEnd }] of this._listeners) {
+ if (this._catchingUp.has(listener))
continue;
- onRange(range);
+ listener.onIteratorRangeFound(range);
if (limit !== -1 && --limit === 0) {
// We've reached our limit; no need to do more work for this listener.
- this._listeners.delete(onRange);
+ this._listeners.delete(listener);
onEnd();
continue;
}
// Save the updated limit globally.
- this._listeners.set(onRange, { limit, onEnd });
+ this._listeners.set(listener, { limit, onEnd });
}
yield range;
if (++iterCount >= kIterationSizeMax) {
iterCount = 0;
// Sleep for the rest of this cycle.
yield new Promise(resolve => window.setTimeout(resolve, 0));
--- a/toolkit/modules/tests/xpcshell/test_FinderIterator.js
+++ b/toolkit/modules/tests/xpcshell/test_FinderIterator.js
@@ -38,96 +38,104 @@ function prepareIterator(findText, range
add_task(function* test_start() {
let findText = "test";
let rangeCount = 300;
prepareIterator(findText, rangeCount);
let count = 0;
yield FinderIterator.start({
finder: gMockFinder,
- onRange: range => {
- ++count;
- Assert.equal(range.toString(), findText, "Text content should match");
+ listener: {
+ onIteratorRangeFound(range) {
+ ++count;
+ Assert.equal(range.toString(), findText, "Text content should match");
+ }
},
word: findText
});
Assert.equal(rangeCount, count, "Amount of ranges yielded should match!");
Assert.ok(!FinderIterator.running, "Running state should match");
Assert.equal(FinderIterator._previousRanges.length, rangeCount, "Ranges cache should match");
+
+ FinderIterator.reset();
});
add_task(function* test_valid_arguments() {
let findText = "foo";
let rangeCount = 20;
prepareIterator(findText, rangeCount);
let count = 0;
yield FinderIterator.start({
finder: gMockFinder,
- onRange: range => ++count,
+ listener: { onIteratorRangeFound(range) { ++count; } },
word: findText
});
let params = FinderIterator._previousParams;
Assert.ok(!params.linksOnly, "Default for linksOnly is false");
Assert.ok(!params.useCache, "Default for useCache is false");
Assert.equal(params.word, findText, "Words should match");
count = 0;
Assert.throws(() => FinderIterator.start({
- onRange: range => ++count,
+ listener: { onIteratorRangeFound(range) { ++count; } },
word: findText
}), /Missing required option 'finder'/, "Should throw when missing an argument");
FinderIterator.reset();
Assert.throws(() => FinderIterator.start({
finder: gMockFinder,
word: findText
- }), /Missing valid, required option 'onRange'/, "Should throw when missing an argument");
+ }), /Missing valid, required option 'listener'/, "Should throw when missing an argument");
FinderIterator.reset();
Assert.throws(() => FinderIterator.start({
finder: gMockFinder,
- onRange: range => ++count
+ listener: { onIteratorRangeFound(range) { ++count; } }
}), /Missing required option 'word'/, "Should throw when missing an argument");
FinderIterator.reset();
Assert.equal(count, 0, "No ranges should've been counted");
+
+ FinderIterator.reset();
});
add_task(function* test_stop() {
let findText = "bar";
let rangeCount = 120;
prepareIterator(findText, rangeCount);
let count = 0;
let whenDone = FinderIterator.start({
finder: gMockFinder,
- onRange: range => ++count,
+ listener: { onIteratorRangeFound(range) { ++count; } },
word: findText
});
FinderIterator.stop();
yield whenDone;
Assert.equal(count, 100, "Number of ranges should match `kIterationSizeMax`");
+
+ FinderIterator.reset();
});
add_task(function* test_reset() {
let findText = "tik";
let rangeCount = 142;
prepareIterator(findText, rangeCount);
let count = 0;
let whenDone = FinderIterator.start({
finder: gMockFinder,
- onRange: range => ++count,
+ listener: { onIteratorRangeFound(range) { ++count; } },
word: findText
});
Assert.ok(FinderIterator.running, "Yup, running we are");
Assert.equal(count, 100, "Number of ranges should match `kIterationSizeMax`");
Assert.equal(FinderIterator.ranges.length, 100,
"Number of ranges should match `kIterationSizeMax`");
@@ -146,28 +154,28 @@ add_task(function* test_parallel_starts(
let findText = "tak";
let rangeCount = 2143;
prepareIterator(findText, rangeCount);
// Start off the iterator.
let count = 0;
let whenDone = FinderIterator.start({
finder: gMockFinder,
- onRange: range => ++count,
+ listener: { onIteratorRangeFound(range) { ++count; } },
word: findText
});
// Start again after a few milliseconds.
yield new Promise(resolve => gMockWindow.setTimeout(resolve, 2));
Assert.ok(FinderIterator.running, "We ought to be running here");
let count2 = 0;
let whenDone2 = FinderIterator.start({
finder: gMockFinder,
- onRange: range => ++count2,
+ listener: { onIteratorRangeFound(range) { ++count2; } },
word: findText
});
// Let the iterator run for a little while longer before we assert the world.
yield new Promise(resolve => gMockWindow.setTimeout(resolve, 10));
FinderIterator.stop();
Assert.ok(!FinderIterator.running, "Stop means stop");