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

Side by Side Diff: third_party/WebKit/Source/devtools/front_end/sass/SASSWorkspaceAdapter.js

Issue 1641893002: DevTools: [SASS] introduce workspace/cssModel adapter for SASS processor. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 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
(Empty)
1 // Copyright 2015 The Chromium Authors. All rights reserved.
dgozman 2016/01/27 23:14:04 2016
lushnikov 2016/01/28 00:04:29 Done.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 /**
6 * @constructor
7 * @param {!WebInspector.CSSStyleModel} cssModel
8 * @param {!WebInspector.Workspace} workspace
9 * @param {!WebInspector.NetworkMapping} networkMapping
10 */
11 WebInspector.SASSWorkspaceAdapter = function(cssModel, workspace, networkMapping )
12 {
13 this._workspace = workspace;
14 this._networkMapping = networkMapping;
15 this._cssModel = cssModel;
16
17 /** @type {!Map<string, number>} */
18 this._versions = new Map();
19 /** @type {!Map<string, !Promise<boolean>>} */
20 this._awaitingPromises = new Map();
21 /** @type {!Map<string, function(boolean)>} */
22 this._awaitingFulfills = new Map();
23
24 /** @type {!Multimap<string, !WebInspector.SASSWorkspaceAdapter.Client>} */
25 this._urlToClients = new Multimap();
26 /** @type {!Set<string>} */
27 this._cssURLs = new Set();
28
29 this._eventListeners = [
30 this._workspace.addEventListener(WebInspector.Workspace.Events.UISourceC odeAdded, this._uiSourceCodeAdded, this),
31 this._workspace.addEventListener(WebInspector.Workspace.Events.UISourceC odeRemoved, this._uiSourceCodeRemoved, this),
32 this._workspace.addEventListener(WebInspector.Workspace.Events.WorkingCo pyChanged, this._uiSourceCodeChanged, this),
33 this._workspace.addEventListener(WebInspector.Workspace.Events.WorkingCo pyCommitted, this._uiSourceCodeChanged, this),
34 this._cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleS heetAdded, this._styleSheetAdded, this),
35 this._cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleS heetRemoved, this._styleSheetRemoved, this),
36 this._cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleS heetChanged, this._styleSheetChanged, this)
37 ];
38 }
39
40 /**
41 * @constructor
42 * @param {string} url
43 * @param {number} version
44 * @param {string} text
45 */
46 WebInspector.SASSWorkspaceAdapter.ContentResponse = function(url, version, text)
47 {
48 this.url = url;
49 this.version = version;
50 this.text = text;
51 }
52
53 WebInspector.SASSWorkspaceAdapter.prototype = {
54 /**
55 * @param {!WebInspector.SourceMap} sourceMap
56 * @return {!WebInspector.SASSWorkspaceAdapter.Client}
dgozman 2016/01/27 23:14:04 WebInspector.SourceMapTracker
lushnikov 2016/01/28 00:04:29 Done.
57 */
58 trackSources: function(sourceMap)
59 {
60 var cssURL = sourceMap.compiledURL();
61 this._cssURLs.add(cssURL);
62
63 var allSources = new Set(sourceMap.sources().concat(cssURL));
64 for (var sourceURL of allSources) {
65 if (this._versions.has(sourceURL))
66 continue;
67 this._versions.set(sourceURL, 1);
68 var promise = new Promise(fulfill => this._awaitingFulfills.set(sour ceURL, fulfill));
69 this._awaitingPromises.set(sourceURL, promise);
70 var contentProvider = sourceURL === cssURL ? this._headersForURL(sou rceURL).peekLast() : this._sourceCodeForURL(sourceURL);
71 if (contentProvider)
72 this._contentProviderAdded(sourceURL);
73 }
74
75 var client = new WebInspector.SASSWorkspaceAdapter.Client(this, sourceMa p);
76 for (var sourceURL of client.allURLs())
77 this._urlToClients.set(sourceURL, client);
78 return client;
79 },
80
81 /**
82 * @param {!WebInspector.SASSWorkspaceAdapter.Client} client
83 */
84 _stopTrackSources: function(client)
85 {
86 for (var sourceURL of client.allURLs()) {
87 this._urlToClients.remove(sourceURL, client);
88 if (!this._urlToClients.has(sourceURL)) {
89 this._awaitingFulfills.get(sourceURL).call(null, false);
90 this._awaitingFulfills.delete(sourceURL);
91 this._awaitingPromises.delete(sourceURL);
92 this._versions.delete(sourceURL);
93 this._cssURLs.delete(sourceURL);
94 }
95 }
96 },
97
98 /**
99 * @param {string} url
100 * @return {?WebInspector.UISourceCode}
101 */
102 _sourceCodeForURL: function(url)
dgozman 2016/01/27 23:14:04 sassUISourceCode(url)
lushnikov 2016/01/28 00:04:29 Done.
103 {
104 return this._networkMapping.uiSourceCodeForURLForAnyTarget(url);
105 },
106
107 /**
108 * @param {string} url
109 * @return {!Array<!WebInspector.CSSStyleSheetHeader>}
110 */
111 _headersForURL: function(url)
112 {
113 return this._cssModel.styleSheetIdsForURL(url)
114 .map(styleSheetId => this._cssModel.styleSheetHeaderForId(styleSheet Id));
115 },
116
117 /**
118 * @param {string} url
119 */
120 _contentProviderAdded: function(url)
121 {
122 this._awaitingFulfills.get(url).call(null, true);
123 },
124
125 /**
126 * @param {string} url
127 */
128 _contentProviderRemoved: function(url)
129 {
130 var clients = new Set(this._urlToClients.get(url));
131 for (var client of clients)
132 client.dispose(client);
dgozman 2016/01/27 23:14:04 client.dispose()
lushnikov 2016/01/28 00:04:30 Done.
133 },
134
135 /**
136 * @param {!WebInspector.Event} event
137 */
138 _uiSourceCodeAdded: function(event)
139 {
140 var uiSourceCode = /** @type {!WebInspector.UISourceCode} */(event.data) ;
141 var url = this._networkMapping.networkURL(uiSourceCode);
142 if (this._cssURLs.has(url) || !this._versions.has(url))
dgozman 2016/01/27 23:14:04 this._isSassURL(url) or comment about it.
lushnikov 2016/01/28 00:04:29 Done.
143 return;
144 this._contentProviderAdded(url);
145 },
146
147 /**
148 * @param {!WebInspector.Event} event
149 */
150 _uiSourceCodeRemoved: function(event)
151 {
152 var uiSourceCode = /** @type {!WebInspector.UISourceCode} */(event.data) ;
153 var url = this._networkMapping.networkURL(uiSourceCode);
154 if (this._cssURLs.has(url) || !this._versions.has(url))
155 return;
156 this._contentProviderRemoved(url);
157 },
158
159 /**
160 * @param {!WebInspector.Event} event
161 */
162 _styleSheetAdded: function(event)
163 {
164 var styleSheetHeader = /** @type {!WebInspector.CSSStyleSheetHeader} */( event.data);
165 var url = styleSheetHeader.sourceURL;
166 if (!this._cssURLs.has(url))
167 return;
168 this._contentProviderAdded(url);
169 },
170
171 /**
172 * @param {!WebInspector.Event} event
173 */
174 _styleSheetRemoved: function(event)
175 {
176 var styleSheetHeader = /** @type {!WebInspector.CSSStyleSheetHeader} */( event.data);
177 var url = styleSheetHeader.sourceURL;
178 if (!this._cssURLs.has(url))
179 return;
180 var headers = this._headersForURL(url);
181 if (headers.length)
182 return;
183 this._contentProviderRemoved(url);
184 },
185
186 /**
187 * @param {!WebInspector.Event} event
188 */
189 _uiSourceCodeChanged: function(event)
190 {
191 var uiSourceCode = /** @type {!WebInspector.UISourceCode} */(event.data. uiSourceCode);
192 var url = this._networkMapping.networkURL(uiSourceCode);
193 if (this._cssURLs.has(url) || !this._versions.has(url))
dgozman 2016/01/27 23:14:04 isSassURL
lushnikov 2016/01/28 00:04:29 Done.
194 return;
195 this._newContentAvailable(url);
196 },
197
198 /**
199 * @param {!WebInspector.Event} event
200 */
201 _styleSheetChanged: function(event)
202 {
203 var styleSheetId = /** @type {!CSSAgent.StyleSheetId} */(event.data.styl eSheetId);
204 var styleSheetHeader = this._cssModel.styleSheetHeaderForId(styleSheetId );
205 var url = styleSheetHeader.sourceURL;
206 if (!this._cssURLs.has(url))
207 return;
208 this._newContentAvailable(url);
209 },
210
211 /**
212 * @param {string} url
213 */
214 _newContentAvailable: function(url)
215 {
216 var newVersion = this._versions.get(url) + 1;
dgozman 2016/01/27 23:14:04 console.assert(this._versions.has(url))
lushnikov 2016/01/28 00:04:30 Done.
217 this._versions.set(url, newVersion);
218 for (var client of this._urlToClients.get(url))
219 client._newContentAvailable(url, newVersion);
220 },
221
222 /**
223 * @param {string} url
224 * @return {number}
225 */
226 _urlVersion: function(url)
227 {
228 var version = this._versions.get(url);
229 console.assert(version, "The '" + url + "' is not tracked.")
230 return version || 0;
231 },
232
233 /**
234 * @param {string} url
235 * @return {!Promise<?WebInspector.SASSWorkspaceAdapter.ContentResponse>}
236 */
237 _getContent: function(url)
238 {
239 console.assert(this._awaitingPromises.has(url), "The '" + url + "' is no t tracked.")
240 return this._awaitingPromises.get(url)
241 .then(onContentProviderResolved.bind(this));
242
243 /**
244 * @param {boolean} success
245 * @return {!Promise<?WebInspector.SASSWorkspaceAdapter.ContentResponse> }
246 * @this {WebInspector.SASSWorkspaceAdapter}
247 */
248 function onContentProviderResolved(success)
249 {
250 if (!success)
251 return Promise.resolve(/** @type {?WebInspector.SASSWorkspaceAda pter.ContentResponse} */(null));
252 var contentProvider = this._cssURLs.has(url) ? this._headersForURL(u rl).peekLast() : this._sourceCodeForURL(url);
253 if (!contentProvider)
254 return Promise.resolve(/** @type {?WebInspector.SASSWorkspaceAda pter.ContentResponse} */(null));
255 return contentProvider.requestContent()
256 .then(text => new WebInspector.SASSWorkspaceAdapter.ContentRespo nse(url, /** @type {number} */(this._versions.get(url)), text || ""));
257 }
258 },
259
260 /**
261 * @param {string} url
262 * @param {string} text
263 * @return {?WebInspector.SASSWorkspaceAdapter.ContentResponse}
264 */
265 _setSASSText: function(url, text)
266 {
267 console.assert(this._versions.has(url) && !this._cssURLs.has(url), "The url '" + url + "' should be a tracked SASS url");
dgozman 2016/01/27 23:14:04 isSassURL
lushnikov 2016/01/28 00:04:29 Done.
268 var uiSourceCode = this._sourceCodeForURL(url);
269 if (!uiSourceCode)
270 return null;
271 setImmediate(() => uiSourceCode.addRevision(text));
272 var futureVersion = this._versions.get(url) + 1;
273 return new WebInspector.SASSWorkspaceAdapter.ContentResponse(url, future Version, text);
274 },
275
276 /**
277 * @param {string} url
278 * @param {string} text
279 * @param {!Array<!WebInspector.SourceEdit>} cssEdits
280 * @return {?WebInspector.SASSWorkspaceAdapter.ContentResponse}
281 */
282 _setCSSText: function(url, text, cssEdits)
283 {
284 console.assert(this._cssURLs.has(url), "The url '" + url + "' should be a tracked CSS url");
285 var headers = this._headersForURL(url);
286 if (!headers.length)
287 return null;
288 for (var i = 0; i < headers.length; ++i)
289 headers[i].setContent(text, function() { });
290 for (var i = cssEdits.length - 1; i >= 0; --i) {
291 var edit = cssEdits[i];
292 var oldRange = edit.oldRange;
293 var newRange = edit.newRange();
294 for (var j = 0; j < headers.length; ++j) {
295 this._cssModel.dispatchEventToListeners(WebInspector.CSSStyleMod el.Events.ExternalRangeEdit, {
296 styleSheetId: headers[j].id,
297 oldRange: oldRange,
298 newRange: newRange
299 });
300 }
301 }
302 var futureVersion = this._versions.get(url) + headers.length;
303 return new WebInspector.SASSWorkspaceAdapter.ContentResponse(url, future Version, text);
304 }
305 }
306
307 /** @enum {string} */
308 WebInspector.SASSWorkspaceAdapter.ClientEvents = {
309 SourceChanged: "SourceChanged",
310 TrackingStopped: "TrackingStopped"
311 }
312
313 /**
314 * @constructor
315 * @extends {WebInspector.Object}
316 * @param {!WebInspector.SASSWorkspaceAdapter} adapter
317 * @param {!WebInspector.SourceMap} sourceMap
318 */
319 WebInspector.SASSWorkspaceAdapter.Client = function(adapter, sourceMap)
320 {
321 WebInspector.Object.call(this);
322 this._adapter = adapter;
323 this._cssURL = sourceMap.compiledURL();
324 this._sassURLs = sourceMap.sources().slice();
325 this._allURLs = this._sassURLs.concat(this._cssURL);
326 this._terminated = false;
327 this._versions = new Map();
328 for (var url of this._allURLs)
329 this._versions.set(url, adapter._urlVersion(url));
330 }
331
332 WebInspector.SASSWorkspaceAdapter.Client.prototype = {
333 /**
334 * @return {!Array<string>}
335 */
336 allURLs: function()
337 {
338 return this._allURLs;
339 },
340
341 /**
342 * @return {string}
343 */
344 cssURL: function()
345 {
346 return this._cssURL;
347 },
348
349 /**
350 * @return {!Array<string>}
351 */
352 sassURLs: function()
353 {
354 return this._sassURLs;
355 },
356
357 /**
358 * @return {boolean}
359 */
360 isOutdated: function()
361 {
362 if (this._terminated)
363 return true;
364 for (var url of this._allURLs) {
365 if (this._adapter._urlVersion(url) > this._versions.get(url))
366 return true;
367 }
368 return false;
369 },
370
371 /**
372 * @param {string} text
373 * @param {!Array<!WebInspector.SourceEdit>} edits
374 * @return {boolean}
375 */
376 setCSSText: function(text, edits)
377 {
378 if (this._terminated || this.isOutdated())
379 return false;
380 var result = this._adapter._setCSSText(this._cssURL, text, edits);
381 return !!this._handleContentResponse(result);
dgozman 2016/01/27 23:14:04 this._handleContentResponse(result); return !!resu
lushnikov 2016/01/28 00:04:29 Done.
382 },
383
384 /**
385 * @param {string} url
386 * @param {string} text
387 * @return {boolean}
388 */
389 setSASSText: function(url, text)
390 {
391 if (this._terminated || this.isOutdated())
392 return false;
393 var result = this._adapter._setSASSText(url, text);
394 return !!this._handleContentResponse(result);
395 },
396
397 /**
398 * @param {?WebInspector.SASSWorkspaceAdapter.ContentResponse} contentRespon se
399 * @return {?string}
400 */
401 _handleContentResponse: function(contentResponse)
402 {
403 if (!contentResponse)
404 return null;
405 this._versions.set(contentResponse.url, contentResponse.version);
406 return contentResponse.text;
407 },
408
409 /**
410 * @param {string} url
411 * @return {!Promise<string>}
412 */
413 content: function(url)
414 {
415 return this._adapter._getContent(url)
416 .then(this._handleContentResponse.bind(this))
417 .then(text => text || "");
418 },
419
420 dispose: function()
421 {
422 if (this._terminated)
423 return;
424 this._terminated = true;
425 this._adapter._stopTrackSources(this);
426 this.dispatchEventToListeners(WebInspector.SASSWorkspaceAdapter.ClientEv ents.TrackingStopped);
427 },
428
429 /**
430 * @param {string} url
431 * @param {number} newVersion
432 */
433 _newContentAvailable: function(url, newVersion)
434 {
435 if (this._versions.get(url) < newVersion)
436 this.dispatchEventToListeners(WebInspector.SASSWorkspaceAdapter.Clie ntEvents.SourceChanged, url);
437 },
438
439 __proto__: WebInspector.Object.prototype
440 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698