Move preset favoriting functions from core/context.js to presets/index.js

Make recent presets persistent and compatible with favorite presets
This commit is contained in:
Quincy Morgan
2019-03-07 16:49:29 -05:00
parent ba185d2ee6
commit 213d0ee3e8
6 changed files with 173 additions and 106 deletions
+2 -65
View File
@@ -57,7 +57,7 @@ export function coreContext() {
addTranslation('en', dataEn);
setLocale('en');
var dispatch = d3_dispatch('enter', 'exit', 'change', 'favoritePreset');
var dispatch = d3_dispatch('enter', 'exit', 'change');
// https://github.com/openstreetmap/iD/issues/772
// http://mathiasbynens.be/notes/localstorage-pattern#comment-9
@@ -313,69 +313,6 @@ export function coreContext() {
var presets;
context.presets = function() { return presets; };
context.getFavoritePresets = function() {
// get favorites from local storage
var favs = JSON.parse(context.storage('favorite_presets')) || [
// use the generic presets as the default favorites
{ id: 'point', geom: 'point'},
{ id: 'line', geom: 'line'},
{ id: 'area', geom: 'area'}
];
return favs.filter(function(d) {
// iD's presets could have changed since this favorite was saved,
// so make sure it's still valid.
var preset = presets.item(d.id);
if (preset === null) {
return false;
} else if (preset.geometry.indexOf(d.geom) === -1) {
return false;
}
return true;
});
};
function setFavoritePresets(favs) {
context.storage('favorite_presets', JSON.stringify(favs));
//and call update on modes
dispatch.call('favoritePreset');
}
context.favoritePreset = function(preset, geom) {
var favs = context.getFavoritePresets();
//add/remove favorites from local storage
if (context.isFavoritePreset(preset, geom)) {
favs = favs.filter(function(d) {
return !(d.id === preset.id && d.geom === geom);
});
} else {
// only allow 10 favorites
if (favs.length === 10) {
// remove the last favorite (last in, first out)
favs.pop();
}
// append array
favs.push({id: preset.id, geom: geom});
}
setFavoritePresets(favs);
};
context.isFavoritePreset = function(preset, geom) {
var favs = context.getFavoritePresets();
return favs.some(function(d) {
return d.id === preset.id && d.geom === geom;
});
};
context.moveFavoritePreset = function(fromIndex, toIndex) {
if (fromIndex === toIndex) return;
var favs = context.getFavoritePresets();
if (fromIndex < 0 || toIndex < 0 ||
fromIndex >= favs.length || toIndex >= favs.length) return;
favs.splice(toIndex, 0, favs.splice(fromIndex, 1)[0]);
setFavoritePresets(favs);
};
/* Map */
var map;
@@ -564,7 +501,7 @@ export function coreContext() {
connection = services.osm;
background = rendererBackground(context);
features = rendererFeatures(context);
presets = presetIndex();
presets = presetIndex(context);
if (services.maprules && utilStringQs(window.location.hash).maprules) {
var maprules = utilStringQs(window.location.hash).maprules;
+150 -19
View File
@@ -3,8 +3,8 @@ import _forEach from 'lodash-es/forEach';
import _isEmpty from 'lodash-es/isEmpty';
import _reject from 'lodash-es/reject';
import _uniq from 'lodash-es/uniq';
import _uniqWith from 'lodash-es/uniqWith';
import { dispatch as d3_dispatch } from 'd3-dispatch';
import { json as d3_json } from 'd3-request';
import { data } from '../../data/index';
@@ -12,6 +12,7 @@ import { presetCategory } from './category';
import { presetCollection } from './collection';
import { presetField } from './field';
import { presetPreset } from './preset';
import { utilRebind } from '../util';
export { presetCategory };
export { presetCollection };
@@ -19,15 +20,17 @@ export { presetField };
export { presetPreset };
export function presetIndex() {
export function presetIndex(context) {
// a presetCollection with methods for
// loading new data and returning defaults
var dispatch = d3_dispatch('favoritePreset');
var all = presetCollection([]);
var _defaults = { area: all, line: all, point: all, vertex: all, relation: all };
var _fields = {};
var _universal = [];
var _recentWithGeometry = [];
var _favorites, _recents;
// Index of presets by (geometry, tag key).
var _index = {
@@ -214,7 +217,8 @@ export function presetIndex() {
all.init = function() {
all.collection = [];
_recentWithGeometry = [];
_favorites = null;
_recents = null;
_fields = {};
_universal = [];
_index = { point: {}, vertex: {}, line: {}, area: {}, relation: {} };
@@ -228,7 +232,8 @@ export function presetIndex() {
_defaults = { area: all, line: all, point: all, vertex: all, relation: all };
_fields = {};
_universal = [];
_recentWithGeometry = [];
_favorites = null;
_recents = null;
// Index of presets by (geometry, tag key).
_index = {
@@ -270,27 +275,153 @@ export function presetIndex() {
};
all.recent = function() {
return presetCollection(_uniq(_recentWithGeometry.map(function(d) {
return presetCollection(_uniq(all.getRecents().map(function(d) {
return d.preset;
})));
};
all.recentWithGeometry = function() {
return _recentWithGeometry;
};
function RibbonItem(preset, geometry, source) {
var item = {};
item.preset = preset;
item.geometry = geometry;
item.source = source;
all.choose = function(preset, geometry) {
if (preset.searchable !== false) {
var newWithGeometry = {
preset: preset,
geometry: geometry
item.matches = function(preset, geometry) {
return item.preset.id === preset.id && item.geometry === geometry;
};
item.minified = function() {
return {
pID: item.preset.id,
geom: item.geometry
};
_recentWithGeometry = _uniqWith([newWithGeometry].concat(_recentWithGeometry), function(d1, d2) {
return d1.preset === d2.preset && d1.geometry === d2.geometry;
});
};
return item;
}
function ribbonItemForMinified(d, source) {
if (d && d.pID && d.geom) {
var preset = all.item(d.pID);
// iD's presets could have changed since this was saved,
// so make sure it's still valid.
if (preset && preset.matchGeometry(d.geom)) {
return RibbonItem(preset, d.geom, source);
}
}
return all;
return null;
}
function setFavorites(items) {
_favorites = items;
var minifiedItems = items.map(function(d) { return d.minified(); });
context.storage('preset_favorites', JSON.stringify(minifiedItems));
// call update
dispatch.call('favoritePreset');
}
all.getFavorites = function() {
if (!_favorites) {
// fetch from local storage
_favorites = (JSON.parse(context.storage('preset_favorites')) || [
// use the generic presets as the default favorites
{ pID: 'point', geom: 'point'},
{ pID: 'line', geom: 'line'},
{ pID: 'area', geom: 'area'}
]).reduce(function(output, d) {
var item = ribbonItemForMinified(d, 'favorite');
if (item) output.push(item);
return output;
}, []);
}
return _favorites;
};
return all;
function setRecents(items) {
_recents = items;
var minifiedItems = items.map(function(d) { return d.minified(); });
context.storage('preset_recents', JSON.stringify(minifiedItems));
}
all.getRecents = function() {
if (!_recents) {
// fetch from local storage
_recents = (JSON.parse(context.storage('preset_recents')) || [])
.reduce(function(output, d) {
var item = ribbonItemForMinified(d, 'recent');
if (item) output.push(item);
return output;
}, []);
}
return _recents;
};
all.toggleFavorite = function(preset, geometry) {
var favs = all.getFavorites();
var favorite = all.isFavorite(preset, geometry);
if (favorite) {
favs.splice(favs.indexOf(favorite), 1);
} else {
// only allow 10 favorites
if (favs.length === 10) {
// remove the last favorite (last in, first out)
favs.pop();
}
// append array
favs.push(RibbonItem(preset, geometry, 'favorite'));
}
setFavorites(favs);
};
all.isFavorite = function(preset, geometry) {
var favs = all.getFavorites();
for (var index in favs) {
if (favs[index].matches(preset, geometry)) {
return favs[index];
}
}
return false;
};
all.isRecent = function(preset, geometry) {
var items = all.getRecents();
for (var index in items) {
if (items[index].matches(preset, geometry)) {
return items[index];
}
}
return false;
};
all.moveFavorite = function(fromIndex, toIndex) {
if (fromIndex === toIndex) return;
var favs = all.getFavorites();
if (fromIndex < 0 || toIndex < 0 ||
fromIndex >= favs.length || toIndex >= favs.length) return;
favs.splice(toIndex, 0, favs.splice(fromIndex, 1)[0]);
setFavorites(favs);
};
all.setMostRecent = function(preset, geometry) {
if (preset.searchable === false) return;
var items = all.getRecents();
var item = all.isRecent(preset, geometry);
if (item) {
items.splice(items.indexOf(item), 1);
} else {
item = RibbonItem(preset, geometry, 'recent');
}
// allow 30 recents
if (items.length === 30) {
// remove the last favorite (first in, first out)
items.pop();
}
// prepend array
items.unshift(item);
setRecents(items);
};
return utilRebind(all, dispatch, 'on');
}
+15 -16
View File
@@ -52,7 +52,7 @@ export function uiModes(context) {
context
.on('enter.modes', update)
.on('favoritePreset.modes', update);
.presets().on('favoritePreset.modes', update);
update();
@@ -63,17 +63,16 @@ export function uiModes(context) {
context.keybinding().off(i.toString());
}
var favoritePresets = context.getFavoritePresets();
var favoritePresets = context.presets().getFavorites();
var favoriteModes = favoritePresets.map(function(d, index) {
var preset = context.presets().item(d.id);
var presetName = preset.name().split(' ')[0];
var markerClass = 'add-preset add-' + d.geom + ' add-preset-' + presetName.replace(/\s+/g, '_')
+ '-' + d.geom; // replace spaces with underscores to avoid css interpretation
if (preset.isFallback()) {
var presetName = d.preset.name().split(' ')[0];
var markerClass = 'add-preset add-' + d.geometry + ' add-preset-' + presetName.replace(/\s+/g, '_')
+ '-' + d.geometry; // replace spaces with underscores to avoid css interpretation
if (d.preset.isFallback()) {
markerClass += ' add-generic-preset';
}
var supportedGeometry = preset.geometry.filter(function(geometry) {
var supportedGeometry = d.preset.geometry.filter(function(geometry) {
return ['vertex', 'point', 'line', 'area'].indexOf(geometry) !== -1;
});
var vertexIndex = supportedGeometry.indexOf('vertex');
@@ -83,18 +82,18 @@ export function uiModes(context) {
}
var tooltipTitleID = 'modes.add_preset.title';
if (supportedGeometry.length !== 1) {
if (preset.setTags({}, d.geom).building) {
if (d.preset.setTags({}, d.geometry).building) {
tooltipTitleID = 'modes.add_preset.building.title';
} else {
tooltipTitleID = 'modes.add_preset.' + d.geom + '.title';
tooltipTitleID = 'modes.add_preset.' + d.geometry + '.title';
}
}
var favoriteMode = {
button: markerClass,
title: presetName,
description: t(tooltipTitleID, { feature: '<strong>' + presetName + '</strong>' }),
preset: preset,
geometry: d.geom
preset: d.preset,
geometry: d.geometry
};
var keyCode;
if (textDirection === 'ltr') {
@@ -117,7 +116,7 @@ export function uiModes(context) {
}
var mode;
switch (d.geom) {
switch (d.geometry) {
case 'point':
case 'vertex':
mode = modeAddPoint(context, favoriteMode);
@@ -169,7 +168,7 @@ export function uiModes(context) {
context.enter(modeBrowse(context));
} else {
if (d.preset) {
context.presets().choose(d.preset, d.geometry);
context.presets().setMostRecent(d.preset, d.geometry);
}
context.enter(d);
}
@@ -256,10 +255,10 @@ export function uiModes(context) {
var y = d3_event.y - dragOrigin.y;
if (y > 50) {
// dragged out of the top bar, remove the favorite
context.favoritePreset(d.preset, d.geometry);
context.presets().toggleFavorite(d.preset, d.geometry);
} else if (targetIndex !== null) {
// dragged to a new position, reorder
context.moveFavoritePreset(index, targetIndex);
context.presets().moveFavorite(index, targetIndex);
}
})
);
+3 -3
View File
@@ -35,7 +35,7 @@ export function uiPresetFavorite(preset, geom, context, klass) {
d3_event.stopPropagation();
d3_event.preventDefault();
context.favoritePreset(preset, geom);
context.presets().toggleFavorite(preset, geom);
update();
});
@@ -45,10 +45,10 @@ export function uiPresetFavorite(preset, geom, context, klass) {
function update() {
_button
.classed('active', context.isFavoritePreset(preset, geom));
.classed('active', context.presets().isFavorite(preset, geom));
}
context.on('favoritePreset.button-' + preset.id.replace(/[^a-zA-Z\d:]/g, '-') + '-' + geom, update);
context.presets().on('favoritePreset.button-' + preset.id.replace(/[^a-zA-Z\d:]/g, '-') + '-' + geom, update);
return presetFavorite;
}
+1 -1
View File
@@ -388,7 +388,7 @@ export function uiPresetList(context) {
item.choose = function() {
if (d3_select(this).classed('disabled')) return;
context.presets().choose(preset, context.geometry(_entityID));
context.presets().setMostRecent(preset, context.geometry(_entityID));
context.perform(
actionChangePreset(_entityID, _currentPreset, preset),
t('operations.change_tags.annotation')
+2 -2
View File
@@ -207,7 +207,7 @@ export function uiSearchAdd(context) {
if (value.length) {
results = presets.search(value, shownGeometry).collection;
} else {
var recents = context.presets().recentWithGeometry();
var recents = context.presets().getRecents();
recents = recents.filter(function(d) {
return shownGeometry.indexOf(d.geometry) !== -1;
});
@@ -504,7 +504,7 @@ export function uiSearchAdd(context) {
mode = modeAddArea(context, modeInfo);
}
search.node().blur();
context.presets().choose(preset, geometry);
context.presets().setMostRecent(preset, geometry);
context.enter(mode);
};
return item;