diff --git a/modules/presets/collection.js b/modules/presets/collection.js index d9e6c5631..f16960173 100644 --- a/modules/presets/collection.js +++ b/modules/presets/collection.js @@ -9,8 +9,8 @@ import { utilEditDistance } from '../util/index'; export function presetCollection(collection) { - var maxSearchResults = 50, - maxSuggestionResults = 10; + var maxSearchResults = 50; + var maxSuggestionResults = 10; var presets = { @@ -51,20 +51,20 @@ export function presetCollection(collection) { value = value.toLowerCase(); var searchable = _filter(this.collection, function(a) { - return a.searchable !== false && a.suggestion !== true; - }), - suggestions = _filter(this.collection, function(a) { - return a.suggestion === true; - }); + return a.searchable !== false && a.suggestion !== true; + }); + var suggestions = _filter(this.collection, function(a) { + return a.suggestion === true; + }); // matches value to preset.name var leading_name = _filter(searchable, function(a) { return leading(a.name().toLowerCase()); }).sort(function(a, b) { - var aCompare = a.name().toLowerCase(), - bCompare = b.name().toLowerCase(), - i; + var aCompare = a.name().toLowerCase(); + var bCompare = b.name().toLowerCase(); + var i; // priority if search string matches preset name exactly - #4325 if (value === aCompare) return -1; @@ -84,21 +84,19 @@ export function presetCollection(collection) { // matches value to preset.terms values var leading_terms = _filter(searchable, function(a) { - return _some(a.terms() || [], leading); - }); + return _some(a.terms() || [], leading); + }); // matches value to preset.tags values var leading_tag_values = _filter(searchable, function(a) { - return _some(_without(_values(a.tags || {}), '*'), leading); - }); + return _some(_without(_values(a.tags || {}), '*'), leading); + }); // finds close matches to value in preset.name - var similar_name = searchable.map(function(a) { - return { - preset: a, - dist: utilEditDistance(value, a.name()) - }; + var similar_name = searchable + .map(function(a) { + return { preset: a, dist: utilEditDistance(value, a.name()) }; }).filter(function(a) { return a.dist + Math.min(value.length - a.preset.name().length, 0) < 3; }).sort(function(a, b) { @@ -125,10 +123,7 @@ export function presetCollection(collection) { }); var similar_suggestions = suggestions.map(function(a) { - return { - preset: a, - dist: utilEditDistance(value, suggestionName(a.name())) - }; + return { preset: a, dist: utilEditDistance(value, suggestionName(a.name())) }; }).filter(function(a) { return a.dist + Math.min(value.length - suggestionName(a.preset.name()).length, 0) < 1; }).sort(function(a, b) { @@ -140,13 +135,13 @@ export function presetCollection(collection) { var other = presets.item(geometry); var results = leading_name.concat( - leading_terms, - leading_tag_values, - leading_suggestions.slice(0, maxSuggestionResults + 5), - similar_name, - similar_terms, - similar_suggestions.slice(0, maxSuggestionResults) - ).slice(0, maxSearchResults - 1); + leading_terms, + leading_tag_values, + leading_suggestions.slice(0, maxSuggestionResults + 5), + similar_name, + similar_terms, + similar_suggestions.slice(0, maxSuggestionResults) + ).slice(0, maxSearchResults - 1); return presetCollection(_uniq(results.concat(other))); } diff --git a/modules/presets/preset.js b/modules/presets/preset.js index f4e4db27d..e31d62e5f 100644 --- a/modules/presets/preset.js +++ b/modules/presets/preset.js @@ -28,8 +28,8 @@ export function presetPreset(id, preset, fields) { preset.matchScore = function(entity) { - var tags = preset.tags, - score = 0; + var tags = preset.tags; + var score = 0; for (var t in tags) { if (entity.tags[t] === tags[t]) { diff --git a/modules/ui/fields/localized.js b/modules/ui/fields/localized.js index b1200694b..518348a75 100644 --- a/modules/ui/fields/localized.js +++ b/modules/ui/fields/localized.js @@ -46,12 +46,48 @@ export function uiFieldLocalized(field, context) { .merge(input); if (field.id === 'name') { - // var preset = context.presets().match(_entity, context.graph()); - // input - // .call(d3_combobox() - // .container(context.container()) - // .fetcher(suggestNames(preset, dataSuggestions)) - // ); + var presets = context.presets(); + var preset = presets.match(_entity, context.graph()); + var isFallback = preset.isFallback(); + var pTag = preset.id.split('/', 2); + var pKey = pTag[0]; + var pValue = pTag[1]; + + var allSuggestions = presets.collection.filter(function(p) { + return p.suggestion === true; + }); + + // This code attempts to determine if the matched preset is the + // kind of preset that even can benefit from name suggestions.. + // - true = shops, cafes, hotels, etc. (also generic and fallback presets) + // - false = churches, parks, hospitals, etc. (things not in the index) + var goodSuggestions = allSuggestions.filter(function(s) { + if (isFallback) return true; + var sTag = s.id.split('/', 2); + var sKey = sTag[0]; + var sValue = sTag[1]; + return pKey === sKey && (!pValue || pValue === sValue); + }); + + // Show the suggestions.. If the user picks one, change the tags.. + if (allSuggestions.length && goodSuggestions.length) { + input + .call(d3_combobox() + .container(context.container()) + .fetcher(suggestNames(preset, allSuggestions)) + .minItems(1) + .on('accept', function(d) { + var tags = _entity.tags; + var geometry = _entity.geometry(context.graph()); + var removed = preset.removeTags(tags, geometry); + for (var k in tags) { + tags[k] = removed[k]; // set removed tags to `undefined` + } + tags = d.suggestion.applyTags(tags, geometry); + dispatch.call('change', this, tags); + }) + ); + } } input @@ -87,31 +123,36 @@ export function uiFieldLocalized(field, context) { function suggestNames(preset, suggestions) { - preset = preset.id.split('/', 2); - var k = preset[0]; - var v = preset[1]; + var pTag = preset.id.split('/', 2); + var pKey = pTag[0]; + var pValue = pTag[1]; return function(value, callback) { - var result = []; + var results = []; if (value && value.length > 2) { - if (suggestions[k] && suggestions[k][v]) { - for (var sugg in suggestions[k][v]) { - var dist = utilEditDistance(value, sugg.substring(0, value.length)); - if (dist < 3) { - result.push({ - title: sugg, - value: sugg, - dist: dist - }); - } + for (var i = 0; i < suggestions.length; i++) { + var s = suggestions[i]; + var sTag = s.id.split('/', 2); + var sKey = sTag[0]; + var sValue = sTag[1]; + var name = s.name(); + var dist = utilEditDistance(value, name.substring(0, value.length)); + var matchesPreset = (pKey === sKey && (!pValue || pValue === sValue)); + + if (dist < 1 || (matchesPreset && dist < 3)) { + var obj = { + title: name, + value: name, + suggestion: s, + dist: dist + (matchesPreset ? 0 : 1) // penalize if not matched preset + }; + results.push(obj); } } - result.sort(function(a, b) { - return a.dist - b.dist; - }); + results.sort(function(a, b) { return a.dist - b.dist; }); } - result = result.slice(0,3); - callback(result); + results = results.slice(0, 10); + callback(results); }; }