@@ -136489,7 +136489,28 @@ define("utils/ColorUtils", function (require, exports, module) {
136489136489 * and "rebeccapurple" from CSS Color Module Level 4
136490136490 * @const @type {Array}
136491136491 */
136492- var COLOR_NAMES = ["aliceblue", "antiquewhite", "aqua", "aquamarine", "azure", "beige", "bisque", "black", "blanchedalmond", "blue", "blueviolet", "brown", "burlywood", "cadetblue", "chartreuse", "chocolate", "coral", "cornflowerblue", "cornsilk", "crimson", "cyan", "darkblue", "darkcyan", "darkgoldenrod", "darkgray", "darkgreen", "darkgrey", "darkkhaki", "darkmagenta", "darkolivegreen", "darkorange", "darkorchid", "darkred", "darksalmon", "darkseagreen", "darkslateblue", "darkslategray", "darkslategrey", "darkturquoise", "darkviolet", "deeppink", "deepskyblue", "dimgray", "dimgrey", "dodgerblue", "firebrick", "floralwhite", "forestgreen", "fuchsia", "gainsboro", "ghostwhite", "gold", "goldenrod", "gray", "green", "greenyellow", "grey", "honeydew", "hotpink", "indianred", "indigo", "ivory", "khaki", "lavender", "lavenderblush", "lawngreen", "lemonchiffon", "lightblue", "lightcoral", "lightcyan", "lightgoldenrodyellow", "lightgray", "lightgreen", "lightgrey", "lightpink", "lightsalmon", "lightseagreen", "lightskyblue", "lightslategray", "lightslategrey", "lightsteelblue", "lightyellow", "lime", "limegreen", "linen", "magenta", "maroon", "mediumaquamarine", "mediumblue", "mediumorchid", "mediumpurple", "mediumseagreen", "mediumslateblue", "mediumspringgreen", "mediumturquoise", "mediumvioletred", "midnightblue", "mintcream", "mistyrose", "moccasin", "navajowhite", "navy", "oldlace", "olive", "olivedrab", "orange", "orangered", "orchid", "palegoldenrod", "palegreen", "paleturquoise", "palevioletred", "papayawhip", "peachpuff", "peru", "pink", "plum", "powderblue", "purple", "rebeccapurple", "red", "rosybrown", "royalblue", "saddlebrown", "salmon", "sandybrown", "seagreen", "seashell", "sienna", "silver", "skyblue", "slateblue", "slategray", "slategrey", "snow", "springgreen", "steelblue", "tan", "teal", "thistle", "tomato", "turquoise", "violet", "wheat", "white", "whitesmoke", "yellow", "yellowgreen"];
136492+ var COLOR_NAMES = ["aliceblue", "antiquewhite", "aqua", "aquamarine", "azure", "beige", "bisque", "black", "blanchedalmond",
136493+ "blue", "blueviolet", "brown", "burlywood", "cadetblue", "chartreuse", "chocolate", "coral",
136494+ "cornflowerblue", "cornsilk", "crimson", "cyan", "darkblue", "darkcyan", "darkgoldenrod", "darkgray",
136495+ "darkgreen", "darkgrey", "darkkhaki", "darkmagenta", "darkolivegreen", "darkorange", "darkorchid",
136496+ "darkred", "darksalmon", "darkseagreen", "darkslateblue", "darkslategray", "darkslategrey",
136497+ "darkturquoise", "darkviolet", "deeppink", "deepskyblue", "dimgray", "dimgrey", "dodgerblue",
136498+ "firebrick", "floralwhite", "forestgreen", "fuchsia", "gainsboro", "ghostwhite", "gold", "goldenrod",
136499+ "gray", "green", "greenyellow", "grey", "honeydew", "hotpink", "indianred", "indigo", "ivory", "khaki",
136500+ "lavender", "lavenderblush", "lawngreen", "lemonchiffon", "lightblue", "lightcoral", "lightcyan",
136501+ "lightgoldenrodyellow", "lightgray", "lightgreen", "lightgrey", "lightpink", "lightsalmon",
136502+ "lightseagreen", "lightskyblue", "lightslategray", "lightslategrey", "lightsteelblue", "lightyellow",
136503+ "lime", "limegreen", "linen", "magenta", "maroon", "mediumaquamarine", "mediumblue", "mediumorchid",
136504+ "mediumpurple", "mediumseagreen", "mediumslateblue", "mediumspringgreen", "mediumturquoise",
136505+ "mediumvioletred", "midnightblue", "mintcream", "mistyrose", "moccasin", "navajowhite", "navy",
136506+ "oldlace", "olive", "olivedrab", "orange", "orangered", "orchid", "palegoldenrod", "palegreen",
136507+ "paleturquoise", "palevioletred", "papayawhip", "peachpuff", "peru", "pink", "plum", "powderblue",
136508+ "purple", "rebeccapurple", "red", "rosybrown", "royalblue", "saddlebrown", "salmon", "sandybrown",
136509+ "seagreen", "seashell", "sienna", "silver", "skyblue", "slateblue", "slategray", "slategrey",
136510+ "snow", "springgreen", "steelblue", "tan", "teal", "thistle", "tomato",
136511+ "turquoise", "violet", "wheat", "white", "whitesmoke", "yellow", "yellowgreen", "black",
136512+ "silver", "gray", "white", "maroon", "red", "purple", "fuchsia", "green", "lime", "olive",
136513+ "yellow", "navy", "blue", "teal", "aqua"];
136493136514
136494136515 /**
136495136516 * Regular expression that matches reasonably well-formed colors in hex format (3 or 6 digits),
@@ -136509,7 +136530,8 @@ define("utils/ColorUtils", function (require, exports, module) {
136509136530 * @return {jQuery} jQuery object with the correct class and/or style applied
136510136531 */
136511136532 function formatColorHint($hintObj, color) {
136512- if (color) {
136533+ const nonColors= ["transparent", "currentColor"];
136534+ if (color && !nonColors.includes(color)) {
136513136535 $hintObj.prepend($("<span>")
136514136536 .addClass("color-swatch")
136515136537 .css("backgroundColor", color));
@@ -142213,7 +142235,9 @@ define("utils/Resizer", function (require, exports, module) {
142213142235define("utils/StringMatch", function (require, exports, module) {
142214142236
142215142237
142216- var _ = require("thirdparty/lodash");
142238+ const _ = require("thirdparty/lodash"),
142239+ // https://www.npmjs.com/package/fuzzball string matching lib
142240+ fuzzball = Phoenix.libs.fuzzball;
142217142241
142218142242 /*
142219142243 * Performs matching that is useful for QuickOpen and similar searches.
@@ -142924,6 +142948,224 @@ define("utils/StringMatch", function (require, exports, module) {
142924142948 return result;
142925142949 }
142926142950
142951+ // see scoring explanation at https://www.npmjs.com/package/fuzzball
142952+ const RANK_MATCH_SCORER = {
142953+ // ratio // "!" Stripped and lowercased in pre-processing by default
142954+ // ("this is a test", "This is a test!"); -> 100
142955+ RATIO: "ratio",
142956+ //Highest scoring substring of the longer string vs. the shorter string.
142957+ // ("test", "testing") -> 100, substring of 2nd is a perfect match of the first
142958+ PARTIAL_RATIO: "partial_ratio",
142959+ // Tokenized, sorted, and then recombined before scoring.
142960+ // ("fuzzy wuzzy was a bear", "wuzzy fuzzy was a bear") -> 100
142961+ TOKEN_SORT_RATIO: "token_sort_ratio",
142962+ // Highest of 3 scores comparing the set intersection,
142963+ // intersection + difference 1 to 2, and intersection + difference 2 to 1.
142964+ // Eg. token_set_ratio("fuzzy was a bear", "fuzzy fuzzy was a bear") -> 100
142965+ // but token_sort_ratio("fuzzy was a bear", "fuzzy fuzzy was a bear") -> 84
142966+ TOKEN_SET_RATIO: "token_set_ratio",
142967+ // Instead of sorting alphabetically, tokens will be sorted by similarity to the smaller set.
142968+ // Useful if the matching token may have a different first letter, but performs a bit slower.
142969+ // Eg. token_similarity_sort_ratio('apple cup zebrah horse foo', 'zapple cub horse bebrah bar')
142970+ // 68
142971+ // But,token_sort_ratio('apple cup zebrah horse foo', 'zapple cub horse bebrah bar')
142972+ // 58
142973+ // token_set_ratio('apple cup zebrah horse foo', 'zapple cub horse bebrah bar')
142974+ // 61
142975+ TOKEN_SIMILARITY_SORT_RATIO: "token_similarity_sort_ratio",
142976+ // Unmodified Levenshtein distance without any additional ratio calculations.
142977+ // distance("fuzzy was a bear", "fozzy was a bear") -> 1
142978+ DISTANCE: "distance",
142979+ CODE_HINTS: "code-hints"
142980+ };
142981+
142982+ /**
142983+ * Ranks the matching strings based on the query.
142984+ *
142985+ * @param {string} query - The query string to match against.
142986+ * @param {Array<string>} choices - The list of strings to rank.
142987+ * @param {{scorer: string}|{}} options - Additional options for ranking.
142988+ * @param {string} options.scorer - The scoring algorithm to use.
142989+ * one of StringMatch.RANK_MATCH_SCORER.* constants
142990+ * @param {number} options.cutoff - The scoring cutoff below which results are
142991+ * treated as no match. default is 0.
142992+ * @param {number} options.limit - The maximum number of results to return. Default is all.
142993+ * @param {Array[string]} options.boostPrefixList - Will rank matching items in the choices to top
142994+ * if query starts with the array. EG: on typing b, we have to show background-color
142995+ * to top. So we pass in ["background-color"] as boost prefix option along with other
142996+ * css properties that we want to boost.
142997+ * @return {Array[SearchResult]} - The best matching string ranking, sorted by top ranked
142998+ */
142999+ function rankMatchingStrings(query, choices, options) {
143000+ options = options || {};
143001+ options.scorer = options.scorer || RANK_MATCH_SCORER.RATIO;
143002+ options.cutoff = options.cutoff === undefined ? 0: options.cutoff;
143003+
143004+ let searchResults = [];
143005+ if(!query) {
143006+ // everything is a 100% match if nothing is specified
143007+ choices = [...choices].sort(); // we still need to sort, not in-place, so cloning
143008+ for(let i=0; i<choices.length; i++) {
143009+ if(options.limit && i>= options.limit){
143010+ break;
143011+ }
143012+ let result = new SearchResult(choices[i]);
143013+ result.matchGoodness = 100;
143014+ result.sourceIndex = i;
143015+ searchResults.push(result);
143016+ }
143017+ return searchResults;
143018+ }
143019+
143020+ if(options.scorer === RANK_MATCH_SCORER.CODE_HINTS) {
143021+ return _rankCodeHints(query, choices, options);
143022+ }
143023+
143024+ const rankedResult = fuzzball.extract(query, choices, {
143025+ scorer: fuzzball[options.scorer],
143026+ limit: options.limit
143027+ });
143028+ // "pointer", ["pointer: none;", "cursor: pointer;", "pointer-events: none;"]
143029+ // sample output is of the form:
143030+ // [choice, score, index in original array] eg:
143031+ // [ ["pointer: none;", 74, 0],
143032+ // ["cursor: pointer;", 67, 1],
143033+ // [ "pointer-events: none;", 54, 2] ]
143034+ for(let rankResult of rankedResult) {
143035+ const score = rankResult[1];
143036+ if(score < options.cutoff) {
143037+ continue;
143038+ }
143039+ let result = new SearchResult(rankResult[0]);
143040+ result.matchGoodness = rankResult[1];
143041+ result.sourceIndex = rankResult[2];
143042+ searchResults.push(result);
143043+ }
143044+ if(options.boostPrefixList) {
143045+ searchResults = _boostPrefixList(searchResults, query, options.boostPrefixList);
143046+ }
143047+ return searchResults;
143048+ }
143049+
143050+ function _computeMatchingRanges(query, searchString) {
143051+ let index = searchString.indexOf(query);
143052+
143053+ if (index === -1) {
143054+ return null;
143055+ }
143056+ // now we have to find segment that matches the given query. Eg:
143057+ // Eg: background-color: blue;
143058+
143059+ if(index === 0 && query.length === searchString.length) {
143060+ // background-color: blue; full match case
143061+ // match is at beginning
143062+ return [{
143063+ text: searchString,
143064+ matched: true
143065+ }];
143066+ }
143067+ if(index === 0) {
143068+ // query = backgou , can be split into 2 parts <backgro>und-color: blue;
143069+ // match is at beginning
143070+ return [{
143071+ text: searchString.substr(0, query.length),
143072+ matched: true
143073+ }, {
143074+ text: searchString.substr(query.length),
143075+ matched: false
143076+ }];
143077+ }
143078+ if((index + query.length) === searchString.length) {
143079+ // query = blue; , can be split into 2 parts: background-color: <blue;>
143080+ // match is at the end
143081+ return [{
143082+ text: searchString.substr(0, index),
143083+ matched: false
143084+ }, {
143085+ text: searchString.substr(index),
143086+ matched: true
143087+ }];
143088+ }
143089+ // query = color , can be split into 3 parts: background-<color>: blue;
143090+ // middle match
143091+ return [{
143092+ text: searchString.substr(0, index),
143093+ matched: false
143094+ }, {
143095+ text: searchString.substring(index, index + query.length),
143096+ matched: true
143097+ }, {
143098+ text: searchString.substr(index + query.length),
143099+ matched: false
143100+ }];
143101+ }
143102+
143103+ function _boostPrefixList(result, query, prefixList) {
143104+ if(!prefixList){
143105+ return result;
143106+ }
143107+ const filteredPrefixMap = {};
143108+ for(let prefix of prefixList){
143109+ if(prefix.startsWith(query)){
143110+ filteredPrefixMap[prefix] = true;
143111+ }
143112+ }
143113+ const resultsWithoutPrefix = [], resultsWithPrefix = {};
143114+ for(let i=0; i<result.length; i++) {
143115+ const resultItem = result[i];
143116+ if(filteredPrefixMap[resultItem.label]) { // if result matches one of the prefix
143117+ resultsWithPrefix[resultItem.label] = resultItem;
143118+ resultItem.matchGoodness = 100; // boosted match
143119+ } else {
143120+ resultsWithoutPrefix.push(resultItem);
143121+ }
143122+ }
143123+ // we have to maintain the ordering of the items in prefix list in
143124+ // items in the result.
143125+ const orderedPrefixResults = [];
143126+ for(let prefixItem of prefixList) {
143127+ if(resultsWithPrefix[prefixItem]){
143128+ orderedPrefixResults.push(resultsWithPrefix[prefixItem]);
143129+ }
143130+ }
143131+ return [...orderedPrefixResults, ...resultsWithoutPrefix];
143132+ }
143133+
143134+ function _rankCodeHints(query, choices, options) {
143135+ query = query || "";
143136+ let filteredChoices = [];
143137+ let filteredIndices;
143138+ if(!query){
143139+ filteredChoices = choices;
143140+ } else {
143141+ filteredIndices = [];
143142+ const queryLower = query.toLowerCase();
143143+ choices.forEach((choice, index) => {
143144+ if (choice.toLowerCase().includes(queryLower)) {
143145+ filteredChoices.push(choice);
143146+ filteredIndices.push(index);
143147+ }
143148+ });
143149+ }
143150+
143151+ let results = rankMatchingStrings(query, filteredChoices, {
143152+ scorer: RANK_MATCH_SCORER.RATIO,
143153+ cutoff: 0,
143154+ limit: options.limit
143155+ });
143156+ if(filteredIndices){
143157+ for(let i=0; i<results.length; i++) {
143158+ const result = results[i];
143159+ result.sourceIndex = filteredIndices[result.sourceIndex];
143160+ // now find the matching segments.
143161+ result.stringRanges = _computeMatchingRanges(query, result.label);
143162+ }
143163+ }
143164+ if(options.boostPrefixList) {
143165+ results = _boostPrefixList(results, query, options.boostPrefixList);
143166+ }
143167+ return results;
143168+ }
142927143169
142928143170 /*
142929143171 * Match str against the query using the QuickOpen algorithm provided by
@@ -143181,6 +143423,8 @@ define("utils/StringMatch", function (require, exports, module) {
143181143423 exports.basicMatchSort = basicMatchSort;
143182143424 exports.multiFieldSort = multiFieldSort;
143183143425 exports.StringMatcher = StringMatcher;
143426+ exports.rankMatchingStrings = rankMatchingStrings;
143427+ exports.RANK_MATCH_SCORER = RANK_MATCH_SCORER;
143184143428});
143185143429
143186143430/*
0 commit comments