Bug 1494162 - Part 2: Lazy load the UndoStack in the markup view. r=pbro
authorGabriel Luong <gabriel.luong@gmail.com>
Fri, 28 Sep 2018 12:32:12 -0400
changeset 494494 ddd66696c9f2979e6bde0137adf5d855b4ade04d
parent 494493 91d895e3296e015b520127645aa8345d26510b1d
child 494495 2f6a1098cf9e7f4a6ee60809f30b046896151006
push id9984
push userffxbld-merge
push dateMon, 15 Oct 2018 21:07:35 +0000
treeherdermozilla-beta@183d27ea8570 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspbro
bugs1494162
milestone64.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 1494162 - Part 2: Lazy load the UndoStack in the markup view. r=pbro
devtools/client/inspector/markup/markup.js
devtools/client/inspector/markup/views/markup-container.js
--- a/devtools/client/inspector/markup/markup.js
+++ b/devtools/client/inspector/markup/markup.js
@@ -9,27 +9,28 @@ const Services = require("Services");
 const nodeConstants = require("devtools/shared/dom-node-constants");
 const nodeFilterConstants = require("devtools/shared/dom-node-filter-constants");
 const EventEmitter = require("devtools/shared/event-emitter");
 const {LocalizationHelper} = require("devtools/shared/l10n");
 const {PluralForm} = require("devtools/shared/plural-form");
 const AutocompletePopup = require("devtools/client/shared/autocomplete-popup");
 const KeyShortcuts = require("devtools/client/shared/key-shortcuts");
 const {scrollIntoViewIfNeeded} = require("devtools/client/shared/scroll");
-const {UndoStack} = require("devtools/client/shared/undo");
 const {HTMLTooltip} = require("devtools/client/shared/widgets/tooltip/HTMLTooltip");
 const {PrefObserver} = require("devtools/client/shared/prefs");
 const MarkupElementContainer = require("devtools/client/inspector/markup/views/element-container");
 const MarkupReadOnlyContainer = require("devtools/client/inspector/markup/views/read-only-container");
 const MarkupTextContainer = require("devtools/client/inspector/markup/views/text-container");
 const SlottedNodeContainer = require("devtools/client/inspector/markup/views/slotted-node-container");
 const RootContainer = require("devtools/client/inspector/markup/views/root-container");
 
+loader.lazyRequireGetter(this, "UndoStack", "devtools/client/shared/undo", true);
+
 const INSPECTOR_L10N =
-      new LocalizationHelper("devtools/client/locales/inspector.properties");
+  new LocalizationHelper("devtools/client/locales/inspector.properties");
 
 // Page size for pageup/pagedown
 const PAGE_SIZE = 10;
 const DEFAULT_MAX_CHILDREN = 100;
 const NEW_SELECTION_HIGHLIGHTER_TIMER = 1000;
 const DRAG_DROP_AUTOSCROLL_EDGE_MAX_DISTANCE = 50;
 const DRAG_DROP_AUTOSCROLL_EDGE_RATIO = 0.1;
 const DRAG_DROP_MIN_AUTOSCROLL_SPEED = 2;
@@ -59,16 +60,17 @@ const ATTR_COLLAPSE_LENGTH_PREF = "devto
  * @param  {Inspector} inspector
  *         The inspector we're watching.
  * @param  {iframe} frame
  *         An iframe in which the caller has kindly loaded markup.xhtml.
  */
 function MarkupView(inspector, frame, controllerWindow) {
   EventEmitter.decorate(this);
 
+  this.controllerWindow = controllerWindow;
   this.inspector = inspector;
   this.highlighters = inspector.highlighters;
   this.walker = this.inspector.walker;
   this._frame = frame;
   this.win = this._frame.contentWindow;
   this.doc = this._frame.contentDocument;
   this._elt = this.doc.querySelector("#root");
   this.telemetry = this.inspector.telemetry;
@@ -80,19 +82,16 @@ function MarkupView(inspector, frame, co
   this.collapseAttributeLength = Services.prefs.getIntPref(ATTR_COLLAPSE_LENGTH_PREF);
 
   // Creating the popup to be used to show CSS suggestions.
   // The popup will be attached to the toolbox document.
   this.popup = new AutocompletePopup(inspector.toolbox.doc, {
     autoSelect: true,
   });
 
-  this.undo = new UndoStack();
-  this.undo.installController(controllerWindow);
-
   this._containers = new Map();
   // This weakmap will hold keys used with the _containers map, in order to retrieve the
   // slotted container for a given node front.
   this._slottedContainerKeys = new WeakMap();
 
   // Binding functions that need to be called in scope.
   this._handleRejectionIfNotDestroyed = this._handleRejectionIfNotDestroyed.bind(this);
   this._isImagePreviewTarget = this._isImagePreviewTarget.bind(this);
@@ -141,16 +140,25 @@ MarkupView.prototype = {
   CONTAINER_FLASHING_DURATION: 500,
 
   _selectedContainer: null,
 
   get toolbox() {
     return this.inspector.toolbox;
   },
 
+  get undo() {
+    if (!this._undo) {
+      this._undo = new UndoStack();
+      this._undo.installController(this.controllerWindow);
+    }
+
+    return this._undo;
+  },
+
   /**
    * Handle promise rejections for various asynchronous actions, and only log errors if
    * the markup view still exists.
    * This is useful to silence useless errors that happen when the markup view is
    * destroyed while still initializing (and making protocol requests).
    */
   _handleRejectionIfNotDestroyed: function(e) {
     if (!this._destroyer) {
@@ -1895,18 +1903,20 @@ MarkupView.prototype = {
 
     this._hoveredContainer = null;
 
     if (this.htmlEditor) {
       this.htmlEditor.destroy();
       this.htmlEditor = null;
     }
 
-    this.undo.destroy();
-    this.undo = null;
+    if (this._undo) {
+      this._undo.destroy();
+      this._undo = null;
+    }
 
     this.popup.destroy();
     this.popup = null;
 
     this._elt.removeEventListener("blur", this._onBlur, true);
     this._elt.removeEventListener("click", this._onMouseClick);
     this._elt.removeEventListener("mousemove", this._onMouseMove);
     this._elt.removeEventListener("mouseout", this._onMouseOut);
@@ -1932,16 +1942,17 @@ MarkupView.prototype = {
     this._containers = null;
 
     this.eventDetailsTooltip.destroy();
     this.eventDetailsTooltip = null;
 
     this.imagePreviewTooltip.destroy();
     this.imagePreviewTooltip = null;
 
+    this.controllerWindow = null;
     this.doc = null;
     this.highlighters = null;
     this.win = null;
 
     this._lastDropTarget = null;
     this._lastDragTarget = null;
 
     return this._destroyer;
--- a/devtools/client/inspector/markup/views/markup-container.js
+++ b/devtools/client/inspector/markup/views/markup-container.js
@@ -31,33 +31,38 @@ function MarkupContainer() { }
 
 /**
  * Unique identifier used to set markup container node id.
  * @type {Number}
  */
 let markupContainerID = 0;
 
 MarkupContainer.prototype = {
+  // Get the UndoStack from the MarkupView.
+  get undo() {
+    // undo is a lazy getter in the MarkupView.
+    return this.markup.undo;
+  },
+
   /*
    * Initialize the MarkupContainer.  Should be called while one
    * of the other contain classes is instantiated.
    *
    * @param  {MarkupView} markupView
    *         The markup view that owns this container.
    * @param  {NodeFront} node
    *         The node to display.
    * @param  {String} type
    *         The type of container to build. One of TYPES.TEXT_CONTAINER,
    *         TYPES.ELEMENT_CONTAINER, TYPES.READ_ONLY_CONTAINER
    */
   initialize: function(markupView, node, type) {
     this.markup = markupView;
     this.node = node;
     this.type = type;
-    this.undo = this.markup.undo;
     this.win = this.markup._frame.contentWindow;
     this.id = "treeitem-" + markupContainerID++;
     this.htmlElt = this.win.document.documentElement;
 
     this.buildMarkup();
 
     this.elt.container = this;