Chromium Code Reviews| Index: third_party/WebKit/Source/devtools/front_end/bindings/ResourceBinding.js |
| diff --git a/third_party/WebKit/Source/devtools/front_end/bindings/ResourceBinding.js b/third_party/WebKit/Source/devtools/front_end/bindings/ResourceBinding.js |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..6576c7979ac2cea7c6ded3f86cdb567a09798025 |
| --- /dev/null |
| +++ b/third_party/WebKit/Source/devtools/front_end/bindings/ResourceBinding.js |
| @@ -0,0 +1,267 @@ |
| +// Copyright 2017 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +/** |
| + * @implements {SDK.SDKModelObserver<!SDK.ResourceTreeModel>} |
| + */ |
| +Bindings.ResourceBindingManager = class { |
|
lushnikov
2017/06/12 23:17:53
Let's drift towards the following naming throughou
lushnikov
2017/06/13 00:49:14
Done.
|
| + /** |
| + * @param {!SDK.TargetManager} targetManager |
| + * @param {!Workspace.Workspace} workspace |
| + */ |
| + constructor(targetManager, workspace) { |
| + this._workspace = workspace; |
| + /** @type {!Map<!SDK.ResourceTreeModel, !Bindings.ResourceBinding>} */ |
| + this._modelToBinding = new Map(); |
| + targetManager.observeModels(SDK.ResourceTreeModel, this); |
| + } |
| + |
| + /** |
| + * @override |
| + * @param {!SDK.ResourceTreeModel} resourceTreeModel |
| + */ |
| + modelAdded(resourceTreeModel) { |
| + var binding = new Bindings.ResourceBinding(this._workspace, resourceTreeModel); |
| + this._modelToBinding.set(resourceTreeModel, binding); |
| + } |
| + |
| + /** |
| + * @override |
| + * @param {!SDK.ResourceTreeModel} resourceTreeModel |
| + */ |
| + modelRemoved(resourceTreeModel) { |
| + var binding = this._modelToBinding.get(resourceTreeModel); |
| + binding.dispose(); |
| + this._modelToBinding.delete(resourceTreeModel); |
| + } |
| + |
| + /** |
| + * @param {!SDK.Target} target |
| + * @return {?Bindings.ResourceBinding} |
| + */ |
| + _bindingForTarget(target) { |
| + var resourceTreeModel = target.model(SDK.ResourceTreeModel); |
| + return resourceTreeModel ? this._modelToBinding.get(resourceTreeModel) : null; |
| + } |
| + |
| + /** |
| + * @param {!SDK.CSSLocation} cssLocation |
| + * @return {?Workspace.UILocation} |
| + */ |
| + cssLocationToUILocation(cssLocation) { |
| + var binding = this._bindingForTarget(cssLocation.cssModel().target()); |
| + if (!binding) |
| + return null; |
| + var uiSourceCode = binding.uiSourceCodeForURL(cssLocation.url); |
| + return uiSourceCode ? uiSourceCode.uiLocation(cssLocation.lineNumber, cssLocation.columnNumber) : null; |
| + } |
| + |
| + /** |
| + * @param {!SDK.DebuggerModel.Location} jsLocation |
| + * @return {?Workspace.UILocation} |
| + */ |
| + jsLocationToUILocation(jsLocation) { |
| + var script = jsLocation.script(); |
| + if (!script) |
| + return null; |
| + var binding = this._bindingForTarget(jsLocation.debuggerModel.target()); |
| + if (!binding) |
| + return null; |
| + var uiSourceCode = binding.uiSourceCodeForURL(script.sourceURL); |
| + return uiSourceCode ? uiSourceCode.uiLocation(jsLocation.lineNumber, jsLocation.columnNumber) : null; |
| + } |
| + |
| + /** |
| + * @param {!SDK.Target} target |
| + */ |
| + _resetForTest(target) { |
| + var resourceTreeModel = target.model(SDK.ResourceTreeModel); |
| + var binding = resourceTreeModel ? this._modelToBinding.get(resourceTreeModel) : null; |
|
lushnikov
2017/06/12 23:17:53
if (binding)
binding._resetForTest();
lushnikov
2017/06/13 00:49:14
Done.
|
| + return binding ? binding._resetForTest() : null; |
| + } |
| +}; |
| + |
| +Bindings.ResourceBinding = class { |
|
lushnikov
2017/06/12 23:17:53
Bindings.ResourceMapping.ModelInfo =
lushnikov
2017/06/13 00:49:13
Done.
|
| + /** |
| + * @param {!Workspace.Workspace} workspace |
| + * @param {!SDK.ResourceTreeModel} resourceTreeModel |
| + */ |
| + constructor(workspace, resourceTreeModel) { |
| + var target = resourceTreeModel.target(); |
| + this._project = new Bindings.ContentProviderBasedProject( |
| + workspace, 'resources:' + target.id(), Workspace.projectTypes.Network, '', false /* isServiceProject */); |
| + Bindings.NetworkProject.setTargetForProject(this._project, target); |
| + |
| + /** @type {!Map<string, !Bindings.ResourceBinding.ResourceFile>} */ |
| + this._resourceFiles = new Map(); |
| + |
| + this._eventListeners = [ |
| + resourceTreeModel.addEventListener(SDK.ResourceTreeModel.Events.ResourceAdded, this._resourceAdded, this), |
| + resourceTreeModel.addEventListener(SDK.ResourceTreeModel.Events.FrameWillNavigate, this._frameWillNavigate, this), |
| + resourceTreeModel.addEventListener(SDK.ResourceTreeModel.Events.FrameDetached, this._frameDetached, this) |
| + ]; |
| + } |
| + |
| + /** |
| + * @param {string} url |
| + * @return {?Workspace.UISourceCode} |
| + */ |
| + uiSourceCodeForURL(url) { |
|
lushnikov
2017/06/12 23:17:53
inline
lushnikov
2017/06/13 00:49:14
Done.
|
| + return this._project.uiSourceCodeForURL(url); |
| + } |
| + |
| + /** |
| + * @param {!SDK.Resource} resource |
| + */ |
| + _acceptsResource(resource) { |
| + var resourceType = resource.resourceType(); |
| + // Only load selected resource types from resources. |
| + if (resourceType !== Common.resourceTypes.Image && resourceType !== Common.resourceTypes.Font && |
| + resourceType !== Common.resourceTypes.Document && resourceType !== Common.resourceTypes.Manifest) |
| + return false; |
| + |
| + // Ignore non-images and non-fonts. |
| + if (resourceType === Common.resourceTypes.Image && resource.mimeType && !resource.mimeType.startsWith('image')) |
| + return false; |
| + if (resourceType === Common.resourceTypes.Font && resource.mimeType && !resource.mimeType.includes('font')) |
| + return false; |
| + if ((resourceType === Common.resourceTypes.Image || resourceType === Common.resourceTypes.Font) && |
| + resource.contentURL().startsWith('data:')) |
| + return false; |
| + return true; |
| + } |
| + |
| + /** |
| + * @param {!Common.Event} event |
| + */ |
| + _resourceAdded(event) { |
| + var resource = /** @type {!SDK.Resource} */ (event.data); |
| + if (!this._acceptsResource(resource)) |
| + return; |
| + |
| + var resourceFile = this._resourceFiles.get(resource.url); |
| + if (!resourceFile) { |
| + resourceFile = new Bindings.ResourceBinding.ResourceFile(this._project, resource); |
| + this._resourceFiles.set(resource.url, resourceFile); |
| + } else { |
| + resourceFile.addResource(resource); |
|
lushnikov
2017/06/12 23:17:53
call this unconditionally
lushnikov
2017/06/13 00:49:14
Kept as-is to be aligned with StylesSOurceMapping
|
| + } |
| + } |
| + |
| + /** |
| + * @param {!SDK.ResourceTreeFrame} frame |
| + */ |
| + _removeFrameResources(frame) { |
| + for (var resource of frame.resources()) { |
| + if (!this._acceptsResource(resource)) |
| + continue; |
| + var resourceFile = this._resourceFiles.get(resource.url); |
| + if (resourceFile._resources.size === 1) { |
|
lushnikov
2017/06/12 23:17:53
if (resourceFile.removeResource(resource))
this.
lushnikov
2017/06/13 00:49:13
Kept as-is to be aligned with StylesSourceMapping
|
| + resourceFile.dispose(); |
| + this._resourceFiles.delete(resource.url); |
| + } else { |
| + resourceFile.removeResource(resource); |
| + } |
| + } |
| + } |
| + |
| + /** |
| + * @param {!Common.Event} event |
| + */ |
| + _frameWillNavigate(event) { |
| + var frame = /** @type {!SDK.ResourceTreeFrame} */ (event.data); |
| + this._removeFrameResources(frame); |
| + } |
| + |
| + /** |
| + * @param {!Common.Event} event |
| + */ |
| + _frameDetached(event) { |
| + var frame = /** @type {!SDK.ResourceTreeFrame} */ (event.data); |
| + this._removeFrameResources(frame); |
| + } |
| + |
| + _resetForTest() { |
| + for (var resourceFile of this._resourceFiles.valuesArray()) |
| + resourceFile.dispose(); |
| + this._resourceFiles.clear(); |
| + } |
| + |
| + dispose() { |
| + Common.EventTarget.removeEventListeners(this._eventListeners); |
| + for (var resourceFile of this._resourceFiles.valuesArray()) |
| + resourceFile.dispose(); |
| + this._resourceFiles.clear(); |
| + this._project.removeProject(); |
| + } |
| +}; |
| + |
| +/** |
| + * @implements {Common.ContentProvider} |
| + */ |
| +Bindings.ResourceBinding.ResourceFile = class { |
| + constructor(project, resource) { |
|
lushnikov
2017/06/12 23:17:53
jsdoc
lushnikov
2017/06/13 00:49:13
Done.
|
| + this._resources = new Set([resource]); |
| + this._project = project; |
| + this._uiSourceCode = this._project.createUISourceCode(resource.url, resource.contentType()); |
| + Bindings.NetworkProject.setInitialFrameAttribution(this._uiSourceCode, resource.frameId); |
| + this._project.addUISourceCodeWithProvider( |
| + this._uiSourceCode, this, Bindings.resourceMetadata(resource), resource.mimeType); |
| + } |
| + |
| + /** |
| + * @param {!SDK.Resource} resource |
| + */ |
| + addResource(resource) { |
| + this._resources.add(resource); |
| + Bindings.NetworkProject.addFrameAttribution(this._uiSourceCode, resource.frameId); |
| + } |
| + |
| + /** |
| + * @param {!SDK.Resource} resource |
| + */ |
| + removeResource(resource) { |
| + this._resources.delete(resource); |
| + Bindings.NetworkProject.removeFrameAttribution(this._uiSourceCode, resource.frameId); |
| + } |
| + |
| + dispose() { |
| + this._project.removeFile(this._uiSourceCode.url()); |
| + } |
| + |
| + /** |
| + * @override |
| + * @return {string} |
| + */ |
| + contentURL() { |
| + return this._resources.firstValue().contentURL(); |
| + } |
| + |
| + /** |
| + * @override |
| + * @return {!Common.ResourceType} |
| + */ |
| + contentType() { |
| + return this._resources.firstValue().contentType(); |
| + } |
| + |
| + /** |
| + * @override |
| + * @return {!Promise<?string>} |
| + */ |
| + requestContent() { |
| + return this._resources.firstValue().requestContent(); |
| + } |
| + |
| + /** |
| + * @override |
| + * @param {string} query |
| + * @param {boolean} caseSensitive |
| + * @param {boolean} isRegex |
| + * @return {!Promise<!Array<!Common.ContentProvider.SearchMatch>>} |
| + */ |
| + searchInContent(query, caseSensitive, isRegex) { |
| + return this._resources.firstValue().searchInContent(query, caseSensitive, isRegex); |
| + } |
| +}; |