Permalink
Browse files

Issue 5989: Add auto-completion to Elements side panel

  • Loading branch information...
1 parent fe98002 commit cdd04180ec14e8f763d6a52e4221cced7de4a078 @simonlindholm simonlindholm committed Oct 23, 2012
@@ -23,12 +23,14 @@ define([
"firebug/lib/options",
"firebug/css/cssModule",
"firebug/css/cssReps",
+ "firebug/css/selectorEditor",
"firebug/editor/editor",
"firebug/editor/editorSelector",
"firebug/chrome/searchBox"
],
function(Obj, Firebug, Domplate, FirebugReps, Locale, Events, Url, SourceLink, Css, Dom, Win,
- Search, Str, Arr, Fonts, Xml, Persist, System, Menu, Options, CSSModule, CSSInfoTip) {
+ Search, Str, Arr, Fonts, Xml, Persist, System, Menu, Options, CSSModule, CSSInfoTip,
+ SelectorEditor) {
with (Domplate) {
@@ -193,7 +195,6 @@ Firebug.CSSStyleRuleTag = CSSStyleRuleTag;
const reSplitCSS = /(url\("?[^"\)]+?"?\))|(rgba?\([^)]*\)?)|(hsla?\([^)]*\)?)|(#[\dA-Fa-f]+)|(-?\d+(\.\d+)?(%|[a-z]{1,4})?)|"([^"]*)"?|'([^']*)'?|([^,\s\/!\(\)]+)|(!(.*)?)/;
const reURL = /url\("?([^"\)]+)?"?\)/;
const reRepeat = /no-repeat|repeat-x|repeat-y|repeat/;
-const reSelectorChar = /[-_0-9a-zA-Z]/;
// ********************************************************************************************* //
// CSS Module
@@ -2053,7 +2054,7 @@ CSSEditor.prototype = domplate(Firebug.InlineEditor.prototype,
}
}
- return stripCompletedParens(keywords, postExpr);
+ return SelectorEditor.stripCompletedParens(keywords, postExpr);
}
},
@@ -2267,8 +2268,7 @@ function CSSRuleEditor(doc)
this.initializeInline(doc);
}
-CSSRuleEditor.uniquifier = 0;
-CSSRuleEditor.prototype = domplate(Firebug.InlineEditor.prototype,
+CSSRuleEditor.prototype = domplate(SelectorEditor.prototype,
{
insertNewRow: function(target, insertWhere)
{
@@ -2434,210 +2434,21 @@ CSSRuleEditor.prototype = domplate(Firebug.InlineEditor.prototype,
{
if (!Css.hasClass(this.target, "cssSelector"))
return;
-
- // Find the word part of an identifier.
- var reIdent = /[-_a-zA-Z0-9]*/;
- var rbefore = Str.reverseString(value.substr(0, offset));
- var after = value.substr(offset);
- var start = offset - reIdent.exec(rbefore)[0].length;
- var end = offset + reIdent.exec(after)[0].length;
-
- // Expand it to include '.', '#', ':', or '::'.
- if (start > 0 && ".#:".indexOf(value.charAt(start-1)) !== -1)
- {
- --start;
- if (start > 0 && value.substr(start-1, 2) === "::")
- --start;
- }
- return {start: start, end: end};
+ return SelectorEditor.prototype.getAutoCompleteRange.apply(this, arguments);
},
getAutoCompleteList: function(preExpr, expr, postExpr, range, cycle, context, out)
{
if (!Css.hasClass(this.target, "cssSelector"))
return [];
-
- // Don't support attribute selectors, for now.
- if (preExpr.lastIndexOf("[") > preExpr.lastIndexOf("]"))
- return [];
-
- if (preExpr.lastIndexOf("(") > preExpr.lastIndexOf(")"))
- {
- // We are in an parenthesized expression, where we can only complete
- // for a few particular pseudo-classes that take selector-like arguments.
- var par = preExpr.lastIndexOf("("), colon = preExpr.lastIndexOf(":", par);
- if (colon === -1)
- return;
- var allowed = ["-moz-any", "not", "-moz-empty-except-children-with-localname"];
- var name = preExpr.substring(colon+1, par);
- if (allowed.indexOf(name) === -1)
- return [];
- }
-
- var includeTagNames = true;
- var includeIds = true;
- var includeClasses = true;
- var includePseudoClasses = true;
- var includePseudoElements = true;
-
- if (expr.length > 0)
- {
- includeTagNames = includeClasses = includeIds =
- includePseudoClasses = includePseudoElements = false;
- if (Str.hasPrefix(expr, "::"))
- includePseudoElements = true;
- else if (expr.charAt(0) === ":")
- includePseudoClasses = true;
- else if (expr.charAt(0) === "#")
- includeIds = true;
- else if (expr.charAt(0) === ".")
- includeClasses = true;
- else
- includeTagNames = true;
- }
- if (preExpr.length > 0 && reSelectorChar.test(preExpr.slice(-1)))
- includeTagNames = false;
-
- var ret = [];
-
- if (includeTagNames || includeIds || includeClasses)
- {
- // Traverse the DOM to get the used ids/classes/tag names that
- // are relevant as continuations.
- // (Tag names could be hard-coded, but finding which ones are
- // actually used hides annoying things like 'b'/'i' when they
- // are not used, and works in other contexts than HTML.)
- // This isn't actually that bad, performance-wise.
- var doc = context.window.document, els;
- if (preExpr && " >+~".indexOf(preExpr.slice(-1)) === -1)
- {
- try
- {
- var preSelector = preExpr.split(",").reverse()[0];
- els = doc.querySelectorAll(preSelector);
- }
- catch (exc)
- {
- if (FBTrace.DBG_CSS)
- FBTrace.sysout("Invalid previous selector part \"" + preSelector + "\"", exc);
- }
- }
- if (!els)
- els = doc.getElementsByTagName("*");
- els = [].slice.call(els);
-
- if (includeTagNames)
- {
- var tagMap = {};
- els.forEach(function(e)
- {
- tagMap[e.localName] = 1;
- });
- ret.push.apply(ret, Object.keys(tagMap));
- }
-
- if (includeIds)
- {
- var ids = [];
- els.forEach(function(e)
- {
- if (e.id)
- ids.push(e.id);
- });
- ids = Arr.sortUnique(ids);
- ret.push.apply(ret, ids.map(function(cl)
- {
- return "#" + cl;
- }));
- }
-
- if (includeClasses)
- {
- var clCombinationMap = {}, classes = [];
- els.forEach(function(e)
- {
- var cl = e.className;
- if (cl && !((","+cl) in clCombinationMap))
- {
- clCombinationMap[","+cl] = 1;
- classes.push.apply(classes, e.classList);
- }
- });
- classes = Arr.sortUnique(classes);
- ret.push.apply(ret, classes.map(function(cl)
- {
- return "." + cl;
- }));
- }
- }
-
- if (includePseudoClasses)
- {
- // Add the pseudo-class-looking :before, :after.
- ret.push(
- ":after",
- ":before"
- );
-
- ret.push.apply(ret, stripCompletedParens(Css.pseudoClasses, postExpr));
- }
-
- if (includePseudoElements)
- {
- ret.push.apply(ret, Css.pseudoElements);
- }
-
- // Don't suggest things that are already included (by way of totally-
- // incorrect-but-probably-good-enough logic).
- var rev = Str.reverseString(preExpr);
- var partInd = rev.search(/[, >+~]/);
- var lastPart = (partInd === -1 ? rev : rev.substr(0, partInd));
- lastPart = Str.reverseString(lastPart);
- if (lastPart !== "")
- {
- ret = ret.filter(function(str)
- {
- var ind = lastPart.indexOf(str);
- if (ind === -1)
- return true;
- var before = ind-1, after = ind+str.length;
- var re = reSelectorChar;
- if (before >= 0 && re.test(str.charAt(0)) && re.test(lastPart.charAt(before)))
- return true;
- if (after < lastPart.length && re.test(lastPart.charAt(after)))
- return true;
- return false;
- });
- }
-
- // Don't suggest internal Firebug things.
- var reInternal = /^[.#]firebug[A-Z]/;
- ret = ret.filter(function(str)
- {
- return !reInternal.test(str);
- });
-
- if (ret.indexOf(":hover") !== -1)
- out.suggestion = ":hover";
-
- return ret.sort();
+ return SelectorEditor.prototype.getAutoCompleteList.apply(this, arguments);
},
getAutoCompletePropSeparator: function(range, expr, prefixOf)
{
if (!Css.hasClass(this.target, "cssSelector"))
return null;
-
- // For e.g. 'd|span', expand to a descendant selector; otherwise assume
- // that this is part of the same selector part.
- return (reSelectorChar.test(prefixOf.charAt(0)) ? " " : "");
- },
-
- autoCompleteAdjustSelection: function(value, offset)
- {
- if (offset >= 2 && value.substr(offset-2, 2) === "()")
- return offset-1;
- return offset;
+ return SelectorEditor.prototype.getAutoCompletePropSeparator.apply(this, arguments);
},
advanceToNext: function(target, charCode)
@@ -2811,23 +2622,6 @@ Firebug.CSSDirtyListener.prototype =
// ********************************************************************************************* //
// Local Helpers
-// Transform completions so that they don't add additional parentheses when
-// ones already exist.
-function stripCompletedParens(list, postExpr)
-{
- var c = postExpr.charAt(0), rem = 0;
- if (c === "(")
- rem = 2;
- else if (c === ")")
- rem = 1;
- else
- return list;
- return list.map(function(cl)
- {
- return (cl.slice(-2) === "()" ? cl.slice(0, -rem) : cl);
- });
-}
-
function parsePriority(value)
{
var rePriority = /(.*?)\s*(!important)?$/;
Oops, something went wrong.

0 comments on commit cdd0418

Please sign in to comment.