diff --git a/Makefile b/Makefile
index c77140312..2652dbca8 100644
--- a/Makefile
+++ b/Makefile
@@ -89,7 +89,8 @@ dist/iD.js: \
js/id/ui/intro/*.js \
js/id/presets.js \
js/id/presets/*.js \
- js/id/validate.js \
+ js/id/validations.js \
+ js/id/validations/*.js \
js/id/end.js \
js/lib/locale.js \
data/introGraph.js
diff --git a/index.html b/index.html
index edf3987d9..cf71e0b9e 100644
--- a/index.html
+++ b/index.html
@@ -233,7 +233,11 @@
-
+
+
+
+
+
diff --git a/js/id/core/history.js b/js/id/core/history.js
index 585005bd8..90cb947af 100644
--- a/js/id/core/history.js
+++ b/js/id/core/history.js
@@ -164,6 +164,13 @@ iD.History = function(context) {
};
},
+ validate: function(changes) {
+ return _(iD.validations)
+ .map(function(fn) { return fn()(changes, stack[index].graph); })
+ .flatten()
+ .value();
+ },
+
hasChanges: function() {
return this.difference().length() > 0;
},
diff --git a/js/id/ui/commit.js b/js/id/ui/commit.js
index e92cf441d..ef5eabe77 100644
--- a/js/id/ui/commit.js
+++ b/js/id/ui/commit.js
@@ -52,7 +52,7 @@ iD.ui.Commit = function(context) {
// Warnings
var warnings = body.selectAll('div.warning-section')
- .data([iD.validate(changes, context.graph())])
+ .data([context.history().validate(changes)])
.enter()
.append('div')
.attr('class', 'modal-section warning-section fillL2')
diff --git a/js/id/validate.js b/js/id/validate.js
deleted file mode 100644
index 7315dfad5..000000000
--- a/js/id/validate.js
+++ /dev/null
@@ -1,53 +0,0 @@
-iD.validate = function(changes, graph) {
- var warnings = [];
-
- // https://github.com/openstreetmap/josm/blob/mirror/src/org/
- // openstreetmap/josm/data/validation/tests/UnclosedWays.java#L80
- function tagSuggestsArea(change) {
- if (_.isEmpty(change.tags)) return false;
- var tags = change.tags;
- var presence = ['landuse', 'amenities', 'tourism', 'shop'];
- for (var i = 0; i < presence.length; i++) {
- if (tags[presence[i]] !== undefined) {
- return presence[i] + '=' + tags[presence[i]];
- }
- }
- if (tags.building && tags.building === 'yes') return 'building=yes';
- }
-
- if (changes.deleted.length > 100) {
- warnings.push({
- message: t('validations.many_deletions', { n: changes.deleted.length })
- });
- }
-
- for (var i = 0; i < changes.created.length; i++) {
- var change = changes.created[i],
- geometry = change.geometry(graph);
-
- if ((geometry === 'point' || geometry === 'line' || geometry === 'area') && !change.isUsed(graph)) {
- warnings.push({
- message: t('validations.untagged_' + geometry),
- tooltip: t('validations.untagged_' + geometry + '_tooltip'),
- entity: change
- });
- }
-
- var deprecatedTags = change.deprecatedTags();
- if (!_.isEmpty(deprecatedTags)) {
- warnings.push({
- message: t('validations.deprecated_tags', {
- tags: iD.util.tagText({ tags: deprecatedTags })
- }), entity: change });
- }
-
- if (geometry === 'line' && tagSuggestsArea(change)) {
- warnings.push({
- message: t('validations.tag_suggests_area', {tag: tagSuggestsArea(change)}),
- entity: change
- });
- }
- }
-
- return warnings;
-};
diff --git a/js/id/validations.js b/js/id/validations.js
new file mode 100644
index 000000000..4bfccb1e4
--- /dev/null
+++ b/js/id/validations.js
@@ -0,0 +1 @@
+iD.validations = {};
diff --git a/js/id/validations/deprecated_tag.js b/js/id/validations/deprecated_tag.js
new file mode 100644
index 000000000..d8b749445
--- /dev/null
+++ b/js/id/validations/deprecated_tag.js
@@ -0,0 +1,22 @@
+iD.validations.DeprecatedTag = function() {
+
+ var validation = function(changes) {
+ var warnings = [];
+ for (var i = 0; i < changes.created.length; i++) {
+ var change = changes.created[i],
+ deprecatedTags = change.deprecatedTags();
+
+ if (!_.isEmpty(deprecatedTags)) {
+ var tags = iD.util.tagText({ tags: deprecatedTags });
+ warnings.push({
+ id: 'deprecated_tags',
+ message: t('validations.deprecated_tags', { tags: tags }),
+ entity: change
+ });
+ }
+ }
+ return warnings;
+ };
+
+ return validation;
+};
diff --git a/js/id/validations/many_deletions.js b/js/id/validations/many_deletions.js
new file mode 100644
index 000000000..96a6ddb85
--- /dev/null
+++ b/js/id/validations/many_deletions.js
@@ -0,0 +1,16 @@
+iD.validations.ManyDeletions = function() {
+ var threshold = 100;
+
+ var validation = function(changes) {
+ var warnings = [];
+ if (changes.deleted.length > threshold) {
+ warnings.push({
+ id: 'many_deletions',
+ message: t('validations.many_deletions', { n: changes.deleted.length })
+ });
+ }
+ return warnings;
+ };
+
+ return validation;
+};
diff --git a/js/id/validations/missing_tag.js b/js/id/validations/missing_tag.js
new file mode 100644
index 000000000..664a9335a
--- /dev/null
+++ b/js/id/validations/missing_tag.js
@@ -0,0 +1,22 @@
+iD.validations.MissingTag = function() {
+
+ var validation = function(changes, graph) {
+ var warnings = [];
+ for (var i = 0; i < changes.created.length; i++) {
+ var change = changes.created[i],
+ geometry = change.geometry(graph);
+
+ if ((geometry === 'point' || geometry === 'line' || geometry === 'area') && !change.isUsed(graph)) {
+ warnings.push({
+ id: 'missing_tag',
+ message: t('validations.untagged_' + geometry),
+ tooltip: t('validations.untagged_' + geometry + '_tooltip'),
+ entity: change
+ });
+ }
+ }
+ return warnings;
+ };
+
+ return validation;
+};
diff --git a/js/id/validations/tag_suggests_area.js b/js/id/validations/tag_suggests_area.js
new file mode 100644
index 000000000..8c91a7d96
--- /dev/null
+++ b/js/id/validations/tag_suggests_area.js
@@ -0,0 +1,37 @@
+iD.validations.TagSuggestsArea = function() {
+
+ // https://github.com/openstreetmap/josm/blob/mirror/src/org/
+ // openstreetmap/josm/data/validation/tests/UnclosedWays.java#L80
+ function tagSuggestsArea(tags) {
+ if (_.isEmpty(tags)) return false;
+
+ var presence = ['landuse', 'amenities', 'tourism', 'shop'];
+ for (var i = 0; i < presence.length; i++) {
+ if (tags[presence[i]] !== undefined) {
+ return presence[i] + '=' + tags[presence[i]];
+ }
+ }
+
+ if (tags.building && tags.building === 'yes') return 'building=yes';
+ }
+
+ var validation = function(changes, graph) {
+ var warnings = [];
+ for (var i = 0; i < changes.created.length; i++) {
+ var change = changes.created[i],
+ geometry = change.geometry(graph),
+ suggestion = (geometry === 'line' ? tagSuggestsArea(change.tags) : undefined);
+
+ if (suggestion) {
+ warnings.push({
+ id: 'tag_suggests_area',
+ message: t('validations.tag_suggests_area', { tag: suggestion }),
+ entity: change
+ });
+ }
+ }
+ return warnings;
+ };
+
+ return validation;
+};
diff --git a/test/index.html b/test/index.html
index d72a3840b..b1f40fddb 100644
--- a/test/index.html
+++ b/test/index.html
@@ -212,7 +212,11 @@
-
+
+
+
+
+