diff options
Diffstat (limited to 'devtools/client/shared/view-source.js')
-rw-r--r-- | devtools/client/shared/view-source.js | 185 |
1 files changed, 185 insertions, 0 deletions
diff --git a/devtools/client/shared/view-source.js b/devtools/client/shared/view-source.js new file mode 100644 index 000000000..6e2623ab4 --- /dev/null +++ b/devtools/client/shared/view-source.js @@ -0,0 +1,185 @@ +/* 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/. */ + +"use strict"; + +var { Task } = require("devtools/shared/task"); + +var Services = require("Services"); +var { gDevTools } = require("devtools/client/framework/devtools"); +var { getSourceText } = require("devtools/client/debugger/content/queries"); + +/** + * Tries to open a Stylesheet file in the Style Editor. If the file is not + * found, it is opened in source view instead. + * Returns a promise resolving to a boolean indicating whether or not + * the source was able to be displayed in the StyleEditor, as the built-in + * Firefox View Source is the fallback. + * + * @param {Toolbox} toolbox + * @param {string} sourceURL + * @param {number} sourceLine + * + * @return {Promise<boolean>} + */ +exports.viewSourceInStyleEditor = Task.async(function* (toolbox, sourceURL, + sourceLine) { + let panel = yield toolbox.loadTool("styleeditor"); + + try { + yield panel.selectStyleSheet(sourceURL, sourceLine); + yield toolbox.selectTool("styleeditor"); + return true; + } catch (e) { + exports.viewSource(toolbox, sourceURL, sourceLine); + return false; + } +}); + +/** + * Tries to open a JavaScript file in the Debugger. If the file is not found, + * it is opened in source view instead. + * Returns a promise resolving to a boolean indicating whether or not + * the source was able to be displayed in the Debugger, as the built-in Firefox + * View Source is the fallback. + * + * @param {Toolbox} toolbox + * @param {string} sourceURL + * @param {number} sourceLine + * + * @return {Promise<boolean>} + */ +exports.viewSourceInDebugger = Task.async(function* (toolbox, sourceURL, sourceLine) { + // If the Debugger was already open, switch to it and try to show the + // source immediately. Otherwise, initialize it and wait for the sources + // to be added first. + let debuggerAlreadyOpen = toolbox.getPanel("jsdebugger"); + let dbg = yield toolbox.loadTool("jsdebugger"); + + // New debugger frontend + if (Services.prefs.getBoolPref("devtools.debugger.new-debugger-frontend")) { + yield toolbox.selectTool("jsdebugger"); + const source = dbg._selectors().getSourceByURL(dbg._getState(), sourceURL); + if (source) { + dbg._actions().selectSourceURL(sourceURL, { line: sourceLine }); + return true; + } + + exports.viewSource(toolbox, sourceURL, sourceLine); + return false; + } + + const win = dbg.panelWin; + + // Old debugger frontend + if (!debuggerAlreadyOpen) { + yield win.DebuggerController.waitForSourcesLoaded(); + } + + let { DebuggerView } = win; + let { Sources } = DebuggerView; + + let item = Sources.getItemForAttachment(a => a.source.url === sourceURL); + if (item) { + yield toolbox.selectTool("jsdebugger"); + + // Determine if the source has already finished loading. There's two cases + // in which we need to wait for the source to be shown: + // 1) The requested source is not yet selected and will be shown once it is + // selected and loaded + // 2) The requested source is selected BUT the source text is still loading. + const { actor } = item.attachment.source; + const state = win.DebuggerController.getState(); + + // (1) Is the source selected? + const selected = state.sources.selectedSource; + const isSelected = selected === actor; + + // (2) Has the source text finished loading? + let isLoading = false; + + // Only check if the source is loading when the source is already selected. + // If the source is not selected, we will select it below and the already + // pending load will be cancelled and this check is useless. + if (isSelected) { + const sourceTextInfo = getSourceText(state, selected); + isLoading = sourceTextInfo && sourceTextInfo.loading; + } + + // Select the requested source + DebuggerView.setEditorLocation(actor, sourceLine, { noDebug: true }); + + // Wait for it to load + if (!isSelected || isLoading) { + yield win.DebuggerController.waitForSourceShown(sourceURL); + } + return true; + } + + // If not found, still attempt to open in View Source + exports.viewSource(toolbox, sourceURL, sourceLine); + return false; +}); + +/** + * Tries to open a JavaScript file in the corresponding Scratchpad. + * + * @param {string} sourceURL + * @param {number} sourceLine + * + * @return {Promise} + */ +exports.viewSourceInScratchpad = Task.async(function* (sourceURL, sourceLine) { + // Check for matching top level scratchpad window. + let wins = Services.wm.getEnumerator("devtools:scratchpad"); + + while (wins.hasMoreElements()) { + let win = wins.getNext(); + + if (!win.closed && win.Scratchpad.uniqueName === sourceURL) { + win.focus(); + win.Scratchpad.editor.setCursor({ line: sourceLine, ch: 0 }); + return; + } + } + + // For scratchpads within toolbox + for (let [, toolbox] of gDevTools) { + let scratchpadPanel = toolbox.getPanel("scratchpad"); + if (scratchpadPanel) { + let { scratchpad } = scratchpadPanel; + if (scratchpad.uniqueName === sourceURL) { + toolbox.selectTool("scratchpad"); + toolbox.raise(); + scratchpad.editor.focus(); + scratchpad.editor.setCursor({ line: sourceLine, ch: 0 }); + return; + } + } + } +}); + +/** + * Open a link in Firefox's View Source. + * + * @param {Toolbox} toolbox + * @param {string} sourceURL + * @param {number} sourceLine + * + * @return {Promise} + */ +exports.viewSource = Task.async(function* (toolbox, sourceURL, sourceLine) { + // Attempt to access view source via a browser first, which may display it in + // a tab, if enabled. + let browserWin = Services.wm.getMostRecentWindow(gDevTools.chromeWindowType); + if (browserWin && browserWin.BrowserViewSourceOfDocument) { + return browserWin.BrowserViewSourceOfDocument({ + URL: sourceURL, + lineNumber: sourceLine + }); + } + let utils = toolbox.gViewSourceUtils; + utils.viewSource(sourceURL, null, toolbox.doc, sourceLine || 0); + return null; +}); |