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));
+};