This commit is contained in:
Robert O'Callahan 2009-04-06 15:56:15 +12:00
Родитель c509a93b95 df02e37eae
Коммит 89a2f08622
4 изменённых файлов: 73 добавлений и 748 удалений

Просмотреть файл

@ -66,8 +66,6 @@ _TEST_FILES = findbar_window.xul \
test_bug437844.xul \
bug451286_window.xul \
test_bug451286.xul \
bug451540_window.xul \
test_bug451540.xul \
test_bug471776.xul \
test_popup_preventdefault_chrome.xul \
window_popup_preventdefault_chrome.xul \

Просмотреть файл

@ -1,212 +0,0 @@
<?xml version="1.0"?>
<!-- ***** BEGIN LICENSE BLOCK *****
- Version: MPL 1.1/GPL 2.0/LGPL 2.1
-
- The contents of this file are subject to the Mozilla Public License Version
- 1.1 (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
- http://www.mozilla.org/MPL/
-
- Software distributed under the License is distributed on an "AS IS" basis,
- WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- for the specific language governing rights and limitations under the
- License.
-
- The Original Code is Findbar Test code
-
- The Initial Developer of the Original Code is
- Graeme McCutcheon <graememcc_firefox@graeme-online.co.uk>.
- Portions created by the Initial Developer are Copyright (C) 2009
- the Initial Developer. All Rights Reserved.
-
- Contributor(s):
-
-
- Alternatively, the contents of this file may be used under the terms of
- either the GNU General Public License Version 2 or later (the "GPL"), or
- the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- in which case the provisions of the GPL or the LGPL are applicable instead
- of those above. If you wish to allow use of your version of this file only
- under the terms of either the GPL or the LGPL, and not to allow others to
- use your version of this file under the terms of the MPL, indicate your
- decision by deleting the provisions above and replace them with the notice
- and other provisions required by the GPL or the LGPL. If you do not delete
- the provisions above, a recipient may use your version of this file under
- the terms of any one of the MPL, the GPL or the LGPL.
-
- ***** END LICENSE BLOCK ***** -->
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<window id="451540test"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
width="600"
height="600"
onload="onLoad();"
title="451540 test">
<script type="application/javascript"><![CDATA[
const Ci = Components.interfaces;
const Cc = Components.classes;
const Cr = Components.results;
const SEARCH_TEXT = "minefield";
var gFindBar = null;
var gBrowser;
var imports = [ "SimpleTest", "ok", "finish"];
for each (var import in imports) {
window[import] = window.opener.wrappedJSObject[import];
}
function finishTest() {
window.close();
SimpleTest.finish();
}
function onLoad() {
var _delayedOnLoad = function() {
gFindBar = document.getElementById("FindToolbar");
gBrowser = document.getElementById("content");
gBrowser.addEventListener("pageshow", onPageShow, false);
var data = 'data:text/html,<input id="inp" type="text" />';
data +='<textarea id="tarea"/>'
gBrowser.loadURI(data);
}
let tm = Cc["@mozilla.org/thread-manager;1"].
getService(Ci.nsIThreadManager);
tm.mainThread.dispatch({
run: function() _delayedOnLoad()
}, Ci.nsIThread.DISPATCH_NORMAL);
}
function resetForNextTest(aElement, aText) {
if (!aText)
aText = SEARCH_TEXT;
// Turn off highlighting
var highlightButton = gFindBar.getElement("highlight");
if (highlightButton.checked)
highlightButton.click();
// Initialise input
aElement.value = aText;
gFindBar._findField.value = SEARCH_TEXT;
// Perform search and turn on highlighting
gFindBar._find();
highlightButton.click();
aElement.focus();
}
function synthesizeKey(target, isKeyCode, key, ctrlKey, shiftKey) {
try {
var event = document.createEvent("KeyEvents");
if (isKeyCode) {
event.initKeyEvent("keypress", true, true, null, ctrlKey, false,
shiftKey, false, key, 0);
} else {
event.initKeyEvent("keypress", true, true, null, ctrlKey, false,
shiftKey, false, 0, key);
}
target.dispatchEvent(event);
} catch (e) {}
}
function testInput(aElement, aTestTypeText) {
// Initialise the findbar
var matchCase = gFindBar.getElement("find-case-sensitive");
if (matchCase.checked)
matchCase.doCommand();
// First check match has been correctly highlighted
resetForNextTest(aElement);
if (aElement instanceof Ci.nsIDOMNSEditableElement) {
var controller = aElement.editor.selectionController;
var selection = controller.getSelection(controller.SELECTION_FIND);
ok(selection.rangeCount == 1, aTestTypeText +
" correctly highlighted match");
// Test 2: check highlight removed when text added within the highlight
synthesizeKey(aElement, true, KeyEvent.DOM_VK_UP, true, false);
synthesizeKey(aElement, true, KeyEvent.DOM_VK_LEFT, true, false);
synthesizeKey(aElement, true, KeyEvent.DOM_VK_RIGHT, false, false);
synthesizeKey(aElement, false, KeyEvent.DOM_VK_A, false, false);
ok(selection.rangeCount == 0, aTestTypeText +
" correctly removed highlight on text insertion");
// Test 3: check highlighting remains when text added before highlight
resetForNextTest(aElement);
synthesizeKey(aElement, true, KeyEvent.DOM_VK_UP, true, false);
synthesizeKey(aElement, true, KeyEvent.DOM_VK_LEFT, true, false);
synthesizeKey(aElement, false, KeyEvent.DOM_VK_A, false, false);
ok(selection.rangeCount == 1, aTestTypeText +
" highlight correctly remained on text insertion at start");
// Test 4: check highlighting remains when text added after highlight
resetForNextTest(aElement);
synthesizeKey(aElement, true, KeyEvent.DOM_VK_UP, true, false);
synthesizeKey(aElement, true, KeyEvent.DOM_VK_LEFT, true, false);
for (var x = 0; x < SEARCH_TEXT.length; x++)
synthesizeKey(aElement, true, KeyEvent.DOM_VK_RIGHT, false, false);
synthesizeKey(aElement, false, KeyEvent.DOM_VK_A, false, false);
ok(selection.rangeCount == 1, aTestTypeText +
" highlight correctly remained on text insertion at end");
// Test 5: deleting text within the highlight
resetForNextTest(aElement);
synthesizeKey(aElement, true, KeyEvent.DOM_VK_UP, true, false);
synthesizeKey(aElement, true, KeyEvent.DOM_VK_LEFT, true, false);
synthesizeKey(aElement, true, KeyEvent.DOM_VK_RIGHT, false, false);
synthesizeKey(aElement, true, KeyEvent.DOM_VK_BACK_SPACE, false, false);
ok(selection.rangeCount == 0, aTestTypeText +
" correctly removed highlight on text deletion");
// Test 6: deleting text at end of highlight
resetForNextTest(aElement, SEARCH_TEXT+"A");
synthesizeKey(aElement, true, KeyEvent.DOM_VK_UP, true, false);
synthesizeKey(aElement, true, KeyEvent.DOM_VK_LEFT, true, false);
for (var x = 0; x < aElement.value.length; x++)
synthesizeKey(aElement, true, KeyEvent.DOM_VK_RIGHT, false, false);
synthesizeKey(aElement, true, KeyEvent.DOM_VK_BACK_SPACE, false, false);
ok(selection.rangeCount == 1, aTestTypeText +
" highlight correctly remained on text deletion at end");
// Test 7: deleting text at start of highlight
resetForNextTest(aElement, "A"+SEARCH_TEXT);
synthesizeKey(aElement, true, KeyEvent.DOM_VK_UP, true, false);
synthesizeKey(aElement, true, KeyEvent.DOM_VK_LEFT, true, false);
synthesizeKey(aElement, true, KeyEvent.DOM_VK_RIGHT, false, false);
synthesizeKey(aElement, true, KeyEvent.DOM_VK_BACK_SPACE, false, false);
ok(selection.rangeCount == 1, aTestTypeText +
" highlight correctly remained on text deletion at start");
// Test 8: deleting selection
resetForNextTest(aElement);
synthesizeKey(aElement, true, KeyEvent.DOM_VK_UP, true, false);
synthesizeKey(aElement, true, KeyEvent.DOM_VK_RIGHT, true, false);
synthesizeKey(aElement, true, KeyEvent.DOM_VK_LEFT, false, true);
synthesizeKey(aElement, true, KeyEvent.DOM_VK_LEFT, false, true);
synthesizeKey(aElement, false, KeyEvent.DOM_VK_X, true, false);
ok(selection.rangeCount == 0, aTestTypeText +
" correctly removed highlight on selection deletion");
}
}
function onPageShow() {
gBrowser.removeEventListener("load", onPageShow, true);
gBrowser.contentWindow.focus();
gFindBar.open();
var input = gBrowser.contentDocument.getElementById("inp");
testInput(input, "Input:");
var textarea = gBrowser.contentDocument.getElementById("tarea");
testInput(textarea, "Textarea:");
finishTest();
}
]]></script>
<browser type="content-primary" flex="1" id="content" src="about:blank"/>
<findbar id="FindToolbar" browserid="content"/>
</window>

Просмотреть файл

@ -1,43 +0,0 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet
href="chrome://mochikit/content/tests/SimpleTest/test.css"
type="text/css"?>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=451540
-->
<window title="Mozilla Bug 451540"
xmlns:html="http://www.w3.org/1999/xhtml"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<title>Test for Bug 451540</title>
<script type="application/javascript"
src="chrome://mochikit/content/MochiKit/packed.js"></script>
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<body xmlns="http://www.w3.org/1999/xhtml">
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=451540">
Mozilla Bug 451540
</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
</pre>
</body>
<script class="testbody" type="application/javascript">
<![CDATA[
/** Test for Bug 451540 **/
SimpleTest.waitForExplicitFinish();
window.open("bug451540_window.xul", "451540test",
"chrome,width=600,height=600");
]]>
</script>
</window>

Просмотреть файл

@ -280,7 +280,7 @@
</xul:hbox>
</content>
<implementation implements="nsIDOMEventListener, nsIEditActionListener">
<implementation implements="nsIDOMEventListener">
<field name="FIND_NORMAL">0</field>
<field name="FIND_TYPEAHEAD">1</field>
<field name="FIND_LINKS">2</field>
@ -290,8 +290,6 @@
<field name="_tmpOutlineOffset">"0"</field>
<field name="_drawOutline">false</field>
<field name="_foundLink">null</field>
<field name="_editors">null</field>
<field name="_stateListeners">null</field>
<field name="_flashFindBar">0</field>
<field name="_initialFlashFindBarCount">6</field>
@ -410,7 +408,6 @@
// Convenience
this.nsITypeAheadFind = Components.interfaces.nsITypeAheadFind;
this.nsISelectionController = Components.interfaces.nsISelectionController;
this._findSelection = this.nsISelectionController.SELECTION_FIND;
// Make sure the FAYT keypress listener is attached by initializing the
// browser property
@ -418,15 +415,6 @@
]]></constructor>
<destructor><![CDATA[
// It is possible that the findbar may be destroyed before any
// documents it is listening to (see nsIEditActionListener code below).
// Thus, to avoid leaking, if we are listening to any editors, unhook
// ourselves now, and remove our cached copies
if (this._editors) {
for (var x = this._editors.length - 1; x >= 0; --x)
this._unhookListenersAtIndex(x);
}
this.browser = null;
var prefsvc =
@ -478,14 +466,6 @@
]]></body>
</method>
<!--
- For a given node, walk up it's parent chain, to try and find an
- editable node.
-
- @param aNode the node we want to check
- @returns the first node in the parent chain that is editable,
- null if there is no such node
-->
<method name="_getEditableNode">
<parameter name="aNode"/>
<body><![CDATA[
@ -499,397 +479,6 @@
]]></body>
</method>
<!--
- Helper method to unhook listeners, remove cached editors
- and keep the relevant arrays in sync
-
- @param aIndex the index into the array of editors/state listeners
- we wish to remove
-->
<method name="_unhookListenersAtIndex">
<parameter name="aIndex"/>
<body><![CDATA[
this._editors[aIndex].removeEditActionListener(this);
this._editors[aIndex]
.removeDocumentStateListener(this._stateListeners[aIndex]);
this._editors.splice(aIndex, 1);
this._stateListeners.splice(aIndex, 1);
if (this._editors.length == 0) {
delete this._editors;
delete this._stateListeners;
}
]]></body>
</method>
<!--
- Remove ourselves as an nsIEditActionListener and
- nsIDocumentStateListener from a given cached editor
-
- @param aEditor the editor we no longer wish to listen to
-->
<method name="_removeEditorListeners">
<parameter name="aEditor"/>
<body><![CDATA[
// aEditor is an editor that we listen to, so therefore must be
// cached. Find the index of this editor
var idx = 0;
while (this._editors[idx] != aEditor)
idx++;
// Now unhook ourselves, and remove our cached copy
this._unhookListenersAtIndex(idx);
]]></body>
</method>
<!--
- nsIEditActionListener logic follows
-
- We implement this interface to allow us to catch the case where
- the findbar found a match in a HTML <input> or <textarea>. If the
- user adjusts the text in some way, it will no longer match, so we
- want to remove the highlight, rather than have it expand/contract
- when letters are added or removed.
-->
<!--
- Helper method used to check whether a selection intersects with
- some highlighting
-
- @param aSelectionRange the range from the selection to check
- @param aFindRange the highlighted range to check against
- @returns true if they intersect, false otherwise
-->
<method name="_checkOverlap">
<parameter name="aSelectionRange"/>
<parameter name="aFindRange"/>
<body><![CDATA[
// The ranges overlap if one of the following is true:
// 1) At least one of the endpoints of the deleted selection
// is in the find selection
// 2) At least one of the endpoints of the find selection
// is in the deleted selection
if (aFindRange.isPointInRange(aSelectionRange.startContainer,
aSelectionRange.startOffset))
return true;
if (aFindRange.isPointInRange(aSelectionRange.endContainer,
aSelectionRange.endOffset))
return true;
if (aSelectionRange.isPointInRange(aFindRange.startContainer,
aFindRange.startOffset))
return true;
if (aSelectionRange.isPointInRange(aFindRange.endContainer,
aFindRange.endOffset))
return true;
return false;
]]></body>
</method>
<!--
- Helper method to determine if an edit occurred within a highlight
-
- @param aSelection the selection we wish to check
- @param aNode the node we want to check is contained in aSelection
- @param aOffset the offset into aNode that we want to check
- @returns the range containing (aNode, aOffset) or null if no ranges
- in the selection contain it
-->
<method name="_findRange">
<parameter name="aSelection"/>
<parameter name="aNode"/>
<parameter name="aOffset"/>
<body><![CDATA[
var rangeCount = aSelection.rangeCount;
var rangeidx = 0;
var foundContainingRange = false;
var range = null;
// Check to see if this node is inside one of the selection's ranges
while (!foundContainingRange && rangeidx < rangeCount) {
range = aSelection.getRangeAt(rangeidx);
if (range.isPointInRange(aNode, aOffset)) {
foundContainingRange = true;
break;
}
rangeidx++;
}
if (foundContainingRange)
return range;
return null;
]]></body>
</method>
<!-- Start of nsIEditActionListener implementations -->
<method name="WillDeleteText">
<parameter name="aTextNode"/>
<parameter name="aOffset"/>
<parameter name="aLength"/>
<body><![CDATA[
var editor = this._getEditableNode(aTextNode).editor;
var controller = editor.selectionController;
var fSelection = controller.getSelection(this._findSelection);
var range = this._findRange(fSelection, aTextNode, aOffset);
if (range) {
// Don't remove the highlighting if the deleted text is at the
// end of the range
if (aTextNode != range.endContainer ||
aOffset != range.endOffset) {
// Text within the highlight is being removed - the text can
// no longer be a match, so remove the highlighting
fSelection.removeRange(range);
if (fSelection.rangeCount == 0)
this._removeEditorListeners(editor);
}
}
]]></body>
</method>
<method name="DidInsertText">
<parameter name="aTextNode"/>
<parameter name="aOffset"/>
<parameter name="aString"/>
<body><![CDATA[
var editor = this._getEditableNode(aTextNode).editor;
var controller = editor.selectionController;
var fSelection = controller.getSelection(this._findSelection);
var range = this._findRange(fSelection, aTextNode, aOffset);
if (range) {
// If the text was inserted before the highlight
// adjust the highlight's bounds accordingly
if (aTextNode == range.startContainer &&
aOffset == range.startOffset)
range.setStart(range.startContainer,
range.startOffset+aString.length);
else if (aTextNode != range.endContainer ||
aOffset != range.endOffset) {
// The edit occurred within the highlight - any addition of text
// will result in the text no longer being a match,
// so remove the highlighting
fSelection.removeRange(range);
if (fSelection.rangeCount == 0)
this._removeEditorListeners(editor);
}
}
]]></body>
</method>
<method name="WillDeleteSelection">
<parameter name="aSelection"/>
<body><![CDATA[
var editor = this._getEditableNode(aSelection.getRangeAt(0)
.startContainer).editor;
var controller = editor.selectionController;
var fSelection = controller.getSelection(this._findSelection);
var selectionIndex = 0;
var findSelectionIndex = 0;
var shouldDelete = {};
var numberOfDeletedSelections = 0;
var numberOfMatches = fSelection.rangeCount;
// We need to test if any ranges in the deleted selection (aSelection)
// are in any of the ranges of the find selection
// Usually both selections will only contain one range, however
// either may contain more than one.
for (var fIndex = 0; fIndex < numberOfMatches; fIndex++) {
shouldDelete[fIndex] = false;
var fRange = fSelection.getRangeAt(fIndex);
for (var index = 0; index < aSelection.rangeCount; index++) {
if (!shouldDelete[fIndex]) {
var selRange = aSelection.getRangeAt(index);
var doesOverlap = this._checkOverlap(selRange, fRange);
if (doesOverlap) {
shouldDelete[fIndex] = true;
numberOfDeletedSelections++;
}
}
}
}
// OK, so now we know what matches (if any) are in the selection
// that is being deleted. Time to remove them.
if (numberOfDeletedSelections == 0)
return;
for (var i = numberOfMatches - 1; i >= 0; i--) {
if (shouldDelete[i]) {
var r = fSelection.getRangeAt(i);
fSelection.removeRange(r);
}
}
// Remove listeners if no more highlights left
if (fSelection.rangeCount == 0)
this._removeEditorListeners(editor);
]]></body>
</method>
<method name="WillInsertText">
<body><![CDATA[
// Unimplemented
]]></body>
</method>
<method name="DidCreateNode">
<body><![CDATA[
// Unimplemented
]]></body>
</method>
<method name="DidDeleteNode">
<body><![CDATA[
// Unimplemented
]]></body>
</method>
<method name="DidDeleteSelection">
<body><![CDATA[
// Unimplemented
]]></body>
</method>
<method name="DidDeleteText">
<body><![CDATA[
// Unimplemented
]]></body>
</method>
<method name="DidInsertNode">
<body><![CDATA[
// Unimplemented
]]></body>
</method>
<method name="DidJoinNodes">
<body><![CDATA[
// Unimplemented
]]></body>
</method>
<method name="DidSplitNode">
<body><![CDATA[
// Unimplemented
]]></body>
</method>
<method name="WillCreateNode">
<body><![CDATA[
// Unimplemented
]]></body>
</method>
<method name="WillDeleteNode">
<body><![CDATA[
// Unimplemented
]]></body>
</method>
<method name="WillInsertNode">
<body><![CDATA[
// Unimplemented
]]></body>
</method>
<method name="WillJoinNodes">
<body><![CDATA[
// Unimplemented
]]></body>
</method>
<method name="WillSplitNode">
<body><![CDATA[
// Unimplemented
]]></body>
</method>
<!-- End of nsIEditActionListener implementations -->
<!--
- nsIDocumentStateListener logic follows
-
- When attaching nsIEditActionListeners, there are no guarantees
- as to whether the findbar or the documents in the browser will get
- destructed first. This leads to the potential to either leak, or to
- hold on to a reference an editable element's editor for too long,
- preventing it from being destructed.
-
- However, when an editor's owning node is being destroyed, the editor
- sends out a DocumentWillBeDestroyed notification. We can use this to
- clean up our references to the object, to allow it to be destroyed in a
- timely fashion.
-->
<!--
- Unhook ourselves when one of our state listeners has been called.
- This can happen in 4 cases:
- 1) The document the editor belongs to is navigated away from, and
- the document is not being cached
-
- 2) The document the editor belongs to is expired from the cache
-
- 3) The tab containing the owning document is closed
-
- 4) The <input> or <textarea> that owns the editor is explicitly
- removed from the DOM
-
- @param the listener that was invoked
-->
<method name="_onEditorDestruction">
<parameter name="aListener"/>
<body><![CDATA[
// First find the index of the editor the given listener listens to.
// The listeners and editors arrays must always be in sync.
// The listener will be in our array of cached listeners, as this
// method could not have been called otherwise.
var idx = 0;
while (this._stateListeners[idx] != aListener)
idx++;
// Unhook both listeners
this._unhookListenersAtIndex(idx);
]]></body>
</method>
<!--
- Creates a unique document state listener for an editor.
-
- It is not possible to simply have the findbar implement the
- listener interface itself, as it wouldn't have sufficient information
- to work out which editor was being destroyed. Therefore, we create new
- listeners on the fly, and cache them in sync with the editors they
- listen to.
-->
<method name="_createStateListener">
<body><![CDATA[
return ({
findbar: this,
QueryInterface: function(aIID) {
if (aIID.equals(Components.interfaces.nsIDocumentStateListener) ||
aIID.equals(Components.interfaces.nsISupports))
return this;
throw Components.results.NS_ERROR_NO_INTERFACE;
},
NotifyDocumentWillBeDestroyed: function() {
this.findbar._onEditorDestruction(this);
},
// Unimplemented
notifyDocumentCreated: function() {},
notifyDocumentStateChanged: function(aDirty) {}
});
]]></body>
</method>
<!--
- Turns highlight on or off.
- @param aHighlight (boolean)
@ -899,11 +488,13 @@
<parameter name="aHighlight"/>
<body><![CDATA[
var word = this._findField.value;
if (!aHighlight)
word = this._lastHighlightString;
// Bug 429723. Don't attempt to highlight ""
if (aHighlight && !word)
if (!word) {
this._updateStatusUI();
return;
}
// We have to update the status because we might still have the status
// of another tab
if (this._highlightDoc(aHighlight, word))
@ -931,6 +522,10 @@
<parameter name="aWindow"/>
<body><![CDATA[
var win = aWindow || this.browser.contentWindow;
if (!aWord)
return false;
var textFound = false;
for (var i = 0; win.frames && i < win.frames.length; i++) {
@ -938,70 +533,67 @@
textFound = true;
}
var controller = this._getSelectionController(win);
if (!controller) {
// Without the selection controller,
// we are unable to (un)highlight any matches
return false;
}
var doc = win.document;
if (!doc || !(doc instanceof HTMLDocument))
return textFound;
if (aHighlight) {
var body = doc.body;
var body = doc.body;
var count = body.childNodes.length;
this._searchRange = doc.createRange();
this._startPt = doc.createRange();
this._endPt = doc.createRange();
var count = body.childNodes.length;
this._searchRange = doc.createRange();
this._startPt = doc.createRange();
this._endPt = doc.createRange();
this._searchRange.setStart(body, 0);
this._searchRange.setEnd(body, count);
this._searchRange.setStart(body, 0);
this._searchRange.setEnd(body, count);
this._startPt.setStart(body, 0);
this._startPt.setEnd(body, 0);
this._endPt.setStart(body, count);
this._endPt.setEnd(body, count);
this._startPt.setStart(body, 0);
this._startPt.setEnd(body, 0);
this._endPt.setStart(body, count);
this._endPt.setEnd(body, count);
var retRange = null;
var finder = Components.classes["@mozilla.org/embedcomp/rangefind;1"]
.createInstance()
.QueryInterface(Components.interfaces.nsIFind);
finder.caseSensitive = this._shouldBeCaseSensitive(aWord);
while ((retRange = finder.Find(aWord, this._searchRange,
this._startPt, this._endPt))) {
this._highlight(retRange, controller);
this._startPt = retRange.endContainer.ownerDocument.createRange();
this._startPt.setStart(retRange.endContainer, retRange.endOffset);
this._startPt.setEnd(retRange.endContainer, retRange.endOffset);
textFound = true;
}
} else {
// First, attempt to remove highlighting from main document
var sel = controller.getSelection(this._findSelection);
sel.removeAllRanges();
// Next, check our editor cache, for editors belonging to this
// document
if (this._editors) {
for (var x = this._editors.length - 1; x >= 0; --x) {
if (this._editors[x].document == doc) {
sel = this._editors[x].selectionController
.getSelection(this._findSelection);
sel.removeAllRanges();
// We don't need to listen to this editor any more
this._unhookListenersAtIndex(x);
}
}
}
return true;
var controller = this._getSelectionController(win);
if (!controller) {
// Without the selection controller,
// we are unable to (un)highlight any matches
return false;
}
// This code should look for individual matches and highlight them
// However, as there's no way to access editable elements individual
// selection controllers from the top level doc, we also have to use
// this to find all the editable matches when clearing the highlight,
// which is horribly inefficient, but still faster than the DOM
// manipulation of old.
// Fixing bug 339400 would make this go away, and allow the removal case
// to be reduced to something like findSelection.removeAllRanges()
var retRange = null;
var finder = Components.classes["@mozilla.org/embedcomp/rangefind;1"]
.createInstance()
.QueryInterface(Components.interfaces.nsIFind);
finder.caseSensitive = this._shouldBeCaseSensitive(aWord);
while((retRange = finder.Find(aWord, this._searchRange,
this._startPt, this._endPt))) {
this._highlight(aHighlight, retRange, controller);
this._startPt = retRange.endContainer.ownerDocument.createRange();
this._startPt.setStart(retRange.endContainer, retRange.endOffset);
this._startPt.setEnd(retRange.endContainer, retRange.endOffset);
textFound = true;
}
if (textFound) {
if (aHighlight)
this._lastHighlightString = aWord;
else {
var sel = controller.getSelection(this.nsISelectionController.SELECTION_FIND);
sel.removeAllRanges();
}
}
return textFound;
]]></body>
</method>
@ -1009,38 +601,28 @@
<!--
- Highlights the word in the passed range.
-
- @param aHighlight
- whether the highlight should be on or off
- @param aRange
- the range that contains the word to highlight
- @param aController
- the current document's selection controller
-->
<method name="_highlight">
<parameter name="aHighlight"/>
<parameter name="aRange"/>
<parameter name="aController"/>
<body><![CDATA[
var node = aRange.startContainer;
var controller = aController;
var editableNode = this._getEditableNode(node);
if (editableNode)
controller = editableNode.editor.selectionController;
var findSelection = controller.getSelection(this._findSelection);
findSelection.addRange(aRange);
if (editableNode) {
// Highlighting added, so cache this editor, and hook up listeners
// to ensure we deal properly with edits within the highlighting
if (!this._editors) {
this._editors = [];
this._stateListeners = [];
}
var x = this._editors.length;
this._editors[x] = editableNode.editor;
this._stateListeners[x] = this._createStateListener();
this._editors[x].addEditActionListener(this);
this._editors[x].addDocumentStateListener(this._stateListeners[x]);
}
var isEditable = this._getEditableNode(node);
if (isEditable)
controller = isEditable.editor.selectionController;
var findSelection = controller.getSelection(this.nsISelectionController.SELECTION_FIND);
if (aHighlight)
findSelection.addRange(aRange);
else if (isEditable)
findSelection.removeAllRanges();
]]></body>
</method>