--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1907,8 +1907,10 @@ pref("browser.reader.detectedFirstArticl
pref("reader.parse-node-limit", 0);
pref("browser.pocket.enabled", true);
pref("browser.pocket.api", "api.getpocket.com");
pref("browser.pocket.site", "getpocket.com");
pref("browser.pocket.oAuthConsumerKey", "40249-e88c401e1b1f2242d9e441c4");
pref("browser.pocket.useLocaleList", true);
pref("browser.pocket.enabledLocales", "en-US de es-ES ja ja-JP-mac ru");
+
+pref("view_source.tab", true);
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -981,16 +981,17 @@ var gBrowserInit = {
DevEdition.init();
AboutPrivateBrowsingListener.init();
let mm = window.getGroupMessageManager("browsers");
mm.loadFrameScript("chrome://browser/content/tab-content.js", true);
mm.loadFrameScript("chrome://browser/content/content.js", true);
mm.loadFrameScript("chrome://browser/content/content-UITour.js", true);
mm.loadFrameScript("chrome://global/content/manifestMessages.js", true);
+ mm.loadFrameScript("chrome://global/content/viewSource-content.js", true);
window.messageManager.addMessageListener("Browser:LoadURI", RedirectLoad);
// initialize observers and listeners
// and give C++ access to gBrowser
XULBrowserWindow.init();
window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(nsIWebNavigation)
@@ -2317,21 +2318,21 @@ function readFromClipboard()
* @param aArgsOrDocument
* Either an object or a Document. Passing a Document is deprecated,
* and is not supported with e10s. This function will throw if
* aArgsOrDocument is a CPOW.
*
* If aArgsOrDocument is an object, that object can take the
* following properties:
*
- * browser:
+ * URL (required):
+ * A string URL for the page we'd like to view the source of.
+ * browser (optional):
* The browser containing the document that we would like to view the
- * source of.
- * URL:
- * A string URL for the page we'd like to view the source of.
+ * source of. This is required if outerWindowID is passed.
* outerWindowID (optional):
* The outerWindowID of the content window containing the document that
* we want to view the source of. You only need to provide this if you
* want to attempt to retrieve the document source from the network
* cache.
* lineNumber (optional):
* The line number to focus on once the source is loaded.
*/
@@ -2354,17 +2355,28 @@ function BrowserViewSourceOfDocument(aAr
let outerWindowID = requestor.getInterface(Ci.nsIDOMWindowUtils)
.outerWindowID;
let URL = browser.currentURI.spec;
args = { browser, outerWindowID, URL };
} else {
args = aArgsOrDocument;
}
- top.gViewSourceUtils.viewSource(args);
+ let inTab = Services.prefs.getBoolPref("view_source.tab");
+ if (inTab) {
+ let viewSourceURL = `view-source:${args.URL}`;
+ let tab = gBrowser.loadOneTab(viewSourceURL, {
+ relatedToCurrent: true,
+ inBackground: false
+ });
+ args.viewSourceBrowser = gBrowser.getBrowserForTab(tab);
+ top.gViewSourceUtils.viewSourceInBrowser(args);
+ } else {
+ top.gViewSourceUtils.viewSource(args);
+ }
}
/**
* Opens the View Source dialog for the source loaded in the root
* top-level document of the browser. This is really just a
* convenience wrapper around BrowserViewSourceOfDocument.
*
* @param browser
new file mode 100644
--- /dev/null
+++ b/toolkit/components/viewsource/ViewSourceBrowser.jsm
@@ -0,0 +1,164 @@
+// -*- indent-tabs-mode: nil; js-indent-level: 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/. */
+
+const { utils: Cu, interfaces: Ci, classes: Cc } = Components;
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "Services",
+ "resource://gre/modules/Services.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "Deprecated",
+ "resource://gre/modules/Deprecated.jsm");
+
+this.EXPORTED_SYMBOLS = ["ViewSourceBrowser"];
+
+/**
+ * ViewSourceBrowser manages for the view source <browser> from the chrome side.
+ * It's companion frame script, viewSource-content.js, needs to be loaded as a
+ * frame script into the browser being managed.
+ *
+ * For a view source window using viewSource.xul, the script viewSource.js in
+ * the window extends an instance of this with more window specific functions.
+ * The page script takes care of load the companion frame script.
+ *
+ * For a view source tab (or some other non-window case), an instance of this is
+ * created by viewSourceUtils.js to wrap the <browser>. The caller that manages
+ * the <browser> is responsible for ensuring the companion frame script has been
+ * loaded.
+ */
+this.ViewSourceBrowser = function ViewSourceBrowser(aBrowser) {
+ this._browser = aBrowser;
+ this.init();
+}
+
+ViewSourceBrowser.prototype = {
+ /**
+ * The <browser> that will be displaying the view source content.
+ */
+ get browser() {
+ return this._browser;
+ },
+
+ /**
+ * These are the messages that ViewSourceBrowser will listen for
+ * from the frame script it injects. Any message names added here
+ * will automatically have ViewSourceBrowser listen for those messages,
+ * and remove the listeners on teardown.
+ */
+ // TODO: Some messages will appear here in a later patch
+ messages: [
+ ],
+
+ /**
+ * This should be called as soon as the script loads. When this function
+ * executes, we can assume the DOM content has not yet loaded.
+ */
+ init() {
+ this.messages.forEach((msgName) => {
+ this.mm.addMessageListener(msgName, this);
+ });
+ },
+
+ /**
+ * This should be called when the window is closing. This function should
+ * clean up event and message listeners.
+ */
+ uninit() {
+ this.messages.forEach((msgName) => {
+ this.mm.removeMessageListener(msgName, this);
+ });
+ },
+
+ /**
+ * Anything added to the messages array will get handled here, and should
+ * get dispatched to a specific function for the message name.
+ */
+ receiveMessage(message) {
+ let data = message.data;
+
+ // TODO: Some messages will appear here in a later patch
+ switch(message.name) {
+ default:
+ // Unhandled
+ return false;
+ }
+ },
+
+ /**
+ * Getter for the message manager of the view source browser.
+ */
+ get mm() {
+ return this.browser.messageManager;
+ },
+
+ /**
+ * Send a message to the view source browser.
+ */
+ sendAsyncMessage(...args) {
+ this.browser.messageManager.sendAsyncMessage(...args);
+ },
+
+ /**
+ * Loads the source for a URL while applying some optional features if
+ * enabled.
+ *
+ * For the viewSource.xul window, this is called by onXULLoaded above.
+ * For view source in a specific browser, this is manually called after
+ * this object is constructed.
+ *
+ * This takes a single object argument containing:
+ *
+ * URL (required):
+ * A string URL for the page we'd like to view the source of.
+ * browser:
+ * The browser containing the document that we would like to view the
+ * source of. This argument is optional if outerWindowID is not passed.
+ * outerWindowID (optional):
+ * The outerWindowID of the content window containing the document that
+ * we want to view the source of. This is the only way of attempting to
+ * load the source out of the network cache.
+ * lineNumber (optional):
+ * The line number to focus on once the source is loaded.
+ */
+ loadViewSource({ URL, browser, outerWindowID, lineNumber }) {
+ if (!URL) {
+ throw new Error("Must supply a URL when opening view source.");
+ }
+
+ if (browser) {
+ // If we're dealing with a remote browser, then the browser
+ // for view source needs to be remote as well.
+ this.updateBrowserRemoteness(browser.isRemoteBrowser);
+ } else {
+ if (outerWindowID) {
+ throw new Error("Must supply the browser if passing the outerWindowID");
+ }
+ }
+
+ this.sendAsyncMessage("ViewSource:LoadSource",
+ { URL, outerWindowID, lineNumber });
+ },
+
+ /**
+ * Updates the "remote" attribute of the view source browser. This
+ * will remove the browser from the DOM, and then re-add it in the
+ * same place it was taken from.
+ *
+ * @param shouldBeRemote
+ * True if the browser should be made remote. If the browsers
+ * remoteness already matches this value, this function does
+ * nothing.
+ */
+ updateBrowserRemoteness(shouldBeRemote) {
+ if (this.browser.isRemoteBrowser != shouldBeRemote) {
+ // In this base case, where we are handed a <browser> someone else is
+ // managing, we don't know for sure that it's safe to toggle remoteness.
+ // For view source in a window, this is overridden to actually do the
+ // flip if needed.
+ throw new Error("View source browser's remoteness mismatch");
+ }
+ },
+};
--- a/toolkit/components/viewsource/content/viewPartialSource.js
+++ b/toolkit/components/viewsource/content/viewPartialSource.js
@@ -169,17 +169,17 @@ function viewPartialSourceForSelection(s
// before drawing the selection.
if (canDrawSelection) {
window.document.getElementById("content").addEventListener("load", drawSelection, true);
}
// all our content is held by the data:URI and URIs are internally stored as utf-8 (see nsIURI.idl)
var loadFlags = Components.interfaces.nsIWebNavigation.LOAD_FLAGS_NONE;
var referrerPolicy = Components.interfaces.nsIHttpChannel.REFERRER_POLICY_DEFAULT;
- ViewSourceChrome.webNav.loadURIWithOptions((isHTML ?
+ viewSourceChrome.webNav.loadURIWithOptions((isHTML ?
"view-source:data:text/html;charset=utf-8," :
"view-source:data:application/xml;charset=utf-8,")
+ encodeURIComponent(tmpNode.innerHTML),
loadFlags,
null, referrerPolicy, // referrer
null, null, // postData, headers
Services.io.newURI(doc.baseURI, null, null));
}
--- a/toolkit/components/viewsource/content/viewPartialSource.xul
+++ b/toolkit/components/viewsource/content/viewPartialSource.xul
@@ -45,19 +45,19 @@
<command id="cmd_close" oncommand="window.close();"/>
<commandset id="editMenuCommands"/>
<command id="cmd_find"
oncommand="document.getElementById('FindToolbar').onFindCommand();"/>
<command id="cmd_findAgain"
oncommand="document.getElementById('FindToolbar').onFindAgainCommand(false);"/>
<command id="cmd_findPrevious"
oncommand="document.getElementById('FindToolbar').onFindAgainCommand(true);"/>
- <command id="cmd_goToLine" oncommand="ViewSourceChrome.promptAndGoToLine();" disabled="true"/>
- <command id="cmd_highlightSyntax" oncommand="ViewSourceChrome.toggleSyntaxHighlighting();"/>
- <command id="cmd_wrapLongLines" oncommand="ViewSourceChrome.toggleWrapping();"/>
+ <command id="cmd_goToLine" oncommand="viewSourceChrome.promptAndGoToLine();" disabled="true"/>
+ <command id="cmd_highlightSyntax" oncommand="viewSourceChrome.toggleSyntaxHighlighting();"/>
+ <command id="cmd_wrapLongLines" oncommand="viewSourceChrome.toggleWrapping();"/>
<command id="cmd_textZoomReduce" oncommand="ZoomManager.reduce();"/>
<command id="cmd_textZoomEnlarge" oncommand="ZoomManager.enlarge();"/>
<command id="cmd_textZoomReset" oncommand="ZoomManager.reset();"/>
<keyset id="editMenuKeys"/>
<keyset id="viewSourceKeys">
<key id="key_savePage" key="&savePageCmd.commandkey;" modifiers="accel" command="cmd_savePage"/>
<key id="key_print" key="&printCmd.commandkey;" modifiers="accel" command="cmd_print"/>
@@ -75,21 +75,21 @@
<menupopup id="viewSourceContextMenu">
<menuitem id="cMenu_findAgain"/>
<menuseparator/>
<menuitem id="cMenu_copy"/>
<menuitem id="context-copyLink"
label="©LinkCmd.label;"
accesskey="©LinkCmd.accesskey;"
- oncommand="ViewSourceChrome.onContextMenuCopyLinkOrEmail();"/>
+ oncommand="viewSourceChrome.onContextMenuCopyLinkOrEmail();"/>
<menuitem id="context-copyEmail"
label="©EmailCmd.label;"
accesskey="©EmailCmd.accesskey;"
- oncommand="ViewSourceChrome.onContextMenuCopyLinkOrEmail();"/>
+ oncommand="viewSourceChrome.onContextMenuCopyLinkOrEmail();"/>
<menuseparator/>
<menuitem id="cMenu_selectAll"/>
</menupopup>
<!-- Menu -->
<toolbox id="viewSource-toolbox">
<menubar id="viewSource-main-menubar">
--- a/toolkit/components/viewsource/content/viewSource-content.js
+++ b/toolkit/components/viewsource/content/viewSource-content.js
@@ -46,16 +46,21 @@ let ViewSourceContent = {
* and removed on pagehide. When the initial about:blank is transitioned
* away from, a pagehide is fired without us having attached ourselves
* first. We use this boolean to keep track of whether or not we're
* attached, so we don't attempt to remove our listener when it's not
* yet there (which throws).
*/
selectionListenerAttached: false,
+ get isViewSource() {
+ let uri = content.document.documentURI;
+ return uri == "about:blank" || uri.startsWith("view-source:");
+ },
+
/**
* This should be called as soon as this frame script has loaded.
*/
init() {
this.messages.forEach((msgName) => {
addMessageListener(msgName, this);
});
@@ -88,16 +93,19 @@ let ViewSourceContent = {
}
},
/**
* Anything added to the messages array will get handled here, and should
* get dispatched to a specific function for the message name.
*/
receiveMessage(msg) {
+ if (!this.isViewSource) {
+ return;
+ }
let data = msg.data;
let objects = msg.objects;
switch(msg.name) {
case "ViewSource:LoadSource":
this.viewSource(data.URL, data.outerWindowID, data.lineNumber,
data.shouldWrap);
break;
case "ViewSource:LoadSourceDeprecated":
@@ -119,16 +127,19 @@ let ViewSourceContent = {
}
},
/**
* Any events should get handled here, and should get dispatched to
* a specific function for the event type.
*/
handleEvent(event) {
+ if (!this.isViewSource) {
+ return;
+ }
switch(event.type) {
case "pagehide":
this.onPageHide(event);
break;
case "pageshow":
this.onPageShow(event);
break;
case "click":
@@ -247,16 +258,21 @@ let ViewSourceContent = {
let loadFromURL = false;
if (forcedCharSet) {
docShell.charset = forcedCharSet;
}
if (lineNumber) {
let doneLoading = (event) => {
+ let uri = content.document.documentURI;
+ // Ignore possible initial load of about:blank
+ if (uri == "about:blank") {
+ return;
+ }
this.goToLine(lineNumber);
removeEventListener("pageshow", doneLoading);
};
addEventListener("pageshow", doneLoading);
}
if (!pageDescriptor) {
@@ -336,21 +352,22 @@ let ViewSourceContent = {
/**
* Handler for the pageshow event.
*
* @param event
* The pageshow event being handled.
*/
onPageShow(event) {
- content.getSelection()
- .QueryInterface(Ci.nsISelectionPrivate)
- .addSelectionListener(this);
- this.selectionListenerAttached = true;
-
+ let selection = content.getSelection();
+ if (selection) {
+ selection.QueryInterface(Ci.nsISelectionPrivate)
+ .addSelectionListener(this);
+ this.selectionListenerAttached = true;
+ }
content.focus();
sendAsyncMessage("ViewSource:SourceLoaded");
},
/**
* Handler for the pagehide event.
*
* @param event
--- a/toolkit/components/viewsource/content/viewSource.js
+++ b/toolkit/components/viewsource/content/viewSource.js
@@ -2,16 +2,17 @@
/* 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/. */
const { utils: Cu, interfaces: Ci, classes: Cc } = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/ViewSourceBrowser.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Services",
"resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "CharsetMenu",
"resource://gre/modules/CharsetMenu.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Deprecated",
"resource://gre/modules/Deprecated.jsm");
@@ -26,19 +27,35 @@ XPCOMUtils.defineLazyModuleGetter(this,
return null;
delete window[name];
return window[name] = element;
});
});
/**
* ViewSourceChrome is the primary interface for interacting with
- * the view source browser. It initializes itself on script load.
+ * the view source browser from a self-contained window. It extends
+ * ViewSourceBrowser with additional things needed inside the special window.
+ *
+ * It initializes itself on script load.
*/
-let ViewSourceChrome = {
+function ViewSourceChrome() {
+ ViewSourceBrowser.call(this);
+}
+
+ViewSourceChrome.prototype = {
+ __proto__: ViewSourceBrowser.prototype,
+
+ /**
+ * The <browser> that will be displaying the view source content.
+ */
+ get browser() {
+ return gBrowser;
+ },
+
/**
* Holds the value of the last line found via the "Go to line"
* command, to pre-populate the prompt the next time it is
* opened.
*/
lastLineFound: null,
/**
@@ -50,78 +67,76 @@ let ViewSourceChrome = {
contextMenuData: {},
/**
* These are the messages that ViewSourceChrome will listen for
* from the frame script it injects. Any message names added here
* will automatically have ViewSourceChrome listen for those messages,
* and remove the listeners on teardown.
*/
- messages: [
+ messages: ViewSourceBrowser.prototype.messages.concat([
"ViewSource:SourceLoaded",
"ViewSource:SourceUnloaded",
"ViewSource:Close",
"ViewSource:OpenURL",
"ViewSource:GoToLine:Success",
"ViewSource:GoToLine:Failed",
"ViewSource:UpdateStatus",
"ViewSource:ContextMenuOpening",
- ],
+ ]),
/**
- * This should be called as soon as the script loads. When this function
- * executes, we can assume the DOM content has not yet loaded.
+ * This called via ViewSourceBrowser's constructor. This should be called as
+ * soon as the script loads. When this function executes, we can assume the
+ * DOM content has not yet loaded.
*/
init() {
- // We use the window message manager so that if we switch remoteness of the
- // browser (which we might do if we're attempting to load the document
- // source out of the network cache), we automatically re-load the frame
- // script.
- let wMM = window.messageManager;
- wMM.loadFrameScript("chrome://global/content/viewSource-content.js", true);
- this.messages.forEach((msgName) => {
- wMM.addMessageListener(msgName, this);
- });
+ this.mm.loadFrameScript("chrome://global/content/viewSource-content.js", true);
this.shouldWrap = Services.prefs.getBoolPref("view_source.wrap_long_lines");
this.shouldHighlight =
Services.prefs.getBoolPref("view_source.syntax_highlight");
addEventListener("load", this);
addEventListener("unload", this);
addEventListener("AppCommand", this, true);
addEventListener("MozSwipeGesture", this, true);
+
+ ViewSourceBrowser.prototype.init.call(this);
},
/**
* This should be called when the window is closing. This function should
* clean up event and message listeners.
*/
uninit() {
- let wMM = window.messageManager;
- this.messages.forEach((msgName) => {
- wMM.removeMessageListener(msgName, this);
- });
+ ViewSourceBrowser.prototype.uninit.call(this);
// "load" event listener is removed in its handler, to
// ensure we only fire it once.
removeEventListener("unload", this);
removeEventListener("AppCommand", this, true);
removeEventListener("MozSwipeGesture", this, true);
gContextMenu.removeEventListener("popupshowing", this);
gContextMenu.removeEventListener("popuphidden", this);
- Services.els.removeSystemEventListener(gBrowser, "dragover", this, true);
- Services.els.removeSystemEventListener(gBrowser, "drop", this, true);
+ Services.els.removeSystemEventListener(this.browser, "dragover", this,
+ true);
+ Services.els.removeSystemEventListener(this.browser, "drop", this, true);
},
/**
* Anything added to the messages array will get handled here, and should
* get dispatched to a specific function for the message name.
*/
receiveMessage(message) {
+ if (ViewSourceBrowser.prototype.receiveMessage.call(this, message)) {
+ // Handled in super class
+ return;
+ }
+
let data = message.data;
switch(message.name) {
case "ViewSource:SourceLoaded":
this.onSourceLoaded();
break;
case "ViewSource:SourceUnloaded":
this.onSourceUnloaded();
@@ -138,17 +153,17 @@ let ViewSourceChrome = {
case "ViewSource:GoToLine:Success":
this.onGoToLineSuccess(data.lineNumber);
break;
case "ViewSource:UpdateStatus":
this.updateStatus(data.label);
break;
case "ViewSource:ContextMenuOpening":
this.onContextMenuOpening(data.isLink, data.isEmail, data.href);
- if (gBrowser.isRemoteBrowser) {
+ if (this.browser.isRemoteBrowser) {
this.openContextMenu(data.screenX, data.screenY);
}
break;
}
},
/**
* Any events should get handled here, and should get dispatched to
@@ -183,45 +198,52 @@ let ViewSourceChrome = {
}
},
/**
* Getter that returns whether or not the view source browser
* has history enabled on it.
*/
get historyEnabled() {
- return !gBrowser.hasAttribute("disablehistory");
+ return !this.browser.hasAttribute("disablehistory");
},
/**
- * Getter for the message manager of the view source browser.
+ * Getter for the message manager used to communicate with the view source
+ * browser.
+ *
+ * In this window version of view source, we use the window message manager
+ * for loading scripts and listening for messages so that if we switch
+ * remoteness of the browser (which we might do if we're attempting to load
+ * the document source out of the network cache), we automatically re-load
+ * the frame script.
*/
get mm() {
- return gBrowser.messageManager;
+ return window.messageManager;
},
/**
* Getter for the nsIWebNavigation of the view source browser.
*/
get webNav() {
- return gBrowser.webNavigation;
+ return this.browser.webNavigation;
},
/**
* Send the browser forward in its history.
*/
goForward() {
- gBrowser.goForward();
+ this.browser.goForward();
},
/**
* Send the browser backward in its history.
*/
goBack() {
- gBrowser.goBack();
+ this.browser.goBack();
},
/**
* This should be called once when the DOM has finished loading. Here we
* set the state of various menu items, and add event listeners to
* DOM nodes.
*
* This is also the place where we handle any arguments that have been
@@ -262,113 +284,94 @@ let ViewSourceChrome = {
let highlightMenuItem = document.getElementById("menu_highlightSyntax");
if (this.shouldHighlight) {
highlightMenuItem.setAttribute("checked", "true");
}
gContextMenu.addEventListener("popupshowing", this);
gContextMenu.addEventListener("popuphidden", this);
- Services.els.addSystemEventListener(gBrowser, "dragover", this, true);
- Services.els.addSystemEventListener(gBrowser, "drop", this, true);
+ Services.els.addSystemEventListener(this.browser, "dragover", this, true);
+ Services.els.addSystemEventListener(this.browser, "drop", this, true);
if (!this.historyEnabled) {
// Disable the BACK and FORWARD commands and hide the related menu items.
let viewSourceNavigation = document.getElementById("viewSourceNavigation");
if (viewSourceNavigation) {
viewSourceNavigation.setAttribute("disabled", "true");
viewSourceNavigation.setAttribute("hidden", "true");
}
}
// This will only work with non-remote browsers. See bug 1158377.
- gBrowser.droppedLinkHandler = function (event, url, name) {
- ViewSourceChrome.loadURL(url);
+ this.browser.droppedLinkHandler = (event, url, name) => {
+ this.loadURL(url);
event.preventDefault();
};
// We require the first argument to do any loading of source.
// otherwise, we're done.
if (!window.arguments[0]) {
return;
}
if (typeof window.arguments[0] == "string") {
// We're using the deprecated API
- return ViewSourceChrome._loadViewSourceDeprecated();
+ return this._loadViewSourceDeprecated(window.arguments);
}
// We're using the modern API, which allows us to view the
// source of documents from out of process browsers.
let args = window.arguments[0];
-
- if (!args.URL) {
- throw new Error("Must supply a URL when opening view source.");
- }
-
- if (args.browser) {
- // If we're dealing with a remote browser, then the browser
- // for view source needs to be remote as well.
- this.updateBrowserRemoteness(args.browser.isRemoteBrowser);
- } else {
- if (args.outerWindowID) {
- throw new Error("Must supply the browser if passing the outerWindowID");
- }
- }
-
- this.mm.sendAsyncMessage("ViewSource:LoadSource", {
- URL: args.URL,
- outerWindowID: args.outerWindowID,
- lineNumber: args.lineNumber,
- });
+ this.loadViewSource(args);
},
/**
* This is the deprecated API for viewSource.xul, for old-timer consumers.
* This API might eventually go away.
*/
- _loadViewSourceDeprecated() {
+ _loadViewSourceDeprecated(aArguments) {
Deprecated.warning("The arguments you're passing to viewSource.xul " +
"are using an out-of-date API.",
"https://developer.mozilla.org/en-US/Add-ons/Code_snippets/View_Source_for_XUL_Applications");
// 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.
// arg[4] - Whether charset was forced by the user
- if (window.arguments[3] == "selection" ||
- window.arguments[3] == "mathml") {
+ if (aArguments[3] == "selection" ||
+ aArguments[3] == "mathml") {
// viewPartialSource.js will take care of loading the content.
return;
}
- if (window.arguments[2]) {
- let pageDescriptor = window.arguments[2];
+ if (aArguments[2]) {
+ let pageDescriptor = aArguments[2];
if (Cu.isCrossProcessWrapper(pageDescriptor)) {
throw new Error("Cannot pass a CPOW as the page descriptor to viewSource.xul.");
}
}
- if (gBrowser.isRemoteBrowser) {
+ if (this.browser.isRemoteBrowser) {
throw new Error("Deprecated view source API should not use a remote browser.");
}
let forcedCharSet;
- if (window.arguments[4] && window.arguments[1].startsWith("charset=")) {
- forcedCharSet = window.arguments[1].split("=")[1];
+ if (aArguments[4] && aArguments[1].startsWith("charset=")) {
+ forcedCharSet = aArguments[1].split("=")[1];
}
- gBrowser.messageManager.sendAsyncMessage("ViewSource:LoadSourceDeprecated", {
- URL: window.arguments[0],
- lineNumber: window.arguments[3],
+ this.sendAsyncMessage("ViewSource:LoadSourceDeprecated", {
+ URL: aArguments[0],
+ lineNumber: aArguments[3],
forcedCharSet,
}, {
- pageDescriptor: window.arguments[2],
+ pageDescriptor: aArguments[2],
});
},
/**
* Handler for the AppCommand event.
*
* @param event
* The AppCommand event being handled.
@@ -415,17 +418,17 @@ let ViewSourceChrome = {
*/
onSourceLoaded() {
document.getElementById("cmd_goToLine").removeAttribute("disabled");
if (this.historyEnabled) {
this.updateCommands();
}
- gBrowser.focus();
+ this.browser.focus();
},
/**
* Called as soon as the frame script reports that some source
* code has been unloaded from the browser.
*/
onSourceUnloaded() {
// Disable "go to line" while reloading due to e.g. change of charset
@@ -441,23 +444,24 @@ let ViewSourceChrome = {
* The click event on a character set menuitem.
*/
onSetCharacterSet(event) {
if (event.target.hasAttribute("charset")) {
let charset = event.target.getAttribute("charset");
// If we don't have history enabled, we have to do a reload in order to
// show the character set change. See bug 136322.
- this.mm.sendAsyncMessage("ViewSource:SetCharacterSet", {
+ this.sendAsyncMessage("ViewSource:SetCharacterSet", {
charset: charset,
doPageLoad: this.historyEnabled,
});
if (this.historyEnabled) {
- gBrowser.reloadWithFlags(Ci.nsIWebNavigation.LOAD_FLAGS_CHARSET_CHANGE);
+ this.browser
+ .reloadWithFlags(Ci.nsIWebNavigation.LOAD_FLAGS_CHARSET_CHANGE);
}
}
},
/**
* Called from the frame script when the context menu is about to
* open. This tells ViewSourceChrome things about the item that
* the context menu is being opened on. This should be called before
@@ -578,17 +582,17 @@ let ViewSourceChrome = {
/**
* Loads the source of a URL. This will probably end up hitting the
* network.
*
* @param URL
* A URL string to be opened in the view source browser.
*/
loadURL(URL) {
- this.mm.sendAsyncMessage("ViewSource:LoadSource", { URL });
+ this.sendAsyncMessage("ViewSource:LoadSource", { URL });
},
/**
* Updates any commands that are dependant on command broadcasters.
*/
updateCommands() {
let backBroadcaster = document.getElementById("Browser:Back");
let forwardBroadcaster = document.getElementById("Browser:Forward");
@@ -651,17 +655,17 @@ let ViewSourceChrome = {
/**
* Go to a particular line of the source code. This act is asynchronous.
*
* @param lineNumber
* The line number to try to go to to.
*/
goToLine(lineNumber) {
- this.mm.sendAsyncMessage("ViewSource:GoToLine", { lineNumber });
+ this.sendAsyncMessage("ViewSource:GoToLine", { lineNumber });
},
/**
* Called when the frame script reports that a line was successfully gotten
* to.
*
* @param lineNumber
* The line number that we successfully got to.
@@ -685,18 +689,18 @@ let ViewSourceChrome = {
gViewSourceBundle.getString("outOfRangeText"));
this.promptAndGoToLine();
},
/**
* Reloads the browser, bypassing the network cache.
*/
reload() {
- gBrowser.reloadWithFlags(Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_PROXY |
- Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_CACHE);
+ this.browser.reloadWithFlags(Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_PROXY |
+ Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_CACHE);
},
/**
* Closes the view source window.
*/
close() {
window.close();
},
@@ -705,78 +709,78 @@ let ViewSourceChrome = {
* Called when the user clicks on the "Wrap Long Lines" menu item, and
* flips the user preference for wrapping long lines in the view source
* browser.
*/
toggleWrapping() {
this.shouldWrap = !this.shouldWrap;
Services.prefs.setBoolPref("view_source.wrap_long_lines",
this.shouldWrap);
- this.mm.sendAsyncMessage("ViewSource:ToggleWrapping");
+ this.sendAsyncMessage("ViewSource:ToggleWrapping");
},
/**
* Called when the user clicks on the "Syntax Highlighting" menu item, and
* flips the user preference for wrapping long lines in the view source
* browser.
*/
toggleSyntaxHighlighting() {
this.shouldHighlight = !this.shouldHighlight;
// We can't flip this value in the child, since prefs are read-only there.
// We flip it here, and then cause a reload in the child to make the change
// occur.
Services.prefs.setBoolPref("view_source.syntax_highlight",
this.shouldHighlight);
- this.mm.sendAsyncMessage("ViewSource:ToggleSyntaxHighlighting");
+ this.sendAsyncMessage("ViewSource:ToggleSyntaxHighlighting");
},
/**
* Updates the "remote" attribute of the view source browser. This
* will remove the browser from the DOM, and then re-add it in the
* same place it was taken from.
*
* @param shouldBeRemote
* True if the browser should be made remote. If the browsers
* remoteness already matches this value, this function does
* nothing.
*/
updateBrowserRemoteness(shouldBeRemote) {
- if (gBrowser.isRemoteBrowser == shouldBeRemote) {
+ if (this.browser.isRemoteBrowser == shouldBeRemote) {
return;
}
- let parentNode = gBrowser.parentNode;
- let nextSibling = gBrowser.nextSibling;
+ let parentNode = this.browser.parentNode;
+ let nextSibling = this.browser.nextSibling;
- gBrowser.remove();
+ this.browser.remove();
if (shouldBeRemote) {
- gBrowser.setAttribute("remote", "true");
+ this.browser.setAttribute("remote", "true");
} else {
- gBrowser.removeAttribute("remote");
+ this.browser.removeAttribute("remote");
}
// If nextSibling was null, this will put the browser at
// the end of the list.
- parentNode.insertBefore(gBrowser, nextSibling);
+ parentNode.insertBefore(this.browser, nextSibling);
if (shouldBeRemote) {
// We're going to send a message down to the remote browser
// to load the source content - however, in order for the
// contentWindowAsCPOW and contentDocumentAsCPOW values on
// the remote browser to be set, we must set up the
// RemoteWebProgress, which is lazily loaded. We only need
// contentWindowAsCPOW for the printing support, and this
// should go away once bug 1146454 is fixed, since we can
- // then just pass the outerWindowID of the gBrowser to
+ // then just pass the outerWindowID of the this.browser to
// PrintUtils.
- gBrowser.webProgress;
+ this.browser.webProgress;
}
},
};
-ViewSourceChrome.init();
+let viewSourceChrome = new ViewSourceChrome();
/**
* PrintUtils uses this to make Print Preview work.
*/
let PrintPreviewListener = {
getPrintPreviewBrowser() {
let browser = document.getElementById("ppBrowser");
if (!browser) {
@@ -815,17 +819,17 @@ let PrintPreviewListener = {
};
// viewZoomOverlay.js uses this
function getBrowser() {
return gBrowser;
}
this.__defineGetter__("gPageLoader", function () {
- var webnav = ViewSourceChrome.webNav;
+ var webnav = viewSourceChrome.webNav;
if (!webnav)
return null;
delete this.gPageLoader;
this.gPageLoader = (webnav instanceof Ci.nsIWebPageDescriptor) ? webnav
: null;
return this.gPageLoader;
});
@@ -838,98 +842,98 @@ function ViewSourceSavePage()
gPageLoader);
}
// Below are old deprecated functions and variables left behind for
// compatibility reasons. These will be removed soon via bug 1159293.
this.__defineGetter__("gLastLineFound", function () {
Deprecated.warning("gLastLineFound is deprecated - please use " +
- "ViewSourceChrome.lastLineFound instead.",
+ "viewSourceChrome.lastLineFound instead.",
"https://developer.mozilla.org/en-US/Add-ons/Code_snippets/View_Source_for_XUL_Applications");
- return ViewSourceChrome.lastLineFound;
+ return viewSourceChrome.lastLineFound;
});
function onLoadViewSource() {
Deprecated.warning("onLoadViewSource() is deprecated - please use " +
- "ViewSourceChrome.onXULLoaded() instead.",
+ "viewSourceChrome.onXULLoaded() instead.",
"https://developer.mozilla.org/en-US/Add-ons/Code_snippets/View_Source_for_XUL_Applications");
- ViewSourceChrome.onXULLoaded();
+ viewSourceChrome.onXULLoaded();
}
function isHistoryEnabled() {
Deprecated.warning("isHistoryEnabled() is deprecated - please use " +
- "ViewSourceChrome.historyEnabled instead.",
+ "viewSourceChrome.historyEnabled instead.",
"https://developer.mozilla.org/en-US/Add-ons/Code_snippets/View_Source_for_XUL_Applications");
- return ViewSourceChrome.historyEnabled;
+ return viewSourceChrome.historyEnabled;
}
function ViewSourceClose() {
Deprecated.warning("ViewSourceClose() is deprecated - please use " +
- "ViewSourceChrome.close() instead.",
+ "viewSourceChrome.close() instead.",
"https://developer.mozilla.org/en-US/Add-ons/Code_snippets/View_Source_for_XUL_Applications");
- ViewSourceChrome.close();
+ viewSourceChrome.close();
}
function ViewSourceReload() {
Deprecated.warning("ViewSourceReload() is deprecated - please use " +
- "ViewSourceChrome.reload() instead.",
+ "viewSourceChrome.reload() instead.",
"https://developer.mozilla.org/en-US/Add-ons/Code_snippets/View_Source_for_XUL_Applications");
- ViewSourceChrome.reload();
+ viewSourceChrome.reload();
}
function getWebNavigation()
{
Deprecated.warning("getWebNavigation() is deprecated - please use " +
- "ViewSourceChrome.webNav instead.",
+ "viewSourceChrome.webNav instead.",
"https://developer.mozilla.org/en-US/Add-ons/Code_snippets/View_Source_for_XUL_Applications");
// The original implementation returned null if anything threw during
// the getting of the webNavigation.
try {
- return ViewSourceChrome.webNav;
+ return viewSourceChrome.webNav;
} catch (e) {
return null;
}
}
function viewSource(url) {
Deprecated.warning("viewSource() is deprecated - please use " +
- "ViewSourceChrome.loadURL() instead.",
+ "viewSourceChrome.loadURL() instead.",
"https://developer.mozilla.org/en-US/Add-ons/Code_snippets/View_Source_for_XUL_Applications");
- ViewSourceChrome.loadURL(url);
+ viewSourceChrome.loadURL(url);
}
function ViewSourceGoToLine()
{
Deprecated.warning("ViewSourceGoToLine() is deprecated - please use " +
- "ViewSourceChrome.promptAndGoToLine() instead.",
+ "viewSourceChrome.promptAndGoToLine() instead.",
"https://developer.mozilla.org/en-US/Add-ons/Code_snippets/View_Source_for_XUL_Applications");
- ViewSourceChrome.promptAndGoToLine();
+ viewSourceChrome.promptAndGoToLine();
}
function goToLine(line)
{
Deprecated.warning("goToLine() is deprecated - please use " +
- "ViewSourceChrome.goToLine() instead.",
+ "viewSourceChrome.goToLine() instead.",
"https://developer.mozilla.org/en-US/Add-ons/Code_snippets/View_Source_for_XUL_Applications");
- ViewSourceChrome.goToLine(line);
+ viewSourceChrome.goToLine(line);
}
function BrowserForward(aEvent) {
Deprecated.warning("BrowserForward() is deprecated - please use " +
- "ViewSourceChrome.goForward() instead.",
+ "viewSourceChrome.goForward() instead.",
"https://developer.mozilla.org/en-US/Add-ons/Code_snippets/View_Source_for_XUL_Applications");
- ViewSourceChrome.goForward();
+ viewSourceChrome.goForward();
}
function BrowserBack(aEvent) {
Deprecated.warning("BrowserBack() is deprecated - please use " +
- "ViewSourceChrome.goBack() instead.",
+ "viewSourceChrome.goBack() instead.",
"https://developer.mozilla.org/en-US/Add-ons/Code_snippets/View_Source_for_XUL_Applications");
- ViewSourceChrome.goBack();
+ viewSourceChrome.goBack();
}
function UpdateBackForwardCommands() {
Deprecated.warning("UpdateBackForwardCommands() is deprecated - please use " +
- "ViewSourceChrome.updateCommands() instead.",
+ "viewSourceChrome.updateCommands() instead.",
"https://developer.mozilla.org/en-US/Add-ons/Code_snippets/View_Source_for_XUL_Applications");
- ViewSourceChrome.updateCommands();
+ viewSourceChrome.updateCommands();
}
--- a/toolkit/components/viewsource/content/viewSource.xul
+++ b/toolkit/components/viewsource/content/viewSource.xul
@@ -49,26 +49,26 @@
<command id="cmd_findAgain"
oncommand="document.getElementById('FindToolbar').onFindAgainCommand(false);"/>
<command id="cmd_findPrevious"
oncommand="document.getElementById('FindToolbar').onFindAgainCommand(true);"/>
#ifdef XP_MACOSX
<command id="cmd_findSelection"
oncommand="document.getElementById('FindToolbar').onFindSelectionCommand();"/>
#endif
- <command id="cmd_reload" oncommand="ViewSourceChrome.reload();"/>
- <command id="cmd_goToLine" oncommand="ViewSourceChrome.promptAndGoToLine();" disabled="true"/>
- <command id="cmd_highlightSyntax" oncommand="ViewSourceChrome.toggleSyntaxHighlighting();"/>
- <command id="cmd_wrapLongLines" oncommand="ViewSourceChrome.toggleWrapping();"/>
+ <command id="cmd_reload" oncommand="viewSourceChrome.reload();"/>
+ <command id="cmd_goToLine" oncommand="viewSourceChrome.promptAndGoToLine();" disabled="true"/>
+ <command id="cmd_highlightSyntax" oncommand="viewSourceChrome.toggleSyntaxHighlighting();"/>
+ <command id="cmd_wrapLongLines" oncommand="viewSourceChrome.toggleWrapping();"/>
<command id="cmd_textZoomReduce" oncommand="ZoomManager.reduce();"/>
<command id="cmd_textZoomEnlarge" oncommand="ZoomManager.enlarge();"/>
<command id="cmd_textZoomReset" oncommand="ZoomManager.reset();"/>
- <command id="Browser:Back" oncommand="ViewSourceChrome.goBack()" observes="viewSourceNavigation"/>
- <command id="Browser:Forward" oncommand="ViewSourceChrome.goForward()" observes="viewSourceNavigation"/>
+ <command id="Browser:Back" oncommand="viewSourceChrome.goBack()" observes="viewSourceNavigation"/>
+ <command id="Browser:Forward" oncommand="viewSourceChrome.goForward()" observes="viewSourceNavigation"/>
<broadcaster id="viewSourceNavigation"/>
<keyset id="editMenuKeys"/>
<keyset id="viewSourceKeys">
<key id="key_savePage" key="&savePageCmd.commandkey;" modifiers="accel" command="cmd_savePage"/>
<key id="key_print" key="&printCmd.commandkey;" modifiers="accel" command="cmd_print"/>
<key id="key_close" key="&closeCmd.commandkey;" modifiers="accel" command="cmd_close"/>
@@ -126,21 +126,21 @@
observes="viewSourceNavigation"/>
<menuseparator observes="viewSourceNavigation"/>
<menuitem id="cMenu_findAgain"/>
<menuseparator/>
<menuitem id="cMenu_copy"/>
<menuitem id="context-copyLink"
label="©LinkCmd.label;"
accesskey="©LinkCmd.accesskey;"
- oncommand="ViewSourceChrome.onContextMenuCopyLinkOrEmail();"/>
+ oncommand="viewSourceChrome.onContextMenuCopyLinkOrEmail();"/>
<menuitem id="context-copyEmail"
label="©EmailCmd.label;"
accesskey="©EmailCmd.accesskey;"
- oncommand="ViewSourceChrome.onContextMenuCopyLinkOrEmail();"/>
+ oncommand="viewSourceChrome.onContextMenuCopyLinkOrEmail();"/>
<menuseparator/>
<menuitem id="cMenu_selectAll"/>
</menupopup>
<!-- Menu -->
<toolbox id="viewSource-toolbox">
<menubar id="viewSource-main-menubar">
@@ -201,17 +201,17 @@
key="key_textZoomReset"/>
</menupopup>
</menu>
<!-- Charset Menu -->
<menu id="charsetMenu"
label="&charsetMenu2.label;"
accesskey="&charsetMenu2.accesskey;"
- oncommand="ViewSourceChrome.onSetCharacterSet(event);"
+ oncommand="viewSourceChrome.onSetCharacterSet(event);"
onpopupshowing="CharsetMenu.build(event.target);"
onpopupshown="CharsetMenu.update(event.target, content.document.characterSet);">
<menupopup/>
</menu>
<menuseparator/>
<menuitem id="menu_wrapLongLines" type="checkbox" command="cmd_wrapLongLines"
label="&menu_wrapLongLines.title;" accesskey="&menu_wrapLongLines.accesskey;"/>
<menuitem type="checkbox" id="menu_highlightSyntax" command="cmd_highlightSyntax"
--- a/toolkit/components/viewsource/content/viewSourceUtils.js
+++ b/toolkit/components/viewsource/content/viewSourceUtils.js
@@ -7,16 +7,20 @@
/*
* To keep the global namespace safe, don't define global variables and
* functions in this file.
*
* This file silently depends on contentAreaUtils.js for
* getDefaultFileName, getNormalizedLeafName and getDefaultExtension
*/
+Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "ViewSourceBrowser",
+ "resource://gre/modules/ViewSourceBrowser.jsm");
+
var gViewSourceUtils = {
mnsIWebBrowserPersist: Components.interfaces.nsIWebBrowserPersist,
mnsIWebProgress: Components.interfaces.nsIWebProgress,
mnsIWebPageDescriptor: Components.interfaces.nsIWebPageDescriptor,
/**
* Opens the view source window.
@@ -55,16 +59,44 @@ var gViewSourceUtils = {
.getService(Components.interfaces.nsIPrefBranch);
if (prefs.getBoolPref("view_source.editor.external")) {
this.openInExternalEditor(aArgsOrURL, aPageDescriptor, aDocument, aLineNumber);
} else {
this._openInInternalViewer(aArgsOrURL, aPageDescriptor, aDocument, aLineNumber);
}
},
+ /**
+ * Displays view source in the provided <browser>. This allows for non-window
+ * display methods, such as a tab from Firefox. The caller that manages
+ * the <browser> is responsible for ensuring the companion frame script,
+ * viewSource-content.js, has been loaded for the <browser>.
+ *
+ * @param aArgs
+ * An object with the following properties:
+ *
+ * URL (required):
+ * A string URL for the page we'd like to view the source of.
+ * viewSourceBrowser (required):
+ * The browser to display the view source in.
+ * browser (optional):
+ * The browser containing the document that we would like to view the
+ * source of. This is required if outerWindowID is passed.
+ * outerWindowID (optional):
+ * The outerWindowID of the content window containing the document that
+ * we want to view the source of. Pass this if you want to attempt to
+ * load the document source out of the network cache.
+ * lineNumber (optional):
+ * The line number to focus on once the source is loaded.
+ */
+ viewSourceInBrowser: function(aArgs) {
+ let viewSourceBrowser = new ViewSourceBrowser(aArgs.viewSourceBrowser);
+ viewSourceBrowser.loadViewSource(aArgs);
+ },
+
// Opens the interval view source viewer
_openInInternalViewer: function(aArgsOrURL, aPageDescriptor, aDocument, aLineNumber)
{
// try to open a view-source window while inheriting the charset (if any)
var charset = null;
var isForcedCharset = false;
if (aDocument) {
if (Components.utils.isCrossProcessWrapper(aDocument)) {
--- a/toolkit/components/viewsource/jar.mn
+++ b/toolkit/components/viewsource/jar.mn
@@ -4,9 +4,9 @@
toolkit.jar:
content/global/viewSource.css (content/viewSource.css)
content/global/viewSource.js (content/viewSource.js)
* content/global/viewSource.xul (content/viewSource.xul)
content/global/viewPartialSource.js (content/viewPartialSource.js)
* content/global/viewPartialSource.xul (content/viewPartialSource.xul)
content/global/viewSourceUtils.js (content/viewSourceUtils.js)
- content/global/viewSource-content.js (content/viewSource-content.js)
\ No newline at end of file
+ content/global/viewSource-content.js (content/viewSource-content.js)
--- a/toolkit/components/viewsource/moz.build
+++ b/toolkit/components/viewsource/moz.build
@@ -4,10 +4,14 @@
# 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/.
BROWSER_CHROME_MANIFESTS += ['test/browser/browser.ini']
MOCHITEST_CHROME_MANIFESTS += ['test/chrome.ini']
JAR_MANIFESTS += ['jar.mn']
+EXTRA_JS_MODULES += [
+ 'ViewSourceBrowser.jsm',
+]
+
with Files('**'):
BUG_COMPONENT = ('Toolkit', 'View Source')
--- a/toolkit/components/viewsource/test/browser/browser_gotoline.js
+++ b/toolkit/components/viewsource/test/browser/browser_gotoline.js
@@ -19,17 +19,17 @@ add_task(function*() {
let checkViewSource = Task.async(function* (aWindow) {
is(aWindow.gBrowser.contentDocument.body.textContent, content, "Correct content loaded");
let selection = aWindow.gBrowser.contentWindow.getSelection();
let statusPanel = aWindow.document.getElementById("statusbar-line-col");
is(statusPanel.getAttribute("label"), "", "Correct status bar text");
for (let i = 1; i <= 3; i++) {
- aWindow.ViewSourceChrome.goToLine(i);
+ aWindow.viewSourceChrome.goToLine(i);
let result = yield ContentTask.spawn(aWindow.gBrowser, i, function*(i) {
let selection = content.getSelection();
return (selection.toString() == "line " + i);
});
ok(result, "Correct text selected");
yield ContentTaskUtils.waitForCondition(() => {