From 8c9aae1499697c7a0e98eab539c4993b279ab7c5 Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Thu, 14 Sep 2017 17:35:06 -0400 Subject: [PATCH 1/6] Add download changes link to uiCommitChanges summary (WIP: still need to check IE11 and fix download on conflict screen) --- css/80_app.css | 1 + data/core.yaml | 1 + dist/locales/en.json | 1 + modules/modes/save.js | 1 + modules/ui/commit_changes.js | 40 +++++++++++++++++++++++++++++++++++- 5 files changed, 43 insertions(+), 1 deletion(-) diff --git a/css/80_app.css b/css/80_app.css index e652cbecf..d050ec313 100644 --- a/css/80_app.css +++ b/css/80_app.css @@ -3532,6 +3532,7 @@ img.tile-removing { border: 1px solid #ccc; border-radius: 4px; background: #fff; + margin-bottom: 10px; } .mode-save .warning-section { diff --git a/data/core.yaml b/data/core.yaml index 82df21868..797f01354 100644 --- a/data/core.yaml +++ b/data/core.yaml @@ -260,6 +260,7 @@ en: save: Upload cancel: Cancel changes: "{count} Changes" + download_changes: Download OsmChange file warnings: Warnings modified: Modified deleted: Deleted diff --git a/dist/locales/en.json b/dist/locales/en.json index 526b80556..63343b1e8 100644 --- a/dist/locales/en.json +++ b/dist/locales/en.json @@ -334,6 +334,7 @@ "save": "Upload", "cancel": "Cancel", "changes": "{count} Changes", + "download_changes": "Download OsmChange file", "warnings": "Warnings", "modified": "Modified", "deleted": "Deleted", diff --git a/modules/modes/save.js b/modules/modes/save.js index 391fe2f47..e071056c5 100644 --- a/modules/modes/save.js +++ b/modules/modes/save.js @@ -249,6 +249,7 @@ export function modeSave(context) { selection.call(uiConflicts(context) .list(conflicts) .on('download', function() { + // FIXME: var data = JXON.stringify(changeset.update({ id: 'CHANGEME' }).osmChangeJXON(origChanges)), win = window.open('data:text/xml,' + encodeURIComponent(data), '_blank'); win.focus(); diff --git a/modules/ui/commit_changes.js b/modules/ui/commit_changes.js index e47fd81b2..7e7dac177 100644 --- a/modules/ui/commit_changes.js +++ b/modules/ui/commit_changes.js @@ -1,6 +1,11 @@ import * as d3 from 'd3'; import { t } from '../util/locale'; +import { JXON } from '../util/jxon'; +import { actionDiscardTags } from '../actions'; +import { osmChangeset } from '../osm'; import { svgIcon } from '../svg'; +import { utilDetect } from '../util/detect'; + import { utilDisplayName, utilDisplayType, @@ -9,10 +14,13 @@ import { export function uiCommitChanges(context) { + var detected = utilDetect(); + function commitChanges(selection) { - var summary = context.history().difference().summary(); + var history = context.history(), + summary = history.difference().summary(); var container = selection.selectAll('.modal-section.commit-section') .data([0]); @@ -85,6 +93,36 @@ export function uiCommitChanges(context) { .on('click', zoomToEntity); + // Download changeset link + var changeset = new osmChangeset({ id: 'CHANGEME' }), + changes = history.changes(actionDiscardTags(history.difference())), + data = JXON.stringify(changeset.osmChangeJXON(changes)), + uri = 'data:text/xml,' + encodeURIComponent(data); + + var downloadLink = container.selectAll('.download-changes') + .data([0]); + + var enter = downloadLink.enter() + .append('a') + .attr('class', 'download-changes') + .attr('href', uri) // no IE11 ? + .attr('download', 'changes.osc') // no IE11 ? + // .attr('target', '_blank') // maybe IE11 ? + .call(svgIcon('#icon-load', 'inline')); + + enter + .append('span') + .text(t('commit.download_changes')); + + downloadLink + .merge(enter) + .on('click.download', function() { + if (!detected.ie) return; // yes IE11 ? + var win = window.open(uri, '_blank'); + win.focus(); + }); + + function mouseover(d) { if (d.entity) { context.surface().selectAll( From a43b1e3c0af4efb88669b2be8f95f2e1f43b8c44 Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Thu, 14 Sep 2017 22:25:17 -0400 Subject: [PATCH 2/6] WIP: fix download changes on save conflicts screen --- modules/modes/save.js | 8 +------ modules/ui/conflicts.js | 53 ++++++++++++++++++++++++++++++----------- 2 files changed, 40 insertions(+), 21 deletions(-) diff --git a/modules/modes/save.js b/modules/modes/save.js index e071056c5..b16f1240e 100644 --- a/modules/modes/save.js +++ b/modules/modes/save.js @@ -3,7 +3,6 @@ import _ from 'lodash'; import { d3keybinding } from '../lib/d3.keybinding.js'; import { t } from '../util/locale'; -import { JXON } from '../util/jxon'; import { actionDiscardTags, @@ -248,12 +247,7 @@ export function modeSave(context) { selection.call(uiConflicts(context) .list(conflicts) - .on('download', function() { - // FIXME: - var data = JXON.stringify(changeset.update({ id: 'CHANGEME' }).osmChangeJXON(origChanges)), - win = window.open('data:text/xml,' + encodeURIComponent(data), '_blank'); - win.focus(); - }) + .origChanges(origChanges) .on('cancel', function() { history.pop(); selection.remove(); diff --git a/modules/ui/conflicts.js b/modules/ui/conflicts.js index c6d023a1c..5b09fd6e4 100644 --- a/modules/ui/conflicts.js +++ b/modules/ui/conflicts.js @@ -1,14 +1,18 @@ import * as d3 from 'd3'; import { t } from '../util/locale'; -import { geoExtent } from '../geo/index'; -import { svgIcon } from '../svg/index'; -import { utilEntityOrMemberSelector } from '../util/index'; +import { JXON } from '../util/jxon'; +import { geoExtent } from '../geo'; +import { osmChangeset } from '../osm'; +import { svgIcon } from '../svg'; +import { utilDetect } from '../util/detect'; +import { utilEntityOrMemberSelector } from '../util'; import { utilRebind } from '../util/rebind'; export function uiConflicts(context) { - var dispatch = d3.dispatch('download', 'cancel', 'save'), - list; + var dispatch = d3.dispatch('cancel', 'save'), + origChanges, + conflictList; function conflicts(selection) { @@ -30,14 +34,28 @@ export function uiConflicts(context) { .append('div') .attr('class', 'body fillL'); + + // Download changes link + var detected = utilDetect(), + changeset = new osmChangeset({ id: 'CHANGEME' }), + data = JXON.stringify(changeset.osmChangeJXON(origChanges)), + uri = 'data:text/xml,' + encodeURIComponent(data); + body .append('div') .attr('class', 'conflicts-help') .text(t('save.conflict.help')) .append('a') .attr('class', 'conflicts-download') + .attr('href', uri) // no IE11 ? + .attr('download', 'changes.osc') // no IE11 ? + // .attr('target', '_blank') // maybe IE11 ? .text(t('save.conflict.download_changes')) - .on('click.download', function() { dispatch.call('download'); }); + .on('click.download', function() { + if (!detected.ie) return; // yes IE11 ? + var win = window.open(uri, '_blank'); + win.focus(); + }); body .append('div') @@ -57,7 +75,7 @@ export function uiConflicts(context) { buttons .append('button') - .attr('disabled', list.length > 1) + .attr('disabled', conflictList.length > 1) .attr('class', 'action conflicts-button col6') .text(t('save.title')) .on('click.try_again', function() { dispatch.call('save'); }); @@ -71,12 +89,12 @@ export function uiConflicts(context) { function showConflict(selection, index) { - if (index < 0 || index >= list.length) return; + if (index < 0 || index >= conflictList.length) return; var parent = d3.select(selection.node().parentNode); // enable save button if this is the last conflict being reviewed.. - if (index === list.length - 1) { + if (index === conflictList.length - 1) { window.setTimeout(function() { parent.select('.conflicts-button') .attr('disabled', null); @@ -90,7 +108,7 @@ export function uiConflicts(context) { var item = selection .selectAll('.conflict') - .data([list[index]]); + .data([conflictList[index]]); var enter = item.enter() .append('div') @@ -99,7 +117,7 @@ export function uiConflicts(context) { enter .append('h4') .attr('class', 'conflict-count') - .text(t('save.conflict.count', { num: index + 1, total: list.length })); + .text(t('save.conflict.count', { num: index + 1, total: conflictList.length })); enter .append('a') @@ -141,7 +159,7 @@ export function uiConflicts(context) { .attr('class', 'conflict-nav-button action col6') .attr('disabled', function(d, i) { return (i === 0 && index === 0) || - (i === 1 && index === list.length - 1) || null; + (i === 1 && index === conflictList.length - 1) || null; }) .on('click', function(d, i) { var container = parent.select('.conflict-container'), @@ -252,8 +270,15 @@ export function uiConflicts(context) { // ] // } conflicts.list = function(_) { - if (!arguments.length) return list; - list = _; + if (!arguments.length) return conflictList; + conflictList = _; + return conflicts; + }; + + + conflicts.origChanges = function(_) { + if (!arguments.length) return origChanges; + origChanges = _; return conflicts; }; From 82494750ef6142669779d2c263269e065588bcfe Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Fri, 15 Sep 2017 16:39:50 -0400 Subject: [PATCH 3/6] Cleanup code, detect download support (alternate flow for IE, Edge) --- modules/ui/commit_changes.js | 45 ++++++++++++++++++--------------- modules/ui/conflicts.js | 48 +++++++++++++++++++++++++----------- modules/util/detect.js | 2 ++ 3 files changed, 60 insertions(+), 35 deletions(-) diff --git a/modules/ui/commit_changes.js b/modules/ui/commit_changes.js index 7e7dac177..b2dac7111 100644 --- a/modules/ui/commit_changes.js +++ b/modules/ui/commit_changes.js @@ -97,30 +97,35 @@ export function uiCommitChanges(context) { var changeset = new osmChangeset({ id: 'CHANGEME' }), changes = history.changes(actionDiscardTags(history.difference())), data = JXON.stringify(changeset.osmChangeJXON(changes)), - uri = 'data:text/xml,' + encodeURIComponent(data); + uri = 'data:text/xml;charset=utf-8,' + encodeURIComponent(data); - var downloadLink = container.selectAll('.download-changes') - .data([0]); - - var enter = downloadLink.enter() + var linkEnter = container.selectAll('.download-changes') + .data([0]) + .enter() .append('a') - .attr('class', 'download-changes') - .attr('href', uri) // no IE11 ? - .attr('download', 'changes.osc') // no IE11 ? - // .attr('target', '_blank') // maybe IE11 ? - .call(svgIcon('#icon-load', 'inline')); + .attr('class', 'download-changes'); - enter - .append('span') - .text(t('commit.download_changes')); + if (detected.download) { // all except IE11 and Edge + linkEnter // download the data uri as a file + .attr('href', uri) + .attr('download', 'changes.osc') + .call(svgIcon('#icon-load', 'inline')) + .append('span') + .text(t('commit.download_changes')); - downloadLink - .merge(enter) - .on('click.download', function() { - if (!detected.ie) return; // yes IE11 ? - var win = window.open(uri, '_blank'); - win.focus(); - }); + } else { // IE11 and Edge + linkEnter // open data uri in a new tab + .attr('target', '_blank') + .call(svgIcon('#icon-load', 'inline')) + .append('span') + .text(t('commit.download_changes')); + + linkEnter + .on('click.download', function() { + var win = window.open(uri, '_blank'); + win.focus(); + }); + } function mouseover(d) { diff --git a/modules/ui/conflicts.js b/modules/ui/conflicts.js index 5b09fd6e4..726cc3e17 100644 --- a/modules/ui/conflicts.js +++ b/modules/ui/conflicts.js @@ -34,28 +34,46 @@ export function uiConflicts(context) { .append('div') .attr('class', 'body fillL'); + var conflictsHelp = body + .append('div') + .attr('class', 'conflicts-help') + .text(t('save.conflict.help')); + // Download changes link var detected = utilDetect(), changeset = new osmChangeset({ id: 'CHANGEME' }), data = JXON.stringify(changeset.osmChangeJXON(origChanges)), - uri = 'data:text/xml,' + encodeURIComponent(data); + uri = 'data:text/xml;charset=utf-8,' + encodeURIComponent(data); - body - .append('div') - .attr('class', 'conflicts-help') - .text(t('save.conflict.help')) + var linkEnter = conflictsHelp.selectAll('.download-changes') + .data([0]) + .enter() .append('a') - .attr('class', 'conflicts-download') - .attr('href', uri) // no IE11 ? - .attr('download', 'changes.osc') // no IE11 ? - // .attr('target', '_blank') // maybe IE11 ? - .text(t('save.conflict.download_changes')) - .on('click.download', function() { - if (!detected.ie) return; // yes IE11 ? - var win = window.open(uri, '_blank'); - win.focus(); - }); + .attr('class', 'download-changes'); + + if (detected.download) { // all except IE11 and Edge + linkEnter // download the data uri as a file + .attr('href', uri) + .attr('download', 'changes.osc') + .call(svgIcon('#icon-load', 'inline')) + .append('span') + .text(t('save.conflict.download_changes')); + + } else { // IE11 and Edge + linkEnter // open data uri in a new tab + .attr('target', '_blank') + .call(svgIcon('#icon-load', 'inline')) + .append('span') + .text(t('save.conflict.download_changes')); + + linkEnter + .on('click.download', function() { + var win = window.open(uri, '_blank'); + win.focus(); + }); + } + body .append('div') diff --git a/modules/util/detect.js b/modules/util/detect.js index ed8f3ad2e..92a9691a5 100644 --- a/modules/util/detect.js +++ b/modules/util/detect.js @@ -110,6 +110,8 @@ export function utilDetect(force) { detected.filedrop = (window.FileReader && 'ondrop' in window); + detected.download = !(detected.ie || detected.browser.toLowerCase() === 'edge'); + function nav(x) { return navigator.userAgent.indexOf(x) !== -1; } From 359eab468c696b362be89e957694716b02f9c481 Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Fri, 15 Sep 2017 19:44:55 -0400 Subject: [PATCH 4/6] OsmChange -> osmChange --- data/core.yaml | 4 ++-- dist/locales/en.json | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/data/core.yaml b/data/core.yaml index 797f01354..87902111f 100644 --- a/data/core.yaml +++ b/data/core.yaml @@ -260,7 +260,7 @@ en: save: Upload cancel: Cancel changes: "{count} Changes" - download_changes: Download OsmChange file + download_changes: Download osmChange file warnings: Warnings modified: Modified deleted: Deleted @@ -464,7 +464,7 @@ en: keep_remote: Use theirs restore: Restore delete: Leave Deleted - download_changes: Or download your changes. + download_changes: Or download osmChange file done: "All conflicts resolved!" help: | Another user changed some of the same map features you changed. diff --git a/dist/locales/en.json b/dist/locales/en.json index 63343b1e8..6ba544542 100644 --- a/dist/locales/en.json +++ b/dist/locales/en.json @@ -334,7 +334,7 @@ "save": "Upload", "cancel": "Cancel", "changes": "{count} Changes", - "download_changes": "Download OsmChange file", + "download_changes": "Download osmChange file", "warnings": "Warnings", "modified": "Modified", "deleted": "Deleted", @@ -573,7 +573,7 @@ "keep_remote": "Use theirs", "restore": "Restore", "delete": "Leave Deleted", - "download_changes": "Or download your changes.", + "download_changes": "Or download osmChange file", "done": "All conflicts resolved!", "help": "Another user changed some of the same map features you changed.\nClick on each feature below for more details about the conflict, and choose whether to keep\nyour changes or the other user's changes.\n" } From 2edc37b74e53dca6da68d00919dfe7c2e87cd254 Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Fri, 15 Sep 2017 20:04:42 -0400 Subject: [PATCH 5/6] Leave out the changeset_id when downloading osmChange file per https://github.com/openstreetmap/iD/pull/4350#discussion_r139261887 --- modules/ui/commit_changes.js | 9 ++++++--- modules/ui/conflicts.js | 7 +++++-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/modules/ui/commit_changes.js b/modules/ui/commit_changes.js index b2dac7111..7d1295ef0 100644 --- a/modules/ui/commit_changes.js +++ b/modules/ui/commit_changes.js @@ -94,9 +94,12 @@ export function uiCommitChanges(context) { // Download changeset link - var changeset = new osmChangeset({ id: 'CHANGEME' }), - changes = history.changes(actionDiscardTags(history.difference())), - data = JXON.stringify(changeset.osmChangeJXON(changes)), + var changeset = new osmChangeset().update({ id: undefined }), + changes = history.changes(actionDiscardTags(history.difference())); + + delete changeset.id; // Export without chnageset_id + + var data = JXON.stringify(changeset.osmChangeJXON(changes)), uri = 'data:text/xml;charset=utf-8,' + encodeURIComponent(data); var linkEnter = container.selectAll('.download-changes') diff --git a/modules/ui/conflicts.js b/modules/ui/conflicts.js index 726cc3e17..1155953f7 100644 --- a/modules/ui/conflicts.js +++ b/modules/ui/conflicts.js @@ -42,8 +42,11 @@ export function uiConflicts(context) { // Download changes link var detected = utilDetect(), - changeset = new osmChangeset({ id: 'CHANGEME' }), - data = JXON.stringify(changeset.osmChangeJXON(origChanges)), + changeset = new osmChangeset(); + + delete changeset.id; // Export without chnageset_id + + var data = JXON.stringify(changeset.osmChangeJXON(origChanges)), uri = 'data:text/xml;charset=utf-8,' + encodeURIComponent(data); var linkEnter = conflictsHelp.selectAll('.download-changes') From 202354508e37d31a003993840866dd6ceb38cd3c Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Sat, 16 Sep 2017 22:39:52 -0400 Subject: [PATCH 6/6] Use file blobs instead of data uri for saving (This seems to be an easier path to IE11/Edge support) --- modules/ui/commit_changes.js | 27 ++++++++++++--------------- modules/ui/conflicts.js | 27 ++++++++++++--------------- 2 files changed, 24 insertions(+), 30 deletions(-) diff --git a/modules/ui/commit_changes.js b/modules/ui/commit_changes.js index 7d1295ef0..c33c1bddb 100644 --- a/modules/ui/commit_changes.js +++ b/modules/ui/commit_changes.js @@ -100,7 +100,8 @@ export function uiCommitChanges(context) { delete changeset.id; // Export without chnageset_id var data = JXON.stringify(changeset.osmChangeJXON(changes)), - uri = 'data:text/xml;charset=utf-8,' + encodeURIComponent(data); + blob = new Blob([data], {type: 'text/xml;charset=utf-8;'}), + fileName = 'changes.osc'; var linkEnter = container.selectAll('.download-changes') .data([0]) @@ -108,28 +109,24 @@ export function uiCommitChanges(context) { .append('a') .attr('class', 'download-changes'); - if (detected.download) { // all except IE11 and Edge - linkEnter // download the data uri as a file - .attr('href', uri) - .attr('download', 'changes.osc') - .call(svgIcon('#icon-load', 'inline')) - .append('span') - .text(t('commit.download_changes')); + if (detected.download) { // All except IE11 and Edge + linkEnter // download the data as a file + .attr('href', window.URL.createObjectURL(blob)) + .attr('download', fileName); } else { // IE11 and Edge linkEnter // open data uri in a new tab .attr('target', '_blank') - .call(svgIcon('#icon-load', 'inline')) - .append('span') - .text(t('commit.download_changes')); - - linkEnter .on('click.download', function() { - var win = window.open(uri, '_blank'); - win.focus(); + navigator.msSaveBlob(blob, fileName); }); } + linkEnter + .call(svgIcon('#icon-load', 'inline')) + .append('span') + .text(t('commit.download_changes')); + function mouseover(d) { if (d.entity) { diff --git a/modules/ui/conflicts.js b/modules/ui/conflicts.js index 1155953f7..ca89b9980 100644 --- a/modules/ui/conflicts.js +++ b/modules/ui/conflicts.js @@ -47,7 +47,8 @@ export function uiConflicts(context) { delete changeset.id; // Export without chnageset_id var data = JXON.stringify(changeset.osmChangeJXON(origChanges)), - uri = 'data:text/xml;charset=utf-8,' + encodeURIComponent(data); + blob = new Blob([data], {type: 'text/xml;charset=utf-8;'}), + fileName = 'changes.osc'; var linkEnter = conflictsHelp.selectAll('.download-changes') .data([0]) @@ -55,28 +56,24 @@ export function uiConflicts(context) { .append('a') .attr('class', 'download-changes'); - if (detected.download) { // all except IE11 and Edge - linkEnter // download the data uri as a file - .attr('href', uri) - .attr('download', 'changes.osc') - .call(svgIcon('#icon-load', 'inline')) - .append('span') - .text(t('save.conflict.download_changes')); + if (detected.download) { // All except IE11 and Edge + linkEnter // download the data as a file + .attr('href', window.URL.createObjectURL(blob)) + .attr('download', fileName); } else { // IE11 and Edge linkEnter // open data uri in a new tab .attr('target', '_blank') - .call(svgIcon('#icon-load', 'inline')) - .append('span') - .text(t('save.conflict.download_changes')); - - linkEnter .on('click.download', function() { - var win = window.open(uri, '_blank'); - win.focus(); + navigator.msSaveBlob(blob, fileName); }); } + linkEnter + .call(svgIcon('#icon-load', 'inline')) + .append('span') + .text(t('save.conflict.download_changes')); + body .append('div')