mirror of
https://github.com/FoggedLens/iD.git
synced 2026-06-05 22:46:38 +02:00
Model preset field state with persistent objects
This commit is contained in:
+160
-122
@@ -1,109 +1,104 @@
|
||||
iD.ui.preset = function(context, entity) {
|
||||
var event = d3.dispatch('change', 'setTags', 'close'),
|
||||
tags,
|
||||
keys,
|
||||
preset,
|
||||
iD.ui.preset = function(context, entity, preset) {
|
||||
var original = context.graph().base().entities[entity.id],
|
||||
event = d3.dispatch('change', 'close'),
|
||||
fields = [],
|
||||
tags = {},
|
||||
formwrap,
|
||||
formbuttonwrap;
|
||||
|
||||
function presets(selection) {
|
||||
selection.html('');
|
||||
function UIField(field, show) {
|
||||
field = _.clone(field);
|
||||
|
||||
keys = [];
|
||||
formwrap = selection.append('div');
|
||||
field.input = iD.ui.preset[field.type](field, context)
|
||||
.on('close', event.close)
|
||||
.on('change', event.change);
|
||||
|
||||
var geometry = entity.geometry(context.graph()),
|
||||
fields = preset.fields.filter(function(f) {
|
||||
return f.matchGeometry(geometry);
|
||||
if (field.type === 'address') {
|
||||
field.input.entity(entity);
|
||||
}
|
||||
|
||||
field.keys = field.keys || [field.key];
|
||||
|
||||
field.show = show;
|
||||
|
||||
field.shown = function() {
|
||||
return field.id === 'name' || field.show || _.any(field.keys, function(key) { return !!tags[key]; });
|
||||
};
|
||||
|
||||
field.modified = function() {
|
||||
return _.any(field.keys, function(key) {
|
||||
return original ? tags[key] !== original.tags[key] : tags[key];
|
||||
});
|
||||
};
|
||||
|
||||
fields.unshift(context.presets().field('name'));
|
||||
|
||||
draw(formwrap, fields);
|
||||
|
||||
var wrap = selection.append('div')
|
||||
.attr('class', 'col12 more-buttons inspector-inner');
|
||||
|
||||
formbuttonwrap = wrap.append('div')
|
||||
.attr('class', 'col12 preset-input');
|
||||
|
||||
formbuttonwrap.selectAll('button')
|
||||
.data(context.presets().universal().filter(notInForm))
|
||||
.enter()
|
||||
.append('button')
|
||||
.attr('class', 'preset-add-field')
|
||||
.on('click', addForm)
|
||||
.call(bootstrap.tooltip()
|
||||
.placement('top')
|
||||
.title(function(d) { return d.label(); }))
|
||||
.append('span')
|
||||
.attr('class', function(d) { return 'icon ' + d.icon; });
|
||||
|
||||
function notInForm(p) {
|
||||
return preset.fields.indexOf(p) < 0;
|
||||
}
|
||||
|
||||
function addForm(d) {
|
||||
var field = draw(formwrap, [d]);
|
||||
|
||||
var input = field.selectAll('input, textarea').node();
|
||||
if (input) input.focus();
|
||||
|
||||
d3.select(this)
|
||||
.style('opacity', 1)
|
||||
.transition()
|
||||
.style('opacity', 0)
|
||||
.remove();
|
||||
|
||||
if (!wrap.selectAll('button').node()) {
|
||||
wrap.remove();
|
||||
}
|
||||
}
|
||||
return field;
|
||||
}
|
||||
|
||||
function draw(selection, fields) {
|
||||
var sections = selection.selectAll('div.form-field')
|
||||
.data(fields, function(field) { return field.id; })
|
||||
.enter()
|
||||
.append('div')
|
||||
fields.push(UIField(context.presets().field('name')));
|
||||
|
||||
var geometry = entity.geometry(context.graph());
|
||||
preset.fields.forEach(function(field) {
|
||||
if (field.matchGeometry(geometry)) {
|
||||
fields.push(UIField(field, true));
|
||||
}
|
||||
});
|
||||
|
||||
context.presets().universal().forEach(function(field) {
|
||||
if (fields.indexOf(field) < 0) {
|
||||
fields.push(UIField(field));
|
||||
}
|
||||
});
|
||||
|
||||
function fieldKey(field) {
|
||||
return field.id;
|
||||
}
|
||||
|
||||
function shown() {
|
||||
return fields.filter(function(field) { return field.shown(); });
|
||||
}
|
||||
|
||||
function notShown() {
|
||||
return fields.filter(function(field) { return !field.shown(); });
|
||||
}
|
||||
|
||||
function show(field) {
|
||||
field.show = true;
|
||||
render();
|
||||
field.input.focus();
|
||||
}
|
||||
|
||||
function revert(field) {
|
||||
var t = {};
|
||||
field.keys.forEach(function(key) {
|
||||
t[key] = original ? original.tags[key] : undefined;
|
||||
});
|
||||
event.change(t);
|
||||
}
|
||||
|
||||
function toggleReference(field) {
|
||||
_.forEach(fields, function(other) {
|
||||
if (other.id === field.id) {
|
||||
other.showingReference = !other.showingReference;
|
||||
} else {
|
||||
other.showingReference = false;
|
||||
}
|
||||
});
|
||||
|
||||
render();
|
||||
}
|
||||
|
||||
function render() {
|
||||
var selection = formwrap.selectAll('.form-field')
|
||||
.data(shown(), fieldKey);
|
||||
|
||||
var enter = selection.enter()
|
||||
.insert('div', '.more-buttons')
|
||||
.style('opacity', 0)
|
||||
.attr('class', function(field) {
|
||||
return 'form-field form-field-' + field.id + ' fillL col12';
|
||||
});
|
||||
|
||||
var label = sections.append('label')
|
||||
.attr('class', 'form-label')
|
||||
.attr('for', function(field) { return 'preset-input-' + field.id; })
|
||||
.text(function(field) { return field.label(); });
|
||||
|
||||
label.append('button')
|
||||
.attr('class', 'fr icon undo modified-icon')
|
||||
.attr('tabindex', -1)
|
||||
.on('click', function(field) {
|
||||
var original = context.graph().base().entities[entity.id];
|
||||
var t = {};
|
||||
(field.keys || [field.key]).forEach(function(key) {
|
||||
t[key] = original ? original.tags[key] : undefined;
|
||||
});
|
||||
event.change(t);
|
||||
});
|
||||
|
||||
label.append('button')
|
||||
.attr('class', 'tag-reference-button')
|
||||
.attr('tabindex', -1)
|
||||
.on('click', function(field) {
|
||||
selection.selectAll('div.tag-help')
|
||||
.style('display', 'none');
|
||||
|
||||
d3.select(d3.select(this).node().parentNode.parentNode)
|
||||
.select('div.tag-help')
|
||||
.style('display', 'block')
|
||||
.call(iD.ui.TagReference(entity, {key: field.key}));
|
||||
})
|
||||
.append('span')
|
||||
.attr('class', 'icon inspect');
|
||||
|
||||
sections.transition()
|
||||
enter.transition()
|
||||
.style('max-height', '0px')
|
||||
.style('padding-top', '0px')
|
||||
.style('opacity', '0')
|
||||
@@ -113,30 +108,83 @@ iD.ui.preset = function(context, entity) {
|
||||
.style('max-height', '200px')
|
||||
.style('opacity', '1');
|
||||
|
||||
sections.each(function(field) {
|
||||
var i = iD.ui.preset[field.type](field, context)
|
||||
.on('close', event.close)
|
||||
.on('change', event.change);
|
||||
var label = enter.append('label')
|
||||
.attr('class', 'form-label')
|
||||
.attr('for', function(field) { return 'preset-input-' + field.id; })
|
||||
.text(function(field) { return field.label(); });
|
||||
|
||||
event.on('setTags.' + field.id, function(tags) {
|
||||
i.tags(_.clone(tags));
|
||||
});
|
||||
label.append('button')
|
||||
.attr('class', 'fr icon undo modified-icon')
|
||||
.attr('tabindex', -1)
|
||||
.on('click', revert);
|
||||
|
||||
if (field.type === 'address') i.entity(entity);
|
||||
label.append('button')
|
||||
.attr('class', 'tag-reference-button')
|
||||
.attr('tabindex', -1)
|
||||
.on('click', toggleReference)
|
||||
.append('span')
|
||||
.attr('class', 'icon inspect');
|
||||
|
||||
keys = keys.concat(field.key ? [field.key] : field.keys);
|
||||
|
||||
d3.select(this).call(i);
|
||||
enter.each(function(field) {
|
||||
d3.select(this).call(field.input);
|
||||
});
|
||||
|
||||
sections.append('div')
|
||||
enter.append('div')
|
||||
.attr('class', 'tag-help');
|
||||
|
||||
return sections;
|
||||
selection
|
||||
.classed('modified', function(field) {
|
||||
return field.modified();
|
||||
});
|
||||
|
||||
selection.selectAll('.tag-help')
|
||||
.style('display', function(field) {
|
||||
return field.showingReference ? 'block' : 'none';
|
||||
})
|
||||
.each(function(field) {
|
||||
if (field.showingReference) {
|
||||
d3.select(this)
|
||||
.call(iD.ui.TagReference(entity, {key: field.key}));
|
||||
}
|
||||
});
|
||||
|
||||
selection.exit()
|
||||
.remove();
|
||||
|
||||
var addFields = formbuttonwrap.selectAll('.preset-add-field')
|
||||
.data(notShown(), fieldKey);
|
||||
|
||||
addFields.enter()
|
||||
.append('button')
|
||||
.attr('class', 'preset-add-field')
|
||||
.on('click', show)
|
||||
.call(bootstrap.tooltip()
|
||||
.placement('top')
|
||||
.title(function(d) { return d.label(); }))
|
||||
.append('span')
|
||||
.attr('class', function(d) { return 'icon ' + d.icon; });
|
||||
|
||||
addFields.exit()
|
||||
.transition()
|
||||
.style('opacity', 0)
|
||||
.remove();
|
||||
|
||||
return selection;
|
||||
}
|
||||
|
||||
function presets(selection) {
|
||||
selection.html('');
|
||||
|
||||
formwrap = selection;
|
||||
|
||||
formbuttonwrap = selection.append('div')
|
||||
.attr('class', 'col12 more-buttons inspector-inner');
|
||||
|
||||
render();
|
||||
}
|
||||
|
||||
presets.rendered = function() {
|
||||
return keys;
|
||||
return _.flatten(shown().map(function(field) { return field.keys; }));
|
||||
};
|
||||
|
||||
presets.preset = function(_) {
|
||||
@@ -145,27 +193,17 @@ iD.ui.preset = function(context, entity) {
|
||||
return presets;
|
||||
};
|
||||
|
||||
presets.change = function(t) {
|
||||
tags = t;
|
||||
presets.change = function(_) {
|
||||
tags = _;
|
||||
|
||||
function haveKey(k) { return k && !!tags[k]; }
|
||||
|
||||
formbuttonwrap.selectAll('button').each(function(p) {
|
||||
if (haveKey(p.key) || _.any(p.keys, haveKey)) {
|
||||
draw(formwrap, [p]);
|
||||
d3.select(this).remove();
|
||||
fields.forEach(function(field) {
|
||||
if (field.shown()) {
|
||||
field.input.tags(_);
|
||||
}
|
||||
});
|
||||
|
||||
formwrap.selectAll('div.form-field')
|
||||
.classed('modified', function(d) {
|
||||
var original = context.graph().base().entities[entity.id];
|
||||
return _.any(d.keys || [d.key], function(key) {
|
||||
return original ? tags[key] !== original.tags[key] : tags[key];
|
||||
});
|
||||
});
|
||||
render();
|
||||
|
||||
event.setTags(tags);
|
||||
return presets;
|
||||
};
|
||||
|
||||
|
||||
@@ -101,5 +101,9 @@ iD.ui.preset.address = function(field, context) {
|
||||
return address;
|
||||
};
|
||||
|
||||
address.focus = function() {
|
||||
housename.node().focus();
|
||||
};
|
||||
|
||||
return d3.rebind(address, event, 'on');
|
||||
};
|
||||
|
||||
@@ -40,5 +40,9 @@ iD.ui.preset.check = function(field) {
|
||||
label.classed('set', !!value);
|
||||
};
|
||||
|
||||
check.focus = function() {
|
||||
box.node().focus();
|
||||
};
|
||||
|
||||
return d3.rebind(check, event, 'on');
|
||||
};
|
||||
|
||||
@@ -48,5 +48,9 @@ iD.ui.preset.combo = function(field) {
|
||||
input.property('value', tags[field.key] || '');
|
||||
};
|
||||
|
||||
combo.focus = function() {
|
||||
input.node().focus();
|
||||
};
|
||||
|
||||
return d3.rebind(combo, event, 'on');
|
||||
};
|
||||
|
||||
@@ -19,5 +19,9 @@ iD.ui.preset.defaultcheck = function(field) {
|
||||
input.property('checked', !!tags[field.key] && tags[field.key] !== 'no');
|
||||
};
|
||||
|
||||
check.focus = function() {
|
||||
input.node().focus();
|
||||
};
|
||||
|
||||
return d3.rebind(check, event, 'on');
|
||||
};
|
||||
|
||||
@@ -52,5 +52,9 @@ iD.ui.preset.url = function(field) {
|
||||
input.property('value', tags[field.key] || '');
|
||||
};
|
||||
|
||||
i.focus = function() {
|
||||
input.node().focus();
|
||||
};
|
||||
|
||||
return d3.rebind(i, event, 'on');
|
||||
};
|
||||
|
||||
@@ -52,5 +52,9 @@ iD.ui.preset.radio = function(field) {
|
||||
});
|
||||
};
|
||||
|
||||
radio.focus = function() {
|
||||
buttons.node().focus();
|
||||
};
|
||||
|
||||
return d3.rebind(radio, event, 'on');
|
||||
};
|
||||
|
||||
@@ -23,5 +23,9 @@ iD.ui.preset.textarea = function(field) {
|
||||
input.text(tags[field.key] || '');
|
||||
};
|
||||
|
||||
i.focus = function() {
|
||||
input.node().focus();
|
||||
};
|
||||
|
||||
return d3.rebind(i, event, 'on');
|
||||
};
|
||||
|
||||
@@ -56,8 +56,7 @@ iD.ui.TagEditor = function(context, entity) {
|
||||
.append('span')
|
||||
.attr('class', geometry + ' preset-icon icon feature-' + icon);
|
||||
|
||||
presetUI = iD.ui.preset(context, entity)
|
||||
.preset(preset)
|
||||
presetUI = iD.ui.preset(context, entity, preset)
|
||||
.on('change', changeTags)
|
||||
.on('close', event.close);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user