diff --git a/css/80_app.css b/css/80_app.css index 68bdd3b6f..2a1e3184f 100644 --- a/css/80_app.css +++ b/css/80_app.css @@ -2707,6 +2707,19 @@ img.tile-removing { position: relative; } +.panel-content-history .links a { + padding-left: 10px; +} +[dir='rtl'] .panel-content-history .links a { + padding-left: auto; + padding-right: 10px; +} + +.panel-content-history .view-history-on-osm { + display: block; + padding: 10px 0; +} + .panel-content-location .location-name { padding-top: 10px; } diff --git a/data/core.yaml b/data/core.yaml index 2a044289f..e9518957b 100644 --- a/data/core.yaml +++ b/data/core.yaml @@ -274,6 +274,16 @@ en: truncated_list: "Edits by {users} and {count} others" infobox: key: I + history: + key: H + title: History + selected: "{n} selected" + version: Version + last_edit: Last Edit + edited_by: Edited By + changeset: Changeset + unknown: Unknown + link_text: History on openstreetmap.org location: key: L title: Location diff --git a/dist/locales/en.json b/dist/locales/en.json index d6f11033f..13ca2d42f 100644 --- a/dist/locales/en.json +++ b/dist/locales/en.json @@ -350,6 +350,17 @@ }, "infobox": { "key": "I", + "history": { + "key": "H", + "title": "History", + "selected": "{n} selected", + "version": "Version", + "last_edit": "Last Edit", + "edited_by": "Edited By", + "changeset": "Changeset", + "unknown": "Unknown", + "link_text": "History on openstreetmap.org" + }, "location": { "key": "L", "title": "Location" diff --git a/modules/ui/panels/history.js b/modules/ui/panels/history.js new file mode 100644 index 000000000..e5bea1d95 --- /dev/null +++ b/modules/ui/panels/history.js @@ -0,0 +1,161 @@ +import * as d3 from 'd3'; +import _ from 'lodash'; +import { t } from '../../util/locale'; +import { svgIcon } from '../../svg'; + + +export function uiPanelHistory(context) { + + + function displayTimestamp(entity) { + if (!entity.timestamp) return t('infobox.history.unknown'); + + var d = new Date(entity.timestamp); + if (isNaN(d.getTime())) return t('infobox.history.unknown'); + + return d.toLocaleString(); + } + + + function displayUser(selection, entity) { + if (!entity.user) { + selection + .append('span') + .text(t('infobox.history.unknown')); + return; + } + + selection + .append('span') + .attr('class', 'user-name') + .text(entity.user); + + var links = selection + .append('div') + .attr('class', 'links'); + + links + .append('a') + .attr('class', 'user-osm-link') + .attr('href', context.connection().userURL(entity.user)) + .attr('target', '_blank') + .attr('tabindex', -1) + .text('OSM'); + + links + .append('a') + .attr('class', 'user-hdyc-link') + .attr('href', 'https://hdyc.neis-one.org/?' + entity.user) + .attr('target', '_blank') + .attr('tabindex', -1) + .text('HDYC'); + } + + + function displayChangeset(selection, entity) { + if (!entity.changeset) { + selection + .append('span') + .text(t('infobox.history.unknown')); + return; + } + + selection + .append('span') + .attr('class', 'changeset-id') + .text(entity.changeset); + + var links = selection + .append('div') + .attr('class', 'links'); + + links + .append('a') + .attr('class', 'changeset-osm-link') + .attr('href', context.connection().userURL(entity.changeset)) + .attr('target', '_blank') + .attr('tabindex', -1) + .text('OSM'); + + links + .append('a') + .attr('class', 'changeset-osmcha-link') + .attr('href', 'https://osmcha.mapbox.com/changesets/' + entity.changeset) + .attr('target', '_blank') + .attr('tabindex', -1) + .text('OSMCha'); + } + + + function redraw(selection) { + if (d3.selectAll('.infobox.hide').size()) return; // infobox is hidden + + var selected = _.filter(context.selectedIDs(), function(e) { return context.hasEntity(e); }), + singular = selected.length === 1 ? selected[0] : null; + + selection.html(''); + + selection + .append('h4') + .attr('class', 'history-heading') + .text(singular || t('infobox.history.selected', { n: selected.length })); + + if (!singular) return; + + var entity = context.entity(singular); + + var list = selection + .append('ul'); + + list + .append('li') + .text(t('infobox.history.version') + ': ' + entity.version); + + list + .append('li') + .text(t('infobox.history.last_edit') + ': ' + displayTimestamp(entity)); + + list + .append('li') + .text(t('infobox.history.edited_by') + ': ') + .call(displayUser, entity); + + list + .append('li') + .text(t('infobox.history.changeset') + ': ') + .call(displayChangeset, entity); + + selection + .append('a') + .attr('class', 'view-history-on-osm') + .attr('target', '_blank') + .attr('tabindex', -1) + .attr('href', context.connection().historyURL(entity)) + .call(svgIcon('#icon-out-link', 'inline')) + .append('span') + .text(t('infobox.history.link_text')); + } + + + + var panel = function(selection) { + selection.call(redraw); + + context.map() + .on('drawn.info-history', function() { + selection.call(redraw); + }); + }; + + panel.off = function() { + context.map() + .on('drawn.info-history', null); + }; + + panel.id = 'history'; + panel.title = t('infobox.history.title'); + panel.key = t('infobox.history.key'); + + + return panel; +} diff --git a/modules/ui/panels/index.js b/modules/ui/panels/index.js index 9fc7475ac..a7a4e2ed1 100644 --- a/modules/ui/panels/index.js +++ b/modules/ui/panels/index.js @@ -1,10 +1,13 @@ +export * from './history'; export * from './location'; export * from './measurement'; +import { uiPanelHistory } from './history'; import { uiPanelLocation } from './location'; import { uiPanelMeasurement } from './measurement'; export var uiInfoPanels = { + history: uiPanelHistory, location: uiPanelLocation, measurement: uiPanelMeasurement, };