/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 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 = {}; 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"); } function loadDialog() { // Set initial dialog field contents. // Set initial dialog field contents. Use the gFindInst attributes first, // this is necessary for window.find() gReplaceDialog.findInput.value = (gFindInst.searchString ? gFindInst.searchString : gFindService.searchString); gReplaceDialog.replaceInput.value = gFindService.replaceString; gReplaceDialog.caseSensitive.checked = (gFindInst.matchCase ? gFindInst.matchCase : gFindService.matchCase); gReplaceDialog.wrap.checked = (gFindInst.wrapFind ? gFindInst.wrapFind : gFindService.wrapFind); gReplaceDialog.searchBackwards.checked = (gFindInst.findBackwards ? gFindInst.findBackwards : gFindService.findBackwards); doEnabling(); } function onLoad() { // Get the xul element: var editorElement = window.arguments[0]; // If we don't get the editor, then we won't allow replacing. gEditor = editorElement.getEditor(editorElement.contentWindow); if (!gEditor) { window.close(); return; } // Get the nsIWebBrowserFind service: gFindInst = editorElement.webBrowserFind; try { // get the find service, which stores global find state gFindService = Components.classes["@mozilla.org/find/find_service;1"] .getService(Components.interfaces.nsIFindService); } catch(e) { dump("No find service!\n"); gFindService = 0; } // Init gReplaceDialog. initDialogObject(); // Change "OK" to "Find". //dialog.find.label = document.getElementById("fBLT").getAttribute("label"); // Fill dialog. loadDialog(); if (gReplaceDialog.findInput.value) gReplaceDialog.findInput.select(); else gReplaceDialog.findInput.focus(); } function onUnload() { // Disconnect context from this dialog. gFindReplaceData.replaceDialog = null; } function saveFindData() { // Set data attributes per user input. if (gFindService) { gFindService.searchString = gReplaceDialog.findInput.value; gFindService.matchCase = gReplaceDialog.caseSensitive.checked; gFindService.wrapFind = gReplaceDialog.wrap.checked; gFindService.findBackwards = gReplaceDialog.searchBackwards.checked; } } function setUpFindInst() { gFindInst.searchString = gReplaceDialog.findInput.value; gFindInst.matchCase = gReplaceDialog.caseSensitive.checked; gFindInst.wrapFind = gReplaceDialog.wrap.checked; gFindInst.findBackwards = gReplaceDialog.searchBackwards.checked; } function onFindNext() { // Transfer dialog contents to the find service. saveFindData(); // set up the find instance setUpFindInst(); // Search. var result = gFindInst.findNext(); if (!result) { var bundle = document.getElementById("findBundle"); AlertWithTitle(null, bundle.getString("notFoundWarning")); SetTextboxFocus(gReplaceDialog.findInput); gReplaceDialog.findInput.select(); gReplaceDialog.findInput.focus(); return false; } return true; } function onReplace() { if (!gEditor) return false; // 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 { var specArray = specStr.match(/\S+|\s+/g); var selArray = selStr.match(/\S+|\s+/g); if ( specArray.length != selArray.length) matches = false; else { for (var i=0; i 0) { newRange = selection.getRangeAt(0).cloneRange(); newRange.collapse(true); } // nsPlaintextEditor::InsertText fails if the string is empty, // so make that a special case: var replStr = gReplaceDialog.replaceInput.value; if (replStr == "") gEditor.deleteSelection(0); else gEditor.insertText(replStr); // For reverse finds, need to move caret just before the replaced text if (gReplaceDialog.searchBackwards.checked && newRange) { gEditor.selection.removeAllRanges(); gEditor.selection.addRange(newRange); } 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(); var finder = Components.classes["@mozilla.org/embedcomp/rangefind;1"].createInstance().QueryInterface(Components.interfaces.nsIFind); finder.caseSensitive = gReplaceDialog.caseSensitive.checked; finder.findBackwards = gReplaceDialog.searchBackwards.checked; // We want the whole operation to be undoable in one swell foop, // so start a transaction: gEditor.beginTransaction(); // and to make sure we close the transaction, guard against exceptions: try { // 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 endPt = gEditor.document.createRange(); if (gReplaceDialog.searchBackwards.checked) { endPt.setStart(wholeDocRange.startContainer, wholeDocRange.startOffset); endPt.setEnd(wholeDocRange.startContainer, wholeDocRange.startOffset); } else { endPt.setStart(wholeDocRange.endContainer, wholeDocRange.endOffset); endPt.setEnd(wholeDocRange.endContainer, wholeDocRange.endOffset); } // Find and replace from here to end (start) of document: var foundRange; var searchRange = wholeDocRange.cloneRange(); while ((foundRange = finder.Find(findStr, searchRange, selecRange, endPt)) != null) { gEditor.selection.removeAllRanges(); gEditor.selection.addRange(foundRange); // The editor will leave the caret at the end of the replaced text. // For reverse finds, we need it at the beginning, // so save the next position now. if (gReplaceDialog.searchBackwards.checked) { selecRange = foundRange.cloneRange(); selecRange.setEnd(selecRange.startContainer, selecRange.startOffset); } // nsPlaintextEditor::InsertText fails if the string is empty, // so make that a special case: if (repStr == "") gEditor.deleteSelection(0); else gEditor.insertText(repStr); // If we're going forward, we didn't save selecRange before, so do it now: if (!gReplaceDialog.searchBackwards.checked) { selection = gEditor.selection; if (selection.rangeCount <= 0) { gEditor.endTransaction(); return; } selecRange = selection.getRangeAt(0).cloneRange(); } } // If no wrapping, then we're done if (!gReplaceDialog.wrap.checked) { gEditor.endTransaction(); return; } // If wrapping, find from start/end of document back to start point. if (gReplaceDialog.searchBackwards.checked) { // Collapse origRange to end origRange.setStart(origRange.endContainer, origRange.endOffset); // Set current position to document end selecRange.setEnd(wholeDocRange.endContainer, wholeDocRange.endOffset); selecRange.setStart(wholeDocRange.endContainer, wholeDocRange.endOffset); } else { // Collapse origRange to start origRange.setEnd(origRange.startContainer, origRange.startOffset); // Set current position to document start selecRange.setStart(wholeDocRange.startContainer, wholeDocRange.startOffset); selecRange.setEnd(wholeDocRange.startContainer, wholeDocRange.startOffset); } while ((foundRange = finder.Find(findStr, wholeDocRange, selecRange, origRange)) != null) { gEditor.selection.removeAllRanges(); gEditor.selection.addRange(foundRange); // Save insert point for backward case if (gReplaceDialog.searchBackwards.checked) { selecRange = foundRange.cloneRange(); selecRange.setEnd(selecRange.startContainer, selecRange.startOffset); } // nsPlaintextEditor::InsertText fails if the string is empty, // so make that a special case: if (repStr == "") gEditor.deleteSelection(0); else gEditor.insertText(repStr); // Get insert point for forward case if (!gReplaceDialog.searchBackwards.checked) { selection = gEditor.selection; if (selection.rangeCount <= 0) { gEditor.endTransaction(); return; } selecRange = selection.getRangeAt(0); } } } // end try catch (e) { } gEditor.endTransaction(); } function doEnabling() { var findStr = gReplaceDialog.findInput.value; var repStr = gReplaceDialog.replaceInput.value; gReplaceDialog.enabled = findStr; gReplaceDialog.findNext.disabled = !findStr; gReplaceDialog.replace.disabled = !findStr; gReplaceDialog.replaceAndFind.disabled = !findStr; gReplaceDialog.replaceAll.disabled = !findStr; }