|
146 | 146 | inputClass: 'selectize-input', |
147 | 147 | dropdownClass: 'selectize-dropdown', |
148 | 148 |
|
| 149 | + score : null, // function(data) |
149 | 150 | onChange : null, // function(value) |
150 | 151 | onItemAdd : null, // function(value, $item) { ... } |
151 | 152 | onItemRemove : null, // function(value) { ... } |
|
908 | 909 | return tokens; |
909 | 910 | }; |
910 | 911 |
|
| 912 | + /** |
| 913 | + * Returns a function to be used to score individual results. |
| 914 | + * Results will be sorted by the score (descending). Scores less |
| 915 | + * than or equal to zero (no match) will not be included in the results. |
| 916 | + * |
| 917 | + * @param {object} data |
| 918 | + * @param {object} search |
| 919 | + * @returns {function} |
| 920 | + */ |
| 921 | + Selectize.prototype.getScoreCallback = function(search) { |
| 922 | + var self = this; |
| 923 | + var tokens = search.tokens; |
| 924 | + |
| 925 | + var calculateFieldScore = (function() { |
| 926 | + if (!tokens.length) { |
| 927 | + return function() { return 0; }; |
| 928 | + } else if (tokens.length === 1) { |
| 929 | + return function(value) { |
| 930 | + var score, pos; |
| 931 | + |
| 932 | + value = String(value || '').toLowerCase(); |
| 933 | + pos = value.search(tokens[0].regex); |
| 934 | + if (pos === -1) return 0; |
| 935 | + score = tokens[0].string.length / value.length; |
| 936 | + if (pos === 0) score += 0.5; |
| 937 | + return score; |
| 938 | + }; |
| 939 | + } else { |
| 940 | + return function(value) { |
| 941 | + var score, pos, i, j; |
| 942 | + |
| 943 | + value = String(value || '').toLowerCase(); |
| 944 | + score = 0; |
| 945 | + for (i = 0, j = tokens.length; i < j; i++) { |
| 946 | + pos = value.search(tokens[i].regex); |
| 947 | + if (pos === -1) return 0; |
| 948 | + if (pos === 0) score += 0.5; |
| 949 | + score += tokens[i].string.length / value.length; |
| 950 | + } |
| 951 | + return score / tokens.length; |
| 952 | + }; |
| 953 | + } |
| 954 | + })(); |
| 955 | + |
| 956 | + var calculateScore = (function() { |
| 957 | + var fields = self.settings.searchField; |
| 958 | + if (typeof fields === 'string') { |
| 959 | + fields = [fields]; |
| 960 | + } |
| 961 | + if (!fields || !fields.length) { |
| 962 | + return function() { return 0; }; |
| 963 | + } else if (fields.length === 1) { |
| 964 | + var field = fields[0]; |
| 965 | + return function(data) { |
| 966 | + if (!data.hasOwnProperty(field)) return 0; |
| 967 | + return calculateFieldScore(data[field]); |
| 968 | + }; |
| 969 | + } else { |
| 970 | + return function(data) { |
| 971 | + var n = 0; |
| 972 | + var score = 0; |
| 973 | + for (var i = 0, j = fields.length; i < j; i++) { |
| 974 | + if (data.hasOwnProperty(fields[i])) { |
| 975 | + score += calculateFieldScore(data[fields[i]]); |
| 976 | + n++; |
| 977 | + } |
| 978 | + } |
| 979 | + return score / n; |
| 980 | + }; |
| 981 | + } |
| 982 | + })(); |
| 983 | + |
| 984 | + return calculateScore; |
| 985 | + }; |
| 986 | + |
911 | 987 | /** |
912 | 988 | * Searches through available options and returns |
913 | 989 | * a sorted array of matches. Includes options that |
|
931 | 1007 | * @returns {object} |
932 | 1008 | */ |
933 | 1009 | Selectize.prototype.search = function(query, settings) { |
| 1010 | + var self = this; |
| 1011 | + var value, score, search, calculateScore; |
| 1012 | + |
934 | 1013 | settings = settings || {}; |
935 | 1014 | query = $.trim(String(query || '').toLowerCase()); |
936 | 1015 |
|
937 | | - var self = this; |
938 | | - var tokens, value, score, results; |
939 | | - |
940 | 1016 | if (query !== this.lastQuery) { |
941 | 1017 | this.lastQuery = query; |
942 | | - tokens = this.parseSearchTokens(query); |
943 | 1018 |
|
944 | | - results = { |
| 1019 | + search = { |
945 | 1020 | query : query, |
946 | | - tokens : tokens, |
| 1021 | + tokens : this.parseSearchTokens(query), |
947 | 1022 | total : 0, |
948 | 1023 | items : [] |
949 | 1024 | }; |
950 | 1025 |
|
951 | | - var calculateFieldScore = (function() { |
952 | | - if (!tokens.length) { |
953 | | - return function() { return 0; }; |
954 | | - } else if (tokens.length === 1) { |
955 | | - return function(value) { |
956 | | - var score, pos; |
957 | | - |
958 | | - value = String(value || '').toLowerCase(); |
959 | | - pos = value.search(tokens[0].regex); |
960 | | - if (pos === -1) return 0; |
961 | | - score = tokens[0].string.length / value.length; |
962 | | - if (pos === 0) score += 0.5; |
963 | | - return score; |
964 | | - }; |
965 | | - } else { |
966 | | - return function(value) { |
967 | | - var score, pos, i, j; |
968 | | - |
969 | | - value = String(value || '').toLowerCase(); |
970 | | - score = 0; |
971 | | - for (i = 0, j = tokens.length; i < j; i++) { |
972 | | - pos = value.search(tokens[i].regex); |
973 | | - if (pos === -1) return 0; |
974 | | - if (pos === 0) score += 0.5; |
975 | | - score += tokens[i].string.length / value.length; |
976 | | - } |
977 | | - return score / tokens.length; |
978 | | - }; |
979 | | - } |
980 | | - })(); |
981 | | - |
982 | | - var calculateScore = (function() { |
983 | | - var fields = self.settings.searchField; |
984 | | - if (typeof fields === 'string') { |
985 | | - fields = [fields]; |
986 | | - } |
987 | | - if (!fields || !fields.length) { |
988 | | - return function() { return 0; }; |
989 | | - } else if (fields.length === 1) { |
990 | | - var field = fields[0]; |
991 | | - return function(data) { |
992 | | - if (!data.hasOwnProperty(field)) return 0; |
993 | | - return calculateFieldScore(data[field]); |
994 | | - }; |
995 | | - } else { |
996 | | - return function(data) { |
997 | | - var n = 0; |
998 | | - var score = 0; |
999 | | - for (var i = 0, j = fields.length; i < j; i++) { |
1000 | | - if (data.hasOwnProperty(fields[i])) { |
1001 | | - score += calculateFieldScore(data[fields[i]]); |
1002 | | - n++; |
1003 | | - } |
1004 | | - } |
1005 | | - return score / n; |
1006 | | - }; |
1007 | | - } |
1008 | | - })(); |
| 1026 | + calculateScore = this.settings.score || this.getScoreCallback(search); |
1009 | 1027 |
|
| 1028 | + // perform search and sort |
1010 | 1029 | if (query.length) { |
1011 | 1030 | for (value in this.options) { |
1012 | 1031 | if (this.options.hasOwnProperty(value)) { |
1013 | 1032 | score = calculateScore(this.options[value]); |
1014 | 1033 | if (score > 0) { |
1015 | | - results.items.push({ |
| 1034 | + search.items.push({ |
1016 | 1035 | score: score, |
1017 | 1036 | value: value |
1018 | 1037 | }); |
1019 | 1038 | } |
1020 | 1039 | } |
1021 | 1040 | } |
1022 | | - results.items.sort(function(a, b) { |
| 1041 | + search.items.sort(function(a, b) { |
1023 | 1042 | return b.score - a.score; |
1024 | 1043 | }); |
1025 | 1044 | } else { |
1026 | 1045 | for (value in this.options) { |
1027 | 1046 | if (this.options.hasOwnProperty(value)) { |
1028 | | - results.items.push({ |
| 1047 | + search.items.push({ |
1029 | 1048 | score: 1, |
1030 | 1049 | value: value |
1031 | 1050 | }); |
1032 | 1051 | } |
1033 | 1052 | } |
1034 | 1053 | if (this.settings.sortField) { |
1035 | | - results.items.sort((function() { |
| 1054 | + search.items.sort((function() { |
1036 | 1055 | var field = self.settings.sortField; |
1037 | 1056 | var multiplier = self.settings.sortDirection === 'desc' ? -1 : 1; |
1038 | 1057 | return function(a, b) { |
|
1045 | 1064 | })()); |
1046 | 1065 | } |
1047 | 1066 | } |
1048 | | - this.currentResults = results; |
| 1067 | + this.currentResults = search; |
1049 | 1068 | } else { |
1050 | | - results = $.extend(true, {}, this.currentResults); |
| 1069 | + search = $.extend(true, {}, this.currentResults); |
1051 | 1070 | } |
1052 | 1071 |
|
1053 | | - return this.prepareResults(results, settings); |
| 1072 | + // apply limits and return |
| 1073 | + return this.prepareResults(search, settings); |
1054 | 1074 | }; |
1055 | 1075 |
|
1056 | 1076 | /** |
|
1061 | 1081 | * @param {object} settings |
1062 | 1082 | * @returns {object} |
1063 | 1083 | */ |
1064 | | - Selectize.prototype.prepareResults = function(results, settings) { |
| 1084 | + Selectize.prototype.prepareResults = function(search, settings) { |
1065 | 1085 | if (this.settings.hideSelected) { |
1066 | | - for (var i = results.items.length - 1; i >= 0; i--) { |
1067 | | - if (this.items.indexOf(String(results.items[i].value)) !== -1) { |
1068 | | - results.items.splice(i, 1); |
| 1086 | + for (var i = search.items.length - 1; i >= 0; i--) { |
| 1087 | + if (this.items.indexOf(String(search.items[i].value)) !== -1) { |
| 1088 | + search.items.splice(i, 1); |
1069 | 1089 | } |
1070 | 1090 | } |
1071 | 1091 | } |
1072 | 1092 |
|
1073 | | - results.total = results.items.length; |
| 1093 | + search.total = search.items.length; |
1074 | 1094 | if (typeof settings.limit === 'number') { |
1075 | | - results.items = results.items.slice(0, settings.limit); |
| 1095 | + search.items = search.items.slice(0, settings.limit); |
1076 | 1096 | } |
1077 | 1097 |
|
1078 | | - return results; |
| 1098 | + return search; |
1079 | 1099 | }; |
1080 | 1100 |
|
1081 | 1101 | /** |
|
1147 | 1167 | * @param {object} data |
1148 | 1168 | */ |
1149 | 1169 | Selectize.prototype.addOption = function(value, data) { |
| 1170 | + if ($.isArray(value)) { |
| 1171 | + for (var i = 0, n = value.length; i < n; i++) { |
| 1172 | + this.addOption(value[i][this.settings.valueField], value[i]); |
| 1173 | + } |
| 1174 | + return; |
| 1175 | + } |
| 1176 | + |
1150 | 1177 | if (this.options.hasOwnProperty(value)) return; |
1151 | 1178 | value = String(value); |
1152 | 1179 | this.userOptions[value] = true; |
|
0 commit comments