mirror of
https://github.com/FoggedLens/iD.git
synced 2026-05-15 21:48:20 +02:00
Improve suggestion combo behavior in the name field
- adds minItems(1) so it will match - displays up to 10 suggestions - correctly removes old tags by setting the `undefined` - adjust the name distance scoring - only shows name suggestions if the preset can benefit from them (i.e. a generic/fallback or a preset that has some suggestions in the index)
This commit is contained in:
@@ -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)));
|
||||
}
|
||||
|
||||
@@ -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]) {
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user