diff --git a/Makefile b/Makefile index 10f8e7a4f..e32d5d78d 100644 --- a/Makefile +++ b/Makefile @@ -26,6 +26,7 @@ dist/iD.js: \ js/lib/d3.trigger.js \ js/lib/d3.typeahead.js \ js/lib/d3.curtain.js \ + js/lib/d3.value.js \ js/lib/jxon.js \ js/lib/lodash.js \ js/lib/osmauth.js \ diff --git a/index.html b/index.html index 440b02fa8..2438b2826 100644 --- a/index.html +++ b/index.html @@ -26,6 +26,7 @@ + diff --git a/js/id/ui/preset/access.js b/js/id/ui/preset/access.js index ab6586017..fa9ca6e75 100644 --- a/js/id/ui/preset/access.js +++ b/js/id/ui/preset/access.js @@ -46,7 +46,7 @@ iD.ui.preset.access = function(field, context) { function change(d) { var tag = {}; - tag[d] = d3.select(this).property('value') || undefined; + tag[d] = d3.select(this).value() || undefined; event.change(tag); } @@ -73,8 +73,7 @@ iD.ui.preset.access = function(field, context) { access.tags = function(tags) { items.selectAll('.preset-input-access') - .property('value', function(d) { return tags[d] || ''; }); - return access; + .value(function(d) { return tags[d] || ''; }); }; access.focus = function() { diff --git a/js/id/ui/preset/address.js b/js/id/ui/preset/address.js index 219ba7ca2..8feee9c2b 100644 --- a/js/id/ui/preset/address.js +++ b/js/id/ui/preset/address.js @@ -90,11 +90,11 @@ iD.ui.preset.address = function(field, context) { function change() { event.change({ - 'addr:housename': housename.property('value') || undefined, - 'addr:housenumber': housenumber.property('value') || undefined, - 'addr:street': street.property('value') || undefined, - 'addr:city': city.property('value') || undefined, - 'addr:postcode': postcode.property('value') || undefined + 'addr:housename': housename.value() || undefined, + 'addr:housenumber': housenumber.value() || undefined, + 'addr:street': street.value() || undefined, + 'addr:city': city.value() || undefined, + 'addr:postcode': postcode.value() || undefined }); } @@ -105,12 +105,11 @@ iD.ui.preset.address = function(field, context) { }; address.tags = function(tags) { - housename.property('value', tags['addr:housename'] || ''); - housenumber.property('value', tags['addr:housenumber'] || ''); - street.property('value', tags['addr:street'] || ''); - city.property('value', tags['addr:city'] || ''); - postcode.property('value', tags['addr:postcode'] || ''); - return address; + housename.value(tags['addr:housename'] || ''); + housenumber.value(tags['addr:housenumber'] || ''); + street.value(tags['addr:street'] || ''); + city.value(tags['addr:city'] || ''); + postcode.value(tags['addr:postcode'] || ''); }; address.focus = function() { diff --git a/js/id/ui/preset/combo.js b/js/id/ui/preset/combo.js index a078ee647..c1ed4cc2c 100644 --- a/js/id/ui/preset/combo.js +++ b/js/id/ui/preset/combo.js @@ -44,12 +44,12 @@ iD.ui.preset.combo = function(field) { function change() { var t = {}; - t[field.key] = input.property('value').replace(' ', '_') || undefined; + t[field.key] = input.value().replace(' ', '_') || undefined; event.change(t); } combo.tags = function(tags) { - input.property('value', tags[field.key] || ''); + input.value(tags[field.key] || ''); }; combo.focus = function() { diff --git a/js/id/ui/preset/input.js b/js/id/ui/preset/input.js index d9b62f1d0..69b7b9749 100644 --- a/js/id/ui/preset/input.js +++ b/js/id/ui/preset/input.js @@ -49,12 +49,12 @@ iD.ui.preset.url = function(field) { function change() { var t = {}; - t[field.key] = input.property('value') || undefined; + t[field.key] = input.value() || undefined; event.change(t); } i.tags = function(tags) { - input.property('value', tags[field.key] || ''); + input.value(tags[field.key] || ''); }; i.focus = function() { diff --git a/js/id/ui/preset/localized.js b/js/id/ui/preset/localized.js index 9957455d6..2b5f1943a 100644 --- a/js/id/ui/preset/localized.js +++ b/js/id/ui/preset/localized.js @@ -48,14 +48,14 @@ iD.ui.preset.localized = function(field, context) { function change() { var t = {}; - t[field.key] = d3.select(this).property('value') || undefined; + t[field.key] = d3.select(this).value() || undefined; event.change(t); } function key(lang) { return field.key + ':' + lang; } function changeLang(d) { - var value = d3.select(this).property('value'), + var value = d3.select(this).value(), t = {}, language = _.find(iD.data.wikipedia, function(d) { return d[0].toLowerCase() === value.toLowerCase() || @@ -79,7 +79,7 @@ iD.ui.preset.localized = function(field, context) { function changeValue(d) { var t = {}; - t[key(d.lang)] = d3.select(this).property('value') || ''; + t[key(d.lang)] = d3.select(this).value() || ''; event.change(t); } @@ -173,18 +173,16 @@ iD.ui.preset.localized = function(field, context) { .style('top','-10px') .remove(); - selection.selectAll('.entry').select('.localized-lang').property('value', function(d) { + selection.selectAll('.entry').select('.localized-lang').value(function(d) { var lang = _.find(iD.data.wikipedia, function(lang) { return lang[2] === d.lang; }); return lang ? lang[1] : d.lang; }); - selection.selectAll('.entry').select('.localized-value').property('value', function(d) { + selection.selectAll('.entry').select('.localized-value').value(function(d) { return d.value; }); - - } i.tags = function(tags) { @@ -200,7 +198,7 @@ iD.ui.preset.localized = function(field, context) { } } - input.property('value', tags[field.key] || ''); + input.value(tags[field.key] || ''); var postfixed = []; for (var i in tags) { diff --git a/js/id/ui/preset/maxspeed.js b/js/id/ui/preset/maxspeed.js index a538ff982..85a39523d 100644 --- a/js/id/ui/preset/maxspeed.js +++ b/js/id/ui/preset/maxspeed.js @@ -49,8 +49,8 @@ iD.ui.preset.maxspeed = function(field, context) { .call(unitCombobox); function changeUnits() { - imperial = unitInput.property('value') === 'mph'; - unitInput.property('value', imperial ? 'mph' : 'km/h'); + imperial = unitInput.value() === 'mph'; + unitInput.value(imperial ? 'mph' : 'km/h'); setSuggestions(); change(); } @@ -59,7 +59,7 @@ iD.ui.preset.maxspeed = function(field, context) { function setSuggestions() { combobox.data((imperial ? imperialValues : metricValues).map(comboValues)); - unitInput.property('value', imperial ? 'mph' : 'km/h'); + unitInput.value(imperial ? 'mph' : 'km/h'); } function comboValues(d) { @@ -71,7 +71,7 @@ iD.ui.preset.maxspeed = function(field, context) { function change() { var tag = {}, - value = input.property('value'); + value = input.value(); if (!value) { tag[field.key] = undefined; @@ -96,7 +96,7 @@ iD.ui.preset.maxspeed = function(field, context) { setSuggestions(); - input.property('value', value || ''); + input.value(value || ''); }; maxspeed.focus = function() { diff --git a/js/id/ui/preset/textarea.js b/js/id/ui/preset/textarea.js index 4a6fdfb36..2ee99aa2b 100644 --- a/js/id/ui/preset/textarea.js +++ b/js/id/ui/preset/textarea.js @@ -19,12 +19,12 @@ iD.ui.preset.textarea = function(field) { function change() { var t = {}; - t[field.key] = input.property('value') || undefined; + t[field.key] = input.value() || undefined; event.change(t); } i.tags = function(tags) { - input.property('value', tags[field.key] || ''); + input.value(tags[field.key] || ''); }; i.focus = function() { diff --git a/js/id/ui/preset/wikipedia.js b/js/id/ui/preset/wikipedia.js index 5306fe611..a7f964370 100644 --- a/js/id/ui/preset/wikipedia.js +++ b/js/id/ui/preset/wikipedia.js @@ -69,7 +69,7 @@ iD.ui.preset.wikipedia = function(field, context) { } function changeLang() { - var value = lang.property('value').toLowerCase(); + var value = lang.value().toLowerCase(); language = _.find(iD.data.wikipedia, function(d) { return d[0].toLowerCase() === value || d[1].toLowerCase() === value || @@ -77,7 +77,7 @@ iD.ui.preset.wikipedia = function(field, context) { }) || iD.data.wikipedia[0]; if (value !== language[0]) { - lang.property('value', language[1]); + lang.value(language[1]); } change(); @@ -86,7 +86,7 @@ iD.ui.preset.wikipedia = function(field, context) { function change() { var t = {}; - var value = title.property('value'); + var value = title.value(); var m = value.match('http://([a-z]+)\\.wikipedia.org/wiki/(.*)'), newlanguage = m && m[1] && m[2] && _.find(iD.data.wikipedia, function(d) { @@ -98,7 +98,7 @@ iD.ui.preset.wikipedia = function(field, context) { value = m[2].replace(/_/g, ' '); value = value.slice(0, 1).toUpperCase() + value.slice(1); language = newlanguage; - lang.property('value', language[0]); + lang.value(language[0]); } t[field.key] = value ? language[2] + ':' + value : undefined; @@ -115,14 +115,14 @@ iD.ui.preset.wikipedia = function(field, context) { // value in correct format if (language) { - lang.property('value', language[1]); - title.property('value', m[2]); + lang.value(language[1]); + title.value(m[2]); link.attr('href', 'http://' + m[1] + '.wikipedia.org/wiki/' + m[2]); // unrecognized value format } else { - lang.property('value', 'English'); - title.property('value', tags[field.key] || ''); + lang.value('English'); + title.value(tags[field.key] || ''); language = iD.data.wikipedia[0]; link.attr('href', 'http://en.wikipedia.org/wiki/Special:Search?search=' + tags[field.key]); } diff --git a/js/lib/d3.value.js b/js/lib/d3.value.js new file mode 100644 index 000000000..1261034e5 --- /dev/null +++ b/js/lib/d3.value.js @@ -0,0 +1,26 @@ +// Like selection.property('value', ...), but avoids no-op value sets, +// which can result in layout/repaint thrashing in some situations. +d3.selection.prototype.value = function(value) { + function d3_selection_value(value) { + function valueNull() { + delete this.value; + } + + function valueConstant() { + if (this.value !== value) this.value = value; + } + + function valueFunction() { + var x = value.apply(this, arguments); + if (x == null) delete this.value; + else if (this.value !== x) this.value = x; + } + + return value == null + ? valueNull : (typeof value === "function" + ? valueFunction : valueConstant); + } + + if (!arguments.length) return this.property('value'); + return this.each(d3_selection_value(value)); +};