Add privacy policy version check to context and splash screen

(closes #7040)

A few other minor things in this commit
- migrated several ui modal files to ES6 syntax
- switched the splash link from ideditor.org -> ideditor.blog
This commit is contained in:
Bryan Housel
2019-12-19 00:11:40 -05:00
parent 7f2c2062b0
commit ada4fb5814
8 changed files with 240 additions and 217 deletions
+3
View File
@@ -4542,6 +4542,9 @@ img.tile-debug {
padding: 20px;
border-bottom: 1px solid #ccc;
}
.modal-section p:not(:last-of-type) {
padding-bottom: 20px;
}
.modal-section.header h3 {
padding: 0;
}
+4 -2
View File
@@ -739,8 +739,8 @@ en:
title: Privacy
privacy_link: View the iD privacy policy
third_party_icons:
description: Show Third Party Preset Icons
tooltip: Uncheck this box to avoid loading preset icons from third party sites such as Wikimedia Commons, Facebook, or Twitter.
description: Show Third Party Icons
tooltip: Uncheck this box to avoid loading icons from third party sites such as Wikimedia Commons, Facebook, or Twitter.
restore:
heading: You have unsaved changes
description: "Do you wish to restore unsaved changes from a previous editing session?"
@@ -802,6 +802,8 @@ en:
splash:
welcome: Welcome to the iD OpenStreetMap editor
text: "iD is a friendly but powerful tool for contributing to the world's best free world map. This is version {version}. For more information see {website} and report bugs at {github}."
privacy_update: "Our privacy policy has recently been updated."
privacy: "{updateMessage} By using this software, you agree to do so in accordance with the iD privacy policy, which can be found {here}."
walkthrough: "Start the Walkthrough"
start: "Edit now"
source_switch:
+4 -2
View File
@@ -933,8 +933,8 @@
"title": "Privacy",
"privacy_link": "View the iD privacy policy",
"third_party_icons": {
"description": "Show Third Party Preset Icons",
"tooltip": "Uncheck this box to avoid loading preset icons from third party sites such as Wikimedia Commons, Facebook, or Twitter."
"description": "Show Third Party Icons",
"tooltip": "Uncheck this box to avoid loading icons from third party sites such as Wikimedia Commons, Facebook, or Twitter."
}
}
},
@@ -1004,6 +1004,8 @@
"splash": {
"welcome": "Welcome to the iD OpenStreetMap editor",
"text": "iD is a friendly but powerful tool for contributing to the world's best free world map. This is version {version}. For more information see {website} and report bugs at {github}.",
"privacy_update": "Our privacy policy has recently been updated.",
"privacy": "{updateMessage} By using this software, you agree to do so in accordance with the iD privacy policy, which can be found {here}.",
"walkthrough": "Start the Walkthrough",
"start": "Edit now"
},
+1
View File
@@ -26,6 +26,7 @@ export function coreContext() {
var _deferred = new Set();
context.version = '2.16.0';
context.privacyVersion = '20191217';
// create a special translation that contains the keys in place of the strings
var tkeys = JSON.parse(JSON.stringify(dataEn)); // clone deep
+41 -41
View File
@@ -3,53 +3,53 @@ import { uiModal } from './modal';
export function uiLoading(context) {
var _modalSelection = d3_select(null);
var _message = '';
var _blocking = false;
let _modalSelection = d3_select(null);
let _message = '';
let _blocking = false;
var loading = function(selection) {
_modalSelection = uiModal(selection, _blocking);
let loading = (selection) => {
_modalSelection = uiModal(selection, _blocking);
var loadertext = _modalSelection.select('.content')
.classed('loading-modal', true)
.append('div')
.attr('class', 'modal-section fillL');
let loadertext = _modalSelection.select('.content')
.classed('loading-modal', true)
.append('div')
.attr('class', 'modal-section fillL');
loadertext
.append('img')
.attr('class', 'loader')
.attr('src', context.imagePath('loader-white.gif'));
loadertext
.append('img')
.attr('class', 'loader')
.attr('src', context.imagePath('loader-white.gif'));
loadertext
.append('h3')
.text(_message);
_modalSelection.select('button.close')
.attr('class', 'hide');
return loading;
};
loading.message = function(_) {
if (!arguments.length) return _message;
_message = _;
return loading;
};
loading.blocking = function(_) {
if (!arguments.length) return _blocking;
_blocking = _;
return loading;
};
loading.close = function() {
_modalSelection.remove();
};
loadertext
.append('h3')
.text(_message);
_modalSelection.select('button.close')
.attr('class', 'hide');
return loading;
};
loading.message = (val) => {
if (!arguments.length) return _message;
_message = val;
return loading;
};
loading.blocking = (val) => {
if (!arguments.length) return _blocking;
_blocking = val;
return loading;
};
loading.close = () => {
_modalSelection.remove();
};
return loading;
}
+60 -63
View File
@@ -1,78 +1,75 @@
import {
event as d3_event,
select as d3_select
} from 'd3-selection';
import { event as d3_event, select as d3_select } from 'd3-selection';
import { svgIcon } from '../svg/icon';
import { utilKeybinding } from '../util';
export function uiModal(selection, blocking) {
var keybinding = utilKeybinding('modal');
var previous = selection.select('div.modal');
var animate = previous.empty();
let keybinding = utilKeybinding('modal');
let previous = selection.select('div.modal');
let animate = previous.empty();
previous.transition()
.duration(200)
.style('opacity', 0)
.remove();
previous.transition()
.duration(200)
.style('opacity', 0)
.remove();
var shaded = selection
.append('div')
.attr('class', 'shaded')
.style('opacity', 0);
let shaded = selection
.append('div')
.attr('class', 'shaded')
.style('opacity', 0);
shaded.close = function() {
shaded
.transition()
.duration(200)
.style('opacity',0)
.remove();
modal
.transition()
.duration(200)
.style('top','0px');
d3_select(document)
.call(keybinding.unbind);
};
var modal = shaded
.append('div')
.attr('class', 'modal fillL');
if (!blocking) {
shaded.on('click.remove-modal', function() {
if (d3_event.target === this) {
shaded.close();
}
});
modal.append('button')
.attr('class', 'close')
.on('click', shaded.close)
.call(svgIcon('#iD-icon-close'));
keybinding
.on('⌫', shaded.close)
.on('⎋', shaded.close);
d3_select(document)
.call(keybinding);
}
shaded.close = () => {
shaded
.transition()
.duration(200)
.style('opacity',0)
.remove();
modal
.append('div')
.attr('class', 'content');
.transition()
.duration(200)
.style('top','0px');
if (animate) {
shaded.transition().style('opacity', 1);
} else {
shaded.style('opacity', 1);
}
d3_select(document)
.call(keybinding.unbind);
};
return shaded;
let modal = shaded
.append('div')
.attr('class', 'modal fillL');
if (!blocking) {
shaded.on('click.remove-modal', () => {
if (d3_event.target === this) {
shaded.close();
}
});
modal
.append('button')
.attr('class', 'close')
.on('click', shaded.close)
.call(svgIcon('#iD-icon-close'));
keybinding
.on('⌫', shaded.close)
.on('⎋', shaded.close);
d3_select(document)
.call(keybinding);
}
modal
.append('div')
.attr('class', 'content');
if (animate) {
shaded.transition().style('opacity', 1);
} else {
shaded.style('opacity', 1);
}
return shaded;
}
+51 -53
View File
@@ -3,70 +3,68 @@ import { uiModal } from './modal';
export function uiRestore(context) {
return function(selection) {
if (!context.history().lock() || !context.history().restorableChanges()) return;
return function(selection) {
if (!context.history().lock() || !context.history().restorableChanges())
return;
let modalSelection = uiModal(selection, true);
var modalSelection = uiModal(selection, true);
modalSelection.select('.modal')
.attr('class', 'modal fillL');
modalSelection.select('.modal')
.attr('class', 'modal fillL');
let introModal = modalSelection.select('.content');
var introModal = modalSelection.select('.content');
introModal
.append('div')
.attr('class', 'modal-section')
.append('h3')
.text(t('restore.heading'));
introModal
.append('div')
.attr('class', 'modal-section')
.append('h3')
.text(t('restore.heading'));
introModal
.append('div')
.attr('class','modal-section')
.append('p')
.text(t('restore.description'));
introModal
.append('div')
.attr('class','modal-section')
.append('p')
.text(t('restore.description'));
let buttonWrap = introModal
.append('div')
.attr('class', 'modal-actions');
var buttonWrap = introModal
.append('div')
.attr('class', 'modal-actions');
let restore = buttonWrap
.append('button')
.attr('class', 'restore')
.on('click', () => {
context.history().restore();
modalSelection.remove();
});
var restore = buttonWrap
.append('button')
.attr('class', 'restore')
.on('click', function() {
context.history().restore();
modalSelection.remove();
});
restore
.append('svg')
.attr('class', 'logo logo-restore')
.append('use')
.attr('xlink:href', '#iD-logo-restore');
restore
.append('svg')
.attr('class', 'logo logo-restore')
.append('use')
.attr('xlink:href', '#iD-logo-restore');
restore
.append('div')
.text(t('restore.restore'));
restore
.append('div')
.text(t('restore.restore'));
let reset = buttonWrap
.append('button')
.attr('class', 'reset')
.on('click', () => {
context.history().clearSaved();
modalSelection.remove();
});
var reset = buttonWrap
.append('button')
.attr('class', 'reset')
.on('click', function() {
context.history().clearSaved();
modalSelection.remove();
});
reset
.append('svg')
.attr('class', 'logo logo-reset')
.append('use')
.attr('xlink:href', '#iD-logo-reset');
reset
.append('svg')
.attr('class', 'logo logo-reset')
.append('use')
.attr('xlink:href', '#iD-logo-reset');
reset
.append('div')
.text(t('restore.reset'));
reset
.append('div')
.text(t('restore.reset'));
restore.node().focus();
};
restore.node().focus();
};
}
+76 -56
View File
@@ -4,77 +4,97 @@ import { uiModal } from './modal';
export function uiSplash(context) {
return (selection) => {
// Exception - if there are restorable changes, skip this splash screen.
// This is because we currently only support one `uiModal` at a time
// and we need to show them `uiRestore`` instead of this one.
if (context.history().lock() && context.history().restorableChanges()) return;
return function(selection) {
if (context.storage('sawSplash'))
return;
// If user has not seen this version of the privacy policy, show the splash again.
let updateMessage = '';
const sawPrivacyVersion = context.storage('sawPrivacyVersion');
if (sawPrivacyVersion !== context.privacyVersion) {
updateMessage = t('splash.privacy_update');
context.storage('sawSplash', null);
}
context.storage('sawSplash', true);
if (context.storage('sawSplash')) return;
var modalSelection = uiModal(selection);
context.storage('sawSplash', true);
context.storage('sawPrivacyVersion', context.privacyVersion);
modalSelection.select('.modal')
.attr('class', 'modal-splash modal');
let modalSelection = uiModal(selection);
var introModal = modalSelection.select('.content')
.append('div')
.attr('class', 'fillL');
modalSelection.select('.modal')
.attr('class', 'modal-splash modal');
introModal
.append('div')
.attr('class','modal-section')
.append('h3').text(t('splash.welcome'));
let introModal = modalSelection.select('.content')
.append('div')
.attr('class', 'fillL');
introModal
.append('div')
.attr('class','modal-section')
.append('p')
.html(t('splash.text', {
version: context.version,
website: '<a href="http://ideditor.com/">ideditor.com</a>',
github: '<a href="https://github.com/openstreetmap/iD">github.com</a>'
}));
introModal
.append('div')
.attr('class','modal-section')
.append('h3')
.text(t('splash.welcome'));
var buttonWrap = introModal
.append('div')
.attr('class', 'modal-actions');
let modalSection = introModal
.append('div')
.attr('class','modal-section');
var walkthrough = buttonWrap
.append('button')
.attr('class', 'walkthrough')
.on('click', function() {
context.container().call(uiIntro(context));
modalSelection.close();
});
modalSection
.append('p')
.html(t('splash.text', {
version: context.version,
website: '<a target="_blank" href="http://ideditor.blog/">ideditor.blog</a>',
github: '<a target="_blank" href="https://github.com/openstreetmap/iD">github.com</a>'
}));
walkthrough
.append('svg')
.attr('class', 'logo logo-walkthrough')
.append('use')
.attr('xlink:href', '#iD-logo-walkthrough');
modalSection
.append('p')
.html(t('splash.privacy', {
updateMessage: updateMessage,
here: '<a target="_blank" href="https://github.com/openstreetmap/iD/blob/master/PRIVACY.md">here</a>'
}));
walkthrough
.append('div')
.text(t('splash.walkthrough'));
let buttonWrap = introModal
.append('div')
.attr('class', 'modal-actions');
var startEditing = buttonWrap
.append('button')
.attr('class', 'start-editing')
.on('click', modalSelection.close);
let walkthrough = buttonWrap
.append('button')
.attr('class', 'walkthrough')
.on('click', () => {
context.container().call(uiIntro(context));
modalSelection.close();
});
startEditing
.append('svg')
.attr('class', 'logo logo-features')
.append('use')
.attr('xlink:href', '#iD-logo-features');
walkthrough
.append('svg')
.attr('class', 'logo logo-walkthrough')
.append('use')
.attr('xlink:href', '#iD-logo-walkthrough');
startEditing
.append('div')
.text(t('splash.start'));
walkthrough
.append('div')
.text(t('splash.walkthrough'));
let startEditing = buttonWrap
.append('button')
.attr('class', 'start-editing')
.on('click', modalSelection.close);
modalSelection.select('button.close')
.attr('class','hide');
startEditing
.append('svg')
.attr('class', 'logo logo-features')
.append('use')
.attr('xlink:href', '#iD-logo-features');
};
startEditing
.append('div')
.text(t('splash.start'));
modalSelection.select('button.close')
.attr('class','hide');
};
}