view-source.js (5503B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 "use strict"; 6 7 /** 8 * Tries to open a Stylesheet file in the Style Editor. If the file is not 9 * found, it is opened in source view instead. 10 * Returns a promise resolving to a boolean indicating whether or not 11 * the source was able to be displayed in the StyleEditor, as the built-in 12 * Firefox View Source is the fallback. 13 * 14 * @param {Toolbox} toolbox 15 * @param {string | object} stylesheetResourceOrGeneratedURL 16 * @param {number} generatedLine 17 * @param {number} generatedColumn 18 * 19 * @return {Promise<boolean>} 20 */ 21 exports.viewSourceInStyleEditor = async function ( 22 toolbox, 23 stylesheetResourceOrGeneratedURL, 24 generatedLine, 25 generatedColumn 26 ) { 27 const originalPanelId = toolbox.currentToolId; 28 29 try { 30 const panel = await toolbox.selectTool("styleeditor", "view-source", { 31 // This will be only used in case the styleeditor wasn't loaded yet, to make the 32 // initialization faster in case we already have a stylesheet resource. We still 33 // need the rest of this function to handle subsequent calls and sourcemapped stylesheets. 34 stylesheetToSelect: { 35 stylesheet: stylesheetResourceOrGeneratedURL, 36 line: generatedLine, 37 column: generatedColumn, 38 }, 39 }); 40 41 let stylesheetResource; 42 if (typeof stylesheetResourceOrGeneratedURL === "string") { 43 stylesheetResource = panel.getStylesheetResourceForGeneratedURL( 44 stylesheetResourceOrGeneratedURL 45 ); 46 } else { 47 stylesheetResource = stylesheetResourceOrGeneratedURL; 48 } 49 50 const originalLocation = stylesheetResource 51 ? await getOriginalLocation( 52 toolbox, 53 stylesheetResource.resourceId, 54 generatedLine, 55 generatedColumn 56 ) 57 : null; 58 59 if (originalLocation) { 60 await panel.selectOriginalSheet( 61 originalLocation.sourceId, 62 originalLocation.line, 63 originalLocation.column 64 ); 65 return true; 66 } 67 68 if (stylesheetResource) { 69 await panel.selectStyleSheet( 70 stylesheetResource, 71 generatedLine, 72 generatedColumn 73 ); 74 return true; 75 } 76 } catch (e) { 77 console.error("Failed to view source in style editor", e); 78 } 79 80 // If we weren't able to select the stylesheet in the style editor, display it in a 81 // view-source tab 82 exports.viewSource( 83 toolbox, 84 typeof stylesheetResourceOrGeneratedURL === "string" 85 ? stylesheetResourceOrGeneratedURL 86 : stylesheetResourceOrGeneratedURL.href || 87 stylesheetResourceOrGeneratedURL.nodeHref, 88 generatedLine 89 ); 90 91 // As we might have moved to the styleeditor, switch back to the original panel 92 await toolbox.selectTool(originalPanelId); 93 94 return false; 95 }; 96 97 /** 98 * Tries to open a JavaScript file in the Debugger. If the file is not found, 99 * it is opened in source view instead. Either the source URL or source actor ID 100 * can be specified. If both are specified, the source actor ID is used. 101 * 102 * Returns a promise resolving to a boolean indicating whether or not 103 * the source was able to be displayed in the Debugger, as the built-in Firefox 104 * View Source is the fallback. 105 * 106 * @param {Toolbox} toolbox 107 * @param {string} sourceURL 108 * @param {number} sourceLine 109 * @param {number} sourceColumn 110 * @param {string} sourceID 111 * @param {(string|object)} [reason=unknown] 112 * 113 * @return {Promise<boolean>} 114 */ 115 exports.viewSourceInDebugger = async function ( 116 toolbox, 117 generatedURL, 118 generatedLine, 119 generatedColumn, 120 sourceActorId, 121 reason = "unknown" 122 ) { 123 // Load the debugger in the background 124 const dbg = await toolbox.loadTool("jsdebugger"); 125 126 const openedSourceInDebugger = await dbg.openSourceInDebugger({ 127 generatedURL, 128 generatedLine, 129 generatedColumn, 130 sourceActorId, 131 reason, 132 }); 133 134 if (openedSourceInDebugger) { 135 toolbox.emitForTests("source-opened-in-debugger"); 136 return true; 137 } 138 139 // Fallback to built-in firefox view-source: 140 exports.viewSource(toolbox, generatedURL, generatedLine, generatedColumn); 141 return false; 142 }; 143 144 async function getOriginalLocation( 145 toolbox, 146 generatedID, 147 generatedLine, 148 generatedColumn 149 ) { 150 // If there is no line number, then there's no chance that we'll get back 151 // a useful original location. 152 if (typeof generatedLine !== "number") { 153 return null; 154 } 155 156 let originalLocation = null; 157 try { 158 originalLocation = await toolbox.sourceMapLoader.getOriginalLocation({ 159 sourceId: generatedID, 160 line: generatedLine, 161 column: generatedColumn, 162 }); 163 if (originalLocation && originalLocation.sourceId === generatedID) { 164 originalLocation = null; 165 } 166 } catch (err) { 167 console.error( 168 "Failed to resolve sourcemapped location for the given source location", 169 { generatedID, generatedLine, generatedColumn }, 170 err 171 ); 172 } 173 return originalLocation; 174 } 175 176 /** 177 * Open a link in Firefox's View Source. 178 * 179 * @param {Toolbox} toolbox 180 * @param {string} sourceURL 181 * @param {number} sourceLine 182 * @param {number} sourceColumn 183 * 184 * @return {Promise} 185 */ 186 exports.viewSource = async function ( 187 toolbox, 188 sourceURL, 189 sourceLine, 190 sourceColumn 191 ) { 192 const utils = toolbox.gViewSourceUtils; 193 utils.viewSource({ 194 URL: sourceURL, 195 lineNumber: sourceLine || -1, 196 columnNumber: sourceColumn || -1, 197 }); 198 };