diff --git a/common/src/viewSource.css b/common/src/viewSource.css new file mode 100644 index 0000000000..4260252a27 --- /dev/null +++ b/common/src/viewSource.css @@ -0,0 +1,7 @@ +/* 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/. */ + +toolbar[printpreview="true"] { + -moz-binding: url("chrome://global/content/printPreviewBindings.xml#printpreviewtoolbar"); +} diff --git a/common/src/viewSource.js b/common/src/viewSource.js new file mode 100644 index 0000000000..714b4b0852 --- /dev/null +++ b/common/src/viewSource.js @@ -0,0 +1,866 @@ +// -*- indent-tabs-mode: nil; js-indent-level: 2 -*- + +/* import-globals-from ../../../content/globalOverlay.js */ +/* import-globals-from ../../printing/content/printUtils.js */ +/* import-globals-from ../../../content/viewZoomOverlay.js */ +/* import-globals-from ../../../content/contentAreaUtils.js */ + +/* 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/. */ + +ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm"); +ChromeUtils.import("resource://gre/modules/ViewSourceBrowser.jsm"); + +ChromeUtils.defineModuleGetter(this, "Services", + "resource://gre/modules/Services.jsm"); +ChromeUtils.defineModuleGetter(this, "CharsetMenu", + "resource://gre/modules/CharsetMenu.jsm"); +ChromeUtils.defineModuleGetter(this, "Deprecated", + "resource://gre/modules/Deprecated.jsm"); + +/* global gBrowser, gViewSourceBundle, gContextMenu */ +[ + ["gBrowser", "content"], + ["gViewSourceBundle", "viewSourceBundle"], + ["gContextMenu", "viewSourceContextMenu"] +].forEach(function([name, id]) { + Object.defineProperty(window, name, { + configurable: true, + enumerable: true, + get() { + var element = document.getElementById(id); + if (!element) + return null; + delete window[name]; + return window[name] = element; + }, + }); +}); + +/** + * ViewSourceChrome is the primary interface for interacting with + * 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. + */ +function ViewSourceChrome() { + ViewSourceBrowser.call(this); +} + +ViewSourceChrome.prototype = { + __proto__: ViewSourceBrowser.prototype, + + /** + * The that will be displaying the view source content. + */ + get browser() { + return gBrowser; + }, + + /** + * The context menu, when opened from the content process, sends + * up a chunk of serialized data describing the items that the + * context menu is being opened on. This allows us to avoid using + * CPOWs. + */ + 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: ViewSourceBrowser.prototype.messages.concat([ + "ViewSource:SourceLoaded", + "ViewSource:SourceUnloaded", + "ViewSource:Close", + "ViewSource:OpenURL", + "ViewSource:ContextMenuOpening", + ]), + + /** + * 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() { + 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() { + 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(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) { + let data = message.data; + + switch (message.name) { + // Begin messages from super class + case "ViewSource:PromptAndGoToLine": + this.promptAndGoToLine(); + break; + case "ViewSource:GoToLine:Success": + this.onGoToLineSuccess(data.lineNumber); + break; + case "ViewSource:GoToLine:Failed": + this.onGoToLineFailed(); + break; + case "ViewSource:StoreWrapping": + this.storeWrapping(data.state); + break; + case "ViewSource:StoreSyntaxHighlighting": + this.storeSyntaxHighlighting(data.state); + break; + // End messages from super class + case "ViewSource:SourceLoaded": + this.onSourceLoaded(); + break; + case "ViewSource:SourceUnloaded": + this.onSourceUnloaded(); + break; + case "ViewSource:Close": + this.close(); + break; + case "ViewSource:OpenURL": + this.openURL(data.URL); + break; + case "ViewSource:ContextMenuOpening": + this.onContextMenuOpening(data.isLink, data.isEmail, data.href); + if (this.browser.isRemoteBrowser) { + this.openContextMenu(data.screenX, data.screenY); + } + break; + } + }, + + /** + * Any events should get handled here, and should get dispatched to + * a specific function for the event type. + */ + handleEvent(event) { + switch (event.type) { + case "unload": + this.uninit(); + break; + case "load": + this.onXULLoaded(); + break; + case "AppCommand": + this.onAppCommand(event); + break; + case "MozSwipeGesture": + this.onSwipeGesture(event); + break; + case "popupshowing": + this.onContextMenuShowing(event); + break; + case "popuphidden": + this.onContextMenuHidden(event); + break; + case "dragover": + this.onDragOver(event); + break; + case "drop": + this.onDrop(event); + break; + } + }, + + /** + * Getter that returns whether or not the view source browser + * has history enabled on it. + */ + get historyEnabled() { + return !this.browser.hasAttribute("disablehistory"); + }, + + /** + * 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 window.messageManager; + }, + + /** + * Getter for the nsIWebNavigation of the view source browser. + */ + get webNav() { + return this.browser.webNavigation; + }, + + /** + * Send the browser forward in its history. + */ + goForward() { + this.browser.goForward(); + }, + + /** + * Send the browser backward in its history. + */ + 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 + * passed to viewSource.xul. + * + * Modern consumers should pass a single object argument to viewSource.xul: + * + * 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. + * + * The deprecated API has the opener pass in a number of arguments: + * + * arg[0] - URL string. + * arg[1] - Charset value string in the form 'charset=xxx'. + * arg[2] - Page descriptor from nsIWebPageDescriptor used to load content + * from the cache. + * arg[3] - Line number to go to. + * arg[4] - Boolean for whether charset was forced by the user + */ + onXULLoaded() { + // This handler should only ever run the first time the XUL is loaded. + removeEventListener("load", this); + + let wrapMenuItem = document.getElementById("menu_wrapLongLines"); + if (this.shouldWrap) { + wrapMenuItem.setAttribute("checked", "true"); + } + + let highlightMenuItem = document.getElementById("menu_highlightSyntax"); + if (this.shouldHighlight) { + highlightMenuItem.setAttribute("checked", "true"); + } + + gContextMenu.addEventListener("popupshowing", this); + gContextMenu.addEventListener("popuphidden", this); + + 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"); + } + } + + // We require the first argument to do any loading of source. + // otherwise, we're done. + if (!window.arguments[0]) { + return undefined; + } + + if (typeof window.arguments[0] == "string") { + // We're using the deprecated API + 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]; + + // viewPartialSource.js will take care of loading the content in partial mode. + if (!args.partial) { + this.loadViewSource(args); + } + + return undefined; + }, + + /** + * This is the deprecated API for viewSource.xul, for old-timer consumers. + * This API might eventually go away. + */ + _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 (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 (this.browser.isRemoteBrowser) { + throw new Error("Deprecated view source API should not use a remote browser."); + } + + let forcedCharSet; + if (aArguments[4] && aArguments[1].startsWith("charset=")) { + forcedCharSet = aArguments[1].split("=")[1]; + } + + this.sendAsyncMessage("ViewSource:LoadSourceDeprecated", { + URL: aArguments[0], + lineNumber: aArguments[3], + forcedCharSet, + }, { + pageDescriptor: aArguments[2], + }); + }, + + /** + * Handler for the AppCommand event. + * + * @param event + * The AppCommand event being handled. + */ + onAppCommand(event) { + event.stopPropagation(); + switch (event.command) { + case "Back": + this.goBack(); + break; + case "Forward": + this.goForward(); + break; + } + }, + + /** + * Handler for the MozSwipeGesture event. + * + * @param event + * The MozSwipeGesture event being handled. + */ + onSwipeGesture(event) { + event.stopPropagation(); + switch (event.direction) { + case SimpleGestureEvent.DIRECTION_LEFT: + this.goBack(); + break; + case SimpleGestureEvent.DIRECTION_RIGHT: + this.goForward(); + break; + case SimpleGestureEvent.DIRECTION_UP: + goDoCommand("cmd_scrollTop"); + break; + case SimpleGestureEvent.DIRECTION_DOWN: + goDoCommand("cmd_scrollBottom"); + break; + } + }, + + /** + * Called as soon as the frame script reports that some source + * code has been loaded in the browser. + */ + onSourceLoaded() { + document.getElementById("cmd_goToLine").removeAttribute("disabled"); + + if (this.historyEnabled) { + this.updateCommands(); + } + + 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 + // or toggling of syntax highlighting. + document.getElementById("cmd_goToLine").setAttribute("disabled", "true"); + }, + + /** + * Called by clicks on a menu populated by CharsetMenu.jsm to + * change the selected character set. + * + * @param event + * 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.sendAsyncMessage("ViewSource:SetCharacterSet", { + charset, + doPageLoad: this.historyEnabled, + }); + + if (!this.historyEnabled) { + 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 + * the popupshowing event handler fires. + */ + onContextMenuOpening(isLink, isEmail, href) { + this.contextMenuData = { isLink, isEmail, href, isOpen: true }; + }, + + /** + * Event handler for the popupshowing event on the context menu. + * This handler is responsible for setting the state on various + * menu items in the context menu, and reads values that were sent + * up from the frame script and stashed into this.contextMenuData. + * + * @param event + * The popupshowing event for the context menu. + */ + onContextMenuShowing(event) { + let copyLinkMenuItem = document.getElementById("context-copyLink"); + copyLinkMenuItem.hidden = !this.contextMenuData.isLink; + + let copyEmailMenuItem = document.getElementById("context-copyEmail"); + copyEmailMenuItem.hidden = !this.contextMenuData.isEmail; + }, + + /** + * Called when the user chooses the "Copy Link" or "Copy Email" + * menu items in the context menu. Copies the relevant selection + * into the system clipboard. + */ + onContextMenuCopyLinkOrEmail() { + // It doesn't make any sense to call this if the context menu + // isn't open... + if (!this.contextMenuData.isOpen) { + return; + } + + let clipboard = Cc["@mozilla.org/widget/clipboardhelper;1"] + .getService(Ci.nsIClipboardHelper); + clipboard.copyString(this.contextMenuData.href); + }, + + /** + * Called when the context menu closes, and invalidates any data + * that the frame script might have sent up about what the context + * menu was opened on. + */ + onContextMenuHidden(event) { + this.contextMenuData = { + isOpen: false, + }; + }, + + /** + * Called when the user drags something over the content browser. + */ + onDragOver(event) { + // For drags that appear to be internal text (for example, tab drags), + // set the dropEffect to 'none'. This prevents the drop even if some + // other listener cancelled the event. + let types = event.dataTransfer.types; + if (types.includes("text/x-moz-text-internal") && !types.includes("text/plain")) { + event.dataTransfer.dropEffect = "none"; + event.stopPropagation(); + event.preventDefault(); + } + + if (Services.droppedLinkHandler.canDropLink(event, false)) { + event.preventDefault(); + } + }, + + /** + * Called twhen the user drops something onto the content browser. + */ + onDrop(event) { + if (event.defaultPrevented) + return; + + let name = { }; + let uri; + try { + // Pass true to prevent the dropping of javascript:/data: URIs + uri = Services.droppedLinkHandler.dropLink(event, name, true); + } catch (e) { + return; + } + + if (uri) { + this.loadURL(uri); + } + }, + + /** + * For remote browsers, the contextmenu event is received in the + * content process, and a message is sent up from the frame script + * to ViewSourceChrome, but then it stops. The event does not bubble + * up to the point that the popup is opened in the parent process. + * ViewSourceChrome is responsible for opening up the context menu in + * that case. This is called when we receive the contextmenu message + * from the child, and we know that the browser is currently remote. + * + * @param screenX + * The screenX coordinate to open the popup at. + * @param screenY + * The screenY coordinate to open the popup at. + */ + openContextMenu(screenX, screenY) { + gContextMenu.openPopupAtScreen(screenX, screenY, true); + }, + + /** + * 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.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"); + + if (this.webNav.canGoBack) { + backBroadcaster.removeAttribute("disabled"); + } else { + backBroadcaster.setAttribute("disabled", "true"); + } + if (this.webNav.canGoForward) { + forwardBroadcaster.removeAttribute("disabled"); + } else { + forwardBroadcaster.setAttribute("disabled", "true"); + } + }, + + /** + * Reloads the browser, bypassing the network cache. + */ + reload() { + this.browser.reloadWithFlags(Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_PROXY | + Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_CACHE); + }, + + /** + * Closes the view source window. + */ + close() { + window.close(); + }, + + /** + * Called when the user clicks on the "Wrap Long Lines" menu item. + */ + toggleWrapping() { + this.shouldWrap = !this.shouldWrap; + this.sendAsyncMessage("ViewSource:ToggleWrapping"); + }, + + /** + * Called when the user clicks on the "Syntax Highlighting" menu item. + */ + toggleSyntaxHighlighting() { + this.shouldHighlight = !this.shouldHighlight; + 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. + * @param remoteType + * The type of remote browser process. + */ + updateBrowserRemoteness(shouldBeRemote, remoteType) { + if (this.browser.isRemoteBrowser == shouldBeRemote && + this.browser.remoteType == remoteType) { + return; + } + + let parentNode = this.browser.parentNode; + let nextSibling = this.browser.nextSibling; + + // Removing and re-adding the browser from and to the DOM strips its XBL + // properties. Save and restore sameProcessAsFrameLoader. Note that when we + // restore sameProcessAsFrameLoader, there won't yet be a binding or + // setter. This works in conjunction with the hack in 's + // constructor to re-get the weak reference to it. + let sameProcessAsFrameLoader = this.browser.sameProcessAsFrameLoader; + + this.browser.remove(); + if (shouldBeRemote) { + this.browser.setAttribute("remote", "true"); + this.browser.setAttribute("remoteType", remoteType); + } else { + this.browser.removeAttribute("remote"); + this.browser.removeAttribute("remoteType"); + } + + this.browser.sameProcessAsFrameLoader = sameProcessAsFrameLoader; + + // If nextSibling was null, this will put the browser at + // the end of the list. + 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 this.browser to + // PrintUtils. + this.browser.webProgress; + } + }, +}; + +var viewSourceChrome = new ViewSourceChrome(); + +/** + * PrintUtils uses this to make Print Preview work. + */ +var PrintPreviewListener = { + _ppBrowser: null, + + getPrintPreviewBrowser() { + if (!this._ppBrowser) { + this._ppBrowser = document.createElement("browser"); + this._ppBrowser.setAttribute("flex", "1"); + this._ppBrowser.setAttribute("type", "content"); + } + + if (gBrowser.isRemoteBrowser) { + this._ppBrowser.setAttribute("remote", "true"); + } else { + this._ppBrowser.removeAttribute("remote"); + } + + let findBar = document.getElementById("FindToolbar"); + document.getElementById("appcontent") + .insertBefore(this._ppBrowser, findBar); + + return this._ppBrowser; + }, + + getSourceBrowser() { + return gBrowser; + }, + + getNavToolbox() { + return document.getElementById("appcontent"); + }, + + onEnter() { + let toolbox = document.getElementById("viewSource-toolbox"); + toolbox.hidden = true; + gBrowser.collapsed = true; + }, + + onExit() { + this._ppBrowser.remove(); + gBrowser.collapsed = false; + document.getElementById("viewSource-toolbox").hidden = false; + }, + + activateBrowser(browser) { + browser.docShellIsActive = true; + }, +}; + +// viewZoomOverlay.js uses this +function getBrowser() { + return gBrowser; +} + +Object.defineProperty(this, "gPageLoader", { + configurable: true, + enumerable: true, + get() { + var webnav = viewSourceChrome.webNav; + if (!webnav) + return null; + delete this.gPageLoader; + this.gPageLoader = (webnav instanceof Ci.nsIWebPageDescriptor) ? webnav + : null; + return this.gPageLoader; + }, +}); + +// Strips the |view-source:| for internalSave() +function ViewSourceSavePage() { + internalSave(gBrowser.currentURI.spec.replace(/^view-source:/i, ""), + null, null, null, null, null, "SaveLinkTitle", + null, null, gBrowser.contentDocumentAsCPOW, null, + gPageLoader); +} + +// Below are old deprecated functions and variables left behind for +// compatibility reasons. These will be removed soon via bug 1159293. + +Object.defineProperty(this, "gLastLineFound", { + configurable: true, + enumerable: true, + get() { + Deprecated.warning("gLastLineFound is deprecated - please use " + + "viewSourceChrome.lastLineFound instead.", + "https://developer.mozilla.org/en-US/Add-ons/Code_snippets/View_Source_for_XUL_Applications"); + return viewSourceChrome.lastLineFound; + }, +}); + +function onLoadViewSource() { + Deprecated.warning("onLoadViewSource() is deprecated - please use " + + "viewSourceChrome.onXULLoaded() instead.", + "https://developer.mozilla.org/en-US/Add-ons/Code_snippets/View_Source_for_XUL_Applications"); + viewSourceChrome.onXULLoaded(); +} + +function isHistoryEnabled() { + Deprecated.warning("isHistoryEnabled() is deprecated - please use " + + "viewSourceChrome.historyEnabled instead.", + "https://developer.mozilla.org/en-US/Add-ons/Code_snippets/View_Source_for_XUL_Applications"); + return viewSourceChrome.historyEnabled; +} + +function ViewSourceClose() { + Deprecated.warning("ViewSourceClose() is deprecated - please use " + + "viewSourceChrome.close() instead.", + "https://developer.mozilla.org/en-US/Add-ons/Code_snippets/View_Source_for_XUL_Applications"); + viewSourceChrome.close(); +} + +function ViewSourceReload() { + Deprecated.warning("ViewSourceReload() is deprecated - please use " + + "viewSourceChrome.reload() instead.", + "https://developer.mozilla.org/en-US/Add-ons/Code_snippets/View_Source_for_XUL_Applications"); + viewSourceChrome.reload(); +} + +function getWebNavigation() { + Deprecated.warning("getWebNavigation() is deprecated - please use " + + "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; + } catch (e) { + return null; + } +} + +function viewSource(url) { + Deprecated.warning("viewSource() is deprecated - please use " + + "viewSourceChrome.loadURL() instead.", + "https://developer.mozilla.org/en-US/Add-ons/Code_snippets/View_Source_for_XUL_Applications"); + viewSourceChrome.loadURL(url); +} + +function ViewSourceGoToLine() { + Deprecated.warning("ViewSourceGoToLine() is deprecated - please use " + + "viewSourceChrome.promptAndGoToLine() instead.", + "https://developer.mozilla.org/en-US/Add-ons/Code_snippets/View_Source_for_XUL_Applications"); + viewSourceChrome.promptAndGoToLine(); +} + +function goToLine(line) { + Deprecated.warning("goToLine() is deprecated - please use " + + "viewSourceChrome.goToLine() instead.", + "https://developer.mozilla.org/en-US/Add-ons/Code_snippets/View_Source_for_XUL_Applications"); + viewSourceChrome.goToLine(line); +} + +function BrowserForward(aEvent) { + Deprecated.warning("BrowserForward() is deprecated - please use " + + "viewSourceChrome.goForward() instead.", + "https://developer.mozilla.org/en-US/Add-ons/Code_snippets/View_Source_for_XUL_Applications"); + viewSourceChrome.goForward(); +} + +function BrowserBack(aEvent) { + Deprecated.warning("BrowserBack() is deprecated - please use " + + "viewSourceChrome.goBack() instead.", + "https://developer.mozilla.org/en-US/Add-ons/Code_snippets/View_Source_for_XUL_Applications"); + viewSourceChrome.goBack(); +} + +function UpdateBackForwardCommands() { + Deprecated.warning("UpdateBackForwardCommands() is deprecated - please use " + + "viewSourceChrome.updateCommands() instead.", + "https://developer.mozilla.org/en-US/Add-ons/Code_snippets/View_Source_for_XUL_Applications"); + viewSourceChrome.updateCommands(); +} diff --git a/common/src/viewSource.xul b/common/src/viewSource.xul new file mode 100644 index 0000000000..dc9aeb59ea --- /dev/null +++ b/common/src/viewSource.xul @@ -0,0 +1,229 @@ + +# -*- Mode: HTML -*- +# 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/. + + + + + + +%brandDTD; + +%sourceDTD; +]> + + + +