Bug 1515951 - [release 112] 7190: Save generated file and source map (#7482). r=bhackett
authorJason Laster <jlaster@mozilla.com>
Sun, 23 Dec 2018 14:45:49 -0500
changeset 452002 796402f4fa52d5e3021b52d1aea86282b2c52a1d
parent 452001 4ca33ee89eb8bc28bb65cccd49a94e30c123f4b4
child 452003 5bfef086654140a79a6164ff660fcc097603e7c8
push id35278
push useraiakab@mozilla.com
push dateThu, 27 Dec 2018 21:57:04 +0000
treeherdermozilla-central@a77e8f3efc4c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbhackett
bugs1515951
milestone66.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1515951 - [release 112] 7190: Save generated file and source map (#7482). r=bhackett
devtools/client/debugger/new/dist/debugger.css
devtools/client/debugger/new/src/components/Editor/EditorMenu.js
devtools/client/debugger/new/src/components/SecondaryPanes/CommandBar.js
devtools/client/debugger/new/src/utils/utils.js
devtools/client/locales/en-US/debugger.properties
--- a/devtools/client/debugger/new/dist/debugger.css
+++ b/devtools/client/debugger/new/dist/debugger.css
@@ -3083,16 +3083,20 @@ debug-expression-error {
 
 .CodeMirror-guttermarker-subtle {
   visibility: hidden;
 }
 
 .visible {
   visibility: visible;
 }
+
+.download-anchor {
+  display: none;
+}
 /* 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/>. */
 
 .cm-highlight {
   position: relative;
 }
 
--- a/devtools/client/debugger/new/src/components/Editor/EditorMenu.js
+++ b/devtools/client/debugger/new/src/components/Editor/EditorMenu.js
@@ -9,17 +9,23 @@ import { isOriginalId } from "devtools-s
 
 import { copyToTheClipboard } from "../../utils/clipboard";
 import { findFunctionText } from "../../utils/function";
 import { findClosestFunction } from "../../utils/ast";
 import {
   getSourceLocationFromMouseEvent,
   toSourceLine
 } from "../../utils/editor";
-import { isPretty, getRawSourceURL, shouldBlackbox } from "../../utils/source";
+import {
+  isPretty,
+  getRawSourceURL,
+  getFilename,
+  shouldBlackbox
+} from "../../utils/source";
+import { downloadFile } from "../../utils/utils";
 import {
   getContextMenu,
   getPrettySource,
   getSelectedLocation,
   getSelectedSource,
   getSymbols
 } from "../../selectors";
 
@@ -88,16 +94,18 @@ function getMenuItems(
   const jumpToMappedLocLabel = L10N.getFormatStr(
     "editor.jumpToMappedLocation1",
     isOriginal ? L10N.getStr("generated") : L10N.getStr("original")
   );
   const revealInTreeKey = L10N.getStr("sourceTabs.revealInTree.accesskey");
   const revealInTreeLabel = L10N.getStr("sourceTabs.revealInTree");
   const watchExpressionKey = L10N.getStr("expressions.accesskey");
   const watchExpressionLabel = L10N.getStr("expressions.label");
+  const downloadKey = L10N.getStr("downloadFile.accesskey");
+  const downloadLabel = L10N.getStr("downloadFile.label");
 
   // menu items
 
   const copyToClipboardItem = {
     id: "node-menu-copy-to-clipboard",
     label: copyToClipboardLabel,
     accesskey: copyToClipboardKey,
     disabled: false,
@@ -174,16 +182,23 @@ function getMenuItems(
   };
 
   const evaluateInConsoleItem = {
     id: "node-menu-evaluate-in-console",
     label: evaluateInConsoleLabel,
     click: () => evaluateInConsole(selectionText)
   };
 
+  const downloadFileItem = {
+    id: "node-menu-download-file",
+    label: downloadLabel,
+    accesskey: downloadKey,
+    click: () => downloadFile(selectedSource.text, getFilename(selectedSource))
+  };
+
   // construct menu
   const menuItems = [
     copyToClipboardItem,
     copySourceItem,
     copySourceUri2Item,
     copyFunctionItem,
     { type: "separator" },
     jumpToMappedLocationItem,
@@ -192,16 +207,18 @@ function getMenuItems(
   ];
 
   // conditionally added items
   // TODO: Find a new way to only add this for mapped sources?
   if (isTextSelected) {
     menuItems.push(watchExpressionItem, evaluateInConsoleItem);
   }
 
+  menuItems.push(downloadFileItem);
+
   return menuItems;
 }
 
 class EditorMenu extends Component {
   props: Props;
 
   shouldComponentUpdate(nextProps) {
     return nextProps.contextMenu.type === "Editor";
--- a/devtools/client/debugger/new/src/components/SecondaryPanes/CommandBar.js
+++ b/devtools/client/debugger/new/src/components/SecondaryPanes/CommandBar.js
@@ -266,17 +266,17 @@ class CommandBar extends Component<Props
       <button
         className={classnames(
           "command-bar-button",
           "command-bar-skip-pausing",
           {
             active: skipPausing
           }
         )}
-        title={L10N.getStr("skipPausingTooltip")}
+        title={L10N.getStr("skipPausingTooltip.label")}
         onClick={toggleSkipPausing}
       >
         <AccessibleImage className="skipPausing" />
       </button>
     );
   }
 
   render() {
--- a/devtools/client/debugger/new/src/utils/utils.js
+++ b/devtools/client/debugger/new/src/utils/utils.js
@@ -47,8 +47,25 @@ export function endTruncateStr(str: any,
     return `…${str.slice(str.length - size)}`;
   }
   return str;
 }
 
 export function waitForMs(ms: number): Promise<void> {
   return new Promise(resolve => setTimeout(resolve, ms));
 }
+
+export function downloadFile(data: string, fileName: string) {
+  const { body } = document;
+  if (!body) {
+    return;
+  }
+
+  const a = document.createElement("a");
+  body.appendChild(a);
+  a.className = "download-anchor";
+  a.href = window.URL.createObjectURL(
+    new Blob([data], { type: "text/javascript" })
+  );
+  a.setAttribute("download", fileName);
+  a.click();
+  body.removeChild(a);
+}
--- a/devtools/client/locales/en-US/debugger.properties
+++ b/devtools/client/locales/en-US/debugger.properties
@@ -77,19 +77,19 @@ stepOverTooltip=Step over %S
 # LOCALIZATION NOTE (stepInTooltip): The label that is displayed on the
 # button that steps into a function call.
 stepInTooltip=Step in %S
 
 # LOCALIZATION NOTE (stepOutTooltip): The label that is displayed on the
 # button that steps out of a function call.
 stepOutTooltip=Step out %S
 
-# LOCALIZATION NOTE (skipPausingTooltip): The tooltip text for disabling all
+# LOCALIZATION NOTE (skipPausingTooltip.label): The tooltip text for disabling all
 # breakpoints and pausing triggers
-skipPausingTooltip=Skip all pausing
+skipPausingTooltip.label=Deactivate breakpoints
 
 # LOCALIZATION NOTE (pauseButtonItem): The label that is displayed for the dropdown pause
 # list item when the debugger is in a running state.
 pauseButtonItem=Pause on Next Statement
 
 # LOCALIZATION NOTE (ignoreExceptionsItem): The pause on exceptions button description
 # when the debugger will not pause on exceptions.
 ignoreExceptionsItem=Ignore exceptions
@@ -505,16 +505,21 @@ editor.conditionalPanel.placeholder=This
 # close button inside ConditionalPanel component
 editor.conditionalPanel.close=Cancel edit breakpoint and close
 
 # LOCALIZATION NOTE (editor.jumpToMappedLocation1): Context menu item
 # for navigating to a source mapped location
 editor.jumpToMappedLocation1=Jump to %S location
 editor.jumpToMappedLocation1.accesskey=m
 
+# LOCALIZATION NOTE (downloadFile.label): Context menu item
+# for downloading a source's content
+downloadFile.label=Download file
+downloadFile.accesskey=d
+
 # LOCALIZATION NOTE (framework.disableGrouping): This is the text that appears in the
 # context menu to disable framework grouping.
 framework.disableGrouping=Disable framework grouping
 framework.disableGrouping.accesskey=u
 
 # LOCALIZATION NOTE (framework.enableGrouping): This is the text that appears in the
 # context menu to enable framework grouping.
 framework.enableGrouping=Enable framework grouping