13e2f99102580136668855658a3c159a95c76235
[WebKit-https.git] / Source / WebInspectorUI / UserInterface / Models / ResourceCollection.js
1 /*
2  * Copyright (C) 2013 Apple Inc. All rights reserved.
3  * Copyright (C) 2016 Devin Rousso <webkit@devinrousso.com>. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
18  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
24  * THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 WI.ResourceCollection = class ResourceCollection extends WI.Collection
28 {
29     constructor(resourceType)
30     {
31         super(WI.ResourceCollection.verifierForType(resourceType));
32
33         this._resourceType = resourceType || null;
34         this._resourceURLMap = new Map;
35         this._resourcesTypeMap = new Map;
36     }
37
38     // Static
39
40     static verifierForType(type) {
41         switch (type) {
42         case WI.Resource.Type.Document:
43             return WI.ResourceCollection.TypeVerifier.Document;
44         case WI.Resource.Type.Stylesheet:
45             return WI.ResourceCollection.TypeVerifier.Stylesheet;
46         case WI.Resource.Type.Image:
47             return WI.ResourceCollection.TypeVerifier.Image;
48         case WI.Resource.Type.Font:
49             return WI.ResourceCollection.TypeVerifier.Font;
50         case WI.Resource.Type.Script:
51             return WI.ResourceCollection.TypeVerifier.Script;
52         case WI.Resource.Type.XHR:
53             return WI.ResourceCollection.TypeVerifier.XHR;
54         case WI.Resource.Type.Fetch:
55             return WI.ResourceCollection.TypeVerifier.Fetch;
56         case WI.Resource.Type.Ping:
57             return WI.ResourceCollection.TypeVerifier.Ping;
58         case WI.Resource.Type.Beacon:
59             return WI.ResourceCollection.TypeVerifier.Beacon;
60         case WI.Resource.Type.WebSocket:
61             return WI.ResourceCollection.TypeVerifier.WebSocket;
62         case WI.Resource.Type.Other:
63             return WI.ResourceCollection.TypeVerifier.Other;
64         default:
65             return WI.Collection.TypeVerifier.Resource;
66         }
67     }
68
69     // Public
70
71     get resourceType() { return this._resourceType; }
72
73     resourceForURL(url)
74     {
75         return this._resourceURLMap.get(url) || null;
76     }
77
78     resourceCollectionForType(type)
79     {
80         if (this._resourceType) {
81             console.assert(type === this._resourceType);
82             return this;
83         }
84
85         let resourcesCollectionForType = this._resourcesTypeMap.get(type);
86         if (!resourcesCollectionForType) {
87             resourcesCollectionForType = new WI.ResourceCollection(type);
88             this._resourcesTypeMap.set(type, resourcesCollectionForType);
89         }
90
91         return resourcesCollectionForType;
92     }
93
94     clear()
95     {
96         super.clear();
97
98         this._resourceURLMap.clear();
99
100         if (!this._resourceType)
101             this._resourcesTypeMap.clear();
102     }
103
104     // Protected
105
106     itemAdded(item)
107     {
108         this._associateWithResource(item);
109     }
110
111     itemRemoved(item)
112     {
113         this._disassociateWithResource(item);
114     }
115
116     itemsCleared(items)
117     {
118         const skipRemoval = true;
119
120         for (let item of items)
121             this._disassociateWithResource(item, skipRemoval);
122     }
123
124     // Private
125
126     _associateWithResource(resource)
127     {
128         this._resourceURLMap.set(resource.url, resource);
129
130         if (!this._resourceType) {
131             let resourcesCollectionForType = this.resourceCollectionForType(resource.type);
132             resourcesCollectionForType.add(resource);
133         }
134
135         resource.addEventListener(WI.Resource.Event.URLDidChange, this._resourceURLDidChange, this);
136         resource.addEventListener(WI.Resource.Event.TypeDidChange, this._resourceTypeDidChange, this);
137     }
138
139     _disassociateWithResource(resource, skipRemoval)
140     {
141         resource.removeEventListener(WI.Resource.Event.URLDidChange, this._resourceURLDidChange, this);
142         resource.removeEventListener(WI.Resource.Event.TypeDidChange, this._resourceTypeDidChange, this);
143
144         if (skipRemoval)
145             return;
146
147         if (!this._resourceType) {
148             let resourcesCollectionForType = this.resourceCollectionForType(resource.type);
149             resourcesCollectionForType.remove(resource);
150         }
151
152         this._resourceURLMap.delete(resource.url);
153     }
154
155     _resourceURLDidChange(event)
156     {
157         let resource = event.target;
158         console.assert(resource instanceof WI.Resource);
159         if (!(resource instanceof WI.Resource))
160             return;
161
162         let oldURL = event.data.oldURL;
163         console.assert(oldURL);
164         if (!oldURL)
165             return;
166
167         this._resourceURLMap.set(resource.url, resource);
168         this._resourceURLMap.delete(oldURL);
169     }
170
171     _resourceTypeDidChange(event)
172     {
173         let resource = event.target;
174         console.assert(resource instanceof WI.Resource);
175         if (!(resource instanceof WI.Resource))
176             return;
177
178         if (this._resourceType) {
179             console.assert(resource.type !== this._resourceType);
180             this.remove(resource);
181             return;
182         }
183
184         console.assert(event.data.oldType);
185
186         let resourcesWithNewType = this.resourceCollectionForType(resource.type);
187         resourcesWithNewType.add(resource);
188
189         // It is not necessary to remove the resource from the sub-collection for the old type since
190         // this is handled by that sub-collection's own _resourceTypeDidChange handler (via the
191         // above if statement).
192     }
193 };
194
195 WI.ResourceCollection.TypeVerifier = {
196     Document: (object) => WI.Collection.TypeVerifier.Resource(object) && object.type === WI.Resource.Type.Document,
197     Stylesheet: (object) => {
198         if (WI.Collection.TypeVerifier.CSSStyleSheet(object))
199             return true;
200         return WI.Collection.TypeVerifier.Resource(object) && object.type === WI.Resource.Type.Stylesheet;
201     },
202     Image: (object) => WI.Collection.TypeVerifier.Resource(object) && object.type === WI.Resource.Type.Image,
203     Font: (object) => WI.Collection.TypeVerifier.Resource(object) && object.type === WI.Resource.Type.Font,
204     Script: (object) => WI.Collection.TypeVerifier.Resource(object) && object.type === WI.Resource.Type.Script,
205     XHR: (object) => WI.Collection.TypeVerifier.Resource(object) && object.type === WI.Resource.Type.XHR,
206     Fetch: (object) => WI.Collection.TypeVerifier.Resource(object) && object.type === WI.Resource.Type.Fetch,
207     Ping: (object) => WI.Collection.TypeVerifier.Resource(object) && object.type === WI.Resource.Type.Ping,
208     Beacon: (object) => WI.Collection.TypeVerifier.Resource(object) && object.type === WI.Resource.Type.Beacon,
209     WebSocket: (object) => WI.Collection.TypeVerifier.Resource(object) && object.type === WI.Resource.Type.WebSocket,
210     Other: (object) => WI.Collection.TypeVerifier.Resource(object) && object.type === WI.Resource.Type.Other,
211 };