OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (C) 2012 Google Inc. 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 are | |
6 * met: | |
7 * | |
8 * * Redistributions of source code must retain the above copyright | |
9 * notice, this list of conditions and the following disclaimer. | |
10 * * Redistributions in binary form must reproduce the above | |
11 * copyright notice, this list of conditions and the following disclaimer | |
12 * in the documentation and/or other materials provided with the | |
13 * distribution. | |
14 * * Neither the name of Google Inc. nor the names of its | |
15 * contributors may be used to endorse or promote products derived from | |
16 * this software without specific prior written permission. | |
17 * | |
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
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. | |
29 */ | |
30 | |
31 /** | |
32 * @constructor | |
33 * @implements {WebInspector.SourceMapping} | |
34 * @param {!WebInspector.CSSStyleModel} cssModel | |
35 * @param {!WebInspector.Workspace} workspace | |
36 */ | |
37 WebInspector.StylesSourceMapping = function(cssModel, workspace) | |
38 { | |
39 this._cssModel = cssModel; | |
40 this._workspace = workspace; | |
41 this._workspace.addEventListener(WebInspector.Workspace.Events.ProjectRemove
d, this._projectRemoved, this); | |
42 this._workspace.addEventListener(WebInspector.Workspace.Events.UISourceCodeA
dded, this._uiSourceCodeAddedToWorkspace, this); | |
43 this._workspace.addEventListener(WebInspector.Workspace.Events.UISourceCodeR
emoved, this._uiSourceCodeRemoved, this); | |
44 | |
45 WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeMod
el.EventTypes.MainFrameNavigated, this._mainFrameNavigated, this); | |
46 | |
47 this._cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleSheet
Changed, this._styleSheetChanged, this); | |
48 this._initialize(); | |
49 } | |
50 | |
51 WebInspector.StylesSourceMapping.MinorChangeUpdateTimeoutMs = 1000; | |
52 | |
53 WebInspector.StylesSourceMapping.prototype = { | |
54 /** | |
55 * @param {!WebInspector.RawLocation} rawLocation | |
56 * @return {?WebInspector.UILocation} | |
57 */ | |
58 rawLocationToUILocation: function(rawLocation) | |
59 { | |
60 var location = /** @type WebInspector.CSSLocation */ (rawLocation); | |
61 var uiSourceCode = this._workspace.uiSourceCodeForURL(location.url); | |
62 if (!uiSourceCode) | |
63 return null; | |
64 return uiSourceCode.uiLocation(location.lineNumber, location.columnNumbe
r); | |
65 }, | |
66 | |
67 /** | |
68 * @param {!WebInspector.UISourceCode} uiSourceCode | |
69 * @param {number} lineNumber | |
70 * @param {number} columnNumber | |
71 * @return {!WebInspector.RawLocation} | |
72 */ | |
73 uiLocationToRawLocation: function(uiSourceCode, lineNumber, columnNumber) | |
74 { | |
75 return new WebInspector.CSSLocation(this._cssModel.target(), null, uiSou
rceCode.url || "", lineNumber, columnNumber); | |
76 }, | |
77 | |
78 /** | |
79 * @return {boolean} | |
80 */ | |
81 isIdentity: function() | |
82 { | |
83 return true; | |
84 }, | |
85 | |
86 /** | |
87 * @param {!WebInspector.UISourceCode} uiSourceCode | |
88 * @param {number} lineNumber | |
89 * @return {boolean} | |
90 */ | |
91 uiLineHasMapping: function(uiSourceCode, lineNumber) | |
92 { | |
93 return true; | |
94 }, | |
95 | |
96 /** | |
97 * @return {!WebInspector.Target} | |
98 */ | |
99 target: function() | |
100 { | |
101 return this._cssModel.target(); | |
102 }, | |
103 | |
104 /** | |
105 * @param {!WebInspector.CSSStyleSheetHeader} header | |
106 */ | |
107 addHeader: function(header) | |
108 { | |
109 var url = header.resourceURL(); | |
110 if (!url) | |
111 return; | |
112 | |
113 WebInspector.cssWorkspaceBinding.pushSourceMapping(header, this); | |
114 var map = this._urlToHeadersByFrameId[url]; | |
115 if (!map) { | |
116 map = /** @type {!StringMap.<!StringMap.<!WebInspector.CSSStyleSheet
Header>>} */ (new StringMap()); | |
117 this._urlToHeadersByFrameId[url] = map; | |
118 } | |
119 var headersById = map.get(header.frameId); | |
120 if (!headersById) { | |
121 headersById = /** @type {!StringMap.<!WebInspector.CSSStyleSheetHead
er>} */ (new StringMap()); | |
122 map.put(header.frameId, headersById); | |
123 } | |
124 headersById.put(header.id, header); | |
125 var uiSourceCode = this._workspace.uiSourceCodeForURL(url); | |
126 if (uiSourceCode) | |
127 this._bindUISourceCode(uiSourceCode, header); | |
128 }, | |
129 | |
130 /** | |
131 * @param {!WebInspector.CSSStyleSheetHeader} header | |
132 */ | |
133 removeHeader: function(header) | |
134 { | |
135 var url = header.resourceURL(); | |
136 if (!url) | |
137 return; | |
138 | |
139 var map = this._urlToHeadersByFrameId[url]; | |
140 console.assert(map); | |
141 var headersById = map.get(header.frameId); | |
142 console.assert(headersById); | |
143 headersById.remove(header.id); | |
144 | |
145 if (!headersById.size()) { | |
146 map.remove(header.frameId); | |
147 if (!map.size()) { | |
148 delete this._urlToHeadersByFrameId[url]; | |
149 var uiSourceCode = this._workspace.uiSourceCodeForURL(url); | |
150 if (uiSourceCode) | |
151 this._unbindUISourceCode(uiSourceCode); | |
152 } | |
153 } | |
154 }, | |
155 | |
156 /** | |
157 * @param {!WebInspector.UISourceCode} uiSourceCode | |
158 */ | |
159 _unbindUISourceCode: function(uiSourceCode) | |
160 { | |
161 var styleFile = this._styleFiles.get(uiSourceCode); | |
162 if (!styleFile) | |
163 return; | |
164 styleFile.dispose(); | |
165 this._styleFiles.remove(uiSourceCode); | |
166 }, | |
167 | |
168 /** | |
169 * @param {!WebInspector.Event} event | |
170 */ | |
171 _uiSourceCodeAddedToWorkspace: function(event) | |
172 { | |
173 var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data
); | |
174 var url = uiSourceCode.url; | |
175 if (!url || !this._urlToHeadersByFrameId[url]) | |
176 return; | |
177 this._bindUISourceCode(uiSourceCode, this._urlToHeadersByFrameId[url].va
lues()[0].values()[0]); | |
178 }, | |
179 | |
180 /** | |
181 * @param {!WebInspector.UISourceCode} uiSourceCode | |
182 * @param {!WebInspector.CSSStyleSheetHeader} header | |
183 */ | |
184 _bindUISourceCode: function(uiSourceCode, header) | |
185 { | |
186 if (this._styleFiles.get(uiSourceCode) || header.isInline) | |
187 return; | |
188 var url = uiSourceCode.url; | |
189 this._styleFiles.put(uiSourceCode, new WebInspector.StyleFile(uiSourceCo
de, this)); | |
190 WebInspector.cssWorkspaceBinding.updateLocations(header); | |
191 }, | |
192 | |
193 /** | |
194 * @param {!WebInspector.Event} event | |
195 */ | |
196 _projectRemoved: function(event) | |
197 { | |
198 var project = /** @type {!WebInspector.Project} */ (event.data); | |
199 var uiSourceCodes = project.uiSourceCodes(); | |
200 for (var i = 0; i < uiSourceCodes.length; ++i) | |
201 this._unbindUISourceCode(uiSourceCodes[i]); | |
202 }, | |
203 | |
204 /** | |
205 * @param {!WebInspector.Event} event | |
206 */ | |
207 _uiSourceCodeRemoved: function(event) | |
208 { | |
209 var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data
); | |
210 this._unbindUISourceCode(uiSourceCode); | |
211 }, | |
212 | |
213 _initialize: function() | |
214 { | |
215 /** @type {!Object.<string, !StringMap.<!StringMap.<!WebInspector.CSSSty
leSheetHeader>>>} */ | |
216 this._urlToHeadersByFrameId = {}; | |
217 /** @type {!Map.<!WebInspector.UISourceCode, !WebInspector.StyleFile>} *
/ | |
218 this._styleFiles = new Map(); | |
219 }, | |
220 | |
221 /** | |
222 * @param {!WebInspector.Event} event | |
223 */ | |
224 _mainFrameNavigated: function(event) | |
225 { | |
226 for (var url in this._urlToHeadersByFrameId) { | |
227 var uiSourceCode = this._workspace.uiSourceCodeForURL(url); | |
228 if (!uiSourceCode) | |
229 continue; | |
230 this._unbindUISourceCode(uiSourceCode); | |
231 } | |
232 this._initialize(); | |
233 }, | |
234 | |
235 /** | |
236 * @param {!WebInspector.UISourceCode} uiSourceCode | |
237 * @param {string} content | |
238 * @param {boolean} majorChange | |
239 * @param {function(?string)} userCallback | |
240 */ | |
241 _setStyleContent: function(uiSourceCode, content, majorChange, userCallback) | |
242 { | |
243 var styleSheetIds = this._cssModel.styleSheetIdsForURL(uiSourceCode.url)
; | |
244 if (!styleSheetIds.length) { | |
245 userCallback("No stylesheet found: " + uiSourceCode.url); | |
246 return; | |
247 } | |
248 | |
249 this._isSettingContent = true; | |
250 | |
251 /** | |
252 * @param {?Protocol.Error} error | |
253 * @this {WebInspector.StylesSourceMapping} | |
254 */ | |
255 function callback(error) | |
256 { | |
257 userCallback(error); | |
258 delete this._isSettingContent; | |
259 } | |
260 this._cssModel.setStyleSheetText(styleSheetIds[0], content, majorChange,
callback.bind(this)); | |
261 }, | |
262 | |
263 /** | |
264 * @param {!WebInspector.Event} event | |
265 */ | |
266 _styleSheetChanged: function(event) | |
267 { | |
268 if (this._isSettingContent) | |
269 return; | |
270 | |
271 if (event.data.majorChange) { | |
272 this._updateStyleSheetText(event.data.styleSheetId); | |
273 return; | |
274 } | |
275 | |
276 this._updateStyleSheetTextSoon(event.data.styleSheetId); | |
277 }, | |
278 | |
279 /** | |
280 * @param {!CSSAgent.StyleSheetId} styleSheetId | |
281 */ | |
282 _updateStyleSheetTextSoon: function(styleSheetId) | |
283 { | |
284 if (this._updateStyleSheetTextTimer) | |
285 clearTimeout(this._updateStyleSheetTextTimer); | |
286 | |
287 this._updateStyleSheetTextTimer = setTimeout(this._updateStyleSheetText.
bind(this, styleSheetId), WebInspector.StylesSourceMapping.MinorChangeUpdateTime
outMs); | |
288 }, | |
289 | |
290 /** | |
291 * @param {!CSSAgent.StyleSheetId} styleSheetId | |
292 */ | |
293 _updateStyleSheetText: function(styleSheetId) | |
294 { | |
295 if (this._updateStyleSheetTextTimer) { | |
296 clearTimeout(this._updateStyleSheetTextTimer); | |
297 delete this._updateStyleSheetTextTimer; | |
298 } | |
299 | |
300 var header = this._cssModel.styleSheetHeaderForId(styleSheetId); | |
301 if (!header) | |
302 return; | |
303 var styleSheetURL = header.resourceURL(); | |
304 if (!styleSheetURL) | |
305 return; | |
306 var uiSourceCode = this._workspace.uiSourceCodeForURL(styleSheetURL) | |
307 if (!uiSourceCode) | |
308 return; | |
309 header.requestContent(callback.bind(this, uiSourceCode)); | |
310 | |
311 /** | |
312 * @param {!WebInspector.UISourceCode} uiSourceCode | |
313 * @param {?string} content | |
314 * @this {WebInspector.StylesSourceMapping} | |
315 */ | |
316 function callback(uiSourceCode, content) | |
317 { | |
318 var styleFile = this._styleFiles.get(uiSourceCode); | |
319 if (styleFile) | |
320 styleFile.addRevision(content || ""); | |
321 } | |
322 } | |
323 } | |
324 | |
325 /** | |
326 * @constructor | |
327 * @param {!WebInspector.UISourceCode} uiSourceCode | |
328 * @param {!WebInspector.StylesSourceMapping} mapping | |
329 */ | |
330 WebInspector.StyleFile = function(uiSourceCode, mapping) | |
331 { | |
332 this._uiSourceCode = uiSourceCode; | |
333 this._mapping = mapping; | |
334 this._uiSourceCode.addEventListener(WebInspector.UISourceCode.Events.Working
CopyChanged, this._workingCopyChanged, this); | |
335 this._uiSourceCode.addEventListener(WebInspector.UISourceCode.Events.Working
CopyCommitted, this._workingCopyCommitted, this); | |
336 this._commitThrottler = new WebInspector.Throttler(WebInspector.StyleFile.up
dateTimeout); | |
337 } | |
338 | |
339 WebInspector.StyleFile.updateTimeout = 200; | |
340 | |
341 WebInspector.StyleFile.prototype = { | |
342 /** | |
343 * @param {!WebInspector.Event} event | |
344 */ | |
345 _workingCopyCommitted: function(event) | |
346 { | |
347 if (this._isAddingRevision) | |
348 return; | |
349 | |
350 this._isMajorChangePending = true; | |
351 this._commitThrottler.schedule(this._commitIncrementalEdit.bind(this), t
rue); | |
352 }, | |
353 | |
354 /** | |
355 * @param {!WebInspector.Event} event | |
356 */ | |
357 _workingCopyChanged: function(event) | |
358 { | |
359 if (this._isAddingRevision) | |
360 return; | |
361 | |
362 this._commitThrottler.schedule(this._commitIncrementalEdit.bind(this), f
alse); | |
363 }, | |
364 | |
365 /** | |
366 * @param {!WebInspector.Throttler.FinishCallback} finishCallback | |
367 */ | |
368 _commitIncrementalEdit: function(finishCallback) | |
369 { | |
370 this._mapping._setStyleContent(this._uiSourceCode, this._uiSourceCode.wo
rkingCopy(), this._isMajorChangePending, this._styleContentSet.bind(this, finish
Callback)); | |
371 this._isMajorChangePending = false; | |
372 }, | |
373 | |
374 /** | |
375 * @param {!WebInspector.Throttler.FinishCallback} finishCallback | |
376 * @param {?string} error | |
377 */ | |
378 _styleContentSet: function(finishCallback, error) | |
379 { | |
380 if (error) | |
381 WebInspector.console.error(error); | |
382 finishCallback(); | |
383 }, | |
384 | |
385 /** | |
386 * @param {string} content | |
387 */ | |
388 addRevision: function(content) | |
389 { | |
390 this._isAddingRevision = true; | |
391 this._uiSourceCode.addRevision(content); | |
392 delete this._isAddingRevision; | |
393 }, | |
394 | |
395 dispose: function() | |
396 { | |
397 this._uiSourceCode.removeEventListener(WebInspector.UISourceCode.Events.
WorkingCopyCommitted, this._workingCopyCommitted, this); | |
398 this._uiSourceCode.removeEventListener(WebInspector.UISourceCode.Events.
WorkingCopyChanged, this._workingCopyChanged, this); | |
399 } | |
400 } | |
OLD | NEW |