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

Unified Diff: Source/devtools/front_end/sources/WatchExpressionsSidebarPane.js

Issue 905743003: DevTools: Reimplemented WI.WatchExpressionsSidebarPane (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Rebase on master Created 5 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 side-by-side diff with in-line comments
Download patch
Index: Source/devtools/front_end/sources/WatchExpressionsSidebarPane.js
diff --git a/Source/devtools/front_end/sources/WatchExpressionsSidebarPane.js b/Source/devtools/front_end/sources/WatchExpressionsSidebarPane.js
index 1180e98e48442091053aaa7e9ada5a931687d40c..9baf020a8d0ea9324f9619f0af31deece5bf91c1 100644
--- a/Source/devtools/front_end/sources/WatchExpressionsSidebarPane.js
+++ b/Source/devtools/front_end/sources/WatchExpressionsSidebarPane.js
@@ -36,8 +36,13 @@ WebInspector.WatchExpressionsSidebarPane = function()
{
WebInspector.SidebarPane.call(this, WebInspector.UIString("Watch Expressions"));
- this.section = new WebInspector.WatchExpressionsSection();
- this.bodyElement.appendChild(this.section.element);
+ this._requiresUpdate = true;
+ /** @type {!Array.<!WebInspector.WatchExpression>} */
+ this._watchExpressions = [];
+
+
+ this.bodyElement.classList.add("vbox", "watch-expressions");
+ this.bodyElement.addEventListener("contextmenu", this._contextMenu.bind(this), false);
var refreshButton = this.titleElement.createChild("button", "pane-title-button refresh");
refreshButton.addEventListener("click", this._refreshButtonClicked.bind(this), false);
@@ -46,8 +51,6 @@ WebInspector.WatchExpressionsSidebarPane = function()
var addButton = this.titleElement.createChild("button", "pane-title-button add");
addButton.addEventListener("click", this._addButtonClicked.bind(this), false);
addButton.title = WebInspector.UIString("Add watch expression");
-
- this._requiresUpdate = true;
WebInspector.context.addFlavorChangeListener(WebInspector.ExecutionContext, this.refreshExpressions, this);
}
@@ -64,426 +67,365 @@ WebInspector.WatchExpressionsSidebarPane.prototype = {
},
/**
- * @param {string} expression
+ * @param {string} expressionString
*/
- addExpression: function(expression)
+ addExpression: function(expressionString)
{
- this.section.addExpression(expression);
this.expand();
+ if (this._requiresUpdate) {
+ this._rebuildWatchExpressions();
+ delete this._requiresUpdate;
+ }
+ this._createWatchExpression(expressionString);
+ this._saveExpressions();
+ },
+
+ _saveExpressions: function()
+ {
+ var toSave = [];
+ for (var i = 0; i < this._watchExpressions.length; i++)
+ if (this._watchExpressions[i].expression())
+ toSave.push(this._watchExpressions[i].expression());
+
+ WebInspector.settings.watchExpressions.set(toSave);
},
_refreshExpressionsIfNeeded: function()
{
if (this._requiresUpdate && this.isShowing()) {
- this.section.update();
+ this._rebuildWatchExpressions();
delete this._requiresUpdate;
} else
this._requiresUpdate = true;
},
+ /**
+ * @param {?Event} event
+ */
_addButtonClicked: function(event)
{
- event.consume();
+ if (event)
+ event.consume(true);
this.expand();
- this.section.addNewExpressionAndEdit();
+ this._createWatchExpression(null).startEditing();
},
+ /**
+ * @param {!Event} event
+ */
_refreshButtonClicked: function(event)
{
event.consume();
this.refreshExpressions();
},
- __proto__: WebInspector.SidebarPane.prototype
-}
-
-/**
- * @constructor
- * @extends {WebInspector.PropertiesSection}
- */
-WebInspector.WatchExpressionsSection = function()
-{
- this._watchObjectGroupId = "watch-group";
-
- WebInspector.PropertiesSection.call(this, "");
- this.treeElementConstructor = WebInspector.ObjectPropertyTreeElement;
- this.skipProto = false;
-
- this.emptyElement = createElementWithClass("div", "info");
- this.emptyElement.textContent = WebInspector.UIString("No Watch Expressions");
-
- /** @type {!Array.<string>} */
- this.watchExpressions = WebInspector.settings.watchExpressions.get();
-
- this.headerElement.className = "hidden";
- this.editable = true;
- this.expand();
- this.propertiesElement.classList.add("watch-expressions");
-
- this.element.addEventListener("mousemove", this._mouseMove.bind(this), true);
- this.element.addEventListener("mouseleave", this._mouseLeave.bind(this), true);
- this.element.addEventListener("dblclick", this._sectionDoubleClick.bind(this), false);
- this.emptyElement.addEventListener("contextmenu", this._emptyElementContextMenu.bind(this), false);
-}
-
-WebInspector.WatchExpressionsSection.NewWatchExpression = "\xA0";
-
-WebInspector.WatchExpressionsSection.prototype = {
- /**
- * @param {!Event=} e
- */
- update: function(e)
+ _rebuildWatchExpressions: function()
{
- if (e)
- e.consume();
-
- /***
- * @param {string} expression
- * @param {number} watchIndex
- * @param {?WebInspector.RemoteObject} result
- * @param {boolean} wasThrown
- * @this {WebInspector.WatchExpressionsSection}
- */
- function appendResult(expression, watchIndex, result, wasThrown)
- {
- if (!result)
- return;
-
- var property = new WebInspector.RemoteObjectProperty(expression, result);
- property.watchIndex = watchIndex;
- property.wasThrown = wasThrown;
-
- // To clarify what's going on here:
- // In the outer function, we calculate the number of properties
- // that we're going to be updating, and set that in the
- // propertyCount variable.
- // In this function, we test to see when we are processing the
- // last property, and then call the superclass's updateProperties()
- // method to get all the properties refreshed at once.
- properties.push(property);
-
- if (properties.length == propertyCount) {
- this.updateProperties(properties);
-
- // check to see if we just added a new watch expression,
- // which will always be the last property
- if (this._newExpressionAdded) {
- delete this._newExpressionAdded;
-
- var treeElement = this.findAddedTreeElement();
- if (treeElement)
- treeElement.startEditing();
- }
-
- // Force displaying delete button for hovered element.
- if (this._lastMouseMovePageY)
- this._updateHoveredElement(this._lastMouseMovePageY);
- }
- }
-
- // TODO: pass exact injected script id.
- WebInspector.targetManager.targets().forEach(function(target) { target.runtimeAgent().releaseObjectGroup(this._watchObjectGroupId); }, this);
- var properties = [];
-
- // Count the properties, so we known when to call this.updateProperties()
- // in appendResult()
- var propertyCount = 0;
- for (var i = 0; i < this.watchExpressions.length; ++i) {
- if (!this.watchExpressions[i])
+ this.bodyElement.removeChildren();
+ this._watchExpressions = [];
+ this._emptyElement = this.bodyElement.createChild("div", "info");
+ this._emptyElement.textContent = WebInspector.UIString("No Watch Expressions");
+ var watchExpressionStrings = WebInspector.settings.watchExpressions.get();
+ for (var i = 0; i < watchExpressionStrings.length; ++i) {
+ var expression = watchExpressionStrings[i];
+ if (!expression)
continue;
- ++propertyCount;
- }
- // Now process all the expressions, since we have the actual count,
- // which is checked in the appendResult inner function.
- var currentExecutionContext = WebInspector.context.flavor(WebInspector.ExecutionContext);
- if (currentExecutionContext) {
- for (var i = 0; i < this.watchExpressions.length; ++i) {
- var expression = this.watchExpressions[i];
- if (!expression)
- continue;
-
- currentExecutionContext.evaluate(expression, this._watchObjectGroupId, false, true, false, false, appendResult.bind(this, expression, i));
- }
+ this._createWatchExpression(expression);
}
-
- if (!propertyCount) {
- this.element.appendChild(this.emptyElement);
- this.propertiesElement.remove();
- this.propertiesTreeOutline.removeChildren();
- } else {
- this.element.appendChild(this.propertiesElement);
- this.emptyElement.remove();
- }
- },
-
- /**
- * @param {!Array.<!WebInspector.RemoteObjectProperty>} properties
- */
- updateProperties: function(properties)
- {
- this.propertiesTreeOutline.removeChildren();
- WebInspector.ObjectPropertyTreeElement.populateWithProperties(this.propertiesTreeOutline, properties, [],
- WebInspector.WatchExpressionTreeElement, WebInspector.WatchExpressionsSection.CompareProperties, false, null);
-
- this.propertiesForTest = properties;
},
/**
- * @param {string} expression
+ * @param {?string} expression
+ * @return {!WebInspector.WatchExpression}
*/
- addExpression: function(expression)
+ _createWatchExpression: function(expression)
{
- this.watchExpressions.push(expression);
- this.saveExpressions();
- this.update();
- },
-
- addNewExpressionAndEdit: function()
- {
- this._newExpressionAdded = true;
- this.watchExpressions.push(WebInspector.WatchExpressionsSection.NewWatchExpression);
- this.update();
- },
-
- _sectionDoubleClick: function(event)
- {
- if (event.target !== this.element && event.target !== this.propertiesElement && event.target !== this.emptyElement)
- return;
- event.consume();
- this.addNewExpressionAndEdit();
+ this._emptyElement.classList.add("hidden");
+ var watchExpression = new WebInspector.WatchExpression(expression);
+ watchExpression.addEventListener(WebInspector.WatchExpression.Events.ExpressionUpdated, this._watchExpressionUpdated.bind(this));
+ this.bodyElement.appendChild(watchExpression.element());
+ this._watchExpressions.push(watchExpression);
+ return watchExpression;
},
/**
- * @param {!WebInspector.ObjectPropertyTreeElement} element
- * @param {?string} value
+ * @param {!WebInspector.Event} event
*/
- updateExpression: function(element, value)
+ _watchExpressionUpdated: function(event)
{
- if (value === null) {
- var index = element.property.watchIndex;
- this.watchExpressions.splice(index, 1);
- } else {
- this.watchExpressions[element.property.watchIndex] = value;
+ var watchExpression = /** @type {!WebInspector.WatchExpression} */ (event.target);
+ if (!watchExpression.expression()) {
+ this._watchExpressions.remove(watchExpression);
+ this.bodyElement.removeChild(watchExpression.element());
+ this._emptyElement.classList.toggle("hidden", !!this._watchExpressions.length);
}
- this.saveExpressions();
- this.update();
- },
- _deleteAllExpressions: function()
- {
- this.watchExpressions = [];
- this.saveExpressions();
- this.update();
+ this._saveExpressions();
},
/**
- * @return {?TreeElement}
+ * @param {!Event} event
*/
- findAddedTreeElement: function()
+ _contextMenu: function(event)
{
- var children = this.propertiesTreeOutline.children;
- for (var i = 0; i < children.length; ++i) {
- if (children[i].property.name === WebInspector.WatchExpressionsSection.NewWatchExpression)
- return children[i];
- }
- return null;
+ var contextMenu = new WebInspector.ContextMenu(event);
+ this._populateContextMenu(contextMenu, event);
+ contextMenu.show();
},
/**
- * @return {number}
+ * @param {!WebInspector.ContextMenu} contextMenu
+ * @param {!Event} event
*/
- saveExpressions: function()
+ _populateContextMenu: function(contextMenu, event)
{
- var toSave = [];
- for (var i = 0; i < this.watchExpressions.length; i++)
- if (this.watchExpressions[i])
- toSave.push(this.watchExpressions[i]);
-
- WebInspector.settings.watchExpressions.set(toSave);
- return toSave.length;
- },
-
- _mouseMove: function(e)
- {
- if (this.propertiesElement.firstChild)
- this._updateHoveredElement(e.pageY);
- },
-
- _mouseLeave: function()
- {
- if (this._hoveredElement) {
- this._hoveredElement.classList.remove("hovered");
- delete this._hoveredElement;
- }
- delete this._lastMouseMovePageY;
- },
+ var isEditing = false;
+ for (var watchExpression of this._watchExpressions)
+ isEditing |= watchExpression.isEditing();
- _updateHoveredElement: function(pageY)
- {
- var candidateElement = this.propertiesElement.firstChild;
- while (true) {
- var next = candidateElement.nextSibling;
- while (next && !next.clientHeight)
- next = next.nextSibling;
- if (!next || next.totalOffsetTop() > pageY)
- break;
- candidateElement = next;
- }
+ if (!isEditing)
+ contextMenu.appendItem(WebInspector.UIString.capitalize("Add ^watch ^expression"), this._addButtonClicked.bind(this));
- if (this._hoveredElement !== candidateElement) {
- if (this._hoveredElement)
- this._hoveredElement.classList.remove("hovered");
- if (candidateElement)
- candidateElement.classList.add("hovered");
- this._hoveredElement = candidateElement;
- }
+ if (this._watchExpressions.length > 1)
+ contextMenu.appendItem(WebInspector.UIString.capitalize("Delete ^all ^watch ^expressions"), this._deleteAllButtonClicked.bind(this));
- this._lastMouseMovePageY = pageY;
+ for (var watchExpression of this._watchExpressions)
+ if (watchExpression.element().containsEventPoint(event))
+ watchExpression._populateContextMenu(contextMenu, event);
},
- _emptyElementContextMenu: function(event)
+ _deleteAllButtonClicked: function()
{
- var contextMenu = new WebInspector.ContextMenu(event);
- contextMenu.appendItem(WebInspector.UIString.capitalize("Add ^watch ^expression"), this.addNewExpressionAndEdit.bind(this));
- contextMenu.show();
+ this._watchExpressions = [];
+ this._saveExpressions();
+ this._rebuildWatchExpressions();
},
- __proto__: WebInspector.PropertiesSection.prototype
+ __proto__: WebInspector.SidebarPane.prototype
}
/**
- * @param {!WebInspector.RemoteObjectProperty} propertyA
- * @param {!WebInspector.RemoteObjectProperty} propertyB
- * @return {number}
+ * @constructor
+ * @extends {WebInspector.Object}
+ * @param {?string} expression
*/
-WebInspector.WatchExpressionsSection.CompareProperties = function(propertyA, propertyB)
+WebInspector.WatchExpression = function(expression)
{
- if (propertyA.watchIndex == propertyB.watchIndex)
- return 0;
- else if (propertyA.watchIndex < propertyB.watchIndex)
- return -1;
- else
- return 1;
+ this._expression = expression;
+ this._element = createElementWithClass("div", "watch-expression monospace");
+ this._editing = false;
+
+ this._createWatchExpression(null, false);
+ this.update();
}
-/**
- * @constructor
- * @extends {WebInspector.ObjectPropertyTreeElement}
- * @param {!WebInspector.RemoteObjectProperty} property
- */
-WebInspector.WatchExpressionTreeElement = function(property)
-{
- WebInspector.ObjectPropertyTreeElement.call(this, property);
+WebInspector.WatchExpression._watchObjectGroupId = "watch-group";
+
+WebInspector.WatchExpression.Events = {
+ ExpressionUpdated: "ExpressionUpdated"
}
-WebInspector.WatchExpressionTreeElement.prototype = {
+WebInspector.WatchExpression.prototype = {
+
/**
- * @override
- * @return {*}
+ * @return {!Element}
*/
- elementIdentity: function()
+ element: function()
{
- return this.property.name;
+ return this._element;
},
- update: function()
+ /**
+ * @return {?string}
+ */
+ expression: function()
{
- WebInspector.ObjectPropertyTreeElement.prototype.update.call(this);
+ return this._expression;
+ },
- if (this.property.wasThrown) {
- this.valueElement.textContent = WebInspector.UIString("<not available>");
- this.listItemElement.classList.add("dimmed");
- } else {
- this.listItemElement.classList.remove("dimmed");
- }
+ update: function()
+ {
+ var currentExecutionContext = WebInspector.context.flavor(WebInspector.ExecutionContext);
+ if (currentExecutionContext && this._expression)
+ currentExecutionContext.evaluate(this._expression, WebInspector.WatchExpression._watchObjectGroupId, false, true, false, false, this._createWatchExpression.bind(this));
+ },
- var deleteButton = createElementWithClass("button", "delete-button");
- deleteButton.title = WebInspector.UIString("Delete watch expression");
- deleteButton.addEventListener("click", this._deleteButtonClicked.bind(this), false);
- this.listItemElement.addEventListener("contextmenu", this._contextMenu.bind(this), false);
- this.listItemElement.insertBefore(deleteButton, this.listItemElement.firstChild);
+ startEditing: function()
+ {
+ this._editing = true;
+ this._element.removeChild(this._objectPresentationElement);
+ var newDiv = this._element.createChild("div");
+ newDiv.textContent = this._nameElement.textContent;
+ this._textPrompt = new WebInspector.ObjectPropertyPrompt();
+ this._textPrompt.renderAsBlock();
+ var proxyElement = this._textPrompt.attachAndStartEditing(newDiv, this._finishEditing.bind(this, this._expression));
+ proxyElement.classList.add("watch-expression-text-prompt-proxy");
+ proxyElement.addEventListener("keydown", this._promptKeyDown.bind(this), false);
+ this._element.getComponentSelection().setBaseAndExtent(newDiv, 0, newDiv, 1);
},
/**
- * @param {!WebInspector.ContextMenu} contextMenu
- * @override
+ * @return {boolean}
*/
- populateContextMenu: function(contextMenu)
+ isEditing: function()
{
- if (!this.isEditing()) {
- contextMenu.appendItem(WebInspector.UIString.capitalize("Add ^watch ^expression"), this.treeOutline.section.addNewExpressionAndEdit.bind(this.treeOutline.section));
- contextMenu.appendItem(WebInspector.UIString.capitalize("Delete ^watch ^expression"), this._deleteButtonClicked.bind(this, null));
- }
- if (this.treeOutline.section.watchExpressions.length > 1)
- contextMenu.appendItem(WebInspector.UIString.capitalize("Delete ^all ^watch ^expressions"), this._deleteAllButtonClicked.bind(this));
- if (!this.isEditing() && (this.property.value.type === "number" || this.property.value.type === "string"))
- contextMenu.appendItem(WebInspector.UIString.capitalize("Copy ^value"), this._copyValueButtonClicked.bind(this));
+ return !!this._editing;
},
- _contextMenu: function(event)
+ /**
+ * @param {?string} newExpression
+ * @param {!Event} event
+ */
+ _finishEditing: function(newExpression, event)
{
- var contextMenu = new WebInspector.ContextMenu(event);
- this.populateContextMenu(contextMenu);
- contextMenu.show();
+ if (event)
+ event.consume(true);
+
+ this._editing = false;
+ this._textPrompt.detach();
+ delete this._textPrompt;
+ this._element.removeChildren();
+ this._element.appendChild(this._objectPresentationElement);
+ this._updateExpression(newExpression);
},
- _deleteAllButtonClicked: function()
+ /**
+ * @param {!Event} event
+ */
+ _dblClickOnWatchExpression: function(event)
{
- this.treeOutline.section._deleteAllExpressions();
+ event.consume();
+ if (!this.isEditing())
+ this.startEditing();
},
- _deleteButtonClicked: function(event)
+ /**
+ * @param {?string} newExpression
+ */
+ _updateExpression: function(newExpression)
{
- if (event)
- event.consume();
- this.treeOutline.section.updateExpression(this, null);
+ this._expression = newExpression;
+ this.update();
+ this.dispatchEventToListeners(WebInspector.WatchExpression.Events.ExpressionUpdated);
},
- _copyValueButtonClicked: function()
+ /**
+ * @param {!Event} event
+ */
+ _deleteWatchExpression: function(event)
{
- InspectorFrontendHost.copyText(this.valueElement.textContent);
+ event.consume(true);
+ this._updateExpression(null);
},
/**
- * @override
- * @return {boolean}
+ * @param {?WebInspector.RemoteObject} result
+ * @param {boolean} wasThrown
*/
- renderPromptAsBlock: function()
+ _createWatchExpression: function(result, wasThrown)
{
- return true;
+ this._result = result;
+
+ var titleElement = createElementWithClass("div", "watch-expression-title");
+ this._nameElement = WebInspector.ObjectPropertiesSection.createNameElement(this._expression);
+ if (wasThrown || !result) {
+ this._valueElement = createElementWithClass("span", "console-formatted-undefined value");
+ titleElement.classList.add("dimmed");
+ this._valueElement.textContent = WebInspector.UIString("<not available>");
+ } else {
+ this._valueElement = WebInspector.ObjectPropertiesSection.createValueElement(result, wasThrown, titleElement);
+ }
+ var separatorElement = createElementWithClass("span", "separator");
+ separatorElement.textContent = ": ";
+ titleElement.appendChildren(this._nameElement, separatorElement, this._valueElement);
+
+ if (!wasThrown && result && result.hasChildren) {
+ var objectPropertiesSection = new WebInspector.ObjectPropertiesSection(result, titleElement);
+ this._objectPresentationElement = objectPropertiesSection.element;
+ objectPropertiesSection.headerElement.addEventListener("click", this._onSectionClick.bind(this, objectPropertiesSection), false);
+ objectPropertiesSection.doNotExpandOnTitleClick();
+ this._installHover(objectPropertiesSection.headerElement);
+ } else {
+ this._objectPresentationElement = this._element.createChild("div", "primitive-value");
+ this._objectPresentationElement.appendChild(titleElement);
+ this._installHover(this._objectPresentationElement);
+ }
+
+ this._element.removeChildren();
+ this._element.appendChild(this._objectPresentationElement);
+ this._element.addEventListener("dblclick", this._dblClickOnWatchExpression.bind(this));
},
/**
- * @override
- * @return {{element: !Element, value: (string|undefined)}}
+ * @param {!Element} hoverableElement
*/
- elementAndValueToEdit: function()
+ _installHover: function(hoverableElement)
{
- return { element: this.nameElement, value: this.property.name.trim() };
+ var deleteButton = createElementWithClass("button", "delete-button");
+ deleteButton.title = WebInspector.UIString("Delete watch expression");
+ deleteButton.addEventListener("click", this._deleteWatchExpression.bind(this), false);
+ hoverableElement.insertBefore(deleteButton, hoverableElement.firstChild);
},
/**
- * @override
+ * @param {!WebInspector.ObjectPropertiesSection} objectPropertiesSection
+ * @param {!Event} event
*/
- editingCancelled: function(element, context)
+ _onSectionClick: function(objectPropertiesSection, event)
{
- if (!context.elementToEdit.textContent)
- this.treeOutline.section.updateExpression(this, null);
+ event.consume(true);
+ if (event.detail == 1) {
+ this._preventClickTimeout = setTimeout(handleClick, 333);
+ } else {
+ clearTimeout(this._preventClickTimeout);
+ delete this._preventClickTimeout;
+ }
+
+ function handleClick()
+ {
+ if (objectPropertiesSection.expanded)
+ objectPropertiesSection.collapse();
+ else
+ objectPropertiesSection.expand();
+ }
+ },
- WebInspector.ObjectPropertyTreeElement.prototype.editingCancelled.call(this, element, context);
+ /**
+ * @param {!Event} event
+ */
+ _promptKeyDown: function(event)
+ {
+ if (isEnterKey(event)) {
+ this._finishEditing(this._textPrompt.text(), event);
+ return;
+ }
+ if (event.keyIdentifier === "U+001B") { // Esc
+ this._finishEditing(this._expression, event);
+ return;
+ }
},
/**
- * @override
- * @param {string} expression
+ * @param {!WebInspector.ContextMenu} contextMenu
+ * @param {!Event} event
*/
- applyExpression: function(expression)
+ _populateContextMenu: function(contextMenu, event)
+ {
+ if (!this.isEditing())
+ contextMenu.appendItem(WebInspector.UIString.capitalize("Delete ^watch ^expression"), this._updateExpression.bind(this, null));
+
+ if (!this.isEditing() && this._result && (this._result.type === "number" || this._result.type === "string"))
+ contextMenu.appendItem(WebInspector.UIString.capitalize("Copy ^value"), this._copyValueButtonClicked.bind(this));
+
+ if (this._valueElement.containsEventPoint(event))
+ contextMenu.appendApplicableItems(this._result);
+ },
+
+ _copyValueButtonClicked: function()
{
- expression = expression.trim();
- this.property.name = expression || null;
- this.treeOutline.section.updateExpression(this, expression);
+ InspectorFrontendHost.copyText(this._valueElement.textContent);
},
- __proto__: WebInspector.ObjectPropertyTreeElement.prototype
+ __proto__: WebInspector.Object.prototype
}
« no previous file with comments | « Source/devtools/front_end/components/ObjectPropertiesSection.js ('k') | Source/devtools/front_end/sources/sourcesPanel.css » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698