mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 13:51:41 +00:00
Bug 1290842 - reduce the amount calls to the highlighter upon the first find action and improve the behavior when modal highlighting is not enabled now that we have a FinderHighlighter class we can use. r=jaws
MozReview-Commit-ID: K01dpqp8LSf
This commit is contained in:
parent
22b8bf8d31
commit
ebc9f1764d
@ -587,6 +587,23 @@
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<method name="_setHighlightTimeout">
|
||||
<body><![CDATA[
|
||||
if (this._highlightTimeout)
|
||||
clearTimeout(this._highlightTimeout);
|
||||
|
||||
let word = this._findField.value;
|
||||
// Bug 429723. Don't attempt to highlight ""
|
||||
if (!this._highlightAll || !word)
|
||||
return;
|
||||
|
||||
this._highlightTimeout = setTimeout(() => {
|
||||
this.browser.finder.highlight(true, word,
|
||||
this._findMode == this.FIND_LINKS);
|
||||
}, 500);
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<!--
|
||||
- Updates the case-sensitivity mode of the findbar and its UI.
|
||||
- @param [optional] aString
|
||||
@ -681,8 +698,7 @@
|
||||
// Just set the pref; our observer will change the find bar behavior.
|
||||
prefsvc.setBoolPref("findbar.entireword", aEntireWord);
|
||||
|
||||
if (this.getElement("highlight").checked)
|
||||
this._setHighlightTimeout();
|
||||
this._setHighlightTimeout();
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
@ -1026,8 +1042,7 @@
|
||||
}
|
||||
|
||||
this._enableFindButtons(val);
|
||||
if (this.getElement("highlight").checked)
|
||||
this._setHighlightTimeout();
|
||||
this._setHighlightTimeout();
|
||||
|
||||
this._updateCaseSensitivity(val);
|
||||
this._updateEntireWord();
|
||||
@ -1070,18 +1085,6 @@
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<method name="_setHighlightTimeout">
|
||||
<body><![CDATA[
|
||||
if (this._highlightTimeout)
|
||||
clearTimeout(this._highlightTimeout);
|
||||
this._highlightTimeout =
|
||||
setTimeout(function(aSelf) {
|
||||
aSelf.toggleHighlight(false);
|
||||
aSelf.toggleHighlight(true);
|
||||
}, 500, this);
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<method name="_findAgain">
|
||||
<parameter name="aFindPrevious"/>
|
||||
<body><![CDATA[
|
||||
|
@ -134,10 +134,12 @@ Finder.prototype = {
|
||||
|
||||
set caseSensitive(aSensitive) {
|
||||
this._fastFind.caseSensitive = aSensitive;
|
||||
this.iterator.reset();
|
||||
},
|
||||
|
||||
set entireWord(aEntireWord) {
|
||||
this._fastFind.entireWord = aEntireWord;
|
||||
this.iterator.reset();
|
||||
},
|
||||
|
||||
get highlighter() {
|
||||
|
@ -19,6 +19,7 @@ XPCOMUtils.defineLazyGetter(this, "kDebug", () => {
|
||||
});
|
||||
|
||||
const kModalHighlightRepaintFreqMs = 10;
|
||||
const kHighlightAllPref = "findbar.highlightAll";
|
||||
const kModalHighlightPref = "findbar.modalHighlight";
|
||||
const kFontPropsCSS = ["color", "font-family", "font-kerning", "font-size",
|
||||
"font-size-adjust", "font-stretch", "font-variant", "font-weight", "letter-spacing",
|
||||
@ -100,7 +101,6 @@ const kModalStyle = `
|
||||
.findbar-modalHighlight-outlineMask[brighttext] > .findbar-modalHighlight-rect {
|
||||
background: #000;
|
||||
}`;
|
||||
const kXULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
||||
|
||||
function mockAnonymousContentNode(domNode) {
|
||||
return {
|
||||
@ -137,8 +137,11 @@ function mockAnonymousContentNode(domNode) {
|
||||
* @param {Finder} finder Finder.jsm instance
|
||||
*/
|
||||
function FinderHighlighter(finder) {
|
||||
this.finder = finder;
|
||||
this._currentFoundRange = null;
|
||||
this._modal = Services.prefs.getBoolPref(kModalHighlightPref);
|
||||
this._highlightAll = Services.prefs.getBoolPref(kHighlightAllPref);
|
||||
this.finder = finder;
|
||||
this.visible = false;
|
||||
}
|
||||
|
||||
FinderHighlighter.prototype = {
|
||||
@ -259,50 +262,47 @@ FinderHighlighter.prototype = {
|
||||
* If modal highlighting is enabled, show the dimmed background that will overlay
|
||||
* the page.
|
||||
*
|
||||
* @param {nsIDOMWindow} window The dimmed background will overlay this window.
|
||||
* Optional, defaults to the finder window.
|
||||
* @return {AnonymousContent} Reference to the node inserted into the
|
||||
* CanvasFrame. It'll also be stored in the
|
||||
* `_modalHighlightOutline` member variable.
|
||||
* @param {nsIDOMWindow} window The dimmed background will overlay this window.
|
||||
* Optional, defaults to the finder window.
|
||||
*/
|
||||
show(window = null) {
|
||||
if (!this._modal)
|
||||
return null;
|
||||
if (!this._modal || this.visible)
|
||||
return;
|
||||
|
||||
this.visible = true;
|
||||
window = window || this.finder._getWindow();
|
||||
let anonNode = this._maybeCreateModalHighlightNodes(window);
|
||||
this._maybeCreateModalHighlightNodes(window);
|
||||
this._addModalHighlightListeners(window);
|
||||
|
||||
return anonNode;
|
||||
},
|
||||
|
||||
/**
|
||||
* Clear all highlighted matches. If modal highlighting is enabled and
|
||||
* the outline + dimmed background is currently visible, both will be hidden.
|
||||
*
|
||||
* @param {nsIDOMWindow} window The dimmed background will overlay this window.
|
||||
* Optional, defaults to the finder window.
|
||||
* @param {nsIDOMRange} skipRange A range that should not be removed from the
|
||||
* find selection.
|
||||
*/
|
||||
hide(window = null) {
|
||||
hide(window = null, skipRange = null) {
|
||||
window = window || this.finder._getWindow();
|
||||
|
||||
let doc = window.document;
|
||||
let controller = this.finder._getSelectionController(window);
|
||||
let sel = controller.getSelection(Ci.nsISelectionController.SELECTION_FIND);
|
||||
sel.removeAllRanges();
|
||||
this._clearSelection(this.finder._getSelectionController(window), skipRange);
|
||||
|
||||
// Next, check our editor cache, for editors belonging to this
|
||||
// document
|
||||
if (this._editors) {
|
||||
for (let x = this._editors.length - 1; x >= 0; --x) {
|
||||
if (this._editors[x].document == doc) {
|
||||
sel = this._editors[x].selectionController
|
||||
.getSelection(Ci.nsISelectionController.SELECTION_FIND);
|
||||
sel.removeAllRanges();
|
||||
this._clearSelection(this._editors[x].selectionController, skipRange);
|
||||
// We don't need to listen to this editor any more
|
||||
this._unhookListenersAtIndex(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!this._modal)
|
||||
if (!this._modal || !this.visible)
|
||||
return;
|
||||
|
||||
if (this._modalHighlightOutline)
|
||||
@ -311,6 +311,8 @@ FinderHighlighter.prototype = {
|
||||
this._removeHighlightAllMask(window);
|
||||
this._removeModalHighlightListeners(window);
|
||||
delete this._brightText;
|
||||
|
||||
this.visible = false;
|
||||
},
|
||||
|
||||
/**
|
||||
@ -335,52 +337,69 @@ FinderHighlighter.prototype = {
|
||||
* by the consumer of the Finder.
|
||||
*/
|
||||
update(data) {
|
||||
if (!this._modal)
|
||||
let window = this.finder._getWindow();
|
||||
let foundRange = this.finder._fastFind.getFoundRange();
|
||||
if (!this._modal) {
|
||||
if (this._highlightAll) {
|
||||
this.hide(window, foundRange);
|
||||
let params = this.iterator.params;
|
||||
if (params.word)
|
||||
this.highlight(true, params.word, params.linksOnly);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Place the match placeholder on top of the current found range.
|
||||
let foundRange = this.finder._fastFind.getFoundRange();
|
||||
if (data.result == Ci.nsITypeAheadFind.FIND_NOTFOUND || !foundRange) {
|
||||
this.hide();
|
||||
return;
|
||||
}
|
||||
|
||||
let window = this.finder._getWindow();
|
||||
let textContent = this._getRangeContentArray(foundRange);
|
||||
if (!textContent.length) {
|
||||
this.hide(window);
|
||||
return;
|
||||
let outlineNode;
|
||||
if (foundRange !== this._currentFoundRange || data.findAgain) {
|
||||
this._currentFoundRange = foundRange;
|
||||
|
||||
let textContent = this._getRangeContentArray(foundRange);
|
||||
if (!textContent.length) {
|
||||
this.hide(window);
|
||||
return;
|
||||
}
|
||||
|
||||
let rect = foundRange.getBoundingClientRect();
|
||||
let fontStyle = this._getRangeFontStyle(foundRange);
|
||||
if (typeof this._brightText == "undefined") {
|
||||
this._brightText = this._isColorBright(fontStyle.color);
|
||||
}
|
||||
|
||||
// Text color in the outline is determined by our stylesheet.
|
||||
delete fontStyle.color;
|
||||
|
||||
if (!this.visible)
|
||||
this.show(window);
|
||||
else
|
||||
this._maybeCreateModalHighlightNodes(window);
|
||||
|
||||
outlineNode = this._modalHighlightOutline;
|
||||
outlineNode.setTextContentForElement(kModalOutlineId + "-text", textContent.join(" "));
|
||||
outlineNode.setAttributeForElement(kModalOutlineId + "-text", "style",
|
||||
this._getHTMLFontStyle(fontStyle));
|
||||
|
||||
if (typeof outlineNode.getAttributeForElement(kModalOutlineId, "hidden") == "string")
|
||||
outlineNode.removeAttributeForElement(kModalOutlineId, "hidden");
|
||||
let { scrollX, scrollY } = this._getScrollPosition(window);
|
||||
outlineNode.setAttributeForElement(kModalOutlineId, "style",
|
||||
`top: ${scrollY + rect.top}px; left: ${scrollX + rect.left}px`);
|
||||
}
|
||||
|
||||
let rect = foundRange.getBoundingClientRect();
|
||||
let fontStyle = this._getRangeFontStyle(foundRange);
|
||||
if (typeof this._brightText == "undefined") {
|
||||
this._brightText = this._isColorBright(fontStyle.color);
|
||||
}
|
||||
|
||||
// Text color in the outline is determined by our stylesheet.
|
||||
delete fontStyle.color;
|
||||
|
||||
let anonNode = this.show(window);
|
||||
|
||||
anonNode.setTextContentForElement(kModalOutlineId + "-text", textContent.join(" "));
|
||||
anonNode.setAttributeForElement(kModalOutlineId + "-text", "style",
|
||||
this._getHTMLFontStyle(fontStyle));
|
||||
|
||||
if (typeof anonNode.getAttributeForElement(kModalOutlineId, "hidden") == "string")
|
||||
anonNode.removeAttributeForElement(kModalOutlineId, "hidden");
|
||||
let { scrollX, scrollY } = this._getScrollPosition(window);
|
||||
anonNode.setAttributeForElement(kModalOutlineId, "style",
|
||||
`top: ${scrollY + rect.top}px; left: ${scrollX + rect.left}px`);
|
||||
|
||||
if (typeof anonNode.getAttributeForElement(kModalOutlineId, "grow") == "string")
|
||||
outlineNode = this._modalHighlightOutline;
|
||||
if (typeof outlineNode.getAttributeForElement(kModalOutlineId, "grow") == "string")
|
||||
return;
|
||||
|
||||
window.requestAnimationFrame(() => {
|
||||
anonNode.setAttributeForElement(kModalOutlineId, "grow", true);
|
||||
outlineNode.setAttributeForElement(kModalOutlineId, "grow", true);
|
||||
this._listenForOutlineEvent(kModalOutlineId, "transitionend", () => {
|
||||
try {
|
||||
anonNode.removeAttributeForElement(kModalOutlineId, "grow");
|
||||
outlineNode.removeAttributeForElement(kModalOutlineId, "grow");
|
||||
} catch (ex) {}
|
||||
});
|
||||
});
|
||||
@ -441,12 +460,33 @@ FinderHighlighter.prototype = {
|
||||
* @param {Boolean} highlightAll
|
||||
*/
|
||||
onHighlightAllChange(highlightAll) {
|
||||
this._highlightAll = highlightAll;
|
||||
if (this._modal && !highlightAll) {
|
||||
this.clear();
|
||||
this._scheduleRepaintOfMask(this.finder._getWindow());
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Utility; removes all ranges from the find selection that belongs to a
|
||||
* controller. Optionally skips a specific range.
|
||||
*
|
||||
* @param {nsISelectionController} controller
|
||||
* @param {nsIDOMRange} skipRange
|
||||
*/
|
||||
_clearSelection(controller, skipRange = null) {
|
||||
let sel = controller.getSelection(Ci.nsISelectionController.SELECTION_FIND);
|
||||
if (!skipRange) {
|
||||
sel.removeAllRanges();
|
||||
} else {
|
||||
for (let i = sel.rangeCount - 1; i >= 0; --i) {
|
||||
let range = sel.getRangeAt(i);
|
||||
if (range !== skipRange)
|
||||
sel.removeRange(range);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Utility; get the nsIDOMWindowUtils for a window.
|
||||
*
|
||||
@ -605,14 +645,16 @@ FinderHighlighter.prototype = {
|
||||
* Lazily insert the nodes we need as anonymous content into the CanvasFrame
|
||||
* of a window.
|
||||
*
|
||||
* @param {nsIDOMWindow} window Window to draw in.
|
||||
* @return {AnonymousContent} The reference to the outline node, NOT the mask.
|
||||
* @param {nsIDOMWindow} window Window to draw in.
|
||||
*/
|
||||
_maybeCreateModalHighlightNodes(window) {
|
||||
if (this._modalHighlightOutline) {
|
||||
if (!this._modalHighlightAllMask)
|
||||
this._repaintHighlightAllMask(window);
|
||||
return this._modalHighlightOutline;
|
||||
if (!this._modalHighlightAllMask) {
|
||||
// Make sure to at least show the dimmed background.
|
||||
this._repaintHighlightAllMask(window, false);
|
||||
this._scheduleRepaintOfMask(window);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
let document = window.document;
|
||||
@ -623,7 +665,7 @@ FinderHighlighter.prototype = {
|
||||
this._maybeCreateModalHighlightNodes(window);
|
||||
};
|
||||
document.addEventListener("visibilitychange", onVisibilityChange);
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
|
||||
this._maybeInstallStyleSheet(window);
|
||||
@ -641,13 +683,12 @@ FinderHighlighter.prototype = {
|
||||
outlineBox.appendChild(outlineBoxText);
|
||||
|
||||
container.appendChild(outlineBox);
|
||||
|
||||
this._repaintHighlightAllMask(window);
|
||||
|
||||
this._modalHighlightOutline = kDebug ?
|
||||
mockAnonymousContentNode(document.body.appendChild(container.firstChild)) :
|
||||
document.insertAnonymousContent(container);
|
||||
return this._modalHighlightOutline;
|
||||
|
||||
// Make sure to at least show the dimmed background.
|
||||
this._repaintHighlightAllMask(window, false);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -656,8 +697,9 @@ FinderHighlighter.prototype = {
|
||||
* the ranges that were found.
|
||||
*
|
||||
* @param {nsIDOMWindow} window Window to draw in.
|
||||
* @param {Boolean} [paintContent]
|
||||
*/
|
||||
_repaintHighlightAllMask(window) {
|
||||
_repaintHighlightAllMask(window, paintContent = true) {
|
||||
let document = window.document;
|
||||
|
||||
const kMaskId = kModalIdPrefix + "-findbar-modalHighlight-outlineMask";
|
||||
@ -671,18 +713,20 @@ FinderHighlighter.prototype = {
|
||||
if (this._brightText)
|
||||
maskNode.setAttribute("brighttext", "true");
|
||||
|
||||
// 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 rects of this._modalHighlightRectsMap.values()) {
|
||||
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>`);
|
||||
if (paintContent) {
|
||||
// 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 rects of this._modalHighlightRectsMap.values()) {
|
||||
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>`);
|
||||
}
|
||||
}
|
||||
}
|
||||
maskNode.innerHTML = maskContent.join("");
|
||||
}
|
||||
maskNode.innerHTML = maskContent.join("");
|
||||
|
||||
// Always remove the current mask and insert it a-fresh, because we're not
|
||||
// free to alter DOM nodes inside the CanvasFrame.
|
||||
|
@ -29,6 +29,10 @@ this.FinderIterator = {
|
||||
// Expose `kIterationSizeMax` to the outside world for unit tests to use.
|
||||
get kIterationSizeMax() { return kIterationSizeMax },
|
||||
|
||||
get params() {
|
||||
return Object.assign({}, this._currentParams || this._previousParams);
|
||||
},
|
||||
|
||||
/**
|
||||
* Start iterating the active Finder docShell, using the options below. When
|
||||
* it already started at the request of another consumer, we first yield the
|
||||
|
Loading…
Reference in New Issue
Block a user