зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1149346 - First word in selector-search also matches classes and ids; r=harth
This commit is contained in:
Родитель
0511749b55
Коммит
4ae0fca079
|
@ -425,16 +425,12 @@ SelectorSearch.prototype = {
|
||||||
/**
|
/**
|
||||||
* Populates the suggestions list and show the suggestion popup.
|
* Populates the suggestions list and show the suggestion popup.
|
||||||
*/
|
*/
|
||||||
_showPopup: function(aList, aFirstPart) {
|
_showPopup: function(aList, aFirstPart, aState) {
|
||||||
let total = 0;
|
let total = 0;
|
||||||
let query = this.searchBox.value;
|
let query = this.searchBox.value;
|
||||||
let toLowerCase = false;
|
|
||||||
let items = [];
|
let items = [];
|
||||||
// In case of tagNames, change the case to small.
|
|
||||||
if (query.match(/.*[\.#][^\.#]{0,}$/) == null) {
|
for (let [value, count, state] of aList) {
|
||||||
toLowerCase = true;
|
|
||||||
}
|
|
||||||
for (let [value, count] of aList) {
|
|
||||||
// for cases like 'div ' or 'div >' or 'div+'
|
// for cases like 'div ' or 'div >' or 'div+'
|
||||||
if (query.match(/[\s>+]$/)) {
|
if (query.match(/[\s>+]$/)) {
|
||||||
value = query + value;
|
value = query + value;
|
||||||
|
@ -449,14 +445,27 @@ SelectorSearch.prototype = {
|
||||||
let lastPart = query.match(/[a-zA-Z][#\.][^#\.\s>+]*$/)[0];
|
let lastPart = query.match(/[a-zA-Z][#\.][^#\.\s>+]*$/)[0];
|
||||||
value = query.slice(0, -1 * lastPart.length + 1) + value;
|
value = query.slice(0, -1 * lastPart.length + 1) + value;
|
||||||
}
|
}
|
||||||
|
|
||||||
let item = {
|
let item = {
|
||||||
preLabel: query,
|
preLabel: query,
|
||||||
label: value,
|
label: value,
|
||||||
count: count
|
count: count
|
||||||
};
|
};
|
||||||
if (toLowerCase) {
|
|
||||||
|
// In case of tagNames, change te case to small
|
||||||
|
if (value.match(/.*[\.#][^\.#]{0,}$/) == null) {
|
||||||
item.label = value.toLowerCase();
|
item.label = value.toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// In case the query's state is tag and the item's state is id or class
|
||||||
|
// adjust the preLabel
|
||||||
|
if (aState === this.States.TAG && state === this.States.CLASS) {
|
||||||
|
item.preLabel = "." + item.preLabel;
|
||||||
|
}
|
||||||
|
if (aState === this.States.TAG && state === this.States.ID) {
|
||||||
|
item.preLabel = "#" + item.preLabel;
|
||||||
|
}
|
||||||
|
|
||||||
items.unshift(item);
|
items.unshift(item);
|
||||||
if (++total > MAX_SUGGESTIONS - 1) {
|
if (++total > MAX_SUGGESTIONS - 1) {
|
||||||
break;
|
break;
|
||||||
|
@ -477,19 +486,21 @@ SelectorSearch.prototype = {
|
||||||
*/
|
*/
|
||||||
showSuggestions: function() {
|
showSuggestions: function() {
|
||||||
let query = this.searchBox.value;
|
let query = this.searchBox.value;
|
||||||
|
let state = this.state;
|
||||||
let firstPart = "";
|
let firstPart = "";
|
||||||
if (this.state == this.States.TAG) {
|
|
||||||
|
if (state == this.States.TAG) {
|
||||||
// gets the tag that is being completed. For ex. 'div.foo > s' returns 's',
|
// gets the tag that is being completed. For ex. 'div.foo > s' returns 's',
|
||||||
// 'di' returns 'di' and likewise.
|
// 'di' returns 'di' and likewise.
|
||||||
firstPart = (query.match(/[\s>+]?([a-zA-Z]*)$/) || ["", query])[1];
|
firstPart = (query.match(/[\s>+]?([a-zA-Z]*)$/) || ["", query])[1];
|
||||||
query = query.slice(0, query.length - firstPart.length);
|
query = query.slice(0, query.length - firstPart.length);
|
||||||
}
|
}
|
||||||
else if (this.state == this.States.CLASS) {
|
else if (state == this.States.CLASS) {
|
||||||
// gets the class that is being completed. For ex. '.foo.b' returns 'b'
|
// gets the class that is being completed. For ex. '.foo.b' returns 'b'
|
||||||
firstPart = query.match(/\.([^\.]*)$/)[1];
|
firstPart = query.match(/\.([^\.]*)$/)[1];
|
||||||
query = query.slice(0, query.length - firstPart.length - 1);
|
query = query.slice(0, query.length - firstPart.length - 1);
|
||||||
}
|
}
|
||||||
else if (this.state == this.States.ID) {
|
else if (state == this.States.ID) {
|
||||||
// gets the id that is being completed. For ex. '.foo#b' returns 'b'
|
// gets the id that is being completed. For ex. '.foo#b' returns 'b'
|
||||||
firstPart = query.match(/#([^#]*)$/)[1];
|
firstPart = query.match(/#([^#]*)$/)[1];
|
||||||
query = query.slice(0, query.length - firstPart.length - 1);
|
query = query.slice(0, query.length - firstPart.length - 1);
|
||||||
|
@ -499,21 +510,24 @@ SelectorSearch.prototype = {
|
||||||
if (/[\s+>~]$/.test(query)) {
|
if (/[\s+>~]$/.test(query)) {
|
||||||
query += "*";
|
query += "*";
|
||||||
}
|
}
|
||||||
|
|
||||||
this._currentSuggesting = query;
|
this._currentSuggesting = query;
|
||||||
return this.walker.getSuggestionsForQuery(query, firstPart, this.state).then(result => {
|
return this.walker.getSuggestionsForQuery(query, firstPart, state).then(result => {
|
||||||
if (this._currentSuggesting != result.query) {
|
if (this._currentSuggesting != result.query) {
|
||||||
// This means that this response is for a previous request and the user
|
// This means that this response is for a previous request and the user
|
||||||
// as since typed something extra leading to a new request.
|
// as since typed something extra leading to a new request.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this._lastToLastValidSearch = this._lastValidSearch;
|
this._lastToLastValidSearch = this._lastValidSearch;
|
||||||
if (this.state == this.States.CLASS) {
|
|
||||||
|
if (state == this.States.CLASS) {
|
||||||
firstPart = "." + firstPart;
|
firstPart = "." + firstPart;
|
||||||
}
|
}
|
||||||
else if (this.state == this.States.ID) {
|
else if (state == this.States.ID) {
|
||||||
firstPart = "#" + firstPart;
|
firstPart = "#" + firstPart;
|
||||||
}
|
}
|
||||||
this._showPopup(result.suggestions, firstPart);
|
|
||||||
|
this._showPopup(result.suggestions, firstPart, state);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -15,7 +15,11 @@ const TEST_URL = TEST_URL_ROOT + "doc_inspector_search-suggestions.html";
|
||||||
const TEST_DATA = [
|
const TEST_DATA = [
|
||||||
{
|
{
|
||||||
key: "d",
|
key: "d",
|
||||||
suggestions: [{label: "div", count: 4}]
|
suggestions: [
|
||||||
|
{label: "div", count: 4},
|
||||||
|
{label: "#d1", count: 1},
|
||||||
|
{label: "#d2", count: 1}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "i",
|
key: "i",
|
||||||
|
@ -67,7 +71,11 @@ const TEST_DATA = [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "VK_BACK_SPACE",
|
key: "VK_BACK_SPACE",
|
||||||
suggestions: [{label: "div", count: 4}]
|
suggestions: [
|
||||||
|
{label: "div", count: 4},
|
||||||
|
{label: "#d1", count: 1},
|
||||||
|
{label: "#d2", count: 1}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "VK_BACK_SPACE",
|
key: "VK_BACK_SPACE",
|
||||||
|
@ -135,16 +143,17 @@ add_task(function* () {
|
||||||
info("Waiting for search query to complete");
|
info("Waiting for search query to complete");
|
||||||
yield inspector.searchSuggestions._lastQuery;
|
yield inspector.searchSuggestions._lastQuery;
|
||||||
|
|
||||||
info("Query completed. Performing checks for input '" + searchBox.value + "'");
|
info("Query completed. Performing checks for input '" + searchBox.value +
|
||||||
|
"' - key pressed: " + key);
|
||||||
let actualSuggestions = popup.getItems().reverse();
|
let actualSuggestions = popup.getItems().reverse();
|
||||||
|
|
||||||
is(popup.isOpen ? actualSuggestions.length: 0, suggestions.length,
|
is(popup.isOpen ? actualSuggestions.length: 0, suggestions.length,
|
||||||
"There are expected number of suggestions.");
|
"There are expected number of suggestions.");
|
||||||
|
|
||||||
for (let i = 0; i < suggestions.length; i++) {
|
for (let i = 0; i < suggestions.length; i++) {
|
||||||
is(suggestions[i].label, actualSuggestions[i].label,
|
is(actualSuggestions[i].label, suggestions[i].label,
|
||||||
"The suggestion at " + i + "th index is correct.");
|
"The suggestion at " + i + "th index is correct.");
|
||||||
is(suggestions[i].count || 1, actualSuggestions[i].count,
|
is(actualSuggestions[i].count, suggestions[i].count || 1,
|
||||||
"The count for suggestion at " + i + "th index is correct.");
|
"The count for suggestion at " + i + "th index is correct.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -152,6 +161,6 @@ add_task(function* () {
|
||||||
|
|
||||||
function formatSuggestions(suggestions) {
|
function formatSuggestions(suggestions) {
|
||||||
return "[" + suggestions
|
return "[" + suggestions
|
||||||
.map(s => "'" + s.label + "' (" + s.count || 1 + ")")
|
.map(s => "'" + s.label + "' (" + (s.count || 1) + ")")
|
||||||
.join(", ") + "]";
|
.join(", ") + "]";
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,11 @@ const TEST_URL = TEST_URL_ROOT + "doc_inspector_search.html";
|
||||||
let TEST_DATA = [
|
let TEST_DATA = [
|
||||||
{
|
{
|
||||||
key: "d",
|
key: "d",
|
||||||
suggestions: [{label: "div", count: 2}]
|
suggestions: [
|
||||||
|
{label: "div", count: 2},
|
||||||
|
{label: "#d1", count: 1},
|
||||||
|
{label: "#d2", count: 1}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "i",
|
key: "i",
|
||||||
|
@ -50,7 +54,11 @@ let TEST_DATA = [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "VK_BACK_SPACE",
|
key: "VK_BACK_SPACE",
|
||||||
suggestions: [{label: "div", count: 2}]
|
suggestions: [
|
||||||
|
{label: "div", count: 2},
|
||||||
|
{label: "#d1", count: 1},
|
||||||
|
{label: "#d2", count: 1}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "VK_BACK_SPACE",
|
key: "VK_BACK_SPACE",
|
||||||
|
@ -179,9 +187,9 @@ add_task(function* () {
|
||||||
"There are expected number of suggestions.");
|
"There are expected number of suggestions.");
|
||||||
|
|
||||||
for (let i = 0; i < suggestions.length; i++) {
|
for (let i = 0; i < suggestions.length; i++) {
|
||||||
is(suggestions[i].label, actualSuggestions[i].label,
|
is(actualSuggestions[i].label, suggestions[i].label,
|
||||||
"The suggestion at " + i + "th index is correct.");
|
"The suggestion at " + i + "th index is correct.");
|
||||||
is(suggestions[i].count || 1, actualSuggestions[i].count,
|
is(actualSuggestions[i].count, suggestions[i].count || 1,
|
||||||
"The count for suggestion at " + i + "th index is correct.");
|
"The count for suggestion at " + i + "th index is correct.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -189,6 +197,6 @@ add_task(function* () {
|
||||||
|
|
||||||
function formatSuggestions(suggestions) {
|
function formatSuggestions(suggestions) {
|
||||||
return "[" + suggestions
|
return "[" + suggestions
|
||||||
.map(s => "'" + s.label + "' (" + s.count || 1 + ")")
|
.map(s => "'" + s.label + "' (" + (s.count || 1) + ")")
|
||||||
.join(", ") + "]";
|
.join(", ") + "]";
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,11 @@ const TEST_URL = "data:text/html;charset=utf-8," +
|
||||||
let TEST_DATA = [
|
let TEST_DATA = [
|
||||||
{
|
{
|
||||||
key: "d",
|
key: "d",
|
||||||
suggestions: [{label: "div", count: 5}]
|
suggestions: [
|
||||||
|
{label: "div", count: 5},
|
||||||
|
{label: "#d1", count: 2},
|
||||||
|
{label: "#d2", count: 2}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "i",
|
key: "i",
|
||||||
|
@ -34,7 +38,11 @@ let TEST_DATA = [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "VK_BACK_SPACE",
|
key: "VK_BACK_SPACE",
|
||||||
suggestions: [{label: "div", count: 5}]
|
suggestions: [
|
||||||
|
{label: "div", count: 5},
|
||||||
|
{label: "#d1", count: 2},
|
||||||
|
{label: "#d2", count: 2}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "VK_BACK_SPACE",
|
key: "VK_BACK_SPACE",
|
||||||
|
@ -90,9 +98,9 @@ add_task(function* () {
|
||||||
"There are expected number of suggestions.");
|
"There are expected number of suggestions.");
|
||||||
|
|
||||||
for (let i = 0; i < suggestions.length; i++) {
|
for (let i = 0; i < suggestions.length; i++) {
|
||||||
is(suggestions[i].label, actualSuggestions[i].label,
|
is(actualSuggestions[i].label, suggestions[i].label,
|
||||||
"The suggestion at " + i + "th index is correct.");
|
"The suggestion at " + i + "th index is correct.");
|
||||||
is(suggestions[i].count || 1, actualSuggestions[i].count,
|
is(actualSuggestions[i].count, suggestions[i].count || 1,
|
||||||
"The count for suggestion at " + i + "th index is correct.");
|
"The count for suggestion at " + i + "th index is correct.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -100,6 +108,6 @@ add_task(function* () {
|
||||||
|
|
||||||
function formatSuggestions(suggestions) {
|
function formatSuggestions(suggestions) {
|
||||||
return "[" + suggestions
|
return "[" + suggestions
|
||||||
.map(s => "'" + s.label + "' (" + s.count || 1 + ")")
|
.map(s => "'" + s.label + "' (" + (s.count || 1) + ")")
|
||||||
.join(", ") + "]";
|
.join(", ") + "]";
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,125 @@
|
||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
// Test that the selector-search input proposes ids and classes even when . and
|
||||||
|
// # is missing, but that this only occurs when the query is one word (no
|
||||||
|
// selector combination)
|
||||||
|
|
||||||
|
function test()
|
||||||
|
{
|
||||||
|
waitForExplicitFinish();
|
||||||
|
|
||||||
|
let inspector, searchBox, state, popup;
|
||||||
|
|
||||||
|
// The various states of the inspector: [key, suggestions array]
|
||||||
|
// [
|
||||||
|
// what key to press,
|
||||||
|
// suggestions array with count [
|
||||||
|
// [suggestion1, count1], [suggestion2] ...
|
||||||
|
// ] count can be left to represent 1
|
||||||
|
// ]
|
||||||
|
let keyStates = [
|
||||||
|
["s", [["span", 1], [".span", 1], ["#span", 1]]],
|
||||||
|
["p", [["span", 1], [".span", 1], ["#span", 1]]],
|
||||||
|
["a", [["span", 1], [".span", 1], ["#span", 1]]],
|
||||||
|
["n", []],
|
||||||
|
[" ", [["span div", 1]]],
|
||||||
|
["d", [["span div", 1]]], // mixed tag/class/id suggestions only work for the first word
|
||||||
|
["VK_BACK_SPACE", [["span div", 1]]],
|
||||||
|
["VK_BACK_SPACE", []],
|
||||||
|
["VK_BACK_SPACE", [["span", 1], [".span", 1], ["#span", 1]]],
|
||||||
|
["VK_BACK_SPACE", [["span", 1], [".span", 1], ["#span", 1]]],
|
||||||
|
["VK_BACK_SPACE", [["span", 1], [".span", 1], ["#span", 1]]],
|
||||||
|
["VK_BACK_SPACE", []],
|
||||||
|
// Test that mixed tags, classes and ids are grouped by types, sorted by
|
||||||
|
// count and alphabetical order
|
||||||
|
["b", [
|
||||||
|
["button", 3],
|
||||||
|
["body", 1],
|
||||||
|
[".bc", 3],
|
||||||
|
[".ba", 1],
|
||||||
|
[".bb", 1],
|
||||||
|
["#ba", 1],
|
||||||
|
["#bb", 1],
|
||||||
|
["#bc", 1]
|
||||||
|
]],
|
||||||
|
];
|
||||||
|
|
||||||
|
gBrowser.selectedTab = gBrowser.addTab();
|
||||||
|
gBrowser.selectedBrowser.addEventListener("load", function onload() {
|
||||||
|
gBrowser.selectedBrowser.removeEventListener("load", onload, true);
|
||||||
|
waitForFocus(setupTest, content);
|
||||||
|
}, true);
|
||||||
|
|
||||||
|
content.location = "data:text/html," +
|
||||||
|
"<span class='span' id='span'>" +
|
||||||
|
" <div class='div' id='div'></div>" +
|
||||||
|
"</span>" +
|
||||||
|
"<button class='ba bc' id='bc'></button>" +
|
||||||
|
"<button class='bb bc' id='bb'></button>" +
|
||||||
|
"<button class='bc' id='ba'></button>";
|
||||||
|
|
||||||
|
function $(id) {
|
||||||
|
if (id == null) return null;
|
||||||
|
return content.document.getElementById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setupTest()
|
||||||
|
{
|
||||||
|
openInspector(startTest);
|
||||||
|
}
|
||||||
|
|
||||||
|
function startTest(aInspector)
|
||||||
|
{
|
||||||
|
inspector = aInspector;
|
||||||
|
|
||||||
|
searchBox =
|
||||||
|
inspector.panelWin.document.getElementById("inspector-searchbox");
|
||||||
|
popup = inspector.searchSuggestions.searchPopup;
|
||||||
|
|
||||||
|
focusSearchBoxUsingShortcut(inspector.panelWin, function() {
|
||||||
|
searchBox.addEventListener("command", checkState, true);
|
||||||
|
checkStateAndMoveOn(0);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkStateAndMoveOn(index) {
|
||||||
|
if (index == keyStates.length) {
|
||||||
|
finishUp();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let [key, suggestions] = keyStates[index];
|
||||||
|
state = index;
|
||||||
|
|
||||||
|
info("pressing key " + key + " to get suggestions " +
|
||||||
|
JSON.stringify(suggestions));
|
||||||
|
EventUtils.synthesizeKey(key, {}, inspector.panelWin);
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkState(event) {
|
||||||
|
inspector.searchSuggestions._lastQuery.then(() => {
|
||||||
|
let [key, suggestions] = keyStates[state];
|
||||||
|
let actualSuggestions = popup.getItems();
|
||||||
|
is(popup.isOpen ? actualSuggestions.length: 0, suggestions.length,
|
||||||
|
"There are expected number of suggestions at " + state + "th step.");
|
||||||
|
actualSuggestions.reverse();
|
||||||
|
for (let i = 0; i < suggestions.length; i++) {
|
||||||
|
is(suggestions[i][0], actualSuggestions[i].label,
|
||||||
|
"The suggestion at " + i + "th index for " + state +
|
||||||
|
"th step is correct.")
|
||||||
|
is(suggestions[i][1] || 1, actualSuggestions[i].count,
|
||||||
|
"The count for suggestion at " + i + "th index for " + state +
|
||||||
|
"th step is correct.")
|
||||||
|
}
|
||||||
|
checkStateAndMoveOn(state + 1);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function finishUp() {
|
||||||
|
searchBox = null;
|
||||||
|
popup = null;
|
||||||
|
gBrowser.removeCurrentTab();
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
}
|
|
@ -757,39 +757,54 @@ CSSCompleter.prototype = {
|
||||||
result = result.suggestions;
|
result = result.suggestions;
|
||||||
let query = this.selector;
|
let query = this.selector;
|
||||||
let completion = [];
|
let completion = [];
|
||||||
for (let value of result) {
|
for (let [value, count, state] of result) {
|
||||||
switch(this.selectorState) {
|
switch(this.selectorState) {
|
||||||
case SELECTOR_STATES.id:
|
case SELECTOR_STATES.id:
|
||||||
case SELECTOR_STATES.class:
|
case SELECTOR_STATES.class:
|
||||||
case SELECTOR_STATES.pseudo:
|
case SELECTOR_STATES.pseudo:
|
||||||
if (/^[.:#]$/.test(this.completing)) {
|
if (/^[.:#]$/.test(this.completing)) {
|
||||||
value[0] = query.slice(0, query.length - this.completing.length) +
|
value = query.slice(0, query.length - this.completing.length) +
|
||||||
value[0];
|
value;
|
||||||
} else {
|
} else {
|
||||||
value[0] = query.slice(0, query.length - this.completing.length - 1) +
|
value = query.slice(0, query.length - this.completing.length - 1) +
|
||||||
value[0];
|
value;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SELECTOR_STATES.tag:
|
case SELECTOR_STATES.tag:
|
||||||
value[0] = query.slice(0, query.length - this.completing.length) +
|
value = query.slice(0, query.length - this.completing.length) +
|
||||||
value[0];
|
value;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SELECTOR_STATES.null:
|
case SELECTOR_STATES.null:
|
||||||
value[0] = query + value[0];
|
value = query + value;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
value[0] = query.slice(0, query.length - this.completing.length) +
|
value = query.slice(0, query.length - this.completing.length) +
|
||||||
value[0];
|
value;
|
||||||
}
|
}
|
||||||
completion.push({
|
|
||||||
label: value[0],
|
let item = {
|
||||||
|
label: value,
|
||||||
preLabel: query,
|
preLabel: query,
|
||||||
text: value[0],
|
text: value,
|
||||||
score: value[1]
|
score: count
|
||||||
});
|
};
|
||||||
|
|
||||||
|
// In case the query's state is tag and the item's state is id or class
|
||||||
|
// adjust the preLabel
|
||||||
|
if (this.selectorState === SELECTOR_STATES.tag &&
|
||||||
|
state === SELECTOR_STATES.class) {
|
||||||
|
item.preLabel = "." + item.preLabel;
|
||||||
|
}
|
||||||
|
if (this.selectorState === SELECTOR_STATES.tag &&
|
||||||
|
state === SELECTOR_STATES.id) {
|
||||||
|
item.preLabel = "#" + item.preLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
completion.push(item);
|
||||||
|
|
||||||
if (completion.length > this.maxEntries - 1)
|
if (completion.length > this.maxEntries - 1)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,8 +21,8 @@
|
||||||
[[21, 9], ["-moz-calc", "auto", "calc", "inherit", "initial","unset"]],
|
[[21, 9], ["-moz-calc", "auto", "calc", "inherit", "initial","unset"]],
|
||||||
[[22, 5], ['color', 'color-interpolation', 'color-interpolation-filters']],
|
[[22, 5], ['color', 'color-interpolation', 'color-interpolation-filters']],
|
||||||
[[25, 26], ['.devtools-toolbarbutton > tab',
|
[[25, 26], ['.devtools-toolbarbutton > tab',
|
||||||
'.devtools-toolbarbutton > .toolbarbutton-menubutton-button',
|
'.devtools-toolbarbutton > hbox',
|
||||||
'.devtools-toolbarbutton > hbox']],
|
'.devtools-toolbarbutton > .toolbarbutton-menubutton-button']],
|
||||||
[[25, 31], ['.devtools-toolbarbutton > hbox.toolbarbutton-menubutton-button']],
|
[[25, 31], ['.devtools-toolbarbutton > hbox.toolbarbutton-menubutton-button']],
|
||||||
[[29, 20], ['.devtools-menulist:after', '.devtools-menulist:active']],
|
[[29, 20], ['.devtools-menulist:after', '.devtools-menulist:active']],
|
||||||
[[30, 10], ['#devtools-anotherone', '#devtools-itjustgoeson', '#devtools-menu',
|
[[30, 10], ['#devtools-anotherone', '#devtools-itjustgoeson', '#devtools-menu',
|
||||||
|
@ -31,6 +31,6 @@
|
||||||
[[43, 51], ['.devtools-toolbarbutton:not([checked=true]):hover:after',
|
[[43, 51], ['.devtools-toolbarbutton:not([checked=true]):hover:after',
|
||||||
'.devtools-toolbarbutton:not([checked=true]):hover:active']],
|
'.devtools-toolbarbutton:not([checked=true]):hover:active']],
|
||||||
[[58, 36], ['!important;']],
|
[[58, 36], ['!important;']],
|
||||||
[[73, 42], [':last-child', ':lang(', ':last-of-type', ':link']],
|
[[73, 42], [':lang(', ':last-of-type', ':link', ':last-child']],
|
||||||
[[77, 25], ['.visible']],
|
[[77, 25], ['.visible']],
|
||||||
]
|
]
|
||||||
|
|
|
@ -1015,7 +1015,7 @@ var NodeListActor = exports.NodeListActor = protocol.ActorClass({
|
||||||
form: function() {
|
form: function() {
|
||||||
return {
|
return {
|
||||||
actor: this.actorID,
|
actor: this.actorID,
|
||||||
length: this.nodeList.length
|
length: this.nodeList ? this.nodeList.length : 0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1868,7 +1868,7 @@ var WalkerActor = protocol.ActorClass({
|
||||||
sugs.classes.delete(HIDDEN_CLASS);
|
sugs.classes.delete(HIDDEN_CLASS);
|
||||||
for (let [className, count] of sugs.classes) {
|
for (let [className, count] of sugs.classes) {
|
||||||
if (className.startsWith(completing)) {
|
if (className.startsWith(completing)) {
|
||||||
result.push(["." + className, count]);
|
result.push(["." + className, count, selectorState]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1885,7 +1885,7 @@ var WalkerActor = protocol.ActorClass({
|
||||||
}
|
}
|
||||||
for (let [id, count] of sugs.ids) {
|
for (let [id, count] of sugs.ids) {
|
||||||
if (id.startsWith(completing)) {
|
if (id.startsWith(completing)) {
|
||||||
result.push(["#" + id, count]);
|
result.push(["#" + id, count, selectorState]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1903,9 +1903,20 @@ var WalkerActor = protocol.ActorClass({
|
||||||
}
|
}
|
||||||
for (let [tag, count] of sugs.tags) {
|
for (let [tag, count] of sugs.tags) {
|
||||||
if ((new RegExp("^" + completing + ".*", "i")).test(tag)) {
|
if ((new RegExp("^" + completing + ".*", "i")).test(tag)) {
|
||||||
result.push([tag, count]);
|
result.push([tag, count, selectorState]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For state 'tag' (no preceding # or .) and when there's no query (i.e.
|
||||||
|
// only one word) then search for the matching classes and ids
|
||||||
|
if (!query) {
|
||||||
|
result = [
|
||||||
|
...result,
|
||||||
|
...this.getSuggestionsForQuery(null, completing, "class").suggestions,
|
||||||
|
...this.getSuggestionsForQuery(null, completing, "id").suggestions
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "null":
|
case "null":
|
||||||
|
@ -1935,11 +1946,38 @@ var WalkerActor = protocol.ActorClass({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort alphabetically in increaseing order.
|
// Sort by count (desc) and name (asc)
|
||||||
result = result.sort();
|
result = result.sort((a, b) => {
|
||||||
// Sort based on count in decreasing order.
|
// Computed a sortable string with first the inverted count, then the name
|
||||||
result = result.sort(function(a, b) {
|
let sortA = (10000-a[1]) + a[0];
|
||||||
return b[1] - a[1];
|
let sortB = (10000-b[1]) + b[0];
|
||||||
|
|
||||||
|
// Prefixing ids, classes and tags, to group results
|
||||||
|
let firstA = a[0].substring(0, 1);
|
||||||
|
let firstB = b[0].substring(0, 1);
|
||||||
|
|
||||||
|
if (firstA === "#") {
|
||||||
|
sortA = "2" + sortA;
|
||||||
|
}
|
||||||
|
else if (firstA === ".") {
|
||||||
|
sortA = "1" + sortA;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sortA = "0" + sortA;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (firstB === "#") {
|
||||||
|
sortB = "2" + sortB;
|
||||||
|
}
|
||||||
|
else if (firstB === ".") {
|
||||||
|
sortB = "1" + sortB;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sortB = "0" + sortB;
|
||||||
|
}
|
||||||
|
|
||||||
|
// String compare
|
||||||
|
return sortA.localeCompare(sortB);
|
||||||
});
|
});
|
||||||
|
|
||||||
result.slice(0, 25);
|
result.slice(0, 25);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче