diff --git a/Makefile b/Makefile index 55ed971e2..c22d5a80a 100644 --- a/Makefile +++ b/Makefile @@ -67,6 +67,7 @@ dist/iD.js: \ js/id/services/mapillary.js \ js/id/services/nominatim.js \ js/id/services/taginfo.js \ + js/id/services/wikidata.js \ js/id/services/wikipedia.js \ js/id/util.js \ js/id/util/session_mutex.js \ diff --git a/data/presets.yaml b/data/presets.yaml index 4c0534523..137cddb63 100644 --- a/data/presets.yaml +++ b/data/presets.yaml @@ -1045,7 +1045,7 @@ en: # 'width=*' label: Width (Meters) wikipedia: - # 'wikipedia=*' + # 'wikipedia=*, wikidata=*' label: Wikipedia presets: address: diff --git a/data/presets/fields.json b/data/presets/fields.json index ee2a6a2f1..203c632a5 100644 --- a/data/presets/fields.json +++ b/data/presets/fields.json @@ -1414,6 +1414,10 @@ }, "wikipedia": { "key": "wikipedia", + "keys": [ + "wikipedia", + "wikidata" + ], "type": "wikipedia", "icon": "wikipedia", "universal": true, diff --git a/data/presets/fields/wikipedia.json b/data/presets/fields/wikipedia.json index 8f4a67d85..466c95520 100644 --- a/data/presets/fields/wikipedia.json +++ b/data/presets/fields/wikipedia.json @@ -1,5 +1,6 @@ { "key": "wikipedia", + "keys": ["wikipedia", "wikidata"], "type": "wikipedia", "icon": "wikipedia", "universal": true, diff --git a/js/id/ui/preset/wikipedia.js b/js/id/ui/preset/wikipedia.js index 0d2317160..9dca790e0 100644 --- a/js/id/ui/preset/wikipedia.js +++ b/js/id/ui/preset/wikipedia.js @@ -4,7 +4,7 @@ iD.ui.preset.wikipedia = function(field, context) { wikidata = iD.services.wikidata(), link, entity, lang, title; - function i(selection) { + function wiki(selection) { var langcombo = d3.combobox() .fetcher(function(value, cb) { var v = value.toLowerCase(); @@ -109,22 +109,37 @@ iD.ui.preset.wikipedia = function(field, context) { title.value(value); } - syncTags[field.key] = value ? language()[2] + ':' + value : undefined; + syncTags.wikipedia = value ? language()[2] + ':' + value : undefined; + syncTags.wikidata = undefined; + dispatch.change(syncTags); + + // attempt asynchronous update of wikidata tag.. if (value && language()[2]) { - wikidata.itemsByTitle(language()[2], value, function (title, entities) { - var qids = entities && Object.keys(entities), - asyncTags = {}; - asyncTags.wikidata = qids && _.find(qids, function (id) { + var initGraph = context.graph(); + wikidata.itemsByTitle(language()[2], value, function (title, data) { + var qids = data && Object.keys(data), + currGraph = context.graph(); + + // only do this if graph is unchanged.. + if (initGraph !== currGraph) return; + + var currEntity = context.entity(entity.id), + currTags = _.clone(currEntity.tags); + + currTags.wikidata = qids && _.find(qids, function (id) { return id.match(/^Q\d+$/); }); - dispatch.change(asyncTags); + + var annotation = t('operations.change_tags.annotation'); + context.overwrite(iD.actions.ChangeTags(currEntity.id, currTags), annotation); + dispatch.change(currTags); }); } } - i.tags = function(tags) { + wiki.tags = function(tags) { var value = tags[field.key] || '', m = value.match(/([^:]+):([^#]+)(?:#(.+))?/), l = m && _.find(iD.data.wikipedia, function(d) { return m[1] === d[2]; }), @@ -143,7 +158,7 @@ iD.ui.preset.wikipedia = function(field, context) { } } link.attr('href', 'https://' + m[1] + '.wikipedia.org/wiki/' + - m[2].replace(/ /g, '_') + (anchor ? ('#' + anchor) : '')); + m[2].replace(/ /g, '_') + (anchor ? ('#' + anchor) : '')); // unrecognized value format } else { @@ -155,13 +170,15 @@ iD.ui.preset.wikipedia = function(field, context) { } }; - i.entity = function(_) { + wiki.entity = function(_) { + if (!arguments.length) return entity; entity = _; + return wiki; }; - i.focus = function() { + wiki.focus = function() { title.node().focus(); }; - return d3.rebind(i, dispatch, 'on'); + return d3.rebind(wiki, dispatch, 'on'); }; diff --git a/test/spec/ui/preset/wikipedia.js b/test/spec/ui/preset/wikipedia.js index fc3ff1b41..721050035 100644 --- a/test/spec/ui/preset/wikipedia.js +++ b/test/spec/ui/preset/wikipedia.js @@ -1,13 +1,16 @@ describe('iD.ui.preset.wikipedia', function() { - var selection, field; + var entity, context, selection, field, entity; beforeEach(function() { + entity = iD.Node({id: 'n12345'}); + context = iD(); + context.history().merge([entity]); selection = d3.select(document.createElement('div')); - field = iD().presets(iD.data.presets).presets().field('wikipedia'); + field = context.presets(iD.data.presets).presets().field('wikipedia'); }); it('recognizes lang:title format', function() { - var wikipedia = iD.ui.preset.wikipedia(field, {}); + var wikipedia = iD.ui.preset.wikipedia(field, context).entity(entity); selection.call(wikipedia); wikipedia.tags({wikipedia: 'en:Title'}); expect(selection.selectAll('.wiki-lang').value()).to.equal('English'); @@ -16,11 +19,11 @@ describe('iD.ui.preset.wikipedia', function() { }); it('sets a new value', function() { - var wikipedia = iD.ui.preset.wikipedia(field, {}); + var wikipedia = iD.ui.preset.wikipedia(field, context).entity(entity); selection.call(wikipedia); wikipedia.on('change', function(tags) { - expect(tags).to.eql({wikipedia: undefined}); + expect(tags).to.eql({wikipedia: undefined, wikidata: undefined}); }); selection.selectAll('.wiki-lang').value('Deutsch'); @@ -37,7 +40,7 @@ describe('iD.ui.preset.wikipedia', function() { }); it('recognizes pasted URLs', function() { - var wikipedia = iD.ui.preset.wikipedia(field, {}); + var wikipedia = iD.ui.preset.wikipedia(field, context).entity(entity); selection.call(wikipedia); selection.selectAll('.wiki-title').value('http://de.wikipedia.org/wiki/Title'); @@ -48,10 +51,10 @@ describe('iD.ui.preset.wikipedia', function() { }); it('preserves existing language', function() { - selection.call(iD.ui.preset.wikipedia(field, {})); + selection.call(iD.ui.preset.wikipedia(field, context).entity(entity)); selection.selectAll('.wiki-lang').value('Deutsch'); - var wikipedia = iD.ui.preset.wikipedia(field, {}); + var wikipedia = iD.ui.preset.wikipedia(field, context).entity(entity); selection.call(wikipedia); wikipedia.tags({});