Add a "Go to line" option to the Edit menu in View Source (bug 104383). Make

the links in the JS console automatically go to the right line in View Source
(bug 79612).  Patch (in bug 104383) by christian@schmidt.net (Christian
Schmidt) with some selection fu from rbs, r=neil, sr=me, a=asa
This commit is contained in:
bzbarsky%mit.edu 2003-05-21 02:23:13 +00:00
parent 27e8c9452b
commit ed8540438c
6 changed files with 216 additions and 4 deletions

View File

@ -31,6 +31,7 @@ comm.jar:
en-US.jar:
locale/en-US/navigator/contents.rdf (resources/locale/en-US/contents.rdf)
locale/en-US/navigator/viewSource.dtd (resources/locale/en-US/viewSource.dtd)
locale/en-US/navigator/viewSource.properties (resources/locale/en-US/viewSource.properties)
locale/en-US/navigator/pageInfo.dtd (resources/locale/en-US/pageInfo.dtd)
locale/en-US/navigator/pageInfo.properties (resources/locale/en-US/pageInfo.properties)
locale/en-US/navigator/navigator.dtd (resources/locale/en-US/navigator.dtd)

View File

@ -67,12 +67,14 @@
<command id="cmd_close" oncommand="ViewSourceClose()"/>
<command id="cmd_savePage" oncommand="ViewSourceSavePage();"/>
<command id="cmd_editPage" oncommand="ViewSourceEditPage();"/>
<command id="cmd_goToLine" oncommand="ViewSourceGoToLine();" disabled="true"/>
</commandset>
</commandset>
<stringbundleset id="viewSource-stringbundleset">
<stringbundle id="bundle_viewZoom"/>
<stringbundle id="findBundle" src="chrome://global/locale/finddialog.properties"/>
<stringbundle id="viewSourceBundle" src="chrome://navigator/locale/viewSource.properties"/>
</stringbundleset>
<!-- keys are appended from the overlay -->
@ -93,6 +95,7 @@
<key id="key_paste"/>
<key id="key_delete"/>
<key id="key_selectAll"/>
<key id="key_goToLine" key="&goToLineCmd.commandkey;" command="cmd_goToLine" modifiers="accel"/>
<key id="key_find" key="&findOnCmd.commandkey;" command="Browser:Find" modifiers="accel"/>
<key id="key_findAgain" key="&findAgainCmd.commandkey;" command="Browser:FindAgain" modifiers="accel"/>
<key id="key_findPrev" key="&findPrevCmd.commandkey;" command="Browser:FindPrev" modifiers="accel, shift"/>
@ -153,6 +156,8 @@
<menuseparator/>
<menuitem id="menu_selectAll"/>
<menuseparator />
<menuitem id="menu_goToLine" key="key_goToLine" command="cmd_goToLine"
label="&goToLineCmd.label;" accesskey="&goToLineCmd.accesskey;"/>
<menuitem id="menu_find" key="key_find" command="Browser:Find"
label="&findOnCmd.label;" accesskey="&findOnCmd.accesskey;"/>
<menuitem id="menu_findAgain" key="key_findAgain" command="Browser:FindAgain"

View File

@ -25,6 +25,9 @@ const pageLoaderIface = Components.interfaces.nsIWebPageDescriptor;
var gBrowser = null;
var gPrefs = null;
var gLastLineFound = '';
var gGoToLine = 0;
try {
var prefService = Components.classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefService);
@ -50,12 +53,16 @@ function viewSource(url)
if (!url)
return false; // throw Components.results.NS_ERROR_FAILURE;
getBrowser().addEventListener("unload", onUnloadContent, true);
getBrowser().addEventListener("load", onLoadContent, true);
var loadFromURL = true;
//
// Parse the 'arguments' supplied with the dialog.
// arg[0] - URL string.
// arg[1] - Charset value in the form 'charset=xxx'.
// arg[2] - Page descriptor used to load content from the cache.
// arg[3] - Line number to go to.
//
if ("arguments" in window) {
var arg;
@ -78,6 +85,13 @@ function viewSource(url)
}
}
//
// Get any specified line to jump to.
//
if (window.arguments.length >= 4) {
arg = window.arguments[3];
gGoToLine = parseInt(arg);
}
//
// Use the page descriptor to load the content from the cache (if
// available).
//
@ -134,6 +148,27 @@ function viewSource(url)
return true;
}
function onLoadContent()
{
//
// If the view source was opened with a "go to line" argument.
//
if (gGoToLine > 0) {
goToLine(gGoToLine);
gGoToLine = 0;
}
document.getElementById('cmd_goToLine').removeAttribute('disabled');
}
function onUnloadContent()
{
//
// Disable "go to line" while reloading due to e.g. change of charset
// or toggling of syntax highlighting.
//
document.getElementById('cmd_goToLine').setAttribute('disabled', 'true');
}
function ViewSourceClose()
{
window.close();
@ -156,12 +191,170 @@ function ViewSourceSavePage()
saveURL(url, null, "SaveLinkTitle");
}
function ViewSourceGoToLine()
{
var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
.getService(Components.interfaces.nsIPromptService);
var viewSourceBundle = document.getElementById('viewSourceBundle');
var input = {value:gLastLineFound};
for (;;) {
var ok = promptService.prompt(
window,
viewSourceBundle.getString("goToLineTitle"),
viewSourceBundle.getString("goToLineText"),
input,
null,
{value:0});
if (!ok) return;
var line = parseInt(input.value);
if (!(line > 0)) {
promptService.alert(window,
viewSourceBundle.getString("invalidInputTitle"),
viewSourceBundle.getString("invalidInputText"));
continue;
}
var found = goToLine(line);
if (found) {
break;
}
promptService.alert(window,
viewSourceBundle.getString("outOfRangeTitle"),
viewSourceBundle.getString("outOfRangeText"));
}
}
function goToLine(line)
{
var viewsource = window._content.document.body;
//
// The source document is made up of a number of pre elements with
// id attributes in the format <pre id="line123">, meaning that
// the first line in the pre element is number 123.
// Do binary search to find the pre element containing the line.
//
var pre, curLine;
for (var lbound = 0, ubound = viewsource.childNodes.length; ; ) {
var middle = (lbound + ubound) >> 1;
pre = viewsource.childNodes[middle];
curLine = parseInt(pre.id.substring(4));
if (lbound == ubound - 1) {
break;
}
if (line >= curLine) {
lbound = middle;
} else {
ubound = middle;
}
}
var range = null;
//
// Walk through each of the text nodes and count newlines.
//
var treewalker = document.createTreeWalker(pre, NodeFilter.SHOW_TEXT, null, false);
for (var textNode = treewalker.firstChild();
textNode && curLine <= line + 1;
textNode = treewalker.nextNode()) {
//
// \r is not a valid character in the DOM, so we only check for \n.
//
var lineArray = textNode.data.split(/\n/);
var lastLineInNode = curLine + lineArray.length - 1;
if (lastLineInNode < line) {
curLine = lastLineInNode;
continue;
}
for (var i = 0, curPos = 0;
i < lineArray.length;
curPos += lineArray[i++].length + 1) {
if (i > 0) {
curLine++;
}
if (curLine == line && !range) {
range = document.createRange();
range.setStart(textNode, curPos);
//
// This will always be overridden later, except when we look for
// the very last line in the file (this is the only line that does
// not end with \n).
//
range.setEndAfter(pre.lastChild);
} else if (curLine == line + 1) {
range.setEnd(textNode, curPos);
curLine++;
break;
}
}
}
if (!range) {
return false;
}
var selection = window._content.getSelection();
selection.removeAllRanges();
var selCon = getBrowser().docShell
.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsISelectionDisplay)
.QueryInterface(Components.interfaces.nsISelectionController);
selCon.setDisplaySelection(
Components.interfaces.nsISelectionController.SELECTION_ON);
selCon.setCaretEnabled(true);
// In our case, the range's startOffset is after "\n" on the previous line.
// Set "hintright" to tune the selection at the beginning of the next line.
selection.QueryInterface(Components.interfaces.nsISelectionPrivate)
.interlinePosition = true;
selection.addRange(range);
// If it is a blank line, collapse to make the caret show up.
// (work-around to bug 156175)
if (range.endContainer == range.startContainer &&
range.endOffset - range.startOffset == 1) {
// note: by construction, there is just a "\n" in-bewteen
selection.collapseToStart();
}
// Scroll the beginning of the line into view.
selCon.scrollSelectionIntoView(
Components.interfaces.nsISelectionController.SELECTION_NORMAL,
Components.interfaces.nsISelectionController.SELECTION_ANCHOR_REGION,
true);
gLastLineFound = line;
return true;
}
//function to toggle long-line wrapping and set the view_source.wrap_long_lines
//pref to persist the last state
function wrapLongLines()
{
//get the first pre tag which surrounds the entire viewsource content
var myWrap = window._content.document.getElementById('viewsource');
var myWrap = window._content.document.body;
if (myWrap.className == '')
myWrap.className = 'wrap';

View File

@ -19,5 +19,9 @@
<!ENTITY findNextCmd.label "Find Next">
<!ENTITY findNextCmd.accesskey "n">
<!ENTITY goToLineCmd.label "Go to line...">
<!ENTITY goToLineCmd.accesskey "G">
<!ENTITY goToLineCmd.commandkey "l">
<!ENTITY printSetupCmd.label "Page Setup...">
<!ENTITY printSetupCmd.accesskey "u">

View File

@ -0,0 +1,7 @@
goToLineTitle = Go to line
goToLineText = Enter line number
invalidInputTitle = Invalid input
invalidInputText = The line number entered is invalid.
outOfRangeTitle = Line not found
outOfRangeText = The specified line was not found.

View File

@ -314,7 +314,7 @@
</xul:box>
<xul:box class="console-row-file" xbl:inherits="hidden=hideSource">
<xul:label class="label" value="&errFile.label;"/>
<xul:box class="console-error-source" xbl:inherits="url"/>
<xul:box class="console-error-source" xbl:inherits="url,line"/>
<spacer flex="1"/>
<xul:label class="label" value="&errLine.label;"/>
<xul:label class="label" xbl:inherits="value=line" flex="1"/>
@ -390,9 +390,11 @@
<handlers>
<handler event="click"><![CDATA[
var url = this.getAttribute("url");
var line = getAttribute("line");
window.openDialog(
"chrome://navigator/content/viewSource.xul", "_blank",
"scrollbars,resizable,chrome,dialog=no", this.getAttribute("url"));
"scrollbars,resizable,chrome,dialog=no", url, null, null, line);
]]></handler>
</handlers>
</binding>