Home | History | Annotate | Download | only in front_end
      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 /**
     31  * @constructor
     32  * @extends {WebInspector.SidebarView}
     33  */
     34 WebInspector.CSSNamedFlowCollectionsView = function()
     35 {
     36     WebInspector.SidebarView.call(this, WebInspector.SidebarView.SidebarPosition.Start);
     37     this.registerRequiredCSS("cssNamedFlows.css");
     38 
     39     this._namedFlows = {};
     40     this._contentNodes = {};
     41     this._regionNodes = {};
     42 
     43     this.element.addStyleClass("css-named-flow-collections-view");
     44     this.element.addStyleClass("fill");
     45 
     46     this._statusElement = document.createElement("span");
     47     this._statusElement.textContent = WebInspector.UIString("CSS Named Flows");
     48 
     49     var sidebarHeader = this.firstElement().createChild("div", "tabbed-pane-header selected sidebar-header");
     50     var tab = sidebarHeader.createChild("div", "tabbed-pane-header-tab");
     51     tab.createChild("span", "tabbed-pane-header-tab-title").textContent = WebInspector.UIString("CSS Named Flows");
     52 
     53     this._sidebarContentElement = this.firstElement().createChild("div", "sidebar-content outline-disclosure");
     54     this._flowListElement = this._sidebarContentElement.createChild("ol");
     55     this._flowTree = new TreeOutline(this._flowListElement);
     56 
     57     this._emptyElement = document.createElement("div");
     58     this._emptyElement.addStyleClass("info");
     59     this._emptyElement.textContent = WebInspector.UIString("No CSS Named Flows");
     60 
     61     this._tabbedPane = new WebInspector.TabbedPane();
     62     this._tabbedPane.closeableTabs = true;
     63     this._tabbedPane.show(this.secondElement());
     64 }
     65 
     66 WebInspector.CSSNamedFlowCollectionsView.prototype = {
     67     showInDrawer: function()
     68     {
     69         WebInspector.showViewInDrawer(this._statusElement, this);
     70     },
     71 
     72     reset: function()
     73     {
     74         if (!this._document)
     75             return;
     76 
     77         WebInspector.cssModel.getNamedFlowCollectionAsync(this._document.id, this._resetNamedFlows.bind(this));
     78     },
     79 
     80     /**
     81      * @param {WebInspector.DOMDocument} document
     82      */
     83     _setDocument: function(document)
     84     {
     85         this._document = document;
     86         this.reset();
     87     },
     88 
     89     /**
     90      * @param {WebInspector.Event} event
     91      */
     92     _documentUpdated: function(event)
     93     {
     94         var document = /** @type {WebInspector.DOMDocument} */ (event.data);
     95         this._setDocument(document);
     96     },
     97 
     98     /**
     99      * @param {boolean} hasContent
    100      */
    101     _setSidebarHasContent: function(hasContent)
    102     {
    103         if (hasContent) {
    104             if (!this._emptyElement.parentNode)
    105                 return;
    106 
    107             this._sidebarContentElement.removeChild(this._emptyElement);
    108             this._sidebarContentElement.appendChild(this._flowListElement);
    109         } else {
    110             if (!this._flowListElement.parentNode)
    111                 return;
    112 
    113             this._sidebarContentElement.removeChild(this._flowListElement);
    114             this._sidebarContentElement.appendChild(this._emptyElement);
    115         }
    116     },
    117 
    118     /**
    119      * @param {WebInspector.NamedFlow} flow
    120      */
    121     _appendNamedFlow: function(flow)
    122     {
    123         var flowHash = this._hashNamedFlow(flow.documentNodeId, flow.name);
    124         var flowContainer = { flow: flow, flowHash: flowHash };
    125 
    126         for (var i = 0; i < flow.content.length; ++i)
    127             this._contentNodes[flow.content[i]] = flowHash;
    128         for (var i = 0; i < flow.regions.length; ++i)
    129             this._regionNodes[flow.regions[i].nodeId] = flowHash;
    130 
    131         var flowTreeItem = new WebInspector.FlowTreeElement(flowContainer);
    132         flowTreeItem.onselect = this._selectNamedFlowTab.bind(this, flowHash);
    133 
    134         flowContainer.flowTreeItem = flowTreeItem;
    135         this._namedFlows[flowHash] = flowContainer;
    136 
    137         if (!this._flowTree.children.length)
    138             this._setSidebarHasContent(true);
    139         this._flowTree.appendChild(flowTreeItem);
    140     },
    141 
    142     /**
    143      * @param {string} flowHash
    144      */
    145     _removeNamedFlow: function(flowHash)
    146     {
    147         var flowContainer = this._namedFlows[flowHash];
    148 
    149         if (this._tabbedPane._tabsById[flowHash])
    150             this._tabbedPane.closeTab(flowHash);
    151         this._flowTree.removeChild(flowContainer.flowTreeItem);
    152 
    153         var flow = flowContainer.flow;
    154         for (var i = 0; i < flow.content.length; ++i)
    155             delete this._contentNodes[flow.content[i]];
    156         for (var i = 0; i < flow.regions.length; ++i)
    157             delete this._regionNodes[flow.regions[i].nodeId];
    158 
    159         delete this._namedFlows[flowHash];
    160 
    161         if (!this._flowTree.children.length)
    162             this._setSidebarHasContent(false);
    163     },
    164 
    165     /**
    166      * @param {WebInspector.NamedFlow} flow
    167      */
    168     _updateNamedFlow: function(flow)
    169     {
    170         var flowHash = this._hashNamedFlow(flow.documentNodeId, flow.name);
    171         var flowContainer = this._namedFlows[flowHash];
    172 
    173         if (!flowContainer)
    174             return;
    175 
    176         var oldFlow = flowContainer.flow;
    177         flowContainer.flow = flow;
    178 
    179         for (var i = 0; i < oldFlow.content.length; ++i)
    180             delete this._contentNodes[oldFlow.content[i]];
    181         for (var i = 0; i < oldFlow.regions.length; ++i)
    182             delete this._regionNodes[oldFlow.regions[i].nodeId];
    183 
    184         for (var i = 0; i < flow.content.length; ++i)
    185             this._contentNodes[flow.content[i]] = flowHash;
    186         for (var i = 0; i < flow.regions.length; ++i)
    187             this._regionNodes[flow.regions[i].nodeId] = flowHash;
    188 
    189         flowContainer.flowTreeItem.setOverset(flow.overset);
    190 
    191         if (flowContainer.flowView)
    192             flowContainer.flowView.flow = flow;
    193     },
    194 
    195     /**
    196      * @param {WebInspector.NamedFlowCollection} namedFlowCollection
    197      */
    198     _resetNamedFlows: function(namedFlowCollection)
    199     {
    200         for (var flowHash in this._namedFlows)
    201             this._removeNamedFlow(flowHash);
    202 
    203         var namedFlows = namedFlowCollection.namedFlowMap;
    204         for (var flowName in namedFlows)
    205             this._appendNamedFlow(namedFlows[flowName]);
    206 
    207         if (!this._flowTree.children.length)
    208             this._setSidebarHasContent(false);
    209         else
    210             this._showNamedFlowForNode(WebInspector.panel("elements").treeOutline.selectedDOMNode());
    211     },
    212 
    213     /**
    214      * @param {WebInspector.Event} event
    215      */
    216     _namedFlowCreated: function(event)
    217     {
    218         // FIXME: We only have support for Named Flows in the main document.
    219         if (event.data.documentNodeId !== this._document.id)
    220             return;
    221 
    222         var flow = /** @type {WebInspector.NamedFlow} */ (event.data);
    223         this._appendNamedFlow(flow);
    224     },
    225 
    226     /**
    227      * @param {WebInspector.Event} event
    228      */
    229     _namedFlowRemoved: function(event)
    230     {
    231         // FIXME: We only have support for Named Flows in the main document.
    232         if (event.data.documentNodeId !== this._document.id)
    233             return;
    234 
    235         this._removeNamedFlow(this._hashNamedFlow(event.data.documentNodeId, event.data.flowName));
    236     },
    237 
    238     /**
    239      * @param {WebInspector.Event} event
    240      */
    241     _regionLayoutUpdated: function(event)
    242     {
    243         // FIXME: We only have support for Named Flows in the main document.
    244         if (event.data.documentNodeId !== this._document.id)
    245             return;
    246 
    247         var flow = /** @type {WebInspector.NamedFlow} */ (event.data);
    248         this._updateNamedFlow(flow);
    249     },
    250 
    251     /**
    252      * @param {WebInspector.Event} event
    253      */
    254     _regionOversetChanged: function(event)
    255     {
    256         // FIXME: We only have support for Named Flows in the main document.
    257         if (event.data.documentNodeId !== this._document.id)
    258             return;
    259 
    260         var flow = /** @type {WebInspector.NamedFlow} */ (event.data);
    261         this._updateNamedFlow(flow);
    262     },
    263 
    264     /**
    265      * @param {DOMAgent.NodeId} documentNodeId
    266      * @param {string} flowName
    267      */
    268     _hashNamedFlow: function(documentNodeId, flowName)
    269     {
    270         return documentNodeId + "|" + flowName;
    271     },
    272 
    273     /**
    274      * @param {string} flowHash
    275      */
    276     _showNamedFlow: function(flowHash)
    277     {
    278         this._selectNamedFlowInSidebar(flowHash);
    279         this._selectNamedFlowTab(flowHash);
    280     },
    281 
    282     /**
    283      * @param {string} flowHash
    284      */
    285     _selectNamedFlowInSidebar: function(flowHash)
    286     {
    287         this._namedFlows[flowHash].flowTreeItem.select(true);
    288     },
    289 
    290     /**
    291      * @param {string} flowHash
    292      */
    293     _selectNamedFlowTab: function(flowHash)
    294     {
    295         var flowContainer = this._namedFlows[flowHash];
    296 
    297         if (this._tabbedPane.selectedTabId === flowHash)
    298             return;
    299 
    300         if (!this._tabbedPane.selectTab(flowHash)) {
    301             if (!flowContainer.flowView)
    302                 flowContainer.flowView = new WebInspector.CSSNamedFlowView(flowContainer.flow);
    303 
    304             this._tabbedPane.appendTab(flowHash, flowContainer.flow.name, flowContainer.flowView);
    305             this._tabbedPane.selectTab(flowHash);
    306         }
    307     },
    308 
    309     /**
    310      * @param {WebInspector.Event} event
    311      */
    312     _selectedNodeChanged: function(event)
    313     {
    314         var node = /** @type {WebInspector.DOMNode} */ (event.data);
    315         this._showNamedFlowForNode(node);
    316     },
    317 
    318     /**
    319      * @param {WebInspector.Event} event
    320      */
    321     _tabSelected: function(event)
    322     {
    323         this._selectNamedFlowInSidebar(event.data.tabId);
    324     },
    325 
    326     /**
    327      * @param {WebInspector.Event} event
    328      */
    329     _tabClosed: function(event)
    330     {
    331         this._namedFlows[event.data.tabId].flowTreeItem.deselect();
    332     },
    333 
    334     /**
    335      * @param {?WebInspector.DOMNode} node
    336      */
    337     _showNamedFlowForNode: function(node)
    338     {
    339         if (!node)
    340             return;
    341 
    342         if (this._regionNodes[node.id]) {
    343             this._showNamedFlow(this._regionNodes[node.id]);
    344             return;
    345         }
    346 
    347         while (node) {
    348             if (this._contentNodes[node.id]) {
    349                 this._showNamedFlow(this._contentNodes[node.id]);
    350                 return;
    351             }
    352 
    353             node = node.parentNode;
    354         }
    355     },
    356 
    357     wasShown: function()
    358     {
    359         WebInspector.SidebarView.prototype.wasShown.call(this);
    360 
    361         WebInspector.domAgent.requestDocument(this._setDocument.bind(this));
    362 
    363         WebInspector.domAgent.addEventListener(WebInspector.DOMAgent.Events.DocumentUpdated, this._documentUpdated, this);
    364 
    365         WebInspector.cssModel.addEventListener(WebInspector.CSSStyleModel.Events.NamedFlowCreated, this._namedFlowCreated, this);
    366         WebInspector.cssModel.addEventListener(WebInspector.CSSStyleModel.Events.NamedFlowRemoved, this._namedFlowRemoved, this);
    367         WebInspector.cssModel.addEventListener(WebInspector.CSSStyleModel.Events.RegionLayoutUpdated, this._regionLayoutUpdated, this);
    368         WebInspector.cssModel.addEventListener(WebInspector.CSSStyleModel.Events.RegionOversetChanged, this._regionOversetChanged, this);
    369 
    370         WebInspector.panel("elements").treeOutline.addEventListener(WebInspector.ElementsTreeOutline.Events.SelectedNodeChanged, this._selectedNodeChanged, this);
    371 
    372         this._tabbedPane.addEventListener(WebInspector.TabbedPane.EventTypes.TabSelected, this._tabSelected, this);
    373         this._tabbedPane.addEventListener(WebInspector.TabbedPane.EventTypes.TabClosed, this._tabClosed, this);
    374     },
    375 
    376     willHide: function()
    377     {
    378         WebInspector.domAgent.removeEventListener(WebInspector.DOMAgent.Events.DocumentUpdated, this._documentUpdated, this);
    379 
    380         WebInspector.cssModel.removeEventListener(WebInspector.CSSStyleModel.Events.NamedFlowCreated, this._namedFlowCreated, this);
    381         WebInspector.cssModel.removeEventListener(WebInspector.CSSStyleModel.Events.NamedFlowRemoved, this._namedFlowRemoved, this);
    382         WebInspector.cssModel.removeEventListener(WebInspector.CSSStyleModel.Events.RegionLayoutUpdated, this._regionLayoutUpdated, this);
    383         WebInspector.cssModel.removeEventListener(WebInspector.CSSStyleModel.Events.RegionOversetChanged, this._regionOversetChanged, this);
    384 
    385         WebInspector.panel("elements").treeOutline.removeEventListener(WebInspector.ElementsTreeOutline.Events.SelectedNodeChanged, this._selectedNodeChanged, this);
    386 
    387         this._tabbedPane.removeEventListener(WebInspector.TabbedPane.EventTypes.TabSelected, this._tabSelected, this);
    388         this._tabbedPane.removeEventListener(WebInspector.TabbedPane.EventTypes.TabClosed, this._tabClosed, this);
    389     },
    390 
    391     __proto__: WebInspector.SidebarView.prototype
    392 }
    393 
    394 /**
    395  * @constructor
    396  * @extends {TreeElement}
    397  */
    398 WebInspector.FlowTreeElement = function(flowContainer)
    399 {
    400     var container = document.createElement("div");
    401     container.createChild("div", "selection");
    402     container.createChild("span", "title").createChild("span").textContent = flowContainer.flow.name;
    403 
    404     TreeElement.call(this, container, flowContainer, false);
    405 
    406     this._overset = false;
    407     this.setOverset(flowContainer.flow.overset);
    408 }
    409 
    410 WebInspector.FlowTreeElement.prototype = {
    411     /**
    412      * @param {boolean} newOverset
    413      */
    414     setOverset: function(newOverset)
    415     {
    416         if (this._overset === newOverset)
    417             return;
    418 
    419         if (newOverset) {
    420             this.title.addStyleClass("named-flow-overflow");
    421             this.tooltip = WebInspector.UIString("Overflows.");
    422         } else {
    423             this.title.removeStyleClass("named-flow-overflow");
    424             this.tooltip = "";
    425         }
    426 
    427         this._overset = newOverset;
    428     },
    429 
    430     __proto__: TreeElement.prototype
    431 }
    432