- Revision
- 222573
- Author
- [email protected]
- Date
- 2017-09-27 13:41:03 -0700 (Wed, 27 Sep 2017)
Log Message
Web Inspector: Create ResourceCollectionContentView and make CollectionContentView easier to extend
https://bugs.webkit.org/show_bug.cgi?id=177419
Reviewed by Devin Rousso.
CollectionContentView should be generic, work with any represented object
Collection, and not perform any type checking. It should just map items
to ContentViews using the provided ContentView constructor.
The behavior when clicking a ContentView in the collection has been extended.
If selection is enabled, clicking a ContentView will cause a "selected" class
to be applied to its element, and a SupplementalRepresentedObjectsDidChange
event is dispatched.
* Localizations/en.lproj/localizedStrings.js:
* UserInterface/Main.html:
New file, move CollectionContentView above subclasses.
* UserInterface/Models/ResourceCollection.js:
(WI.ResourceCollection.prototype.get resourceType):
Make resource type publicly available.
* UserInterface/Views/CollectionContentView.js:
Move type checking of the collection out of the base class and assert
that ContentViews are created when invoking `contentViewConstructor`.
(WI.CollectionContentView):
(WI.CollectionContentView.titleForCollection):
(WI.CollectionContentView.prototype.get supplementalRepresentedObjects):
(WI.CollectionContentView.prototype.get selectionEnabled):
(WI.CollectionContentView.prototype.set selectionEnabled):
(WI.CollectionContentView.prototype.addContentViewForItem):
(WI.CollectionContentView.prototype.removeContentViewForItem):
(WI.CollectionContentView.prototype.contentViewAdded):
(WI.CollectionContentView.prototype.contentViewRemoved):
(WI.CollectionContentView.prototype.initialLayout):
(WI.CollectionContentView.prototype.attached):
(WI.CollectionContentView.prototype.detached):
(WI.CollectionContentView.prototype._handleItemAdded):
(WI.CollectionContentView.prototype._handleItemRemoved):
(WI.CollectionContentView.prototype._selectItem):
(WI.CollectionContentView.prototype._addContentViewForItem): Deleted.
(WI.CollectionContentView.prototype._removeContentViewForItem): Deleted.
* UserInterface/Views/ContentView.js:
(WI.ContentView.createFromRepresentedObject):
Create a ResourceCollectionContentView. In the future, additional
Collection types can be mapped to their associated CollectionContentView.
* UserInterface/Views/ResourceCollectionContentView.js: Added.
New class for resource-specific logic previously in CollectionContentView.
(WI.ResourceCollectionContentView):
(WI.ResourceCollectionContentView.prototype.contentViewAdded):
(WI.ResourceCollectionContentView.prototype._handleContentError):
Remove ContentView without removing the resource from its collection.
Modified Paths
Added Paths
Diff
Modified: trunk/Source/WebInspectorUI/ChangeLog (222572 => 222573)
--- trunk/Source/WebInspectorUI/ChangeLog 2017-09-27 20:38:14 UTC (rev 222572)
+++ trunk/Source/WebInspectorUI/ChangeLog 2017-09-27 20:41:03 UTC (rev 222573)
@@ -1,3 +1,60 @@
+2017-09-27 Matt Baker <[email protected]>
+
+ Web Inspector: Create ResourceCollectionContentView and make CollectionContentView easier to extend
+ https://bugs.webkit.org/show_bug.cgi?id=177419
+
+ Reviewed by Devin Rousso.
+
+ CollectionContentView should be generic, work with any represented object
+ Collection, and not perform any type checking. It should just map items
+ to ContentViews using the provided ContentView constructor.
+
+ The behavior when clicking a ContentView in the collection has been extended.
+ If selection is enabled, clicking a ContentView will cause a "selected" class
+ to be applied to its element, and a SupplementalRepresentedObjectsDidChange
+ event is dispatched.
+
+ * Localizations/en.lproj/localizedStrings.js:
+ * UserInterface/Main.html:
+ New file, move CollectionContentView above subclasses.
+
+ * UserInterface/Models/ResourceCollection.js:
+ (WI.ResourceCollection.prototype.get resourceType):
+ Make resource type publicly available.
+
+ * UserInterface/Views/CollectionContentView.js:
+ Move type checking of the collection out of the base class and assert
+ that ContentViews are created when invoking `contentViewConstructor`.
+ (WI.CollectionContentView):
+ (WI.CollectionContentView.titleForCollection):
+ (WI.CollectionContentView.prototype.get supplementalRepresentedObjects):
+ (WI.CollectionContentView.prototype.get selectionEnabled):
+ (WI.CollectionContentView.prototype.set selectionEnabled):
+ (WI.CollectionContentView.prototype.addContentViewForItem):
+ (WI.CollectionContentView.prototype.removeContentViewForItem):
+ (WI.CollectionContentView.prototype.contentViewAdded):
+ (WI.CollectionContentView.prototype.contentViewRemoved):
+ (WI.CollectionContentView.prototype.initialLayout):
+ (WI.CollectionContentView.prototype.attached):
+ (WI.CollectionContentView.prototype.detached):
+ (WI.CollectionContentView.prototype._handleItemAdded):
+ (WI.CollectionContentView.prototype._handleItemRemoved):
+ (WI.CollectionContentView.prototype._selectItem):
+ (WI.CollectionContentView.prototype._addContentViewForItem): Deleted.
+ (WI.CollectionContentView.prototype._removeContentViewForItem): Deleted.
+
+ * UserInterface/Views/ContentView.js:
+ (WI.ContentView.createFromRepresentedObject):
+ Create a ResourceCollectionContentView. In the future, additional
+ Collection types can be mapped to their associated CollectionContentView.
+
+ * UserInterface/Views/ResourceCollectionContentView.js: Added.
+ New class for resource-specific logic previously in CollectionContentView.
+ (WI.ResourceCollectionContentView):
+ (WI.ResourceCollectionContentView.prototype.contentViewAdded):
+ (WI.ResourceCollectionContentView.prototype._handleContentError):
+ Remove ContentView without removing the resource from its collection.
+
2017-09-27 Ross Kirsling <[email protected]>
Web Inspector: Fix Layers tab sidebar popover.
Modified: trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js (222572 => 222573)
--- trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js 2017-09-27 20:38:14 UTC (rev 222572)
+++ trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js 2017-09-27 20:41:03 UTC (rev 222573)
@@ -204,6 +204,7 @@
localizedStrings["Collapse All"] = "Collapse All";
localizedStrings["Collapse columns"] = "Collapse columns";
localizedStrings["Collect garbage"] = "Collect garbage";
+localizedStrings["Collection"] = "Collection";
localizedStrings["Color"] = "Color";
localizedStrings["Comment"] = "Comment";
localizedStrings["Comment All Properties"] = "Comment All Properties";
Modified: trunk/Source/WebInspectorUI/UserInterface/Main.html (222572 => 222573)
--- trunk/Source/WebInspectorUI/UserInterface/Main.html 2017-09-27 20:38:14 UTC (rev 222572)
+++ trunk/Source/WebInspectorUI/UserInterface/Main.html 2017-09-27 20:41:03 UTC (rev 222573)
@@ -522,6 +522,8 @@
<script src=""
<script src=""
+ <script src=""
+
<script src=""
<script src=""
<script src=""
@@ -550,7 +552,6 @@
<script src=""
<script src=""
<script src=""
- <script src=""
<script src=""
<script src=""
<script src=""
@@ -682,6 +683,7 @@
<script src=""
<script src=""
<script src=""
+ <script src=""
<script src=""
<script src=""
<script src=""
Modified: trunk/Source/WebInspectorUI/UserInterface/Models/ResourceCollection.js (222572 => 222573)
--- trunk/Source/WebInspectorUI/UserInterface/Models/ResourceCollection.js 2017-09-27 20:38:14 UTC (rev 222572)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/ResourceCollection.js 2017-09-27 20:41:03 UTC (rev 222573)
@@ -64,6 +64,8 @@
// Public
+ get resourceType() { return this._resourceType; }
+
resourceForURL(url)
{
return this._resourceURLMap.get(url) || null;
Modified: trunk/Source/WebInspectorUI/UserInterface/Views/CollectionContentView.js (222572 => 222573)
--- trunk/Source/WebInspectorUI/UserInterface/Views/CollectionContentView.js 2017-09-27 20:38:14 UTC (rev 222572)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/CollectionContentView.js 2017-09-27 20:41:03 UTC (rev 222573)
@@ -25,118 +25,104 @@
WI.CollectionContentView = class CollectionContentView extends WI.ContentView
{
- constructor(collection)
+ constructor(collection, contentViewConstructor, contentPlaceholderText)
{
console.assert(collection instanceof WI.Collection);
super(collection);
- this.representedObject.addEventListener(WI.Collection.Event.ItemAdded, this._handleItemAdded, this);
- this.representedObject.addEventListener(WI.Collection.Event.ItemRemoved, this._handleItemRemoved, this);
+ this.element.classList.add("collection");
- this._contentViewMap = new WeakMap;
+ this._contentPlaceholder = new WI.TitleView(contentPlaceholderText || WI.CollectionContentView.titleForCollection(collection));
+ this._contentViewConstructor = contentViewConstructor;
+ this._contentViewMap = new Map;
this._handleClickMap = new WeakMap;
+ this._selectedItem = null;
+ this._selectionEnabled = false;
+ }
- this._contentViewConstructor = null;
- let title = "";
- switch (this.representedObject.typeVerifier) {
+ static titleForCollection(collection)
+ {
+ switch (collection.typeVerifier) {
case WI.Collection.TypeVerifier.Frame:
- title = WI.UIString("Frames");
- break;
-
+ return WI.UIString("Frames");
+ case WI.Collection.TypeVerifier.Resource:
+ return WI.UIString("Resources");
case WI.Collection.TypeVerifier.Script:
- title = WI.UIString("Extra Scripts");
- break;
+ return WI.UIString("Scripts");
+ case WI.Collection.TypeVerifier.CSSStyleSheet:
+ return WI.UIString("Stylesheets");
+ case WI.Collection.TypeVerifier.Canvas:
+ return WI.UIString("Canvases");
+ case WI.Collection.TypeVerifier.ShaderProgram:
+ return WI.UIString("Shader Programs");
+ }
- case WI.Collection.TypeVerifier.Resource:
- title = WI.UIString("Resource");
- break;
+ console.warn("No default title for Collection type verifier.", collection.typeVerifier);
+ return WI.UIString("Collection");
+ }
- case WI.ResourceCollection.TypeVerifier.Document:
- title = WI.Resource.displayNameForType(WI.Resource.Type.Document, true);
- break;
+ // Public
- case WI.ResourceCollection.TypeVerifier.Stylesheet:
- title = WI.Resource.displayNameForType(WI.Resource.Type.Stylesheet, true);
- break;
+ get supplementalRepresentedObjects()
+ {
+ if (this._selectedItem)
+ return [this._selectedItem];
+ return [];
+ }
- case WI.ResourceCollection.TypeVerifier.Image:
- this._contentViewConstructor = WI.ImageResourceContentView;
- title = WI.Resource.displayNameForType(WI.Resource.Type.Image, true);
- break;
-
- case WI.ResourceCollection.TypeVerifier.Font:
- title = WI.Resource.displayNameForType(WI.Resource.Type.Font, true);
- break;
-
- case WI.ResourceCollection.TypeVerifier.Script:
- title = WI.Resource.displayNameForType(WI.Resource.Type.Script, true);
- break;
-
- case WI.ResourceCollection.TypeVerifier.XHR:
- title = WI.Resource.displayNameForType(WI.Resource.Type.XHR, true);
- break;
-
- case WI.ResourceCollection.TypeVerifier.Fetch:
- title = WI.Resource.displayNameForType(WI.Resource.Type.Fetch, true);
- break;
-
- case WI.ResourceCollection.TypeVerifier.WebSocket:
- title = WI.Resource.displayNameForType(WI.Resource.Type.WebSocket, true);
- break;
-
- case WI.ResourceCollection.TypeVerifier.Other:
- title = WI.Resource.displayNameForType(WI.Resource.Type.Other, true);
- break;
- }
-
- this._contentPlaceholder = new WI.TitleView(title);
-
- this.element.classList.add("collection");
+ get selectionEnabled()
+ {
+ return this._selectionEnabled;
}
- // Public
+ set selectionEnabled(value)
+ {
+ if (this._selectionEnabled === value)
+ return;
- initialLayout()
- {
- let items = this.representedObject.items;
- if (this._contentViewConstructor && items.size) {
- for (let item of items)
- this._addContentViewForItem(item);
- } else
- this.addSubview(this._contentPlaceholder);
+ this._selectionEnabled = value;
+ if (!this._selectionEnabled)
+ this._selectItem(null);
}
- // Private
+ // Protected
- _addContentViewForItem(item)
+ addContentViewForItem(item)
{
if (!this._contentViewConstructor)
return;
+ if (this._contentViewMap.has(item)) {
+ console.assert(false, "Already added ContentView for item.", item);
+ return;
+ }
+
if (this._contentPlaceholder.parentView)
this.removeSubview(this._contentPlaceholder);
let contentView = new this._contentViewConstructor(item);
+ console.assert(contentView instanceof WI.ContentView);
- contentView.addEventListener(WI.ResourceContentView.Event.ContentError, this._handleContentError, this);
-
let handleClick = (event) => {
if (event.button !== 0 || event.ctrlKey)
return;
- WI.showRepresentedObject(item);
+ if (this._selectionEnabled)
+ this._selectItem(item);
+ else
+ WI.showRepresentedObject(item);
};
+
+ this._contentViewMap.set(item, contentView);
this._handleClickMap.set(item, handleClick);
contentView.element.addEventListener("click", handleClick);
- contentView.element.title = WI.displayNameForURL(item.url, item.urlComponents);
-
this.addSubview(contentView);
- this._contentViewMap.set(item, contentView);
+ this.contentViewAdded(contentView);
}
- _removeContentViewForItem(item)
+ removeContentViewForItem(item)
{
if (!this._contentViewConstructor)
return;
@@ -148,20 +134,78 @@
this.removeSubview(contentView);
this._contentViewMap.delete(item);
+ this.contentViewRemoved(contentView);
contentView.removeEventListener(null, null, this);
let handleClick = this._handleClickMap.get(item);
console.assert(handleClick);
+
if (handleClick) {
contentView.element.removeEventListener("click", handleClick);
this._handleClickMap.delete(item);
}
- if (!this.representedObject.resources.length)
+ if (this._selectedItem === item)
+ this._selectItem(null);
+
+ if (!this.subviews.length)
this.addSubview(this._contentPlaceholder);
}
+ contentViewAdded(contentView)
+ {
+ // Implemented by subclasses.
+ }
+
+ contentViewRemoved(contentView)
+ {
+ // Implemented by subclasses.
+ }
+
+ initialLayout()
+ {
+ let items = this.representedObject.items;
+ if (!items.size || !this._contentViewConstructor) {
+ this.addSubview(this._contentPlaceholder);
+ return;
+ }
+
+ for (let item of items)
+ this.addContentViewForItem(item);
+ }
+
+ attached()
+ {
+ super.attached();
+
+ this.representedObject.addEventListener(WI.Collection.Event.ItemAdded, this._handleItemAdded, this);
+ this.representedObject.addEventListener(WI.Collection.Event.ItemRemoved, this._handleItemRemoved, this);
+
+ for (let item of this._contentViewMap.keys()) {
+ if (this.representedObject.items.has(item))
+ continue;
+
+ this.removeContentViewForItem(item);
+ if (this._selectedItem === item)
+ this._selectItem(null);
+ }
+
+ for (let item of this.representedObject.items) {
+ if (!this._contentViewMap.has(item))
+ this.addContentViewForItem(item);
+ }
+ }
+
+ detached()
+ {
+ this.representedObject.removeEventListener(null, null, this);
+
+ super.detached();
+ }
+
+ // Private
+
_handleItemAdded(event)
{
let item = event.data.item;
@@ -168,7 +212,7 @@
if (!item)
return;
- this._addContentViewForItem(item);
+ this.addContentViewForItem(item);
}
_handleItemRemoved(event)
@@ -177,7 +221,7 @@
if (!item)
return;
- this._removeContentViewForItem(item);
+ this.removeContentViewForItem(item);
}
_handleContentError(event)
@@ -185,4 +229,26 @@
if (event && event.target)
this._removeContentViewForItem(event.target.representedObject);
}
+
+ _selectItem(item)
+ {
+ if (this._selectedItem === item)
+ return;
+
+ if (this._selectedItem) {
+ let contentView = this._contentViewMap.get(this._selectedItem);
+ console.assert(contentView, "Missing ContentView for deselected item.", this._selectedItem);
+ contentView.element.classList.remove("selected");
+ }
+
+ this._selectedItem = item;
+
+ if (this._selectedItem) {
+ let selectedContentView = this._contentViewMap.get(this._selectedItem);
+ console.assert(selectedContentView, "Missing ContentView for selected item.", this._selectedItem);
+ selectedContentView.element.classList.add("selected");
+ }
+
+ this.dispatchEventToListeners(WI.ContentView.Event.SupplementalRepresentedObjectsDidChange);
+ }
};
Modified: trunk/Source/WebInspectorUI/UserInterface/Views/ContentView.js (222572 => 222573)
--- trunk/Source/WebInspectorUI/UserInterface/Views/ContentView.js 2017-09-27 20:38:14 UTC (rev 222572)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/ContentView.js 2017-09-27 20:41:03 UTC (rev 222573)
@@ -161,6 +161,9 @@
if (representedObject instanceof WI.Recording)
return new WI.RecordingContentView(representedObject, extraArguments);
+ if (representedObject instanceof WI.ResourceCollection)
+ return new WI.ResourceCollectionContentView(representedObject, extraArguments);
+
if (representedObject instanceof WI.Collection)
return new WI.CollectionContentView(representedObject, extraArguments);
Added: trunk/Source/WebInspectorUI/UserInterface/Views/ResourceCollectionContentView.js (0 => 222573)
--- trunk/Source/WebInspectorUI/UserInterface/Views/ResourceCollectionContentView.js (rev 0)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/ResourceCollectionContentView.js 2017-09-27 20:41:03 UTC (rev 222573)
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+WI.ResourceCollectionContentView = class ResourceCollectionContentView extends WI.CollectionContentView
+{
+ constructor(collection)
+ {
+ console.assert(collection instanceof WI.ResourceCollection);
+
+ let contentViewConstructor = null;
+ if (collection.resourceType === WI.Resource.Type.Image)
+ contentViewConstructor = WI.ImageResourceContentView;
+
+ const plural = true;
+ let contentPlaceholderText = WI.Resource.displayNameForType(collection.resourceType, plural);
+
+ super(collection, contentViewConstructor, contentPlaceholderText);
+ }
+
+ // Protected
+
+ contentViewAdded(contentView)
+ {
+ console.assert(contentView instanceof WI.ResourceContentView);
+
+ let resource = contentView.representedObject;
+ console.assert(resource instanceof WI.Resource);
+
+ contentView.addEventListener(WI.ResourceContentView.Event.ContentError, this._handleContentError, this);
+ contentView.element.title = WI.displayNameForURL(resource.url, resource.urlComponents);
+ }
+
+ // Private
+
+ _handleContentError(event)
+ {
+ if (event && event.target)
+ this.removeContentViewForItem(event.target.representedObject);
+ }
+};