From 1fde438170122f486b62eec43acf34583f3b18c2 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Sat, 23 May 2015 18:17:50 -0500 Subject: [PATCH] Bug 1067325 - Extract view source core to support tabs. r=mconley --- browser/app/profile/firefox.js | 2 + browser/base/content/browser.js | 22 +- .../viewsource/ViewSourceBrowser.jsm | 161 +++++++++++++ .../viewsource/content/viewPartialSource.js | 7 +- .../viewsource/content/viewPartialSource.xul | 10 +- .../viewsource/content/viewSource-content.js | 34 ++- .../viewsource/content/viewSource.js | 219 +++++++++--------- .../viewsource/content/viewSource.xul | 18 +- .../viewsource/content/viewSourceUtils.js | 32 +++ toolkit/components/viewsource/jar.mn | 2 +- toolkit/components/viewsource/moz.build | 4 + .../test/browser/browser_gotoline.js | 2 +- 12 files changed, 367 insertions(+), 146 deletions(-) create mode 100644 toolkit/components/viewsource/ViewSourceBrowser.jsm diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js index 3fdcc75af52..489916ffd6d 100644 --- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -1921,3 +1921,5 @@ 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); diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index 2c93704cdc9..112d9d86154 100644 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -986,6 +986,7 @@ var gBrowserInit = { 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); @@ -2322,11 +2323,11 @@ function readFromClipboard() * If aArgsOrDocument is an object, that object can take the * following properties: * - * browser: - * The browser containing the document that we would like to view the - * source of. - * URL: + * 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. 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 @@ -2359,7 +2360,18 @@ function BrowserViewSourceOfDocument(aArgsOrDocument) { 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); + } } /** diff --git a/toolkit/components/viewsource/ViewSourceBrowser.jsm b/toolkit/components/viewsource/ViewSourceBrowser.jsm new file mode 100644 index 00000000000..b4284cc6ed3 --- /dev/null +++ b/toolkit/components/viewsource/ViewSourceBrowser.jsm @@ -0,0 +1,161 @@ +// -*- 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 the view source 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 loading 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 . The caller that manages + * the is responsible for ensuring the companion frame script has been + * loaded. + */ +this.ViewSourceBrowser = function ViewSourceBrowser(aBrowser) { + this._browser = aBrowser; + this.init(); +} + +ViewSourceBrowser.prototype = { + /** + * The 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) { + } + }, + + /** + * 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 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"); + } + }, +}; diff --git a/toolkit/components/viewsource/content/viewPartialSource.js b/toolkit/components/viewsource/content/viewPartialSource.js index ba42d26e3cb..892e8955a66 100644 --- a/toolkit/components/viewsource/content/viewPartialSource.js +++ b/toolkit/components/viewsource/content/viewPartialSource.js @@ -40,11 +40,6 @@ function onLoadViewPartialSource() else viewPartialSourceForFragment(window.arguments[2], window.arguments[3]); - gBrowser.droppedLinkHandler = function (event, url, name) { - viewSource(url) - event.preventDefault(); - } - window.content.focus(); } @@ -174,7 +169,7 @@ function viewPartialSourceForSelection(selection) // 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), diff --git a/toolkit/components/viewsource/content/viewPartialSource.xul b/toolkit/components/viewsource/content/viewPartialSource.xul index 9bb19808b6e..3af4e9c114a 100644 --- a/toolkit/components/viewsource/content/viewPartialSource.xul +++ b/toolkit/components/viewsource/content/viewPartialSource.xul @@ -50,9 +50,9 @@ oncommand="document.getElementById('FindToolbar').onFindAgainCommand(false);"/> - - - + + + @@ -80,11 +80,11 @@ + oncommand="viewSourceChrome.onContextMenuCopyLinkOrEmail();"/> + oncommand="viewSourceChrome.onContextMenuCopyLinkOrEmail();"/> diff --git a/toolkit/components/viewsource/content/viewSource-content.js b/toolkit/components/viewsource/content/viewSource-content.js index bee997554b6..491e93b2cb9 100644 --- a/toolkit/components/viewsource/content/viewSource-content.js +++ b/toolkit/components/viewsource/content/viewSource-content.js @@ -51,6 +51,16 @@ let ViewSourceContent = { */ selectionListenerAttached: false, + get isViewSource() { + let uri = content.document.documentURI; + return uri.startsWith("view-source:"); + }, + + get isAboutBlank() { + let uri = content.document.documentURI; + return uri == "about:blank"; + }, + /** * This should be called as soon as this frame script has loaded. */ @@ -93,6 +103,9 @@ let ViewSourceContent = { * get dispatched to a specific function for the message name. */ receiveMessage(msg) { + if (!this.isViewSource && !this.isAboutBlank) { + return; + } let data = msg.data; let objects = msg.objects; switch(msg.name) { @@ -124,6 +137,9 @@ let ViewSourceContent = { * a specific function for the event type. */ handleEvent(event) { + if (!this.isViewSource) { + return; + } switch(event.type) { case "pagehide": this.onPageHide(event); @@ -250,8 +266,13 @@ let ViewSourceContent = { docShell.charset = forcedCharSet; } - if (lineNumber) { + if (lineNumber && lineNumber > 0) { let doneLoading = (event) => { + // Ignore possible initial load of about:blank + if (this.isAboutBlank || + !content.document.body) { + return; + } this.goToLine(lineNumber); removeEventListener("pageshow", doneLoading); }; @@ -341,11 +362,12 @@ let ViewSourceContent = { * 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"); }, diff --git a/toolkit/components/viewsource/content/viewSource.js b/toolkit/components/viewsource/content/viewSource.js index a2754abba5a..ada2fd6a7d3 100644 --- a/toolkit/components/viewsource/content/viewSource.js +++ b/toolkit/components/viewsource/content/viewSource.js @@ -7,6 +7,7 @@ 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"); @@ -31,9 +32,25 @@ XPCOMUtils.defineLazyModuleGetter(this, "Deprecated", /** * 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 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 @@ -55,7 +72,7 @@ let ViewSourceChrome = { * 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", @@ -64,22 +81,15 @@ let ViewSourceChrome = { "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 = @@ -89,6 +99,8 @@ let ViewSourceChrome = { addEventListener("unload", this); addEventListener("AppCommand", this, true); addEventListener("MozSwipeGesture", this, true); + + ViewSourceBrowser.prototype.init.call(this); }, /** @@ -96,10 +108,7 @@ let ViewSourceChrome = { * 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. @@ -108,8 +117,9 @@ let ViewSourceChrome = { 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); }, /** @@ -143,7 +153,7 @@ let ViewSourceChrome = { 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; @@ -188,35 +198,42 @@ let ViewSourceChrome = { * 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(); }, /** @@ -267,8 +284,8 @@ let ViewSourceChrome = { 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. @@ -279,12 +296,6 @@ let ViewSourceChrome = { } } - // This will only work with non-remote browsers. See bug 1158377. - gBrowser.droppedLinkHandler = function (event, url, name) { - ViewSourceChrome.loadURL(url); - event.preventDefault(); - }; - // We require the first argument to do any loading of source. // otherwise, we're done. if (!window.arguments[0]) { @@ -293,39 +304,20 @@ let ViewSourceChrome = { 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"); @@ -336,34 +328,34 @@ let ViewSourceChrome = { // 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], }); }, @@ -420,7 +412,7 @@ let ViewSourceChrome = { this.updateCommands(); } - gBrowser.focus(); + this.browser.focus(); }, /** @@ -446,13 +438,14 @@ let ViewSourceChrome = { // 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); } } }, @@ -583,7 +576,7 @@ let ViewSourceChrome = { * A URL string to be opened in the view source browser. */ loadURL(URL) { - this.mm.sendAsyncMessage("ViewSource:LoadSource", { URL }); + this.sendAsyncMessage("ViewSource:LoadSource", { URL }); }, /** @@ -656,7 +649,7 @@ let ViewSourceChrome = { * The line number to try to go to to. */ goToLine(lineNumber) { - this.mm.sendAsyncMessage("ViewSource:GoToLine", { lineNumber }); + this.sendAsyncMessage("ViewSource:GoToLine", { lineNumber }); }, /** @@ -690,8 +683,8 @@ let ViewSourceChrome = { * 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); }, /** @@ -710,7 +703,7 @@ let ViewSourceChrome = { this.shouldWrap = !this.shouldWrap; Services.prefs.setBoolPref("view_source.wrap_long_lines", this.shouldWrap); - this.mm.sendAsyncMessage("ViewSource:ToggleWrapping"); + this.sendAsyncMessage("ViewSource:ToggleWrapping"); }, /** @@ -725,7 +718,7 @@ let ViewSourceChrome = { // occur. Services.prefs.setBoolPref("view_source.syntax_highlight", this.shouldHighlight); - this.mm.sendAsyncMessage("ViewSource:ToggleSyntaxHighlighting"); + this.sendAsyncMessage("ViewSource:ToggleSyntaxHighlighting"); }, /** @@ -739,22 +732,22 @@ let ViewSourceChrome = { * 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 @@ -764,14 +757,14 @@ let ViewSourceChrome = { // 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. @@ -820,7 +813,7 @@ function getBrowser() { } this.__defineGetter__("gPageLoader", function () { - var webnav = ViewSourceChrome.webNav; + var webnav = viewSourceChrome.webNav; if (!webnav) return null; delete this.gPageLoader; @@ -843,48 +836,48 @@ function ViewSourceSavePage() 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; } @@ -892,44 +885,44 @@ function getWebNavigation() 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(); } diff --git a/toolkit/components/viewsource/content/viewSource.xul b/toolkit/components/viewsource/content/viewSource.xul index b8d81843da2..9669f5608bb 100644 --- a/toolkit/components/viewsource/content/viewSource.xul +++ b/toolkit/components/viewsource/content/viewSource.xul @@ -54,16 +54,16 @@ #endif - - - - + + + + - - + + @@ -131,11 +131,11 @@ + oncommand="viewSourceChrome.onContextMenuCopyLinkOrEmail();"/> + oncommand="viewSourceChrome.onContextMenuCopyLinkOrEmail();"/> @@ -206,7 +206,7 @@ diff --git a/toolkit/components/viewsource/content/viewSourceUtils.js b/toolkit/components/viewsource/content/viewSourceUtils.js index 303280362ac..c2505c9b137 100644 --- a/toolkit/components/viewsource/content/viewSourceUtils.js +++ b/toolkit/components/viewsource/content/viewSourceUtils.js @@ -12,6 +12,10 @@ * 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, @@ -60,6 +64,34 @@ var gViewSourceUtils = { } }, + /** + * Displays view source in the provided . This allows for non-window + * display methods, such as a tab from Firefox. The caller that manages + * the is responsible for ensuring the companion frame script, + * viewSource-content.js, has been loaded for the . + * + * @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) { diff --git a/toolkit/components/viewsource/jar.mn b/toolkit/components/viewsource/jar.mn index 249a0ccaf77..00a1f19a46f 100644 --- a/toolkit/components/viewsource/jar.mn +++ b/toolkit/components/viewsource/jar.mn @@ -9,4 +9,4 @@ toolkit.jar: 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) diff --git a/toolkit/components/viewsource/moz.build b/toolkit/components/viewsource/moz.build index 7ed8b22d845..0d195c398ef 100644 --- a/toolkit/components/viewsource/moz.build +++ b/toolkit/components/viewsource/moz.build @@ -9,5 +9,9 @@ MOCHITEST_CHROME_MANIFESTS += ['test/chrome.ini'] JAR_MANIFESTS += ['jar.mn'] +EXTRA_JS_MODULES += [ + 'ViewSourceBrowser.jsm', +] + with Files('**'): BUG_COMPONENT = ('Toolkit', 'View Source') diff --git a/toolkit/components/viewsource/test/browser/browser_gotoline.js b/toolkit/components/viewsource/test/browser/browser_gotoline.js index aff9241fd41..2db18adb111 100644 --- a/toolkit/components/viewsource/test/browser/browser_gotoline.js +++ b/toolkit/components/viewsource/test/browser/browser_gotoline.js @@ -24,7 +24,7 @@ let checkViewSource = Task.async(function* (aWindow) { 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);