Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(86)

Side by Side Diff: third_party/WebKit/Source/devtools/front_end/bindings/StylesSourceMapping.js

Issue 2662513003: DevTools: make StylesSourceMapping in charge of creating and removing UISourceCodes (Closed)
Patch Set: Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2012 Google Inc. All rights reserved. 2 * Copyright (C) 2012 Google Inc. All rights reserved.
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are 5 * modification, are permitted provided that the following conditions are
6 * met: 6 * met:
7 * 7 *
8 * * Redistributions of source code must retain the above copyright 8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer. 9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above 10 * * Redistributions in binary form must reproduce the above
(...skipping 16 matching lines...) Expand all
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 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. 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */ 29 */
30 30
31 /** 31 /**
32 * @unrestricted 32 * @unrestricted
33 */ 33 */
34 Bindings.StylesSourceMapping = class { 34 Bindings.StylesSourceMapping = class {
35 /** 35 /**
36 * @param {!SDK.CSSModel} cssModel 36 * @param {!SDK.CSSModel} cssModel
37 * @param {!Workspace.Workspace} workspace 37 * @param {!Bindings.NetworkProject} networkProject
38 */ 38 */
39 constructor(cssModel, workspace) { 39 constructor(cssModel, networkProject) {
40 this._cssModel = cssModel; 40 this._cssModel = cssModel;
41 this._workspace = workspace; 41 this._networkProject = networkProject;
42 42
43 /** @type {!Map<string, !Map<string, !Map<string, !SDK.CSSStyleSheetHeader>> >} */
44 this._urlToHeadersByFrameId = new Map();
45 /** @type {!Map.<!Workspace.UISourceCode, !Bindings.StyleFile>} */ 43 /** @type {!Map.<!Workspace.UISourceCode, !Bindings.StyleFile>} */
46 this._styleFiles = new Map(); 44 this._styleFiles = new Map();
47 45
48 this._eventListeners = [ 46 this._eventListeners = [
49 this._workspace.addEventListener(Workspace.Workspace.Events.ProjectRemoved , this._projectRemoved, this),
50 this._workspace.addEventListener(
51 Workspace.Workspace.Events.UISourceCodeAdded, this._uiSourceCodeAddedT oWorkspace, this),
52 this._workspace.addEventListener(Workspace.Workspace.Events.UISourceCodeRe moved, this._uiSourceCodeRemoved, this),
53 this._cssModel.addEventListener(SDK.CSSModel.Events.StyleSheetAdded, this. _styleSheetAdded, this), 47 this._cssModel.addEventListener(SDK.CSSModel.Events.StyleSheetAdded, this. _styleSheetAdded, this),
54 this._cssModel.addEventListener(SDK.CSSModel.Events.StyleSheetRemoved, thi s._styleSheetRemoved, this), 48 this._cssModel.addEventListener(SDK.CSSModel.Events.StyleSheetRemoved, thi s._styleSheetRemoved, this),
55 this._cssModel.addEventListener(SDK.CSSModel.Events.StyleSheetChanged, thi s._styleSheetChanged, this), 49 this._cssModel.addEventListener(SDK.CSSModel.Events.StyleSheetChanged, thi s._styleSheetChanged, this)
56 SDK.ResourceTreeModel.fromTarget(cssModel.target())
57 .addEventListener(SDK.ResourceTreeModel.Events.MainFrameNavigated, thi s._unbindAllUISourceCodes, this)
dgozman 2017/01/27 23:49:13 Why we don't need this anymore?
lushnikov 2017/01/30 14:19:15 We receive "styleSheetRemoved" events in this case
58 ]; 50 ];
59 } 51 }
60 52
61 /** 53 /**
62 * @param {!SDK.CSSLocation} rawLocation 54 * @param {!SDK.CSSLocation} rawLocation
63 * @return {?Workspace.UILocation} 55 * @return {?Workspace.UILocation}
64 */ 56 */
65 rawLocationToUILocation(rawLocation) { 57 rawLocationToUILocation(rawLocation) {
66 var uiSourceCode = 58 var uiSourceCode = this._networkProject.getFile(
67 Bindings.NetworkProject.uiSourceCodeForStyleURL(this._workspace, rawLoca tion.url, rawLocation.header()); 59 rawLocation.url, SDK.ResourceTreeFrame.fromStyleSheet(rawLocation.header ()), false);
68 if (!uiSourceCode) 60 if (!uiSourceCode)
69 return null; 61 return null;
70 var lineNumber = rawLocation.lineNumber; 62 var lineNumber = rawLocation.lineNumber;
71 var columnNumber = rawLocation.columnNumber; 63 var columnNumber = rawLocation.columnNumber;
72 var header = this._cssModel.styleSheetHeaderForId(rawLocation.styleSheetId); 64 var header = rawLocation.header();
73 if (header && header.isInline && header.hasSourceURL) { 65 if (header && header.isInline && header.hasSourceURL) {
74 lineNumber -= header.lineNumberInSource(0); 66 lineNumber -= header.lineNumberInSource(0);
75 columnNumber -= header.columnNumberInSource(lineNumber, 0); 67 columnNumber -= header.columnNumberInSource(lineNumber, 0);
76 } 68 }
77 return uiSourceCode.uiLocation(lineNumber, columnNumber); 69 return uiSourceCode.uiLocation(lineNumber, columnNumber);
78 } 70 }
79 71
80 /** 72 /**
81 * @param {!Common.Event} event 73 * @param {!Common.Event} event
82 */ 74 */
83 _styleSheetAdded(event) { 75 _styleSheetAdded(event) {
84 var header = /** @type {!SDK.CSSStyleSheetHeader} */ (event.data); 76 var header = /** @type {!SDK.CSSStyleSheetHeader} */ (event.data);
77 if (header.isInline && !header.hasSourceURL && header.origin !== 'inspector' )
78 return;
79
85 var url = header.resourceURL(); 80 var url = header.resourceURL();
86 if (!url) 81 if (!url)
87 return; 82 return;
88 83
89 var map = this._urlToHeadersByFrameId.get(url); 84 var uiSourceCode = this._networkProject.getFile(url, SDK.ResourceTreeFrame.f romStyleSheet(header), false);
90 if (!map) { 85 if (!uiSourceCode) {
91 map = /** @type {!Map.<string, !Map.<string, !SDK.CSSStyleSheetHeader>>} * / (new Map()); 86 uiSourceCode = this._networkProject.createFileForStyleSheetHeader(header);
92 this._urlToHeadersByFrameId.set(url, map); 87 this._styleFiles.set(uiSourceCode, new Bindings.StyleFile(this._cssModel, uiSourceCode));
93 } 88 }
94 var headersById = map.get(header.frameId); 89 var styleFile = this._styleFiles.get(uiSourceCode);
95 if (!headersById) { 90 styleFile.addHeader(header);
96 headersById = /** @type {!Map.<string, !SDK.CSSStyleSheetHeader>} */ (new Map()); 91
97 map.set(header.frameId, headersById); 92 Bindings.cssWorkspaceBinding.updateLocations(header);
98 }
99 headersById.set(header.id, header);
100 var uiSourceCode = Bindings.NetworkProject.uiSourceCodeForStyleURL(this._wor kspace, url, header);
101 if (uiSourceCode)
102 this._bindUISourceCode(uiSourceCode, header);
103 } 93 }
104 94
105 /** 95 /**
106 * @param {!Common.Event} event 96 * @param {!Common.Event} event
107 */ 97 */
108 _styleSheetRemoved(event) { 98 _styleSheetRemoved(event) {
109 var header = /** @type {!SDK.CSSStyleSheetHeader} */ (event.data); 99 var header = /** @type {!SDK.CSSStyleSheetHeader} */ (event.data);
110 var url = header.resourceURL(); 100 var url = header.resourceURL();
111 if (!url) 101 var frame = SDK.ResourceTreeFrame.fromStyleSheet(header);
102 var uiSourceCode = this._networkProject.getFile(url, frame, false);
103 if (!uiSourceCode)
112 return; 104 return;
113
114 var map = this._urlToHeadersByFrameId.get(url);
115 console.assert(map);
116 var headersById = map.get(header.frameId);
117 console.assert(headersById);
118 headersById.delete(header.id);
119
120 if (!headersById.size) {
121 map.delete(header.frameId);
122 if (!map.size) {
123 this._urlToHeadersByFrameId.delete(url);
124 var uiSourceCode = Bindings.NetworkProject.uiSourceCodeForStyleURL(this. _workspace, url, header);
125 if (uiSourceCode)
126 this._unbindUISourceCode(uiSourceCode);
127 }
128 }
129 }
130
131 /**
132 * @param {!Workspace.UISourceCode} uiSourceCode
133 */
134 _unbindUISourceCode(uiSourceCode) {
135 var styleFile = this._styleFiles.get(uiSourceCode); 105 var styleFile = this._styleFiles.get(uiSourceCode);
136 if (!styleFile) 106 styleFile.removeHeader(header);
107 if (styleFile.hasHeaders())
137 return; 108 return;
138 styleFile.dispose(); 109 styleFile.dispose();
139 this._styleFiles.delete(uiSourceCode); 110 this._styleFiles.delete(uiSourceCode);
140 } 111 this._networkProject.removeFile(uiSourceCode);
141
142 /**
143 * @param {!Common.Event} event
144 */
145 _unbindAllUISourceCodes(event) {
146 if (event.data.target() !== this._cssModel.target())
147 return;
148 for (var styleFile of this._styleFiles.values())
149 styleFile.dispose();
150 this._styleFiles.clear();
151 this._urlToHeadersByFrameId = new Map();
152 }
153
154 /**
155 * @param {!Common.Event} event
156 */
157 _uiSourceCodeAddedToWorkspace(event) {
158 var uiSourceCode = /** @type {!Workspace.UISourceCode} */ (event.data);
159 if (!this._urlToHeadersByFrameId.has(uiSourceCode.url()))
160 return;
161 this._bindUISourceCode(
162 uiSourceCode, this._urlToHeadersByFrameId.get(uiSourceCode.url()).values Array()[0].valuesArray()[0]);
163 }
164
165 /**
166 * @param {!Workspace.UISourceCode} uiSourceCode
167 * @param {!SDK.CSSStyleSheetHeader} header
168 */
169 _bindUISourceCode(uiSourceCode, header) {
170 if (this._styleFiles.get(uiSourceCode) || (header.isInline && !header.hasSou rceURL))
171 return;
172 this._styleFiles.set(uiSourceCode, new Bindings.StyleFile(uiSourceCode, this ));
173 Bindings.cssWorkspaceBinding.updateLocations(header);
174 }
175
176 /**
177 * @param {!Common.Event} event
178 */
179 _projectRemoved(event) {
180 var project = /** @type {!Workspace.Project} */ (event.data);
181 var uiSourceCodes = project.uiSourceCodes();
182 for (var i = 0; i < uiSourceCodes.length; ++i)
183 this._unbindUISourceCode(uiSourceCodes[i]);
184 }
185
186 /**
187 * @param {!Common.Event} event
188 */
189 _uiSourceCodeRemoved(event) {
190 var uiSourceCode = /** @type {!Workspace.UISourceCode} */ (event.data);
191 this._unbindUISourceCode(uiSourceCode);
192 }
193
194 /**
195 * @param {!Workspace.UISourceCode} uiSourceCode
196 * @param {string} content
197 * @param {boolean} majorChange
198 * @return {!Promise<?string>}
199 */
200 _setStyleContent(uiSourceCode, content, majorChange) {
201 var styleSheetIds = this._cssModel.styleSheetIdsForURL(uiSourceCode.url());
202 if (!styleSheetIds.length)
203 return Promise.resolve(/** @type {?string} */ ('No stylesheet found: ' + u iSourceCode.url()));
204
205 this._isSettingContent = true;
206
207 /**
208 * @param {?string} error
209 * @this {Bindings.StylesSourceMapping}
210 * @return {?string}
211 */
212 function callback(error) {
213 delete this._isSettingContent;
214 return error || null;
215 }
216
217 var promises = [];
218 for (var i = 0; i < styleSheetIds.length; ++i)
219 promises.push(this._cssModel.setStyleSheetText(styleSheetIds[i], content, majorChange));
220
221 return Promise.all(promises).spread(callback.bind(this));
222 } 112 }
223 113
224 /** 114 /**
225 * @param {!Common.Event} event 115 * @param {!Common.Event} event
226 */ 116 */
227 _styleSheetChanged(event) { 117 _styleSheetChanged(event) {
228 if (this._isSettingContent) 118 var styleSheetId = event.data.styleSheetId;
229 return;
230
231 this._updateStyleSheetTextSoon(event.data.styleSheetId);
232 }
233
234 /**
235 * @param {!Protocol.CSS.StyleSheetId} styleSheetId
236 */
237 _updateStyleSheetTextSoon(styleSheetId) {
238 if (this._updateStyleSheetTextTimer)
239 clearTimeout(this._updateStyleSheetTextTimer);
240
241 this._updateStyleSheetTextTimer = setTimeout(
242 this._updateStyleSheetText.bind(this, styleSheetId), Bindings.StylesSour ceMapping.ChangeUpdateTimeoutMs);
243 }
244
245 /**
246 * @param {!Protocol.CSS.StyleSheetId} styleSheetId
247 */
248 _updateStyleSheetText(styleSheetId) {
249 if (this._updateStyleSheetTextTimer) {
250 clearTimeout(this._updateStyleSheetTextTimer);
251 delete this._updateStyleSheetTextTimer;
252 }
253
254 var header = this._cssModel.styleSheetHeaderForId(styleSheetId); 119 var header = this._cssModel.styleSheetHeaderForId(styleSheetId);
255 if (!header) 120 var uiSourceCode =
dgozman 2017/01/27 23:49:12 Why do we have to consult with NetworkProject firs
lushnikov 2017/01/30 14:19:15 NetworkProject already has the knowledge of creati
256 return; 121 this._networkProject.getFile(header.resourceURL(), SDK.ResourceTreeFrame .fromStyleSheet(header), false);
257 var styleSheetURL = header.resourceURL(); 122 var styleFile = uiSourceCode ? this._styleFiles.get(uiSourceCode) : null;
258 if (!styleSheetURL) 123 if (styleFile)
259 return; 124 styleFile.styleSheetChanged(header);
260 var uiSourceCode = Bindings.NetworkProject.uiSourceCodeForStyleURL(this._wor kspace, styleSheetURL, header);
261 if (!uiSourceCode)
262 return;
263 header.requestContent().then(callback.bind(this, uiSourceCode));
264
265 /**
266 * @param {!Workspace.UISourceCode} uiSourceCode
267 * @param {?string} content
268 * @this {Bindings.StylesSourceMapping}
269 */
270 function callback(uiSourceCode, content) {
271 var styleFile = this._styleFiles.get(uiSourceCode);
272 if (styleFile)
273 styleFile.addRevision(content || '');
274 }
275 } 125 }
276 126
277 dispose() { 127 dispose() {
128 for (var uiSourceCode of this._styleFiles.keys()) {
129 this._networkProject.removeFile(uiSourceCode);
130 var styleFile = this._styleFiles.get(uiSourceCode);
131 styleFile.dispose();
132 }
133 this._styleFiles.clear();
278 Common.EventTarget.removeEventListeners(this._eventListeners); 134 Common.EventTarget.removeEventListeners(this._eventListeners);
279 } 135 }
280 }; 136 };
281 137
282 Bindings.StylesSourceMapping.ChangeUpdateTimeoutMs = 200;
283
284 /** 138 /**
285 * @unrestricted 139 * @unrestricted
286 */ 140 */
287 Bindings.StyleFile = class { 141 Bindings.StyleFile = class {
288 /** 142 /**
143 * @param {!SDK.CSSModel} cssModel
289 * @param {!Workspace.UISourceCode} uiSourceCode 144 * @param {!Workspace.UISourceCode} uiSourceCode
290 * @param {!Bindings.StylesSourceMapping} mapping
291 */ 145 */
292 constructor(uiSourceCode, mapping) { 146 constructor(cssModel, uiSourceCode) {
147 this._cssModel = cssModel;
293 this._uiSourceCode = uiSourceCode; 148 this._uiSourceCode = uiSourceCode;
294 this._mapping = mapping; 149 /** @type {!Set<!SDK.CSSStyleSheetHeader>} */
150 this._headers = new Set();
295 this._eventListeners = [ 151 this._eventListeners = [
296 this._uiSourceCode.addEventListener( 152 this._uiSourceCode.addEventListener(
297 Workspace.UISourceCode.Events.WorkingCopyChanged, this._workingCopyCha nged, this), 153 Workspace.UISourceCode.Events.WorkingCopyChanged, this._workingCopyCha nged, this),
298 this._uiSourceCode.addEventListener( 154 this._uiSourceCode.addEventListener(
299 Workspace.UISourceCode.Events.WorkingCopyCommitted, this._workingCopyC ommitted, this) 155 Workspace.UISourceCode.Events.WorkingCopyCommitted, this._workingCopyC ommitted, this)
300 ]; 156 ];
301 this._commitThrottler = new Common.Throttler(Bindings.StyleFile.updateTimeou t); 157 this._commitThrottler = new Common.Throttler(Bindings.StyleFile.updateTimeou t);
302 this._terminated = false; 158 this._terminated = false;
303 } 159 }
304 160
305 /** 161 /**
162 * @param {!SDK.CSSStyleSheetHeader} header
163 */
164 addHeader(header) {
165 this._headers.add(header);
166 }
167
168 /**
169 * @param {!SDK.CSSStyleSheetHeader} header
170 */
171 removeHeader(header) {
172 this._headers.delete(header);
173 }
174
175 /**
176 * @return {boolean}
177 */
178 hasHeaders() {
179 return !!this._headers.size;
180 }
181
182 /**
183 * @param {!SDK.CSSStyleSheetHeader} header
184 */
185 styleSheetChanged(header) {
186 if (this._isSettingStyleSheetContents)
187 return;
188
189 this._commitThrottler.schedule(this._syncStyleSheetChange.bind(this, header) , false);
190 }
191
192 /**
306 * @param {!Common.Event} event 193 * @param {!Common.Event} event
307 */ 194 */
308 _workingCopyCommitted(event) { 195 _workingCopyCommitted(event) {
309 if (this._isAddingRevision) 196 if (this._isAddingRevision)
310 return; 197 return;
311 198
312 this._isMajorChangePending = true; 199 this._isMajorChangePending = true;
313 this._commitThrottler.schedule(this._commitIncrementalEdit.bind(this), true) ; 200 this._commitThrottler.schedule(this._syncUISourceCodeChange.bind(this), true );
314 } 201 }
315 202
316 /** 203 /**
317 * @param {!Common.Event} event 204 * @param {!Common.Event} event
318 */ 205 */
319 _workingCopyChanged(event) { 206 _workingCopyChanged(event) {
320 if (this._isAddingRevision) 207 if (this._isAddingRevision)
321 return; 208 return;
322 209
323 this._commitThrottler.schedule(this._commitIncrementalEdit.bind(this), false ); 210 this._commitThrottler.schedule(this._syncUISourceCodeChange.bind(this), fals e);
324 } 211 }
325 212
326 _commitIncrementalEdit() { 213 /**
214 * @param {!SDK.CSSStyleSheetHeader} header
215 * @return {!Promise}
216 */
217 _syncStyleSheetChange(header) {
218 if (this._terminated || !this._headers.has(header))
219 return Promise.resolve();
220
221 return header.requestContent().then(onHeaderContent.bind(this));
222
223 /**
224 * @param {?string} content
225 * @return {!Promise}
226 * @this {Bindings.StyleFile}
227 */
228 function onHeaderContent(content) {
229 if (this._terminated || content === null)
230 return Promise.resolve();
231 this._isAddingRevision = true;
232 this._uiSourceCode.addRevision(content);
233 delete this._isAddingRevision;
234 return this._setStyleSheetContents(content, header, true);
235 }
236 }
237
238 /**
239 * @return {!Promise}
240 */
241 _syncUISourceCodeChange() {
327 if (this._terminated) 242 if (this._terminated)
328 return; 243 return Promise.resolve();
329 var promise = 244 var promise = this._setStyleSheetContents(this._uiSourceCode.workingCopy(), null, this._isMajorChangePending);
330 this._mapping._setStyleContent(this._uiSourceCode, this._uiSourceCode.wo rkingCopy(), this._isMajorChangePending)
331 .then(this._styleContentSet.bind(this));
332 this._isMajorChangePending = false; 245 this._isMajorChangePending = false;
333 return promise; 246 return promise;
334 } 247 }
335 248
336 /** 249 /**
337 * @param {?string} error 250 * @param {string} content
251 * @param {?SDK.CSSStyleSheetHeader} skipStyleSheet
252 * @param {boolean} majorChange
253 * @return {!Promise}
338 */ 254 */
339 _styleContentSet(error) { 255 _setStyleSheetContents(content, skipStyleSheet, majorChange) {
340 if (error) 256 this._isSettingStyleSheetContents = true;
341 console.error(error); 257 var promises = [];
342 } 258 for (var header of this._headers) {
259 if (header === skipStyleSheet)
260 continue;
261 promises.push(this._cssModel.setStyleSheetText(header.id, content, majorCh ange));
262 }
343 263
344 /** 264 return Promise.all(promises).then(onStyleSheetContentsUpdated.bind(this));
345 * @param {string} content 265
346 */ 266 /**
347 addRevision(content) { 267 * @param {!Array<?Protocol.Error>} errors
348 this._isAddingRevision = true; 268 * @this {Bindings.StyleFile}
349 this._uiSourceCode.addRevision(content); 269 */
350 delete this._isAddingRevision; 270 function onStyleSheetContentsUpdated(errors) {
271 delete this._isSettingStyleSheetContents;
272 errors = errors.filter(error => !!error);
273 for (var error of errors) {
274 if (!error)
dgozman 2017/01/27 23:49:13 Filtered them already.
275 continue;
276 console.error(error);
277 }
278 }
351 } 279 }
352 280
353 dispose() { 281 dispose() {
354 if (this._terminated) 282 if (this._terminated)
355 return; 283 return;
356 this._terminated = true; 284 this._terminated = true;
357 Common.EventTarget.removeEventListeners(this._eventListeners); 285 Common.EventTarget.removeEventListeners(this._eventListeners);
358 } 286 }
359 }; 287 };
360 288
361 Bindings.StyleFile.updateTimeout = 200; 289 Bindings.StyleFile.updateTimeout = 200;
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698