diff --git a/css/80_app.css b/css/80_app.css index 11bfa43cb..ada187611 100644 --- a/css/80_app.css +++ b/css/80_app.css @@ -1303,6 +1303,7 @@ img.tag-reference-wiki-image { background-color: #f1f1f1; } .form-field-button .icon { + fill: #333; opacity: .5; } @@ -1336,12 +1337,12 @@ img.tag-reference-wiki-image { width: 100%; } .form-field ul.labeled-inputs li { - border-bottom: 1px solid #ccc; + border-top: 1px solid #ccc; display: flex; flex-flow: row nowrap; } -.form-field ul.labeled-inputs li:last-child { - border-bottom: 0; +.form-field ul.labeled-inputs li:first-child { + border-top: 0; } .form-field ul.labeled-inputs li > span, .form-field ul.labeled-inputs li > div { diff --git a/data/core.yaml b/data/core.yaml index 6d672ae10..50e7a3031 100644 --- a/data/core.yaml +++ b/data/core.yaml @@ -5,6 +5,8 @@ en: remove: remove undo: undo zoom_to: zoom to + copy: copy + open_wikidata: open on wikidata.org modes: add_area: title: Area @@ -1243,3 +1245,7 @@ en: west: "W" coordinate: "{coordinate}{direction}" coordinate_pair: "{latitude}, {longitude}" + wikidata: + identifier: "Identifier" + label: "Label" + description: "Description" diff --git a/data/presets.yaml b/data/presets.yaml index a2850372b..45a4bae42 100644 --- a/data/presets.yaml +++ b/data/presets.yaml @@ -2025,6 +2025,9 @@ en: width: # width=* label: Width (Meters) + wikidata: + # wikidata=* + label: Wikidata wikipedia: # 'wikipedia=*, wikidata=*' label: Wikipedia diff --git a/data/presets/fields.json b/data/presets/fields.json index fafe8b83d..056f65bd3 100644 --- a/data/presets/fields.json +++ b/data/presets/fields.json @@ -342,6 +342,7 @@ "wheelchair": {"key": "wheelchair", "type": "radio", "options": ["yes", "limited", "no"], "icon": "maki-wheelchair", "universal": true, "label": "Wheelchair Access"}, "wholesale": {"key": "wholesale", "type": "typeCombo", "label": "Wholesale"}, "width": {"key": "width", "type": "number", "minValue": 0, "label": "Width (Meters)"}, + "wikidata": {"key": "wikidata", "type": "wikidata", "icon": "wikipedia", "universal": true, "label": "Wikidata"}, "wikipedia": {"key": "wikipedia", "keys": ["wikipedia", "wikidata"], "type": "wikipedia", "icon": "wikipedia", "universal": true, "label": "Wikipedia"}, "windings": {"key": "windings", "type": "number", "minValue": 1, "label": "Windings", "placeholder": "1, 2, 3..."}, "windings/configuration": {"key": "windings:configuration", "type": "combo", "label": "Windings Configuration", "strings": {"options": {"star": "Star / Wye", "delta": "Delta", "open-delta": "Open Delta", "zigzag": "Zig Zag", "open": "Open", "scott": "Scott", "leblanc": "Leblanc"}}} diff --git a/data/presets/fields/wikidata.json b/data/presets/fields/wikidata.json new file mode 100644 index 000000000..d1c5f478a --- /dev/null +++ b/data/presets/fields/wikidata.json @@ -0,0 +1,7 @@ +{ + "key": "wikidata", + "type": "wikidata", + "icon": "wikipedia", + "universal": true, + "label": "Wikidata" +} diff --git a/data/presets/schema/field.json b/data/presets/schema/field.json index 0683361b1..b77a28413 100644 --- a/data/presets/schema/field.json +++ b/data/presets/schema/field.json @@ -71,6 +71,7 @@ "text", "typeCombo", "url", + "wikidata", "wikipedia" ], "required": true diff --git a/data/taginfo.json b/data/taginfo.json index 40341d1f6..f94b703b2 100644 --- a/data/taginfo.json +++ b/data/taginfo.json @@ -8054,8 +8054,8 @@ {"key": "wheelchair", "description": "🄵 Wheelchair Access"}, {"key": "wholesale", "description": "🄵 Wholesale"}, {"key": "width", "description": "🄵 Width (Meters)"}, + {"key": "wikidata", "description": "🄵 Wikidata, 🄵 Wikipedia"}, {"key": "wikipedia", "description": "🄵 Wikipedia"}, - {"key": "wikidata", "description": "🄵 Wikipedia"}, {"key": "windings", "description": "🄵 Windings"}, { "key": "windings:configuration", diff --git a/dist/locales/en.json b/dist/locales/en.json index 94c267637..c7ffc067d 100644 --- a/dist/locales/en.json +++ b/dist/locales/en.json @@ -5,7 +5,9 @@ "information": "info", "remove": "remove", "undo": "undo", - "zoom_to": "zoom to" + "zoom_to": "zoom to", + "copy": "copy", + "open_wikidata": "open on wikidata.org" }, "modes": { "add_area": { @@ -1437,6 +1439,11 @@ "coordinate": "{coordinate}{direction}", "coordinate_pair": "{latitude}, {longitude}" }, + "wikidata": { + "identifier": "Identifier", + "label": "Label", + "description": "Description" + }, "presets": { "categories": { "category-barrier": { @@ -3158,6 +3165,9 @@ "width": { "label": "Width (Meters)" }, + "wikidata": { + "label": "Wikidata" + }, "wikipedia": { "label": "Wikipedia" }, @@ -7508,6 +7518,9 @@ "SPW_PICC": { "name": "SPW(allonie) PICC numerical imagery" }, + "US-TIGER-Roads-2012": { + "name": "TIGER Roads 2012" + }, "US-TIGER-Roads-2014": { "description": "At zoom level 16+, public domain map data from the US Census. At lower zooms, only changes since 2006 minus changes already incorporated into OpenStreetMap", "name": "TIGER Roads 2014" @@ -7516,10 +7529,6 @@ "description": "Yellow = Public domain map data from the US Census. Red = Data not found in OpenStreetMap", "name": "TIGER Roads 2017" }, - "US-TIGER-Roads-2018": { - "description": "Yellow = Public domain map data from the US Census. Red = Data not found in OpenStreetMap", - "name": "TIGER Roads 2018" - }, "US_Forest_Service_roads_overlay": { "description": "Highway: Green casing = unclassified. Brown casing = track. Surface: gravel = light brown fill, Asphalt = black, paved = gray, ground =white, concrete = blue, grass = green. Seasonal = white bars", "name": "U.S. Forest Roads Overlay" @@ -7620,33 +7629,11 @@ "description": "Japan GSI Standard Map. Widely covered.", "name": "Japan GSI Standard Map" }, - "helsingborg-orto": { + "hike_n_bike": { "attribution": { - "text": "© Helsingborg municipality" + "text": "© OpenStreetMap contributors" }, - "description": "Orthophotos from the municipality of Helsingborg 2016, public domain", - "name": "Helsingborg Orthophoto" - }, - "kalmar-orto-2014": { - "attribution": { - "text": "© Kalmar municipality" - }, - "description": "Orthophotos for the north coast of the municipality of Kalmar 2014", - "name": "Kalmar North Orthophoto 2014" - }, - "kalmar-orto-2016": { - "attribution": { - "text": "© Kalmar municipality" - }, - "description": "Orthophotos for the south coast of the municipality of Kalmar 2016", - "name": "Kalmar South Orthophoto 2016" - }, - "kalmar-orto-2018": { - "attribution": { - "text": "© Kalmar municipality" - }, - "description": "Orthophotos for urban areas of the municipality of Kalmar 2018", - "name": "Kalmar Urban Orthophoto 2018" + "name": "Hike & Bike" }, "kelkkareitit": { "attribution": { @@ -7669,20 +7656,6 @@ "description": "Mosaic of Swedish orthophotos from the period 1970–1980. Is under construction.", "name": "Lantmäteriet Historic Orthophoto 1975" }, - "lantmateriet-topowebb": { - "attribution": { - "text": "© Lantmäteriet, CC0" - }, - "description": "Topographic map of Sweden 1:50 000", - "name": "Lantmäteriet Topographic Map" - }, - "linkoping-orto": { - "attribution": { - "text": "© Linköping municipality" - }, - "description": "Orthophotos from the municipality of Linköping 2010, open data", - "name": "Linköping Orthophoto" - }, "mapbox_locator_overlay": { "attribution": { "text": "Terms & Feedback" @@ -7747,13 +7720,6 @@ }, "name": "Stamen Terrain" }, - "stockholm-orto": { - "attribution": { - "text": "© Stockholm municipality, CC0" - }, - "description": "Orthophotos from the municipality of Stockholm 2015, CC0 license", - "name": "Stockholm Orthophoto" - }, "tf-cycle": { "attribution": { "text": "Maps © Thunderforest, Data © OpenStreetMap contributors" diff --git a/modules/presets/index.js b/modules/presets/index.js index 70038eef7..9a7297803 100644 --- a/modules/presets/index.js +++ b/modules/presets/index.js @@ -139,6 +139,10 @@ export function presetIndex() { }); } + // move the wikidata field to directly follow the wikipedia field + _universal.splice(_universal.indexOf(_fields.wikidata), 1); + _universal.splice(_universal.indexOf(_fields.wikipedia)+1, 0, _fields.wikidata); + if (d.presets) { _forEach(d.presets, function(d, id) { all.collection.push(presetPreset(id, d, _fields)); diff --git a/modules/services/wikidata.js b/modules/services/wikidata.js index 1e80e32a1..83301fc65 100644 --- a/modules/services/wikidata.js +++ b/modules/services/wikidata.js @@ -2,6 +2,7 @@ import { json as d3_json } from 'd3-request'; import { utilQsString } from '../util'; +import { currentLocale } from '../util/locale'; var endpoint = 'https://www.wikidata.org/w/api.php?'; @@ -34,6 +35,32 @@ export default { callback(title, data.entities || {}); } }); + }, + + entityByQID: function(qid, callback) { + if (!qid) { + callback('', {}); + return; + } + + var lang = currentLocale.replace(/-/g, '_'); + + d3_json(endpoint + utilQsString({ + action: 'wbgetentities', + format: 'json', + ids: qid, + props: /*sitelinks|*/'labels|descriptions', + //sitefilter: lang + 'wiki', + languages: lang, + languagefallback: 1, + origin: '*' + }), function(err, data) { + if (err || !data || data.error) { + callback('', {}); + } else { + callback(qid, data.entities[qid] || {}); + } + }); } }; diff --git a/modules/ui/fields/index.js b/modules/ui/fields/index.js index 27950023a..12f5a7350 100644 --- a/modules/ui/fields/index.js +++ b/modules/ui/fields/index.js @@ -10,6 +10,7 @@ export * from './maxspeed'; export * from './radio'; export * from './restrictions'; export * from './textarea'; +export * from './wikidata'; export * from './wikipedia'; import { @@ -47,6 +48,7 @@ import { uiFieldLocalized } from './localized'; import { uiFieldMaxspeed } from './maxspeed'; import { uiFieldRestrictions } from './restrictions'; import { uiFieldTextarea } from './textarea'; +import { uiFieldWikidata } from './wikidata'; import { uiFieldWikipedia } from './wikipedia'; export var uiFields = { @@ -73,5 +75,6 @@ export var uiFields = { textarea: uiFieldTextarea, typeCombo: uiFieldTypeCombo, url: uiFieldUrl, + wikidata: uiFieldWikidata, wikipedia: uiFieldWikipedia }; diff --git a/modules/ui/fields/wikidata.js b/modules/ui/fields/wikidata.js new file mode 100644 index 000000000..63fdc5d09 --- /dev/null +++ b/modules/ui/fields/wikidata.js @@ -0,0 +1,196 @@ +import { dispatch as d3_dispatch } from 'd3-dispatch'; + +import { + select as d3_select, + event as d3_event +} from 'd3-selection'; + +import { services } from '../../services/index'; + +import { svgIcon } from '../../svg/index'; +import { + utilGetSetValue, + utilNoAuto, + utilRebind +} from '../../util'; + +import { t } from '../../util/locale'; + + +export function uiFieldWikidata(field) { + var wikidata = services.wikidata; + var dispatch = d3_dispatch('change'), + link = d3_select(null), + title = d3_select(null), + wikiURL = '', + entity; + + + function wiki(selection) { + + var wrap = selection.selectAll('.form-field-input-wrap') + .data([0]); + + wrap = wrap.enter() + .append('div') + .attr('class', 'form-field-input-wrap form-field-input-' + field.type) + .merge(wrap); + + + var list = wrap.selectAll('ul') + .data([0]); + + list = list.enter() + .append('ul') + .attr('class', 'labeled-inputs') + .merge(list); + + var wikidataProperties = ['identifier', 'label', 'description']; + + var items = list.selectAll('li') + .data(wikidataProperties); + + // Enter + var enter = items.enter() + .append('li') + .attr('class', function(d) { return 'preset-wikidata-' + d; }); + + enter + .append('span') + .attr('class', 'label') + .attr('for', function(d) { return 'preset-input-wikidata-' + d; }) + .text(function(d) { return t('wikidata.'+d); }); + + var inputWrap = enter + .append('div') + .attr('class', 'input-wrap'); + + inputWrap.append('input') + .attr('type', 'text') + .attr('class', 'preset-input-wikidata') + .attr('id', function(d) { return 'preset-input-wikidata-' + d; }); + + title = wrap.select('.preset-wikidata-identifier input') + .call(utilNoAuto) + .merge(title); + + title + .on('blur', blur) + .on('change', change); + + var idItem = wrap.select('.preset-wikidata-identifier'); + + idItem.select('button') + .remove(); + + link = idItem.append('button') + .attr('class', 'form-field-button wiki-link') + .attr('title', t('icons.open_wikidata')) + .attr('tabindex', -1) + .call(svgIcon('#iD-icon-out-link')) + .merge(link); + + link + .on('click', function() { + d3_event.preventDefault(); + if (wikiURL) window.open(wikiURL, '_blank'); + }); + + var readOnlyItems = wrap.selectAll('li:not(.preset-wikidata-identifier)'); + + readOnlyItems.select('input') + .classed('disabled', 'true') + .attr('readonly', 'true'); + + readOnlyItems.select('button') + .remove(); + + readOnlyItems.append('button') + .attr('class', 'form-field-button wiki-link') + .attr('title', t('icons.copy')) + .attr('tabindex', -1) + .call(svgIcon('#iD-operation-copy')) + .on('click', function() { + d3_event.preventDefault(); + d3_select(this.parentNode) + .select('input') + .node() + .select(); + document.execCommand('copy'); + }); + } + + + function blur() { + change(); + } + + + function change() { + var syncTags = { + wikidata: utilGetSetValue(title) + }; + dispatch.call('change', this, syncTags); + } + + + wiki.tags = function(tags) { + var value = tags[field.key] || '', + matches = value.match(/^Q[0-9]*$/); + + utilGetSetValue(title, value); + + // value in correct format + if (matches) { + wikiURL = 'https://wikidata.org/wiki/' + value; + wikidata.entityByQID(value, function(qid, entity) { + var label = '', description = ''; + + if (entity.labels && Object.keys(entity.labels).length > 0) { + label = entity.labels[Object.keys(entity.labels)[0]].value; + } + if (entity.descriptions && Object.keys(entity.descriptions).length > 0) { + description = entity.descriptions[Object.keys(entity.descriptions)[0]].value; + } + + d3_select('.preset-wikidata-label') + .style('display', function(){ + return label.length > 0 ? 'flex' : 'none'; + }) + .select('input') + .attr('value', label); + + d3_select('.preset-wikidata-description') + .style('display', function(){ + return description.length > 0 ? 'flex' : 'none'; + }) + .select('input') + .attr('value', description); + }); + // unrecognized value format + } else { + d3_select('.preset-wikidata-label').style('display', 'none'); + d3_select('.preset-wikidata-description').style('display', 'none'); + if (value && value !== '') { + wikiURL = 'https://wikidata.org/wiki/Special:Search?search=' + value; + } else { + wikiURL = ''; + } + } + }; + + + wiki.entity = function(_) { + if (!arguments.length) return entity; + entity = _; + return wiki; + }; + + + wiki.focus = function() { + title.node().focus(); + }; + + + return utilRebind(wiki, dispatch, 'on'); +}