80805: patch up find/replace, particularly replace all. r=cmanske sr=dveditz a=asa

git-svn-id: svn://10.0.0.236/trunk@116693 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
akkana%netscape.com
2002-03-16 04:34:28 +00:00
parent 7f2161c735
commit fdf2606445
2 changed files with 177 additions and 56 deletions

View File

@@ -26,21 +26,22 @@
var gReplaceDialog; // Quick access to document/form elements.
var gFindInst; // nsIWebBrowserFind that we're going to use
var gFindService; // Global service which remembers find params
var gEditor; // the editor we're using
function initDialogObject()
{
// Create gReplaceDialog object and initialize.
gReplaceDialog = new Object();
gReplaceDialog.findKey = document.getElementById("dialog.findKey");
gReplaceDialog.replaceKey = document.getElementById("dialog.replaceKey");
gReplaceDialog.findInput = document.getElementById("dialog.findInput");
gReplaceDialog.replaceInput = document.getElementById("dialog.replaceInput");
gReplaceDialog.caseSensitive = document.getElementById("dialog.caseSensitive");
gReplaceDialog.wrap = document.getElementById("dialog.wrap");
gReplaceDialog.searchBackwards = document.getElementById("dialog.searchBackwards");
gReplaceDialog.findNext = document.getElementById("findNext");
gReplaceDialog.replace = document.getElementById("replace");
gReplaceDialog.replaceAndFind = document.getElementById("replaceAndFind");
gReplaceDialog.replaceAll = document.getElementById("replaceAll");
gReplaceDialog.bundle = null;
gReplaceDialog.editor = null;
gEditor = null;
}
function loadDialog()
@@ -48,10 +49,10 @@ function loadDialog()
// Set initial dialog field contents.
// Set initial dialog field contents. Use the gFindInst attributes first,
// this is necessary for window.find()
gReplaceDialog.findKey.value = (gFindInst.searchString
gReplaceDialog.findInput.value = (gFindInst.searchString
? gFindInst.searchString
: gFindService.searchString);
gReplaceDialog.replaceKey.value = gFindService.replaceString;
gReplaceDialog.replaceInput.value = gFindService.replaceString;
gReplaceDialog.caseSensitive.checked = (gFindInst.matchCase
? gFindInst.matchCase
: gFindService.matchCase);
@@ -67,13 +68,10 @@ function loadDialog()
function onLoad()
{
dump("EdReplace: onLoad()\n");
// Get the xul <editor> element:
var editorXUL = window.opener.document.getElementById("content-frame");
// Get the nsIWebBrowserFind service:
//gFindInst = editorXUL.docShell.QueryInterface(Components.interfaces.nsIWebBrowserFind);
gFindInst = editorXUL.webBrowserFind;
try {
@@ -86,7 +84,7 @@ function onLoad()
initDialogObject();
try {
gReplaceDialog.editor = editorXUL.editor.QueryInterface(Components.interfaces.nsIPlaintextEditor);
gEditor = editorXUL.editorShell.editor.QueryInterface(Components.interfaces.nsIPlaintextEditor);
} catch(e) { dump("Couldn't get an editor! " + e + "\n"); }
// If we don't get the editor, then we won't allow replacing.
@@ -96,10 +94,10 @@ function onLoad()
// Fill dialog.
loadDialog();
if (gReplaceDialog.findKey.value)
gReplaceDialog.findKey.select();
if (gReplaceDialog.findInput.value)
gReplaceDialog.findInput.select();
else
gReplaceDialog.findKey.focus();
gReplaceDialog.findInput.focus();
}
function onUnload() {
@@ -112,7 +110,7 @@ function saveFindData()
// Set data attributes per user input.
if (gFindService)
{
gFindService.searchString = gReplaceDialog.findKey.value;
gFindService.searchString = gReplaceDialog.findInput.value;
gFindService.matchCase = gReplaceDialog.caseSensitive.checked;
gFindService.wrapFind = gReplaceDialog.wrap.checked;
gFindService.findBackwards = gReplaceDialog.searchBackwards.checked;
@@ -121,7 +119,7 @@ function saveFindData()
function setUpFindInst()
{
gFindInst.searchString = gReplaceDialog.findKey.value;
gFindInst.searchString = gReplaceDialog.findInput.value;
gFindInst.matchCase = gReplaceDialog.caseSensitive.checked;
gFindInst.wrapFind = gReplaceDialog.wrap.checked;
gFindInst.findBackwards = gReplaceDialog.searchBackwards.checked;
@@ -139,51 +137,165 @@ function onFindNext()
if (!result)
{
if (!gReplaceDialog.bundle)
gReplaceDialog.bundle = document.getElementById("findBundle");
window.alert(gReplaceDialog.bundle.getString("notFoundWarning"));
gReplaceDialog.findKey.select();
gReplaceDialog.findKey.focus();
var bundle = document.getElementById("findBundle");
window.alert(bundle.getString("notFoundWarning"));
SetTextboxFocus(gReplaceDialog.findKey);
gReplaceDialog.findInput.select();
gReplaceDialog.findInput.focus();
return false;
}
return false;
return true;
}
function onReplace()
{
if (!gReplaceDialog.editor)
if (!gEditor)
return;
// Does the current selection match the find string?
var selection = gEditor.selection;
var selStr = selection.toString();
var specStr = gReplaceDialog.findInput.value;
if (!gReplaceDialog.caseSensitive.checked)
{
selStr = selStr.toLowerCase();
specStr = specStr.toLowerCase();
}
// Unfortunately, because of whitespace we can't just check
// whether (selStr == specStr), but have to loop ourselves.
// N chars of whitespace in specStr can match any M >= N in selStr.
var matches = true;
var specLen = specStr.length;
var selLen = selStr.length;
if (selLen < specLen)
matches = false;
else
{
specArray = specStr.match(/\S+|\s+/g);
selArray = selStr.match(/\S+|\s+/g);
if ( specArray.length != selArray.length)
matches = false;
else
{
for (i=0; i<selArray.length; i++)
{
if (selArray[i] != specArray[i])
{
if ( selArray[i][0].search(/\s/) == -1 ||
specArray[i][0].search(/\s/) == -1)
{
// lowercase \s, not a space chunk -- match fails
matches = false;
break;
}
else if ( selArray[i].length < specArray[i].length )
{
// if it's a space chunk then we only care that sel be
// at least as long as spec
matches = false;
break;
}
}
}
}
}
// If the current selection doesn't match the pattern,
// then we want to find the next match, but not do the replace.
// That's what most other apps seem to do.
if (!matches)
return onFindNext();
// Transfer dialog contents to the find service.
saveFindData();
gReplaceDialog.editor.insertText(gReplaceDialog.replaceKey.value);
gEditor.insertText(gReplaceDialog.replaceInput.value);
return true;
}
function onReplaceAll()
{
if (!gEditor)
return;
var findStr = gReplaceDialog.findInput.value;
var repStr = gReplaceDialog.replaceInput.value;
// Transfer dialog contents to the find service.
saveFindData();
// set up the find instance
setUpFindInst();
// Search.
while (true) {
var result = gFindInst.findNext();
dump("result of find: " + result + "\n");
if (!result)
break;
gReplaceDialog.editor.insertText(gReplaceDialog.replaceKey.value);
var finder = Components.classes["@mozilla.org/embedcomp/rangefind;1"].createInstance().QueryInterface(Components.interfaces.nsIFind);
finder.caseSensitive = gReplaceDialog.caseSensitive.checked;
finder.findBackwards = gReplaceDialog.searchBackwards.checked;
// Make a range containing the current selection,
// so we don't go past it when we wrap.
var selection = gEditor.selection;
var selecRange;
if (selection.rangeCount > 0)
selecRange = selection.getRangeAt(0);
var origRange = selecRange.cloneRange();
// We'll need a range for the whole document:
var wholeDocRange = gEditor.document.createRange();
var rootNode = gEditor.rootElement.QueryInterface(Components.interfaces.nsIDOMNode);
wholeDocRange.selectNodeContents(rootNode);
// And start and end points:
var startPt = gEditor.document.createRange();
startPt.setStart(wholeDocRange.startContainer, wholeDocRange.startOffset);
startPt.setEnd(wholeDocRange.startContainer, wholeDocRange.startOffset);
var endPt = gEditor.document.createRange();
endPt.setStart(wholeDocRange.endContainer, wholeDocRange.endOffset);
endPt.setEnd(wholeDocRange.endContainer, wholeDocRange.endOffset);
// Find and replace from here to end of document:
var foundRange;
while ((foundRange = finder.Find(findStr, wholeDocRange,
selecRange, endPt)) != null)
{
gEditor.selection.removeAllRanges();
gEditor.selection.addRange(foundRange);
gEditor.insertText(repStr);
selection = gEditor.selection;
if (selection.rangeCount <= 0) {
return;
}
selecRange = selection.getRangeAt(0);
}
return false;
// If wrapping, find from start of document back to start point.
selecRange.setStart(wholeDocRange.startContainer, wholeDocRange.startOffset);
selecRange.setEnd(wholeDocRange.startContainer, wholeDocRange.startOffset);
// Collapse origRange to start:
origRange.setEnd(origRange.startContainer, origRange.startOffset);
if (gReplaceDialog.wrap.checked)
{
while ((foundRange = finder.Find(findStr, wholeDocRange,
selecRange, origRange)) != null)
{
gEditor.selection.removeAllRanges();
gEditor.selection.addRange(foundRange);
gEditor.insertText(repStr);
selection = gEditor.selection;
if (selection.rangeCount <= 0) {
return;
}
selecRange = selection.getRangeAt(0);
}
}
}
function doEnabling()
{
gReplaceDialog.enabled = gReplaceDialog.findKey.value;
gReplaceDialog.findNext.disabled = !gReplaceDialog.findKey.value;
gReplaceDialog.replace.disabled = (!gReplaceDialog.findKey.value
|| !gReplaceDialog.replaceKey.value);
gReplaceDialog.replaceAll.disabled = (!gReplaceDialog.findKey.value
|| !gReplaceDialog.replaceKey.value);
var findStr = gReplaceDialog.findInput.value;
var repStr = gReplaceDialog.replaceInput.value;
gReplaceDialog.enabled = findStr;
gReplaceDialog.findNext.disabled = !findStr;
gReplaceDialog.replace.disabled = (!findStr || !repStr);
gReplaceDialog.replaceAndFind.disabled = (!findStr || !repStr);
gReplaceDialog.replaceAll.disabled = (!findStr || !repStr);
}

View File

@@ -33,6 +33,7 @@ Contributor(s): Akkana Peck <akkana@netscape.com>
<dialog id="replaceDlg" title="&replaceDialog.title;"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
persist="screenX screenY"
buttons="cancel"
onload = "onLoad()"
ondialogaccept="return onFindNext();">
@@ -43,29 +44,37 @@ Contributor(s): Akkana Peck <akkana@netscape.com>
<stringbundle id="findBundle" src="chrome://global/locale/finddialog.properties"/>
<hbox>
<!-- hack. we seem to need this separator to get it to render -->
<separator orient="vertical" class="thin"/>
<vbox>
<label value="&findField.label;"/>
<separator class="thin"/>
<label value="&replaceField.label;"/>
</vbox>
<vbox>
<textbox id="dialog.findKey" oninput="doEnabling();"/>
<textbox id="dialog.replaceKey" oninput="doEnabling();"/>
<vbox align="start">
<checkbox id="dialog.caseSensitive" label="&caseSensitiveCheckbox.label;"/>
<checkbox id="dialog.wrap" label="&wrapCheckbox.label;"/>
<checkbox id="dialog.searchBackwards" label="&backwardsCheckbox.label;"/>
</vbox>
<spacer class="spacer"/>
<grid align="start">
<columns><column/><column/></columns>
<rows>
<row align="center">
<label value="&findField.label;"/>
<textbox id="dialog.findInput" oninput="doEnabling();"/>
</row>
<row align="center">
<label value="&replaceField.label;"/>
<textbox id="dialog.replaceInput" oninput="doEnabling();"/>
</row>
<row align="start">
<spacer/>
<vbox align="start">
<spacer class="bigspacer"/>
<checkbox id="dialog.caseSensitive" label="&caseSensitiveCheckbox.label;"/>
<checkbox id="dialog.wrap" label="&wrapCheckbox.label;"/>
<checkbox id="dialog.searchBackwards" label="&backwardsCheckbox.label;"/>
</vbox>
</row>
</rows>
</grid>
</vbox>
<vbox>
<button id="findNext" label="&findNextButton.label;" oncommand="onFindNext();" default="true"/>
<button id="replace" label="&replaceButton.label;" oncommand="onReplace();"/>
<button id="replaceAndFind" label="&replaceAndFindButton.label;" oncommand="onReplace(); onFindNext();"/>
<button id="replaceAll" label="&replaceAllButton.label;" oncommand="onReplaceAll();"/>
<button dlgtype="cancel" label="&closeButton.label;"/>
</vbox>
</hbox>
</dialog>