|
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