LayerTree.js 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. /*
  2. * Copyright (C) 2013 Google Inc. All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions are
  6. * met:
  7. *
  8. * * Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * * Redistributions in binary form must reproduce the above
  11. * copyright notice, this list of conditions and the following disclaimer
  12. * in the documentation and/or other materials provided with the
  13. * distribution.
  14. * * Neither the name of Google Inc. nor the names of its
  15. * contributors may be used to endorse or promote products derived from
  16. * this software without specific prior written permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  19. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  20. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  21. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  22. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  23. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  24. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  25. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  26. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  27. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  28. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29. */
  30. /**
  31. * @constructor
  32. * @param {WebInspector.LayerTreeModel} model
  33. * @param {TreeOutline} treeOutline
  34. * @extends {WebInspector.Object}
  35. */
  36. WebInspector.LayerTree = function(model, treeOutline)
  37. {
  38. WebInspector.Object.call(this);
  39. this._model = model;
  40. this._treeOutline = treeOutline;
  41. this._treeOutline.childrenListElement.addEventListener("mousemove", this._onMouseMove.bind(this), false);
  42. this._treeOutline.childrenListElement.addEventListener("mouseout", this._onMouseMove.bind(this), false);
  43. this._treeOutline.childrenListElement.addEventListener("contextmenu", this._onContextMenu.bind(this), true);
  44. this._model.addEventListener(WebInspector.LayerTreeModel.Events.LayerTreeChanged, this._update.bind(this));
  45. this._lastHoveredNode = null;
  46. this._needsUpdate = true;
  47. }
  48. /**
  49. * @enum {string}
  50. */
  51. WebInspector.LayerTree.Events = {
  52. LayerHovered: "LayerHovered",
  53. LayerSelected: "LayerSelected"
  54. }
  55. WebInspector.LayerTree.prototype = {
  56. /**
  57. * @param {boolean} visible
  58. */
  59. setVisible: function(visible)
  60. {
  61. if (this._isVisible === visible)
  62. return;
  63. this._isVisible = visible;
  64. if (visible && this._needsUpdate)
  65. this._update();
  66. },
  67. /**
  68. * @param {WebInspector.Layer} layer
  69. */
  70. selectLayer: function(layer)
  71. {
  72. this.hoverLayer(null);
  73. var node = layer && this._treeOutline.getCachedTreeElement(layer);
  74. if (node)
  75. node.revealAndSelect(true);
  76. else if (this._treeOutline.selectedTreeElement)
  77. this._treeOutline.selectedTreeElement.deselect();
  78. },
  79. /**
  80. * @param {WebInspector.Layer} layer
  81. */
  82. hoverLayer: function(layer)
  83. {
  84. var node = layer && this._treeOutline.getCachedTreeElement(layer);
  85. if (node === this._lastHoveredNode)
  86. return;
  87. if (this._lastHoveredNode)
  88. this._lastHoveredNode.setHovered(false);
  89. if (node)
  90. node.setHovered(true);
  91. this._lastHoveredNode = node;
  92. },
  93. _update: function()
  94. {
  95. if (!this._isVisible) {
  96. this._needsUpdate = true;
  97. return;
  98. }
  99. this._needsUpdate = false;
  100. var seenLayers = {};
  101. /**
  102. * @param {WebInspector.Layer} layer
  103. */
  104. function updateLayer(layer)
  105. {
  106. var id = layer.id();
  107. if (seenLayers[id])
  108. console.assert(false, "Duplicate layer id: " + id);
  109. seenLayers[id] = true;
  110. var node = this._treeOutline.getCachedTreeElement(layer);
  111. var parent = layer === this._model.contentRoot() ? this._treeOutline : this._treeOutline.getCachedTreeElement(layer.parent());
  112. if (!parent)
  113. console.assert(false, "Parent is not in the tree");
  114. if (!node) {
  115. node = new WebInspector.LayerTreeElement(this, layer);
  116. parent.appendChild(node);
  117. } else {
  118. var oldParentId = node.parent.representedObject && node.parent.representedObject.id();
  119. if (oldParentId !== layer.parentId()) {
  120. (node.parent || this._treeOutline).removeChild(node);
  121. parent.appendChild(node);
  122. }
  123. node._update();
  124. }
  125. }
  126. this._model.forEachLayer(updateLayer.bind(this), this._model.contentRoot());
  127. // Cleanup layers that don't exist anymore from tree
  128. for (var i = 0; i < this._treeOutline.children.length; ++i) {
  129. for (var node = this._treeOutline.children[i]; node;) {
  130. if (seenLayers[node.representedObject.id()]) {
  131. node = node.traverseNextTreeElement(false);
  132. } else {
  133. var nextNode = node.nextSibling || node.parent;
  134. node.parent.removeChild(node);
  135. if (node === this._lastHoveredNode)
  136. this._lastHoveredNode = null;
  137. node = nextNode;
  138. }
  139. }
  140. }
  141. },
  142. /**
  143. * @param {Event} event
  144. */
  145. _onMouseMove: function(event)
  146. {
  147. var node = this._treeOutline.treeElementFromPoint(event.pageX, event.pageY);
  148. if (node === this._lastHoveredNode)
  149. return;
  150. this.dispatchEventToListeners(WebInspector.LayerTree.Events.LayerHovered, node && node.representedObject);
  151. },
  152. /**
  153. * @param {WebInspector.LayerTreeElement} node
  154. */
  155. _selectedNodeChanged: function(node)
  156. {
  157. var layer = /** @type {WebInspector.Layer} */ (node.representedObject);
  158. this.dispatchEventToListeners(WebInspector.LayerTree.Events.LayerSelected, layer);
  159. },
  160. /**
  161. * @param {Event} event
  162. */
  163. _onContextMenu: function(event)
  164. {
  165. var node = this._treeOutline.treeElementFromPoint(event.pageX, event.pageY);
  166. if (!node || !node.representedObject)
  167. return;
  168. var layer = /** @type {WebInspector.Layer} */ (node.representedObject);
  169. if (!layer)
  170. return;
  171. var nodeId = layer.nodeId();
  172. if (!nodeId)
  173. return;
  174. var domNode = WebInspector.domAgent.nodeForId(nodeId);
  175. if (!domNode)
  176. return;
  177. var contextMenu = new WebInspector.ContextMenu(event);
  178. contextMenu.appendApplicableItems(domNode);
  179. contextMenu.show();
  180. },
  181. __proto__: WebInspector.Object.prototype
  182. }
  183. /**
  184. * @constructor
  185. * @param {WebInspector.LayerTree} tree
  186. * @param {WebInspector.Layer} layer
  187. * @extends {TreeElement}
  188. */
  189. WebInspector.LayerTreeElement = function(tree, layer)
  190. {
  191. TreeElement.call(this, "", layer);
  192. this._layerTree = tree;
  193. this._update();
  194. }
  195. WebInspector.LayerTreeElement.prototype = {
  196. onattach: function()
  197. {
  198. var selection = document.createElement("div");
  199. selection.className = "selection";
  200. this.listItemElement.insertBefore(selection, this.listItemElement.firstChild);
  201. },
  202. _update: function()
  203. {
  204. var layer = /** @type {WebInspector.Layer} */ (this.representedObject);
  205. var nodeId = layer.nodeIdForSelfOrAncestor();
  206. var node = nodeId && WebInspector.domAgent.nodeForId(nodeId);
  207. var title = document.createDocumentFragment();
  208. title.createChild("div", "selection");
  209. title.appendChild(document.createTextNode(node ? node.appropriateSelectorFor(false) : "#" + layer.id()));
  210. var details = title.createChild("span", "dimmed");
  211. details.textContent = WebInspector.UIString(" (%d × %d)", layer.width(), layer.height());
  212. this.title = title;
  213. },
  214. onselect: function()
  215. {
  216. this._layerTree._selectedNodeChanged(this);
  217. },
  218. /**
  219. * @param {boolean} hovered
  220. */
  221. setHovered: function(hovered)
  222. {
  223. this.listItemElement.enableStyleClass("hovered", hovered);
  224. },
  225. __proto__: TreeElement.prototype
  226. }