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

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

Issue 2893523002: DevTools: make StyleSourceMapping in charge of managing UISourceCodes (Closed)
Patch Set: update test Created 3 years, 7 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 side-by-side diff with in-line comments
Download patch
Index: third_party/WebKit/Source/devtools/front_end/bindings/StylesSourceMapping.js
diff --git a/third_party/WebKit/Source/devtools/front_end/bindings/StylesSourceMapping.js b/third_party/WebKit/Source/devtools/front_end/bindings/StylesSourceMapping.js
index 41c26e1c3de7a24b730082d135723bd4c94dcda8..df138a05b79c527b25740551dfde4828bccee890 100644
--- a/third_party/WebKit/Source/devtools/front_end/bindings/StylesSourceMapping.js
+++ b/third_party/WebKit/Source/devtools/front_end/bindings/StylesSourceMapping.js
@@ -39,24 +39,16 @@ Bindings.StylesSourceMapping = class {
*/
constructor(cssModel, workspace) {
this._cssModel = cssModel;
- this._workspace = workspace;
+ var target = this._cssModel.target();
+ this._project = new Bindings.ContentProviderBasedProject(
+ workspace, 'css:' + target.id(), Workspace.projectTypes.Network, '', false /* isServiceProject */);
+ Bindings.NetworkProject.setTargetForProject(this._project, target);
- /** @type {!Map<string, !Map<string, !Map<string, !SDK.CSSStyleSheetHeader>>>} */
- this._urlToHeadersByFrameId = new Map();
- /** @type {!Map.<!Workspace.UISourceCode, !Bindings.StyleFile>} */
+ /** @type {!Map.<string, !Bindings.StyleFile>} */
this._styleFiles = new Map();
-
this._eventListeners = [
- this._workspace.addEventListener(Workspace.Workspace.Events.ProjectRemoved, this._projectRemoved, this),
- this._workspace.addEventListener(
- Workspace.Workspace.Events.UISourceCodeAdded, this._uiSourceCodeAddedToWorkspace, this),
- this._workspace.addEventListener(Workspace.Workspace.Events.UISourceCodeRemoved, this._uiSourceCodeRemoved, this),
this._cssModel.addEventListener(SDK.CSSModel.Events.StyleSheetAdded, this._styleSheetAdded, this),
this._cssModel.addEventListener(SDK.CSSModel.Events.StyleSheetRemoved, this._styleSheetRemoved, this),
- this._cssModel.addEventListener(SDK.CSSModel.Events.StyleSheetChanged, this._styleSheetChanged, this),
- cssModel.target()
- .model(SDK.ResourceTreeModel)
- .addEventListener(SDK.ResourceTreeModel.Events.MainFrameNavigated, this._unbindAllUISourceCodes, this)
dgozman 2017/05/17 16:46:20 Why don't we need this anymore?
lushnikov 2017/05/20 01:24:18 1. CSSModel handles MainFrameNavigation by itself
];
}
@@ -67,10 +59,10 @@ Bindings.StylesSourceMapping = class {
*/
rawLocationToUILocation(rawLocation) {
var header = rawLocation.header();
- if (!header)
+ if (!header || !this._acceptsHeader(header))
return null;
- var uiSourceCode = Bindings.NetworkProject.uiSourceCodeForStyleURL(this._workspace, rawLocation.url, header);
- if (!uiSourceCode)
+ var styleFile = this._styleFiles.get(header.resourceURL());
+ if (!styleFile)
return null;
var lineNumber = rawLocation.lineNumber;
var columnNumber = rawLocation.columnNumber;
@@ -78,7 +70,7 @@ Bindings.StylesSourceMapping = class {
lineNumber -= header.lineNumberInSource(0);
columnNumber -= header.columnNumberInSource(lineNumber, 0);
}
- return uiSourceCode.uiLocation(lineNumber, columnNumber);
+ return styleFile.uiSourceCode().uiLocation(lineNumber, columnNumber);
}
/**
@@ -87,17 +79,32 @@ Bindings.StylesSourceMapping = class {
* @return {!Array<!SDK.CSSLocation>}
*/
uiLocationToRawLocations(uiLocation) {
- // TODO(caseq,lushnikov): return multiple raw locations.
- var header = Bindings.NetworkProject.styleHeaderForUISourceCode(uiLocation.uiSourceCode);
- if (!header)
+ var styleFile = uiLocation.uiSourceCode[Bindings.StyleFile._symbol];
+ if (!styleFile)
return [];
- var lineNumber = uiLocation.lineNumber;
- var columnNumber = uiLocation.columnNumber;
- if (header.isInline && header.hasSourceURL) {
- columnNumber = header.columnNumberInSource(lineNumber, columnNumber);
- lineNumber = header.lineNumberInSource(lineNumber);
+ var headers = styleFile.headers();
+ var rawLocations = [];
+ for (var header of headers) {
+ var lineNumber = uiLocation.lineNumber;
+ var columnNumber = uiLocation.columnNumber;
+ if (header.isInline && header.hasSourceURL) {
+ columnNumber = header.columnNumberInSource(lineNumber, columnNumber);
+ lineNumber = header.lineNumberInSource(lineNumber);
+ }
+ rawLocations.push(new SDK.CSSLocation(header, lineNumber, columnNumber));
}
- return [new SDK.CSSLocation(header, lineNumber, columnNumber)];
+ return rawLocations;
+ }
+
+ /**
+ * @param {!SDK.CSSStyleSheetHeader} header
+ */
+ _acceptsHeader(header) {
+ if (header.isInline && !header.hasSourceURL && header.origin !== 'inspector')
+ return false;
+ if (!header.resourceURL())
+ return false;
+ return true;
}
/**
@@ -105,24 +112,17 @@ Bindings.StylesSourceMapping = class {
*/
_styleSheetAdded(event) {
var header = /** @type {!SDK.CSSStyleSheetHeader} */ (event.data);
- var url = header.resourceURL();
- if (!url)
+ if (!this._acceptsHeader(header))
return;
- var map = this._urlToHeadersByFrameId.get(url);
- if (!map) {
- map = /** @type {!Map.<string, !Map.<string, !SDK.CSSStyleSheetHeader>>} */ (new Map());
- this._urlToHeadersByFrameId.set(url, map);
- }
- var headersById = map.get(header.frameId);
- if (!headersById) {
- headersById = /** @type {!Map.<string, !SDK.CSSStyleSheetHeader>} */ (new Map());
- map.set(header.frameId, headersById);
+ var url = header.resourceURL();
+ var styleFile = this._styleFiles.get(url);
+ if (!styleFile) {
+ styleFile = new Bindings.StyleFile(this._cssModel, this._project, header);
+ this._styleFiles.set(url, styleFile);
+ } else {
+ styleFile.addHeader(header);
}
- headersById.set(header.id, header);
- var uiSourceCode = Bindings.NetworkProject.uiSourceCodeForStyleURL(this._workspace, url, header);
- if (uiSourceCode)
- this._bindUISourceCode(uiSourceCode, header);
}
/**
@@ -130,201 +130,106 @@ Bindings.StylesSourceMapping = class {
*/
_styleSheetRemoved(event) {
var header = /** @type {!SDK.CSSStyleSheetHeader} */ (event.data);
- var url = header.resourceURL();
- if (!url)
+ if (!this._acceptsHeader(header))
return;
-
- var map = this._urlToHeadersByFrameId.get(url);
- console.assert(map);
- var headersById = map.get(header.frameId);
- console.assert(headersById);
- headersById.delete(header.id);
-
- if (!headersById.size) {
- map.delete(header.frameId);
- if (!map.size) {
- this._urlToHeadersByFrameId.delete(url);
- var uiSourceCode = Bindings.NetworkProject.uiSourceCodeForStyleURL(this._workspace, url, header);
- if (uiSourceCode)
- this._unbindUISourceCode(uiSourceCode);
- }
+ var url = header.resourceURL();
+ var styleFile = this._styleFiles.get(url);
+ if (styleFile.headers().size === 1) {
+ styleFile.dispose();
+ this._styleFiles.delete(url);
+ } else {
+ styleFile.removeHeader(header);
}
}
- /**
- * @param {!Workspace.UISourceCode} uiSourceCode
- */
- _unbindUISourceCode(uiSourceCode) {
- var styleFile = this._styleFiles.get(uiSourceCode);
- if (!styleFile)
- return;
- styleFile.dispose();
- this._styleFiles.delete(uiSourceCode);
- }
-
- /**
- * @param {!Common.Event} event
- */
- _unbindAllUISourceCodes(event) {
+ dispose() {
for (var styleFile of this._styleFiles.values())
styleFile.dispose();
this._styleFiles.clear();
- this._urlToHeadersByFrameId = new Map();
- }
-
- /**
- * @param {!Common.Event} event
- */
- _uiSourceCodeAddedToWorkspace(event) {
- var uiSourceCode = /** @type {!Workspace.UISourceCode} */ (event.data);
- if (!this._urlToHeadersByFrameId.has(uiSourceCode.url()))
- return;
- this._bindUISourceCode(
- uiSourceCode, this._urlToHeadersByFrameId.get(uiSourceCode.url()).valuesArray()[0].valuesArray()[0]);
+ Common.EventTarget.removeEventListeners(this._eventListeners);
}
+};
+/**
+ * @unrestricted
+ */
+Bindings.StyleFile = class {
/**
- * @param {!Workspace.UISourceCode} uiSourceCode
+ * @param {!SDK.CSSModel} cssModel
+ * @param {!Bindings.ContentProviderBasedProject} project
* @param {!SDK.CSSStyleSheetHeader} header
*/
- _bindUISourceCode(uiSourceCode, header) {
- if (this._styleFiles.get(uiSourceCode) || (header.isInline && !header.hasSourceURL))
- return;
- this._styleFiles.set(uiSourceCode, new Bindings.StyleFile(uiSourceCode, this));
- Bindings.cssWorkspaceBinding.updateLocations(header);
- }
-
- /**
- * @param {!Common.Event} event
- */
- _projectRemoved(event) {
- var project = /** @type {!Workspace.Project} */ (event.data);
- var uiSourceCodes = project.uiSourceCodes();
- for (var i = 0; i < uiSourceCodes.length; ++i)
- this._unbindUISourceCode(uiSourceCodes[i]);
- }
+ constructor(cssModel, project, header) {
+ this._cssModel = cssModel;
+ this._project = project;
+ /** @type {!Set<!SDK.CSSStyleSheetHeader>} */
+ this._headers = new Set([header]);
- /**
- * @param {!Common.Event} event
- */
- _uiSourceCodeRemoved(event) {
- var uiSourceCode = /** @type {!Workspace.UISourceCode} */ (event.data);
- this._unbindUISourceCode(uiSourceCode);
- }
+ var target = cssModel.target();
- /**
- * @param {!Workspace.UISourceCode} uiSourceCode
- * @param {string} content
- * @param {boolean} majorChange
- * @return {!Promise<?string>}
- */
- _setStyleContent(uiSourceCode, content, majorChange) {
- var styleSheetIds = this._cssModel.styleSheetIdsForURL(uiSourceCode.url());
- if (!styleSheetIds.length)
- return Promise.resolve(/** @type {?string} */ ('No stylesheet found: ' + uiSourceCode.url()));
+ var url = header.resourceURL();
+ var originalContentProvider = header.originalContentProvider();
+ var metadata = Bindings.metadataForURL(target, header.frameId, url);
- this._isSettingContent = true;
+ this._uiSourceCode = this._project.createUISourceCode(url, originalContentProvider.contentType());
+ this._uiSourceCode[Bindings.StyleFile._symbol] = this;
+ Bindings.NetworkProject.setInitialFrameAttribution(this._uiSourceCode, header.frameId);
+ Bindings.NetworkProject.forceCanonicalMimeType(this._uiSourceCode);
+ this._project.addUISourceCodeWithProvider(this._uiSourceCode, originalContentProvider, metadata);
- /**
- * @param {?string} error
- * @this {Bindings.StylesSourceMapping}
- * @return {?string}
- */
- function callback(error) {
- delete this._isSettingContent;
- return error || null;
- }
+ this._styleSheetChangedBound = this._styleSheetChanged.bind(this);
- var promises = [];
- for (var i = 0; i < styleSheetIds.length; ++i)
- promises.push(this._cssModel.setStyleSheetText(styleSheetIds[i], content, majorChange));
-
- return Promise.all(promises).spread(callback.bind(this));
+ this._cssModel.subscribeToStyleSheetChanged(header.id, this._styleSheetChangedBound);
+ this._eventListeners = [
+ this._uiSourceCode.addEventListener(
+ Workspace.UISourceCode.Events.WorkingCopyChanged, this._workingCopyChanged, this),
+ this._uiSourceCode.addEventListener(
+ Workspace.UISourceCode.Events.WorkingCopyCommitted, this._workingCopyCommitted, this)
+ ];
+ this._throttler = new Common.Throttler(Bindings.StyleFile.updateTimeout);
+ this._terminated = false;
}
/**
- * @param {!Common.Event} event
+ * @param {!SDK.CSSStyleSheetHeader} header
*/
- _styleSheetChanged(event) {
dgozman 2017/05/17 16:46:20 I feel like moving all these method could be postp
lushnikov 2017/05/20 01:24:18 This is possible, though I feel it's harder to val
- if (this._isSettingContent)
- return;
-
- this._updateStyleSheetTextSoon(event.data.styleSheetId);
+ addHeader(header) {
+ this._headers.add(header);
+ this._cssModel.subscribeToStyleSheetChanged(header.id, this._styleSheetChangedBound);
+ Bindings.NetworkProject.addFrameAttribution(this._uiSourceCode, header.frameId);
}
/**
- * @param {!Protocol.CSS.StyleSheetId} styleSheetId
+ * @param {!SDK.CSSStyleSheetHeader} header
*/
- _updateStyleSheetTextSoon(styleSheetId) {
- if (this._updateStyleSheetTextTimer)
- clearTimeout(this._updateStyleSheetTextTimer);
-
- this._updateStyleSheetTextTimer = setTimeout(
- this._updateStyleSheetText.bind(this, styleSheetId), Bindings.StylesSourceMapping.ChangeUpdateTimeoutMs);
+ removeHeader(header) {
+ this._headers.delete(header);
+ this._cssModel.unsubscribeFromStyleSheetChanged(header.id, this._styleSheetChangedBound);
+ Bindings.NetworkProject.removeFrameAttribution(this._uiSourceCode, header.frameId);
}
/**
- * @param {!Protocol.CSS.StyleSheetId} styleSheetId
+ * @return {!Set<!SDK.CSSStyleSheetHeader>}
*/
- _updateStyleSheetText(styleSheetId) {
- if (this._updateStyleSheetTextTimer) {
- clearTimeout(this._updateStyleSheetTextTimer);
- delete this._updateStyleSheetTextTimer;
- }
-
- var header = this._cssModel.styleSheetHeaderForId(styleSheetId);
- if (!header)
- return;
- var styleSheetURL = header.resourceURL();
- if (!styleSheetURL)
- return;
- var uiSourceCode = Bindings.NetworkProject.uiSourceCodeForStyleURL(this._workspace, styleSheetURL, header);
- if (!uiSourceCode)
- return;
- header.requestContent().then(callback.bind(this, uiSourceCode));
-
- /**
- * @param {!Workspace.UISourceCode} uiSourceCode
- * @param {?string} content
- * @this {Bindings.StylesSourceMapping}
- */
- function callback(uiSourceCode, content) {
- var styleFile = this._styleFiles.get(uiSourceCode);
- if (typeof content === 'string' && styleFile)
- styleFile.addRevision(content);
- this._styleFileSyncedForTest();
- }
+ headers() {
dgozman 2017/05/17 16:46:20 I find these "API" methods between tightly coupled
lushnikov 2017/05/20 01:24:18 Agreed and inlined both headers() and uiSourceCode
+ return this._headers;
}
- _styleFileSyncedForTest() {
- }
-
- dispose() {
- Common.EventTarget.removeEventListeners(this._eventListeners);
+ /**
+ * @return {!Workspace.UISourceCode}
+ */
+ uiSourceCode() {
+ return this._uiSourceCode;
}
-};
-Bindings.StylesSourceMapping.ChangeUpdateTimeoutMs = 200;
-
-/**
- * @unrestricted
- */
-Bindings.StyleFile = class {
/**
- * @param {!Workspace.UISourceCode} uiSourceCode
- * @param {!Bindings.StylesSourceMapping} mapping
+ * @param {!SDK.CSSStyleSheetHeader} header
*/
- constructor(uiSourceCode, mapping) {
- this._uiSourceCode = uiSourceCode;
- this._mapping = mapping;
- this._eventListeners = [
- this._uiSourceCode.addEventListener(
- Workspace.UISourceCode.Events.WorkingCopyChanged, this._workingCopyChanged, this),
- this._uiSourceCode.addEventListener(
- Workspace.UISourceCode.Events.WorkingCopyCommitted, this._workingCopyCommitted, this)
- ];
- this._commitThrottler = new Common.Throttler(Bindings.StyleFile.updateTimeout);
- this._terminated = false;
+ _styleSheetChanged(header) {
+ if (this._isUpdatingHeaders)
+ return;
+ var mirrorContentBound = this._mirrorContent.bind(this, header, true /* majorChange */);
+ this._throttler.schedule(mirrorContentBound, false /* asSoonAsPossible */);
}
/**
@@ -333,9 +238,8 @@ Bindings.StyleFile = class {
_workingCopyCommitted(event) {
if (this._isAddingRevision)
return;
-
- this._isMajorChangePending = true;
- this._commitThrottler.schedule(this._commitIncrementalEdit.bind(this), true);
+ var mirrorContentBound = this._mirrorContent.bind(this, this._uiSourceCode, true /* majorChange */);
+ this._throttler.schedule(mirrorContentBound, true /* asSoonAsPossible */);
}
/**
@@ -344,43 +248,60 @@ Bindings.StyleFile = class {
_workingCopyChanged(event) {
if (this._isAddingRevision)
return;
-
- this._commitThrottler.schedule(this._commitIncrementalEdit.bind(this), false);
- }
-
- _commitIncrementalEdit() {
- if (this._terminated)
- return;
- var promise =
- this._mapping._setStyleContent(this._uiSourceCode, this._uiSourceCode.workingCopy(), this._isMajorChangePending)
- .then(this._styleContentSet.bind(this));
- this._isMajorChangePending = false;
- return promise;
+ var mirrorContentBound = this._mirrorContent.bind(this, this._uiSourceCode, false /* majorChange */);
+ this._throttler.schedule(mirrorContentBound, false /* asSoonAsPossible */);
}
/**
- * @param {?string} error
+ * @param {!Common.ContentProvider} fromProvider
+ * @param {boolean} majorChange
+ * @return {!Promise}
*/
- _styleContentSet(error) {
- if (error)
- console.error(error);
+ async _mirrorContent(fromProvider, majorChange) {
+ var newContent = null;
+ if (fromProvider === this._uiSourceCode)
+ newContent = this._uiSourceCode.workingCopy();
+ else
+ newContent = await fromProvider.requestContent();
dgozman 2017/05/17 16:46:20 Per recent discussions, you have to add comment be
lushnikov 2017/05/20 01:24:18 Added the ASYNC comment. The previous version of
+
+ if (newContent === null || this._terminated) {
+ this._styleFileSyncedForTest();
+ return;
+ }
+
+ if (fromProvider !== this._uiSourceCode) {
+ this._isAddingRevision = true;
+ this._uiSourceCode.addRevision(newContent);
+ this._isAddingRevision = false;
+ }
+
+ this._isUpdatingHeaders = true;
+ var promises = [];
+ for (var header of this._headers) {
+ if (header === fromProvider)
+ continue;
+ promises.push(this._cssModel.setStyleSheetText(header.id, newContent, majorChange));
+ }
+ var errors = await Promise.all(promises);
dgozman 2017/05/17 16:46:20 Same here.
lushnikov 2017/05/20 01:24:18 Done.
+ this._isUpdatingHeaders = false;
+ errors.filter(error => !!error).forEach(console.error);
+ this._styleFileSyncedForTest();
}
- /**
- * @param {string} content
- */
- addRevision(content) {
- this._isAddingRevision = true;
- this._uiSourceCode.addRevision(content);
- delete this._isAddingRevision;
+ _styleFileSyncedForTest() {
}
dispose() {
if (this._terminated)
return;
this._terminated = true;
+ for (var header of this._headers)
+ this._cssModel.unsubscribeFromStyleSheetChanged(header.id, this._styleSheetChangedBound);
+ this._project.removeFile(this._uiSourceCode.url());
Common.EventTarget.removeEventListeners(this._eventListeners);
}
};
+Bindings.StyleFile._symbol = Symbol('Bindings.StyleFile._symbol');
+
Bindings.StyleFile.updateTimeout = 200;

Powered by Google App Engine
This is Rietveld 408576698