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

Unified Diff: third_party/WebKit/Source/devtools/front_end/elements/ClassesPaneWidget.js

Issue 2343773002: DevTools: Autocomplete class names in ClassesPaneWidget (Closed)
Patch Set: Simplified Created 4 years, 3 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
« no previous file with comments | « no previous file | third_party/WebKit/Source/devtools/front_end/elements/elementsPanel.css » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: third_party/WebKit/Source/devtools/front_end/elements/ClassesPaneWidget.js
diff --git a/third_party/WebKit/Source/devtools/front_end/elements/ClassesPaneWidget.js b/third_party/WebKit/Source/devtools/front_end/elements/ClassesPaneWidget.js
index b0bada022b10ab39a9c8379afb97d078f1c7817a..c4401357a29271503be914aadfcd2f08204213f1 100644
--- a/third_party/WebKit/Source/devtools/front_end/elements/ClassesPaneWidget.js
+++ b/third_party/WebKit/Source/devtools/front_end/elements/ClassesPaneWidget.js
@@ -11,14 +11,24 @@ WebInspector.ClassesPaneWidget = function()
WebInspector.Widget.call(this);
this.element.className = "styles-element-classes-pane";
var container = this.element.createChild("div", "title-container");
- this._input = container.createChild("input", "new-class-input monospace");
- this._input.placeholder = WebInspector.UIString("Add new class");
- this._input.addEventListener("keydown", this._onKeyDown.bind(this), false);
+ this._input = container.createChild("div", "new-class-input monospace");
+ this._input.setAttribute("placeholder" , WebInspector.UIString("Add new class"));
this.setDefaultFocusedElement(this._input);
+
this._classesContainer = this.element.createChild("div", "source-code");
this._classesContainer.classList.add("styles-element-classes-container");
+ this._prompt = new WebInspector.ClassesPaneWidget.ClassNamePrompt();
+ this._prompt.setAutocompletionTimeout(0);
+ this._prompt.renderAsBlock();
+
+ this._frameClasses = new Map();
+ this._selectedNode = null;
+ var proxyElement = this._prompt.attach(this._input);
+ proxyElement.addEventListener("keydown", this._onKeyDown.bind(this), false);
WebInspector.targetManager.addModelListener(WebInspector.DOMModel, WebInspector.DOMModel.Events.DOMMutated, this._onDOMMutated, this);
+ WebInspector.targetManager.addEventListener(WebInspector.TargetManager.Events.MainFrameNavigated, this._mainFrameNavigated, this);
+
/** @type {!Set<!WebInspector.DOMNode>} */
this._mutatingNodes = new Set();
WebInspector.context.addFlavorChangeListener(WebInspector.DOMNode, this._update, this);
@@ -32,21 +42,24 @@ WebInspector.ClassesPaneWidget.prototype = {
*/
_onKeyDown: function(event)
{
- var text = event.target.value;
+ var text = event.target.innerText;
if (isEscKey(event)) {
- event.target.value = "";
+ this._hidePrompt();
+ event.target.innerText = "";
if (!text.isWhitespace())
event.consume(true);
return;
}
-
+ if (!this._prompt.isSuggestBoxVisible()) {
+ this._collectFrameClasses(this._selectedFrameId());
+ }
if (!isEnterKey(event))
return;
var node = WebInspector.context.flavor(WebInspector.DOMNode);
if (!node)
return;
-
- event.target.value = "";
+ this._hidePrompt();
+ event.target.innerText = "";
var classNames = text.split(/[.,\s]/);
for (var className of classNames) {
var className = className.trim();
@@ -62,6 +75,134 @@ WebInspector.ClassesPaneWidget.prototype = {
/**
* @param {!WebInspector.Event} event
*/
+ _mainFrameNavigated: function(event)
+ {
+ this._selectedNode = null;
+ this._frameClasses = new Map();
+ this._prompt.clearCompletions();
+ },
+
+ _hidePrompt: function()
lushnikov 2016/09/20 17:11:09 let's inline this
+ {
+ this._prompt.clearAutoComplete();
+ },
+
+ _getDomClasses: function()
lushnikov 2016/09/20 16:46:21 Can we move all the logic inside the ClassNameProm
ahmetemirercin 2016/09/20 18:38:40 Correct me if I'm wrong: cssModel will collect sty
+ {
+ if (!this._selectedNode)
+ return;
+
+ var inspectedDocument = this._selectedNode.ownerDocument;
+
+ if (!inspectedDocument)
+ return;
+
+ var frameId = this._getNodeFrameId(inspectedDocument);
+ /**
+ * @param {!Array.<string>} classNames
+ * @this {!WebInspector.ClassesPaneWidget}
+ */
+ function classNamesCallback(classNames)
+ {
+ this._addFrameClasses(frameId, classNames);
+ }
+
+ inspectedDocument.domModel().classNamesPromise(inspectedDocument.id).then(classNamesCallback.bind(this));
+ },
+
+ _getCssClasses: function()
+ {
+ if (!this._selectedNode)
+ return;
+
+ var frameId = this._selectedFrameId();
+ var cssModel = WebInspector.CSSModel.fromTarget(this._selectedNode.target());
+ var headers = cssModel.allStyleSheets();
+ for (var stylesheet of cssModel.allStyleSheets())
+ if (stylesheet.frameId === frameId)
+ this._getStylesheetClasses(stylesheet);
+ },
+
+ /**
+ * @param {?PageAgent.FrameId} frameId
+ * @return {!Set<string>}
+ */
+ _getFrameClasses: function(frameId)
+ {
+ if (!this._frameClasses.get(frameId))
+ this._frameClasses.set(frameId, new Set());
+
+ return this._frameClasses.get(frameId);
+ },
+
+ /**
+ * @return {?PageAgent.FrameId}
+ */
+ _selectedFrameId: function()
+ {
+ return this._getNodeFrameId(this._selectedNode);
+ },
+
+ /**
+ * @param {?WebInspector.DOMNode} node
+ * @return {?PageAgent.FrameId}
+ */
+ _getNodeFrameId: function(node){
+ return node ? node.frameId() || WebInspector.ResourceTreeModel.fromTarget(node.target()).mainFrame.id : 0;
+ },
+
+ /**
+ * @param {!WebInspector.CSSStyleSheetHeader} stylesheet
+ */
+ _getStylesheetClasses: function(stylesheet)
+ {
+ /**
+ * @param {!WebInspector.CSSStyleSheetHeader} stylsheet
+ * @param {!Array.<string>} classNames
+ * @this {!WebInspector.ClassesPaneWidget}
+ */
+ function classNamesCallback(stylsheet, classNames)
+ {
+ this._addFrameClasses(stylsheet.frameId, classNames);
+ }
+
+ var cssModel = stylesheet.cssModel();
+ cssModel.classNamesPromise(stylesheet.id).then(classNamesCallback.bind(this, stylesheet));
+ },
+
+ /**
+ * @param {?PageAgent.FrameId} frameId
+ * @param {!Array.<string>} classNames
+ */
+ _addFrameClasses: function(frameId, classNames)
+ {
+ if (!classNames)
+ return;
+ this._getFrameClasses(frameId).addAll(classNames);
+ this._updateCompletions(frameId);
+ },
+
+ /**
+ * @param {?PageAgent.FrameId} frameId
+ */
+ _updateCompletions: function(frameId)
+ {
+ if (frameId === this._selectedFrameId())
+ this._prompt.updateCompletions(this._getFrameClasses(frameId).valuesArray().sort());
+ },
+
+ /**
+ * @param {?PageAgent.FrameId} frameId
+ */
+ _collectFrameClasses: function(frameId)
+ {
+ this._getDomClasses();
+ this._getCssClasses();
+ },
+
+ /**
+ * @param {!WebInspector.Event} event
+ */
_onDOMMutated: function(event)
{
var node = /** @type {!WebInspector.DOMNode} */(event.data);
@@ -83,7 +224,6 @@ WebInspector.ClassesPaneWidget.prototype = {
{
if (!this.isShowing())
return;
-
var node = WebInspector.context.flavor(WebInspector.DOMNode);
if (node)
node = node.enclosingElementOrSelf();
@@ -94,6 +234,7 @@ WebInspector.ClassesPaneWidget.prototype = {
if (!node)
return;
+ this._selectedNode = node;
var classes = this._nodeClasses(node);
var keys = classes.keysArray();
keys.sort(String.caseInsensetiveComparator);
@@ -211,3 +352,71 @@ WebInspector.ClassesPaneWidget.ButtonProvider.prototype = {
return this._button;
}
}
+
+/**
+ * @constructor
+ * @extends {WebInspector.TextPrompt}
+ */
+WebInspector.ClassesPaneWidget.ClassNamePrompt = function()
+{
+ WebInspector.TextPrompt.call(this, this._buildClassNameCompletions.bind(this), " ");
+ this.setSuggestBoxEnabled(true);
+ this.disableDefaultSuggestionForEmptyInput();
+ this._classNameCompletions = [];
+}
+
+WebInspector.ClassesPaneWidget.ClassNamePrompt.prototype = {
+ /**
+ * @override
+ * @param {!Event} event
+ */
+ onKeyDown: function(event)
+ {
+ switch (event.key) {
+ case "Enter":
+ // Accept any available autocompletions and advance to the next field.
+ if (this.autoCompleteElement && this.autoCompleteElement.textContent.length) {
+ this.acceptAutoComplete();
+ return;
+ }
+ break;
+ }
+
+ WebInspector.TextPrompt.prototype.onKeyDown.call(this, event);
+ },
+
+ /**
+ * @param {!Array.<string>} classNameList
+ */
+ updateCompletions: function(classNameList)
+ {
+ this._classNameCompletions = classNameList;
+ },
+
+ clearCompletions: function()
+ {
+ this._classNameCompletions = [];
+ },
+
+ /**
+ * @param {!Element} proxyElement
+ * @param {!Range} wordRange
+ * @param {boolean} force
+ * @param {function(!Array.<string>, number=)} completionsReadyCallback
+ */
+ _buildClassNameCompletions: function(proxyElement, wordRange, force, completionsReadyCallback)
+ {
+ var prefix = wordRange.toString();
+
+ if (!prefix && !force && !proxyElement.textContent.length) {
+ completionsReadyCallback([]);
+ return;
+ }
+
+ var results = this._classNameCompletions.filter((value) => value.startsWith(prefix));
+ var selectedIndex = 0;
+ completionsReadyCallback(results, selectedIndex);
+ },
+
+ __proto__: WebInspector.TextPrompt.prototype
+}
« no previous file with comments | « no previous file | third_party/WebKit/Source/devtools/front_end/elements/elementsPanel.css » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698