mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-16 22:04:36 +00:00
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:
parent
27e8c9452b
commit
ed8540438c
@ -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)
|
||||
|
@ -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"
|
||||
|
@ -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';
|
||||
|
@ -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">
|
||||
|
@ -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.
|
||||
|
@ -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>
|
||||
|
Loading…
x
Reference in New Issue
Block a user