зеркало из https://github.com/mozilla/pjs.git
Back out bug 451540
This commit is contained in:
Коммит
89a2f08622
|
@ -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>
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче