| 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 0bfe38050cf19bd1741d74de24ac2f00ada987ae..4b426067278222ea83b797533c8de70990d3af5f 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,17 @@ 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)
|
| ];
|
| }
|
|
|
| @@ -67,10 +60,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 +71,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 +80,31 @@ 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 rawLocations = [];
|
| + for (var header of styleFile._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,246 +130,211 @@ 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
|
| + * @param {!Common.Event} event
|
| */
|
| - _unbindUISourceCode(uiSourceCode) {
|
| - var styleFile = this._styleFiles.get(uiSourceCode);
|
| - if (!styleFile)
|
| + _styleSheetChanged(event) {
|
| + var header = this._cssModel.styleSheetHeaderForId(event.data.styleSheetId);
|
| + if (!header || !this._acceptsHeader(header))
|
| return;
|
| - styleFile.dispose();
|
| - this._styleFiles.delete(uiSourceCode);
|
| + var styleFile = this._styleFiles.get(header.resourceURL());
|
| + styleFile._styleSheetChanged(header);
|
| }
|
|
|
| - /**
|
| - * @param {!Common.Event} event
|
| - */
|
| - _unbindAllUISourceCodes(event) {
|
| + dispose() {
|
| for (var styleFile of this._styleFiles.values())
|
| styleFile.dispose();
|
| this._styleFiles.clear();
|
| - this._urlToHeadersByFrameId = new Map();
|
| + Common.EventTarget.removeEventListeners(this._eventListeners);
|
| + this._project.removeProject();
|
| }
|
| +};
|
|
|
| +/**
|
| + * @implements {Common.ContentProvider}
|
| + * @unrestricted
|
| + */
|
| +Bindings.StyleFile = class {
|
| /**
|
| - * @param {!Common.Event} event
|
| + * @param {!SDK.CSSModel} cssModel
|
| + * @param {!Bindings.ContentProviderBasedProject} project
|
| + * @param {!SDK.CSSStyleSheetHeader} header
|
| */
|
| - _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]);
|
| + constructor(cssModel, project, header) {
|
| + this._cssModel = cssModel;
|
| + this._project = project;
|
| + /** @type {!Set<!SDK.CSSStyleSheetHeader>} */
|
| + this._headers = new Set([header]);
|
| +
|
| + var target = cssModel.target();
|
| +
|
| + var url = header.resourceURL();
|
| + var metadata = Bindings.metadataForURL(target, header.frameId, url);
|
| +
|
| + this._uiSourceCode = this._project.createUISourceCode(url, header.contentType());
|
| + this._uiSourceCode[Bindings.StyleFile._symbol] = this;
|
| + Bindings.NetworkProject.setInitialFrameAttribution(this._uiSourceCode, header.frameId);
|
| + this._project.addUISourceCodeWithProvider(this._uiSourceCode, this, metadata, 'text/css');
|
| +
|
| + 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 {!Workspace.UISourceCode} uiSourceCode
|
| * @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);
|
| + addHeader(header) {
|
| + this._headers.add(header);
|
| + Bindings.NetworkProject.addFrameAttribution(this._uiSourceCode, header.frameId);
|
| }
|
|
|
| /**
|
| - * @param {!Common.Event} event
|
| + * @param {!SDK.CSSStyleSheetHeader} header
|
| */
|
| - _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]);
|
| + removeHeader(header) {
|
| + this._headers.delete(header);
|
| + Bindings.NetworkProject.removeFrameAttribution(this._uiSourceCode, header.frameId);
|
| }
|
|
|
| /**
|
| - * @param {!Common.Event} event
|
| + * @param {!SDK.CSSStyleSheetHeader} header
|
| */
|
| - _uiSourceCodeRemoved(event) {
|
| - var uiSourceCode = /** @type {!Workspace.UISourceCode} */ (event.data);
|
| - this._unbindUISourceCode(uiSourceCode);
|
| + _styleSheetChanged(header) {
|
| + console.assert(this._headers.has(header));
|
| + if (this._isUpdatingHeaders || !this._headers.has(header))
|
| + return;
|
| + var mirrorContentBound = this._mirrorContent.bind(this, header, true /* majorChange */);
|
| + this._throttler.schedule(mirrorContentBound, false /* asSoonAsPossible */);
|
| }
|
|
|
| /**
|
| - * @param {!Workspace.UISourceCode} uiSourceCode
|
| - * @param {string} content
|
| - * @param {boolean} majorChange
|
| - * @return {!Promise<?string>}
|
| + * @param {!Common.Event} event
|
| */
|
| - async _setStyleContent(uiSourceCode, content, majorChange) {
|
| - var styleSheetIds = this._cssModel.styleSheetIdsForURL(uiSourceCode.url());
|
| - if (!styleSheetIds.length)
|
| - return 'No stylesheet found: ' + uiSourceCode.url();
|
| - this._isSettingContent = true;
|
| - var promises = styleSheetIds.map(id => this._cssModel.setStyleSheetText(id, content, majorChange));
|
| -
|
| - var results = await Promise.all(promises);
|
| -
|
| - delete this._isSettingContent;
|
| - return results.find(error => !!error);
|
| + _workingCopyCommitted(event) {
|
| + if (this._isAddingRevision)
|
| + return;
|
| + var mirrorContentBound = this._mirrorContent.bind(this, this._uiSourceCode, true /* majorChange */);
|
| + this._throttler.schedule(mirrorContentBound, true /* asSoonAsPossible */);
|
| }
|
|
|
| /**
|
| * @param {!Common.Event} event
|
| */
|
| - _styleSheetChanged(event) {
|
| - if (this._isSettingContent)
|
| + _workingCopyChanged(event) {
|
| + if (this._isAddingRevision)
|
| return;
|
| -
|
| - this._updateStyleSheetTextSoon(event.data.styleSheetId);
|
| + var mirrorContentBound = this._mirrorContent.bind(this, this._uiSourceCode, false /* majorChange */);
|
| + this._throttler.schedule(mirrorContentBound, false /* asSoonAsPossible */);
|
| }
|
|
|
| /**
|
| - * @param {!Protocol.CSS.StyleSheetId} styleSheetId
|
| + * @param {!Common.ContentProvider} fromProvider
|
| + * @param {boolean} majorChange
|
| + * @return {!Promise}
|
| */
|
| - _updateStyleSheetTextSoon(styleSheetId) {
|
| - if (this._updateStyleSheetTextTimer)
|
| - clearTimeout(this._updateStyleSheetTextTimer);
|
| -
|
| - this._updateStyleSheetTextTimer = setTimeout(
|
| - this._updateStyleSheetText.bind(this, styleSheetId), Bindings.StylesSourceMapping.ChangeUpdateTimeoutMs);
|
| - }
|
| + async _mirrorContent(fromProvider, majorChange) {
|
| + if (this._terminated) {
|
| + this._styleFileSyncedForTest();
|
| + return;
|
| + }
|
|
|
| - /**
|
| - * @param {!Protocol.CSS.StyleSheetId} styleSheetId
|
| - */
|
| - _updateStyleSheetText(styleSheetId) {
|
| - if (this._updateStyleSheetTextTimer) {
|
| - clearTimeout(this._updateStyleSheetTextTimer);
|
| - delete this._updateStyleSheetTextTimer;
|
| + var newContent = null;
|
| + if (fromProvider === this._uiSourceCode) {
|
| + newContent = this._uiSourceCode.workingCopy();
|
| + } else {
|
| + // ------ ASYNC ------
|
| + newContent = await fromProvider.requestContent();
|
| }
|
|
|
| - 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);
|
| + 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));
|
| }
|
| + // ------ ASYNC ------
|
| + await Promise.all(promises);
|
| + this._isUpdatingHeaders = false;
|
| + this._styleFileSyncedForTest();
|
| }
|
|
|
| _styleFileSyncedForTest() {
|
| }
|
|
|
| dispose() {
|
| + if (this._terminated)
|
| + return;
|
| + this._terminated = true;
|
| + this._project.removeFile(this._uiSourceCode.url());
|
| Common.EventTarget.removeEventListeners(this._eventListeners);
|
| }
|
| -};
|
| -
|
| -Bindings.StylesSourceMapping.ChangeUpdateTimeoutMs = 200;
|
| -
|
| -/**
|
| - * @unrestricted
|
| - */
|
| -Bindings.StyleFile = class {
|
| - /**
|
| - * @param {!Workspace.UISourceCode} uiSourceCode
|
| - * @param {!Bindings.StylesSourceMapping} mapping
|
| - */
|
| - 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;
|
| - }
|
|
|
| /**
|
| - * @param {!Common.Event} event
|
| + * @override
|
| + * @return {string}
|
| */
|
| - _workingCopyCommitted(event) {
|
| - if (this._isAddingRevision)
|
| - return;
|
| -
|
| - this._isMajorChangePending = true;
|
| - this._commitThrottler.schedule(this._commitIncrementalEdit.bind(this), true);
|
| + contentURL() {
|
| + return this._headers.firstValue().originalContentProvider().contentURL();
|
| }
|
|
|
| /**
|
| - * @param {!Common.Event} event
|
| + * @override
|
| + * @return {!Common.ResourceType}
|
| */
|
| - _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;
|
| + contentType() {
|
| + return this._headers.firstValue().originalContentProvider().contentType();
|
| }
|
|
|
| /**
|
| - * @param {?string} error
|
| + * @override
|
| + * @return {!Promise<?string>}
|
| */
|
| - _styleContentSet(error) {
|
| - if (error)
|
| - console.error(error);
|
| + requestContent() {
|
| + return this._headers.firstValue().originalContentProvider().requestContent();
|
| }
|
|
|
| /**
|
| - * @param {string} content
|
| + * @override
|
| + * @param {string} query
|
| + * @param {boolean} caseSensitive
|
| + * @param {boolean} isRegex
|
| + * @return {!Promise<!Array<!Common.ContentProvider.SearchMatch>>}
|
| */
|
| - addRevision(content) {
|
| - this._isAddingRevision = true;
|
| - this._uiSourceCode.addRevision(content);
|
| - delete this._isAddingRevision;
|
| - }
|
| -
|
| - dispose() {
|
| - if (this._terminated)
|
| - return;
|
| - this._terminated = true;
|
| - Common.EventTarget.removeEventListeners(this._eventListeners);
|
| + searchInContent(query, caseSensitive, isRegex) {
|
| + return this._headers.firstValue().originalContentProvider().searchInContent(query, caseSensitive, isRegex);
|
| }
|
| };
|
|
|
| +Bindings.StyleFile._symbol = Symbol('Bindings.StyleFile._symbol');
|
| +
|
| Bindings.StyleFile.updateTimeout = 200;
|
|
|