Files
iD/js/id/ui/inspector.js
2013-02-07 18:24:01 -05:00

312 lines
9.4 KiB
JavaScript

iD.ui.inspector = function() {
var event = d3.dispatch('changeTags', 'close'),
taginfo = iD.taginfo(),
initial = false,
context,
tagList;
function inspector(selection) {
var entity = selection.datum();
var inspector = selection.append('div')
.attr('class','inspector content');
inspector.append('div')
.attr('class', 'head inspector-inner fillL')
.call(drawHead);
var inspectorbody = inspector.append('div')
.attr('class', 'inspector-body');
var inspectorwrap = inspectorbody.append('div')
.attr('class', 'inspector-inner tag-wrap fillL2');
inspectorwrap.append('h4')
.text(t('edit_tags'));
tagList = inspectorwrap.append('ul');
var newTag = inspectorwrap.append('button')
.attr('class', 'add-tag');
newTag.on('click', function() {
addTag();
focusNewKey();
});
newTag.append('span').attr('class', 'icon icon-pre-text plus');
newTag.append('span').attr('class','label').text(t('inspector.new_tag'));
drawTags(entity.tags);
inspectorbody.append('div')
.attr('class', 'inspector-buttons pad1 fillD')
.call(drawButtons);
}
function drawHead(selection) {
var entity = selection.datum();
var h2 = selection.append('h2');
h2.append('span')
.attr('class', 'icon big icon-pre-text big-' + entity.geometry(context.graph()));
h2.append('span')
.text(entity.friendlyName());
}
function drawButtons(selection) {
var entity = selection.datum();
var inspectorButton = selection.append('button')
.attr('class', 'apply action')
.on('click', apply);
inspectorButton.append('span').attr('class','label').text(t('okay'));
var minorButtons = selection.append('div').attr('class','minor-buttons fl');
minorButtons.append('a')
.attr('href', 'http://www.openstreetmap.org/browse/' + entity.type + '/' + entity.osmId())
.attr('target', '_blank')
.text('View on OSM');
}
function drawTags(tags) {
var entity = tagList.datum();
tags = d3.entries(tags);
if (!tags.length) {
tags = [{key: '', value: ''}];
}
var li = tagList.html('')
.selectAll('li')
.data(tags, function(d) { return d.key; });
li.exit().remove();
var row = li.enter().append('li')
.attr('class', 'tag-row');
var inputs = row.append('div')
.attr('class', 'input-wrap');
inputs.append('input')
.property('type', 'text')
.attr('class', 'key')
.attr('maxlength', 255)
.property('value', function(d) { return d.key; })
.on('change', function(d) { d.key = this.value; });
inputs.append('input')
.property('type', 'text')
.attr('class', 'value')
.attr('maxlength', 255)
.property('value', function(d) { return d.value; })
.on('change', function(d) { d.value = this.value; })
.on('keydown.push-more', pushMore);
inputs.each(bindTypeahead);
var removeBtn = row.append('button')
.attr('tabindex', -1)
.attr('class','remove minor')
.on('click', removeTag);
removeBtn.append('span')
.attr('class', 'icon delete');
function findLocal(docs) {
var locale = iD.detect().locale.toLowerCase(),
localized;
localized = _.find(docs, function(d) {
return d.lang.toLowerCase() === locale;
});
if (localized) return localized;
// try the non-regional version of a language, like
// 'en' if the language is 'en-US'
if (locale.indexOf('-') !== -1) {
var first = locale.split('-')[0];
localized = _.find(docs, function(d) {
return d.lang.toLowerCase() === first;
});
if (localized) return localized;
}
// finally fall back to english
return _.find(docs, function(d) {
return d.lang.toLowerCase() === 'en';
});
}
function keyValueReference(err, docs) {
var local;
if (!err && docs) {
local = findLocal(docs);
}
if (local) {
var types = [];
if (local.on_area) types.push('area');
if (local.on_node) types.push('point');
if (local.on_way) types.push('line');
local.types = types;
iD.ui.modal(context.container())
.select('.content')
.datum(local)
.call(iD.ui.tagReference);
} else {
iD.ui.flash(context.container())
.select('.content')
.append('h3')
.text(t('inspector.no_documentation_combination'));
}
}
function keyReference(err, values) {
if (!err && values.data.length) {
iD.ui.modal(context.container())
.select('.content')
.datum({
data: values.data,
title: 'Key:' + params.key,
geometry: params.geometry
})
.call(iD.keyReference(context));
} else {
iD.ui.flash(context.container())
.select('.content')
.append('h3')
.text(t('inspector.no_documentation_key'));
}
}
var helpBtn = row.append('button')
.attr('tabindex', -1)
.attr('class', 'tag-help minor')
.on('click', function(d) {
var params = _.extend({}, d, {
geometry: entity.geometry(context.graph())
});
if (d.key && d.value) {
taginfo.docs(params, keyValueReference);
} else if (d.key) {
taginfo.values(params, keyReference);
}
});
helpBtn.append('span')
.attr('class', 'icon inspect');
if (initial && tags.length === 1 &&
tags[0].key === '' && tags[0].value === '') {
focusNewKey();
}
return li;
}
function pushMore() {
if (d3.event.keyCode === 9 &&
tagList.selectAll('li:last-child input.value').node() === this) {
addTag();
focusNewKey();
d3.event.preventDefault();
}
}
function bindTypeahead() {
var entity = tagList.datum(),
geometry = entity.geometry(context.graph()),
row = d3.select(this),
key = row.selectAll('.key'),
value = row.selectAll('.value');
function sort(value, data) {
var sameletter = [],
other = [];
for (var i = 0; i < data.length; i++) {
if (data[i].value.substring(0, value.length) === value) {
sameletter.push(data[i]);
} else {
other.push(data[i]);
}
}
return sameletter.concat(other);
}
key.call(d3.typeahead()
.data(_.debounce(function(_, callback) {
taginfo.keys({
geometry: geometry,
query: key.property('value')
}, function(err, data) {
if (!err) callback(sort(key.property('value'), data));
});
}, 500)));
value.call(d3.typeahead()
.data(_.debounce(function(_, callback) {
taginfo.values({
key: key.property('value'),
geometry: geometry,
query: value.property('value')
}, function(err, data) {
if (!err) callback(sort(value.property('value'), data));
});
}, 500)));
}
function focusNewKey() {
tagList.selectAll('li:last-child input.key').node().focus();
}
function addTag() {
var tags = inspector.tags();
tags[''] = '';
drawTags(tags);
}
function removeTag(d) {
var tags = inspector.tags();
delete tags[d.key];
drawTags(tags);
}
function apply(entity) {
event.changeTags(entity, inspector.tags());
event.close(entity);
}
inspector.tags = function(tags) {
if (!arguments.length) {
tags = {};
tagList.selectAll('li').each(function() {
var row = d3.select(this),
key = row.selectAll('.key').property('value'),
value = row.selectAll('.value').property('value');
if (key !== '') tags[key] = value;
});
return tags;
} else {
drawTags(tags);
}
};
inspector.initial = function(_) {
initial = _;
return inspector;
};
inspector.context = function(_) {
context = _;
return inspector;
};
return d3.rebind(inspector, event, 'on');
};