diff --git a/modules/ui/success.js b/modules/ui/success.js index aabde0ecb..e6970195e 100644 --- a/modules/ui/success.js +++ b/modules/ui/success.js @@ -10,377 +10,375 @@ import { utilRebind } from '../util/rebind'; export function uiSuccess(context) { - var MAXEVENTS = 2; - var detected = utilDetect(); - var dispatch = d3_dispatch('cancel'); - var _changeset; - var _location; + const MAXEVENTS = 2; + const detected = utilDetect(); + const dispatch = d3_dispatch('cancel'); + let _changeset; + let _location; - // string-to-date parsing in JavaScript is weird - function parseEventDate(when) { - if (!when) return; + // string-to-date parsing in JavaScript is weird + function parseEventDate(when) { + if (!when) return; - var raw = when.trim(); - if (!raw) return; + let raw = when.trim(); + if (!raw) return; - if (!/Z$/.test(raw)) { // if no trailing 'Z', add one - raw += 'Z'; // this forces date to be parsed as a UTC date - } - - var parsed = new Date(raw); - return new Date(parsed.toUTCString().substr(0, 25)); // convert to local timezone + if (!/Z$/.test(raw)) { // if no trailing 'Z', add one + raw += 'Z'; // this forces date to be parsed as a UTC date } - - function success(selection) { - var header = selection - .append('div') - .attr('class', 'header fillL'); - - header - .append('button') - .attr('class', 'fr') - .on('click', function() { dispatch.call('cancel'); }) - .call(svgIcon('#iD-icon-close')); - - header - .append('h3') - .text(t('success.just_edited')); - - var body = selection - .append('div') - .attr('class', 'body save-success fillL'); - - var summary = body - .append('div') - .attr('class', 'save-summary'); - - summary - .append('h3') - .text(t('success.thank_you' + (_location ? '_location' : ''), { where: _location })); - - summary - .append('p') - .text(t('success.help_html')) - .append('a') - .attr('class', 'link-out') - .attr('target', '_blank') - .attr('tabindex', -1) - .attr('href', t('success.help_link_url')) - .call(svgIcon('#iD-icon-out-link', 'inline')) - .append('span') - .text(t('success.help_link_text')); - - var osm = context.connection(); - if (!osm) return; - - var changesetURL = osm.changesetURL(_changeset.id); - - var table = summary - .append('table') - .attr('class', 'summary-table'); - - var row = table - .append('tr') - .attr('class', 'summary-row'); - - row - .append('td') - .attr('class', 'cell-icon summary-icon') - .append('a') - .attr('target', '_blank') - .attr('href', changesetURL) - .append('svg') - .attr('class', 'logo-small') - .append('use') - .attr('xlink:href', '#iD-logo-osm'); - - var summaryDetail = row - .append('td') - .attr('class', 'cell-detail summary-detail'); - - summaryDetail - .append('a') - .attr('class', 'cell-detail summary-view-on-osm') - .attr('target', '_blank') - .attr('href', changesetURL) - .text(t('success.view_on_osm')); - - summaryDetail - .append('div') - .html(t('success.changeset_id', { - changeset_id: '' + _changeset.id + '' - })); + const parsed = new Date(raw); + return new Date(parsed.toUTCString().substr(0, 25)); // convert to local timezone + } - // Gather community polygon IDs intersecting the map.. - var matchFeatures = data.community.query(context.map().center(), true) || []; - var matchIDs = matchFeatures.map(function(feature) { return feature.id; }); + function success(selection) { + let header = selection + .append('div') + .attr('class', 'header fillL'); - // Gather community resources that are either global or match a polygon. - var matchResources = Object.values(data.community.resources) - .filter(function(v) { return !v.featureId || matchIDs.indexOf(v.featureId) !== -1; }); + header + .append('button') + .attr('class', 'fr') + .on('click', () => dispatch.call('cancel')) + .call(svgIcon('#iD-icon-close')); - if (matchResources.length) { - // sort by size ascending, then by community rank - matchResources.sort(function(a, b) { - var aSize = Infinity; - var bSize = Infinity; - var aOrder = a.order || 0; - var bOrder = b.order || 0; + header + .append('h3') + .text(t('success.just_edited')); - if (a.featureId) { - aSize = data.community.features[a.featureId].properties.area; - } - if (b.featureId) { - bSize = data.community.features[b.featureId].properties.area; - } + let body = selection + .append('div') + .attr('class', 'body save-success fillL'); - return aSize < bSize ? -1 : aSize > bSize ? 1 : bOrder - aOrder; - }); + let summary = body + .append('div') + .attr('class', 'save-summary'); - body - .call(showCommunityLinks, matchResources); + summary + .append('h3') + .text(t('success.thank_you' + (_location ? '_location' : ''), { where: _location })); + + summary + .append('p') + .text(t('success.help_html')) + .append('a') + .attr('class', 'link-out') + .attr('target', '_blank') + .attr('tabindex', -1) + .attr('href', t('success.help_link_url')) + .call(svgIcon('#iD-icon-out-link', 'inline')) + .append('span') + .text(t('success.help_link_text')); + + let osm = context.connection(); + if (!osm) return; + + let changesetURL = osm.changesetURL(_changeset.id); + + let table = summary + .append('table') + .attr('class', 'summary-table'); + + let row = table + .append('tr') + .attr('class', 'summary-row'); + + row + .append('td') + .attr('class', 'cell-icon summary-icon') + .append('a') + .attr('target', '_blank') + .attr('href', changesetURL) + .append('svg') + .attr('class', 'logo-small') + .append('use') + .attr('xlink:href', '#iD-logo-osm'); + + let summaryDetail = row + .append('td') + .attr('class', 'cell-detail summary-detail'); + + summaryDetail + .append('a') + .attr('class', 'cell-detail summary-view-on-osm') + .attr('target', '_blank') + .attr('href', changesetURL) + .text(t('success.view_on_osm')); + + summaryDetail + .append('div') + .html(t('success.changeset_id', { + changeset_id: `${_changeset.id}` + })); + + + // Gather community polygon IDs intersecting the map.. + let matchFeatures = data.community.query(context.map().center(), true) || []; + let matchIDs = matchFeatures.map(feature => feature.id); + + // Gather community resources that are either global or match a polygon. + let matchResources = Object.values(data.community.resources) + .filter(v => { return !v.featureId || matchIDs.indexOf(v.featureId) !== -1; }); + + if (matchResources.length) { + // sort by size ascending, then by community rank + matchResources.sort((a, b) => { + let aSize = Infinity; + let bSize = Infinity; + let aOrder = a.order || 0; + let bOrder = b.order || 0; + + if (a.featureId) { + aSize = data.community.features[a.featureId].properties.area; } + if (b.featureId) { + bSize = data.community.features[b.featureId].properties.area; + } + + return aSize < bSize ? -1 : aSize > bSize ? 1 : bOrder - aOrder; + }); + + body + .call(showCommunityLinks, matchResources); } + } - function showCommunityLinks(selection, matchResources) { - var communityLinks = selection - .append('div') - .attr('class', 'save-communityLinks'); + function showCommunityLinks(selection, matchResources) { + let communityLinks = selection + .append('div') + .attr('class', 'save-communityLinks'); - communityLinks - .append('h3') - .text(t('success.like_osm')); + communityLinks + .append('h3') + .text(t('success.like_osm')); - var table = communityLinks - .append('table') - .attr('class', 'community-table'); + let table = communityLinks + .append('table') + .attr('class', 'community-table'); - var row = table.selectAll('.community-row') - .data(matchResources); + let row = table.selectAll('.community-row') + .data(matchResources); - var rowEnter = row.enter() - .append('tr') - .attr('class', 'community-row'); + let rowEnter = row.enter() + .append('tr') + .attr('class', 'community-row'); - rowEnter - .append('td') - .attr('class', 'cell-icon community-icon') - .append('a') - .attr('target', '_blank') - .attr('href', function(d) { return d.url; }) - .append('svg') - .attr('class', 'logo-small') - .append('use') - .attr('xlink:href', function(d) { return '#community-' + d.type; }); + rowEnter + .append('td') + .attr('class', 'cell-icon community-icon') + .append('a') + .attr('target', '_blank') + .attr('href', d => d.url) + .append('svg') + .attr('class', 'logo-small') + .append('use') + .attr('xlink:href', d => `#community-${d.type}`); - var communityDetail = rowEnter - .append('td') - .attr('class', 'cell-detail community-detail'); + let communityDetail = rowEnter + .append('td') + .attr('class', 'cell-detail community-detail'); - communityDetail - .each(showCommunityDetails); + communityDetail + .each(showCommunityDetails); - communityLinks - .append('div') - .attr('class', 'community-missing') - .text(t('success.missing')) - .append('a') - .attr('class', 'link-out') - .attr('target', '_blank') - .attr('tabindex', -1) - .call(svgIcon('#iD-icon-out-link', 'inline')) - .attr('href', 'https://github.com/osmlab/osm-community-index/issues') - .append('span') - .text(t('success.tell_us')); - } + communityLinks + .append('div') + .attr('class', 'community-missing') + .text(t('success.missing')) + .append('a') + .attr('class', 'link-out') + .attr('target', '_blank') + .attr('tabindex', -1) + .call(svgIcon('#iD-icon-out-link', 'inline')) + .attr('href', 'https://github.com/osmlab/osm-community-index/issues') + .append('span') + .text(t('success.tell_us')); + } - function showCommunityDetails(d) { - var selection = d3_select(this); - var communityID = d.id; - var replacements = { - url: linkify(d.url), - signupUrl: linkify(d.signupUrl || d.url) - }; - - selection - .append('div') - .attr('class', 'community-name') - .append('a') - .attr('target', '_blank') - .attr('href', d.url) - .text(t('community.' + d.id + '.name')); - - var descriptionHTML = t('community.' + d.id + '.description', replacements); - - if (d.type === 'reddit') { // linkify subreddits #4997 - descriptionHTML = descriptionHTML - .replace(/(\/r\/\w*\/*)/i, function(match) { return linkify(d.url, match); }); - } - - selection - .append('div') - .attr('class', 'community-description') - .html(descriptionHTML); - - if (d.extendedDescription || (d.languageCodes && d.languageCodes.length)) { - selection - .append('div') - .call(uiDisclosure(context, 'community-more-' + d.id, false) - .expanded(false) - .updatePreference(false) - .title(t('success.more')) - .content(showMore) - ); - } - - var nextEvents = (d.events || []) - .map(function(event) { - event.date = parseEventDate(event.when); - return event; - }) - .filter(function(event) { // date is valid and future (or today) - var t = event.date.getTime(); - var now = (new Date()).setHours(0,0,0,0); - return !isNaN(t) && t >= now; - }) - .sort(function(a, b) { // sort by date ascending - return a.date < b.date ? -1 : a.date > b.date ? 1 : 0; - }) - .slice(0, MAXEVENTS); // limit number of events shown - - if (nextEvents.length) { - selection - .append('div') - .call(uiDisclosure(context, 'community-events-' + d.id, false) - .expanded(false) - .updatePreference(false) - .title(t('success.events')) - .content(showNextEvents) - ) - .select('.hide-toggle') - .append('span') - .attr('class', 'badge-text') - .text(nextEvents.length); - } - - - function showMore(selection) { - var more = selection.selectAll('.community-more') - .data([0]); - - var moreEnter = more.enter() - .append('div') - .attr('class', 'community-more'); - - if (d.extendedDescription) { - moreEnter - .append('div') - .attr('class', 'community-extended-description') - .html(t('community.' + d.id + '.extendedDescription', replacements)); - } - - if (d.languageCodes && d.languageCodes.length) { - var languageList = d.languageCodes.map(function(code) { - return languageName(code); - }).join(', '); - - moreEnter - .append('div') - .attr('class', 'community-languages') - .text(t('success.languages', { languages: languageList })); - } - } - - - function showNextEvents(selection) { - var events = selection - .append('div') - .attr('class', 'community-events'); - - var item = events.selectAll('.community-event') - .data(nextEvents); - - var itemEnter = item.enter() - .append('div') - .attr('class', 'community-event'); - - itemEnter - .append('div') - .attr('class', 'community-event-name') - .append('a') - .attr('target', '_blank') - .attr('href', function(d) { return d.url; }) - .text(function(d) { - var name = d.name; - if (d.i18n && d.id) { - name = t('community.' + communityID + '.events.' + d.id + '.name', { default: name }); - } - return name; - }); - - itemEnter - .append('div') - .attr('class', 'community-event-when') - .text(function(d) { - var options = { - weekday: 'short', day: 'numeric', month: 'short', year: 'numeric' - }; - if (d.date.getHours() || d.date.getMinutes()) { // include time if it has one - options.hour = 'numeric'; - options.minute = 'numeric'; - } - return d.date.toLocaleString(detected.locale, options); - }); - - itemEnter - .append('div') - .attr('class', 'community-event-where') - .text(function(d) { - var where = d.where; - if (d.i18n && d.id) { - where = t('community.' + communityID + '.events.' + d.id + '.where', { default: where }); - } - return where; - }); - - itemEnter - .append('div') - .attr('class', 'community-event-description') - .text(function(d) { - var description = d.description; - if (d.i18n && d.id) { - description = t('community.' + communityID + '.events.' + d.id + '.description', { default: description }); - } - return description; - }); - } - - - function linkify(url, text) { - text = text || url; - return '' + text + ''; - } - } - - - success.changeset = function(_) { - if (!arguments.length) return _changeset; - _changeset = _; - return success; + function showCommunityDetails(d) { + let selection = d3_select(this); + let communityID = d.id; + let replacements = { + url: linkify(d.url), + signupUrl: linkify(d.signupUrl || d.url) }; + selection + .append('div') + .attr('class', 'community-name') + .append('a') + .attr('target', '_blank') + .attr('href', d.url) + .text(t(`community.${d.id}.name`)); - success.location = function(_) { - if (!arguments.length) return _location; - _location = _; - return success; - }; + let descriptionHTML = t(`community.${d.id}.description`, replacements); + + if (d.type === 'reddit') { // linkify subreddits #4997 + descriptionHTML = descriptionHTML + .replace(/(\/r\/\w*\/*)/i, match => linkify(d.url, match)); + } + + selection + .append('div') + .attr('class', 'community-description') + .html(descriptionHTML); + + if (d.extendedDescription || (d.languageCodes && d.languageCodes.length)) { + selection + .append('div') + .call(uiDisclosure(context, `community-more-${d.id}`, false) + .expanded(false) + .updatePreference(false) + .title(t('success.more')) + .content(showMore) + ); + } + + let nextEvents = (d.events || []) + .map(event => { + event.date = parseEventDate(event.when); + return event; + }) + .filter(event => { // date is valid and future (or today) + const t = event.date.getTime(); + const now = (new Date()).setHours(0,0,0,0); + return !isNaN(t) && t >= now; + }) + .sort((a, b) => { // sort by date ascending + return a.date < b.date ? -1 : a.date > b.date ? 1 : 0; + }) + .slice(0, MAXEVENTS); // limit number of events shown + + if (nextEvents.length) { + selection + .append('div') + .call(uiDisclosure(context, `community-events-${d.id}`, false) + .expanded(false) + .updatePreference(false) + .title(t('success.events')) + .content(showNextEvents) + ) + .select('.hide-toggle') + .append('span') + .attr('class', 'badge-text') + .text(nextEvents.length); + } - return utilRebind(success, dispatch, 'on'); + function showMore(selection) { + let more = selection.selectAll('.community-more') + .data([0]); + + let moreEnter = more.enter() + .append('div') + .attr('class', 'community-more'); + + if (d.extendedDescription) { + moreEnter + .append('div') + .attr('class', 'community-extended-description') + .html(t(`community.${d.id}.extendedDescription`, replacements)); + } + + if (d.languageCodes && d.languageCodes.length) { + const languageList = d.languageCodes + .map(code => languageName(code)) + .join(', '); + + moreEnter + .append('div') + .attr('class', 'community-languages') + .text(t('success.languages', { languages: languageList })); + } + } + + + function showNextEvents(selection) { + let events = selection + .append('div') + .attr('class', 'community-events'); + + let item = events.selectAll('.community-event') + .data(nextEvents); + + let itemEnter = item.enter() + .append('div') + .attr('class', 'community-event'); + + itemEnter + .append('div') + .attr('class', 'community-event-name') + .append('a') + .attr('target', '_blank') + .attr('href', d => d.url) + .text(d => { + let name = d.name; + if (d.i18n && d.id) { + name = t(`community.${communityID}.events.${d.id}.name`, { default: name }); + } + return name; + }); + + itemEnter + .append('div') + .attr('class', 'community-event-when') + .text(d => { + let options = { weekday: 'short', day: 'numeric', month: 'short', year: 'numeric' }; + if (d.date.getHours() || d.date.getMinutes()) { // include time if it has one + options.hour = 'numeric'; + options.minute = 'numeric'; + } + return d.date.toLocaleString(detected.locale, options); + }); + + itemEnter + .append('div') + .attr('class', 'community-event-where') + .text(d => { + let where = d.where; + if (d.i18n && d.id) { + where = t(`community.${communityID}.events.${d.id}.where`, { default: where }); + } + return where; + }); + + itemEnter + .append('div') + .attr('class', 'community-event-description') + .text(d => { + let description = d.description; + if (d.i18n && d.id) { + description = t(`community.${communityID}.events.${d.id}.description`, { default: description }); + } + return description; + }); + } + + + function linkify(url, text) { + text = text || url; + return `${text}`; + } + } + + + success.changeset = (val) => { + if (!arguments.length) return _changeset; + _changeset = val; + return success; + }; + + + success.location = (val) => { + if (!arguments.length) return _location; + _location = val; + return success; + }; + + + return utilRebind(success, dispatch, 'on'); }