CSSNamedFlowCollectionsView.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431
  1. /*
  2. * Copyright (C) 2012 Adobe Systems Incorporated. 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
  6. * are met:
  7. *
  8. * 1. Redistributions of source code must retain the above
  9. * copyright notice, this list of conditions and the following
  10. * disclaimer.
  11. * 2. Redistributions in binary form must reproduce the above
  12. * copyright notice, this list of conditions and the following
  13. * disclaimer in the documentation and/or other materials
  14. * provided with the distribution.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  17. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  18. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  19. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  20. * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
  21. * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  22. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  23. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  24. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  25. * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  26. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  27. * OF THE POSSIBILITY OF SUCH DAMAGE.
  28. */
  29. /**
  30. * @constructor
  31. * @extends {WebInspector.SidebarView}
  32. */
  33. WebInspector.CSSNamedFlowCollectionsView = function()
  34. {
  35. WebInspector.SidebarView.call(this, WebInspector.SidebarView.SidebarPosition.Start);
  36. this.registerRequiredCSS("cssNamedFlows.css");
  37. this._namedFlows = {};
  38. this._contentNodes = {};
  39. this._regionNodes = {};
  40. this.element.addStyleClass("css-named-flow-collections-view");
  41. this.element.addStyleClass("fill");
  42. this._statusElement = document.createElement("span");
  43. this._statusElement.textContent = WebInspector.UIString("CSS Named Flows");
  44. var sidebarHeader = this.firstElement().createChild("div", "tabbed-pane-header selected sidebar-header");
  45. var tab = sidebarHeader.createChild("div", "tabbed-pane-header-tab");
  46. tab.createChild("span", "tabbed-pane-header-tab-title").textContent = WebInspector.UIString("CSS Named Flows");
  47. this._sidebarContentElement = this.firstElement().createChild("div", "sidebar-content outline-disclosure");
  48. this._flowListElement = this._sidebarContentElement.createChild("ol");
  49. this._flowTree = new TreeOutline(this._flowListElement);
  50. this._emptyElement = document.createElement("div");
  51. this._emptyElement.addStyleClass("info");
  52. this._emptyElement.textContent = WebInspector.UIString("No CSS Named Flows");
  53. this._tabbedPane = new WebInspector.TabbedPane();
  54. this._tabbedPane.closeableTabs = true;
  55. this._tabbedPane.show(this.secondElement());
  56. }
  57. WebInspector.CSSNamedFlowCollectionsView.prototype = {
  58. showInDrawer: function()
  59. {
  60. WebInspector.showViewInDrawer(this._statusElement, this);
  61. },
  62. reset: function()
  63. {
  64. if (!this._document)
  65. return;
  66. WebInspector.cssModel.getNamedFlowCollectionAsync(this._document.id, this._resetNamedFlows.bind(this));
  67. },
  68. /**
  69. * @param {WebInspector.DOMDocument} document
  70. */
  71. _setDocument: function(document)
  72. {
  73. this._document = document;
  74. this.reset();
  75. },
  76. /**
  77. * @param {WebInspector.Event} event
  78. */
  79. _documentUpdated: function(event)
  80. {
  81. var document = /** @type {WebInspector.DOMDocument} */ (event.data);
  82. this._setDocument(document);
  83. },
  84. /**
  85. * @param {boolean} hasContent
  86. */
  87. _setSidebarHasContent: function(hasContent)
  88. {
  89. if (hasContent) {
  90. if (!this._emptyElement.parentNode)
  91. return;
  92. this._sidebarContentElement.removeChild(this._emptyElement);
  93. this._sidebarContentElement.appendChild(this._flowListElement);
  94. } else {
  95. if (!this._flowListElement.parentNode)
  96. return;
  97. this._sidebarContentElement.removeChild(this._flowListElement);
  98. this._sidebarContentElement.appendChild(this._emptyElement);
  99. }
  100. },
  101. /**
  102. * @param {WebInspector.NamedFlow} flow
  103. */
  104. _appendNamedFlow: function(flow)
  105. {
  106. var flowHash = this._hashNamedFlow(flow.documentNodeId, flow.name);
  107. var flowContainer = { flow: flow, flowHash: flowHash };
  108. for (var i = 0; i < flow.content.length; ++i)
  109. this._contentNodes[flow.content[i]] = flowHash;
  110. for (var i = 0; i < flow.regions.length; ++i)
  111. this._regionNodes[flow.regions[i].nodeId] = flowHash;
  112. var flowTreeItem = new WebInspector.FlowTreeElement(flowContainer);
  113. flowTreeItem.onselect = this._selectNamedFlowTab.bind(this, flowHash);
  114. flowContainer.flowTreeItem = flowTreeItem;
  115. this._namedFlows[flowHash] = flowContainer;
  116. if (!this._flowTree.children.length)
  117. this._setSidebarHasContent(true);
  118. this._flowTree.appendChild(flowTreeItem);
  119. },
  120. /**
  121. * @param {string} flowHash
  122. */
  123. _removeNamedFlow: function(flowHash)
  124. {
  125. var flowContainer = this._namedFlows[flowHash];
  126. if (this._tabbedPane._tabsById[flowHash])
  127. this._tabbedPane.closeTab(flowHash);
  128. this._flowTree.removeChild(flowContainer.flowTreeItem);
  129. var flow = flowContainer.flow;
  130. for (var i = 0; i < flow.content.length; ++i)
  131. delete this._contentNodes[flow.content[i]];
  132. for (var i = 0; i < flow.regions.length; ++i)
  133. delete this._regionNodes[flow.regions[i].nodeId];
  134. delete this._namedFlows[flowHash];
  135. if (!this._flowTree.children.length)
  136. this._setSidebarHasContent(false);
  137. },
  138. /**
  139. * @param {WebInspector.NamedFlow} flow
  140. */
  141. _updateNamedFlow: function(flow)
  142. {
  143. var flowHash = this._hashNamedFlow(flow.documentNodeId, flow.name);
  144. var flowContainer = this._namedFlows[flowHash];
  145. if (!flowContainer)
  146. return;
  147. var oldFlow = flowContainer.flow;
  148. flowContainer.flow = flow;
  149. for (var i = 0; i < oldFlow.content.length; ++i)
  150. delete this._contentNodes[oldFlow.content[i]];
  151. for (var i = 0; i < oldFlow.regions.length; ++i)
  152. delete this._regionNodes[oldFlow.regions[i].nodeId];
  153. for (var i = 0; i < flow.content.length; ++i)
  154. this._contentNodes[flow.content[i]] = flowHash;
  155. for (var i = 0; i < flow.regions.length; ++i)
  156. this._regionNodes[flow.regions[i].nodeId] = flowHash;
  157. flowContainer.flowTreeItem.setOverset(flow.overset);
  158. if (flowContainer.flowView)
  159. flowContainer.flowView.flow = flow;
  160. },
  161. /**
  162. * @param {WebInspector.NamedFlowCollection} namedFlowCollection
  163. */
  164. _resetNamedFlows: function(namedFlowCollection)
  165. {
  166. for (var flowHash in this._namedFlows)
  167. this._removeNamedFlow(flowHash);
  168. var namedFlows = namedFlowCollection.namedFlowMap;
  169. for (var flowName in namedFlows)
  170. this._appendNamedFlow(namedFlows[flowName]);
  171. if (!this._flowTree.children.length)
  172. this._setSidebarHasContent(false);
  173. else
  174. this._showNamedFlowForNode(WebInspector.panel("elements").treeOutline.selectedDOMNode());
  175. },
  176. /**
  177. * @param {WebInspector.Event} event
  178. */
  179. _namedFlowCreated: function(event)
  180. {
  181. // FIXME: We only have support for Named Flows in the main document.
  182. if (event.data.documentNodeId !== this._document.id)
  183. return;
  184. var flow = /** @type {WebInspector.NamedFlow} */ (event.data);
  185. this._appendNamedFlow(flow);
  186. },
  187. /**
  188. * @param {WebInspector.Event} event
  189. */
  190. _namedFlowRemoved: function(event)
  191. {
  192. // FIXME: We only have support for Named Flows in the main document.
  193. if (event.data.documentNodeId !== this._document.id)
  194. return;
  195. this._removeNamedFlow(this._hashNamedFlow(event.data.documentNodeId, event.data.flowName));
  196. },
  197. /**
  198. * @param {WebInspector.Event} event
  199. */
  200. _regionLayoutUpdated: function(event)
  201. {
  202. // FIXME: We only have support for Named Flows in the main document.
  203. if (event.data.documentNodeId !== this._document.id)
  204. return;
  205. var flow = /** @type {WebInspector.NamedFlow} */ (event.data);
  206. this._updateNamedFlow(flow);
  207. },
  208. /**
  209. * @param {WebInspector.Event} event
  210. */
  211. _regionOversetChanged: function(event)
  212. {
  213. // FIXME: We only have support for Named Flows in the main document.
  214. if (event.data.documentNodeId !== this._document.id)
  215. return;
  216. var flow = /** @type {WebInspector.NamedFlow} */ (event.data);
  217. this._updateNamedFlow(flow);
  218. },
  219. /**
  220. * @param {DOMAgent.NodeId} documentNodeId
  221. * @param {string} flowName
  222. */
  223. _hashNamedFlow: function(documentNodeId, flowName)
  224. {
  225. return documentNodeId + "|" + flowName;
  226. },
  227. /**
  228. * @param {string} flowHash
  229. */
  230. _showNamedFlow: function(flowHash)
  231. {
  232. this._selectNamedFlowInSidebar(flowHash);
  233. this._selectNamedFlowTab(flowHash);
  234. },
  235. /**
  236. * @param {string} flowHash
  237. */
  238. _selectNamedFlowInSidebar: function(flowHash)
  239. {
  240. this._namedFlows[flowHash].flowTreeItem.select(true);
  241. },
  242. /**
  243. * @param {string} flowHash
  244. */
  245. _selectNamedFlowTab: function(flowHash)
  246. {
  247. var flowContainer = this._namedFlows[flowHash];
  248. if (this._tabbedPane.selectedTabId === flowHash)
  249. return;
  250. if (!this._tabbedPane.selectTab(flowHash)) {
  251. if (!flowContainer.flowView)
  252. flowContainer.flowView = new WebInspector.CSSNamedFlowView(flowContainer.flow);
  253. this._tabbedPane.appendTab(flowHash, flowContainer.flow.name, flowContainer.flowView);
  254. this._tabbedPane.selectTab(flowHash);
  255. }
  256. },
  257. /**
  258. * @param {WebInspector.Event} event
  259. */
  260. _selectedNodeChanged: function(event)
  261. {
  262. var node = /** @type {WebInspector.DOMNode} */ (event.data);
  263. this._showNamedFlowForNode(node);
  264. },
  265. /**
  266. * @param {WebInspector.Event} event
  267. */
  268. _tabSelected: function(event)
  269. {
  270. this._selectNamedFlowInSidebar(event.data.tabId);
  271. },
  272. /**
  273. * @param {WebInspector.Event} event
  274. */
  275. _tabClosed: function(event)
  276. {
  277. this._namedFlows[event.data.tabId].flowTreeItem.deselect();
  278. },
  279. /**
  280. * @param {?WebInspector.DOMNode} node
  281. */
  282. _showNamedFlowForNode: function(node)
  283. {
  284. if (!node)
  285. return;
  286. if (this._regionNodes[node.id]) {
  287. this._showNamedFlow(this._regionNodes[node.id]);
  288. return;
  289. }
  290. while (node) {
  291. if (this._contentNodes[node.id]) {
  292. this._showNamedFlow(this._contentNodes[node.id]);
  293. return;
  294. }
  295. node = node.parentNode;
  296. }
  297. },
  298. wasShown: function()
  299. {
  300. WebInspector.SidebarView.prototype.wasShown.call(this);
  301. WebInspector.domAgent.requestDocument(this._setDocument.bind(this));
  302. WebInspector.domAgent.addEventListener(WebInspector.DOMAgent.Events.DocumentUpdated, this._documentUpdated, this);
  303. WebInspector.cssModel.addEventListener(WebInspector.CSSStyleModel.Events.NamedFlowCreated, this._namedFlowCreated, this);
  304. WebInspector.cssModel.addEventListener(WebInspector.CSSStyleModel.Events.NamedFlowRemoved, this._namedFlowRemoved, this);
  305. WebInspector.cssModel.addEventListener(WebInspector.CSSStyleModel.Events.RegionLayoutUpdated, this._regionLayoutUpdated, this);
  306. WebInspector.cssModel.addEventListener(WebInspector.CSSStyleModel.Events.RegionOversetChanged, this._regionOversetChanged, this);
  307. WebInspector.panel("elements").treeOutline.addEventListener(WebInspector.ElementsTreeOutline.Events.SelectedNodeChanged, this._selectedNodeChanged, this);
  308. this._tabbedPane.addEventListener(WebInspector.TabbedPane.EventTypes.TabSelected, this._tabSelected, this);
  309. this._tabbedPane.addEventListener(WebInspector.TabbedPane.EventTypes.TabClosed, this._tabClosed, this);
  310. },
  311. willHide: function()
  312. {
  313. WebInspector.domAgent.removeEventListener(WebInspector.DOMAgent.Events.DocumentUpdated, this._documentUpdated, this);
  314. WebInspector.cssModel.removeEventListener(WebInspector.CSSStyleModel.Events.NamedFlowCreated, this._namedFlowCreated, this);
  315. WebInspector.cssModel.removeEventListener(WebInspector.CSSStyleModel.Events.NamedFlowRemoved, this._namedFlowRemoved, this);
  316. WebInspector.cssModel.removeEventListener(WebInspector.CSSStyleModel.Events.RegionLayoutUpdated, this._regionLayoutUpdated, this);
  317. WebInspector.cssModel.removeEventListener(WebInspector.CSSStyleModel.Events.RegionOversetChanged, this._regionOversetChanged, this);
  318. WebInspector.panel("elements").treeOutline.removeEventListener(WebInspector.ElementsTreeOutline.Events.SelectedNodeChanged, this._selectedNodeChanged, this);
  319. this._tabbedPane.removeEventListener(WebInspector.TabbedPane.EventTypes.TabSelected, this._tabSelected, this);
  320. this._tabbedPane.removeEventListener(WebInspector.TabbedPane.EventTypes.TabClosed, this._tabClosed, this);
  321. },
  322. __proto__: WebInspector.SidebarView.prototype
  323. }
  324. /**
  325. * @constructor
  326. * @extends {TreeElement}
  327. */
  328. WebInspector.FlowTreeElement = function(flowContainer)
  329. {
  330. var container = document.createElement("div");
  331. container.createChild("div", "selection");
  332. container.createChild("span", "title").createChild("span").textContent = flowContainer.flow.name;
  333. TreeElement.call(this, container, flowContainer, false);
  334. this._overset = false;
  335. this.setOverset(flowContainer.flow.overset);
  336. }
  337. WebInspector.FlowTreeElement.prototype = {
  338. /**
  339. * @param {boolean} newOverset
  340. */
  341. setOverset: function(newOverset)
  342. {
  343. if (this._overset === newOverset)
  344. return;
  345. if (newOverset) {
  346. this.title.addStyleClass("named-flow-overflow");
  347. this.tooltip = WebInspector.UIString("Overflows.");
  348. } else {
  349. this.title.removeStyleClass("named-flow-overflow");
  350. this.tooltip = "";
  351. }
  352. this._overset = newOverset;
  353. },
  354. __proto__: TreeElement.prototype
  355. }