From 992a6aa958294188c44a181ff0acbb9367b96711 Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Sat, 15 Apr 2017 00:32:36 -0400 Subject: [PATCH] More guard code to protect against user undos and mode changes --- modules/renderer/map.js | 2 +- modules/ui/intro/area.js | 173 +++++++++++++++++++------- modules/ui/intro/building.js | 218 +++++++++++++++++++++------------ modules/ui/intro/line.js | 4 +- modules/ui/intro/navigation.js | 64 +++++----- modules/ui/intro/point.js | 137 ++++++++++++++------- modules/ui/intro/welcome.js | 4 +- 7 files changed, 400 insertions(+), 202 deletions(-) diff --git a/modules/renderer/map.js b/modules/renderer/map.js index e99c37590..855a6b623 100644 --- a/modules/renderer/map.js +++ b/modules/renderer/map.js @@ -74,7 +74,7 @@ export function rendererMap(context) { context.history() .on('change.map', immediateRedraw) - .on('undone.context redone.context', function(stack) { + .on('undone.map redone.map', function(stack) { var followSelected = false; if (Array.isArray(stack.selectedIDs)) { followSelected = (stack.selectedIDs.length === 1 && stack.selectedIDs[0][0] === 'n'); diff --git a/modules/ui/intro/area.js b/modules/ui/intro/area.js index 8d5877210..2cb2b48f8 100644 --- a/modules/ui/intro/area.js +++ b/modules/ui/intro/area.js @@ -1,5 +1,6 @@ import * as d3 from 'd3'; import { t } from '../../util/locale'; +import { modeBrowse, modeSelect } from '../../modes'; import { utilRebind } from '../../util/rebind'; import { icon, pad, transitionTime } from './helper'; @@ -9,7 +10,8 @@ export function uiIntroArea(context, reveal) { playground = [-85.63552, 41.94159], playgroundPreset = context.presets().item('leisure/playground'), descriptionField = context.presets().field('description'), - timeouts = []; + timeouts = [], + areaId; var chapter = { @@ -29,7 +31,9 @@ export function uiIntroArea(context, reveal) { function addArea() { + context.enter(modeBrowse(context)); context.history().reset('initial'); + areaId = null; var msec = transitionTime(playground, context.map().center()); if (msec) { reveal(null, null, { duration: 0 }); } @@ -63,6 +67,8 @@ export function uiIntroArea(context, reveal) { return chapter.restart(); } + areaId = null; + var padding = 120 * Math.pow(2, context.map().zoom() - 19); var box = pad(playground, padding, context); reveal(box, t('intro.areas.start_playground')); @@ -91,23 +97,27 @@ export function uiIntroArea(context, reveal) { return chapter.restart(); } - var padding = 150 * Math.pow(2, context.map().zoom() - 19); + areaId = null; + + var padding = 120 * Math.pow(2, context.map().zoom() - 19); var box = pad(playground, padding, context); reveal(box, t('intro.areas.continue_playground')); context.map().on('move.intro drawn.intro', function() { - padding = 150 * Math.pow(2, context.map().zoom() - 19); + padding = 120 * Math.pow(2, context.map().zoom() - 19); box = pad(playground, padding, context); reveal(box, t('intro.areas.continue_playground'), {duration: 0}); }); context.on('enter.intro', function(mode) { - if (mode.id === 'draw-area') + if (mode.id === 'draw-area') { return; - else if (mode.id === 'select') + } else if (mode.id === 'select') { + areaId = context.selectedIDs()[0]; return continueTo(searchPresets); - else + } else { return chapter.restart(); + } }); function continueTo(nextStep) { @@ -119,58 +129,93 @@ export function uiIntroArea(context, reveal) { function searchPresets() { - if (context.mode().id !== 'select') { - return chapter.restart(); + if (!areaId || !context.hasEntity(areaId)) { + return addArea(); + } + var ids = context.selectedIDs(); + if (context.mode().id !== 'select' || !ids.length || ids[0] !== areaId) { + context.enter(modeSelect(context, [areaId])); } - context.on('exit.intro', function() { - return chapter.restart(); - }); - - d3.select('.preset-search-input') - .on('keyup.intro', checkPresetSearch); - timeout(function() { + // reset pane, in case user somehow happened to change it.. + d3.select('.inspector-wrap .panewrap').style('right', '-100%'); + + d3.select('.preset-search-input') + .on('keydown.intro', null) + .on('keyup.intro', checkPresetSearch); + reveal('.preset-search-input', t('intro.areas.search_playground', { preset: playgroundPreset.name() }) ); - }, 500); - } + }, 400); // after preset list pane visible.. + context.on('enter.intro', function(mode) { + if (!areaId || !context.hasEntity(areaId)) { + return continueTo(addArea); + } - function checkPresetSearch() { - var first = d3.select('.preset-list-item:first-child'); + var ids = context.selectedIDs(); + if (mode.id !== 'select' || !ids.length || ids[0] !== areaId) { + // keep the user's area selected.. + context.enter(modeSelect(context, [areaId])); - if (first.classed('preset-leisure-playground')) { - reveal(first.select('.preset-list-button').node(), - t('intro.areas.choose_playground', { preset: playgroundPreset.name() }), - { duration: 300 } - ); + // reset pane, in case user somehow happened to change it.. + d3.select('.inspector-wrap .panewrap').style('right', '-100%'); - d3.select('.preset-search-input') - .on('keydown.intro', eventCancel, true) - .on('keyup.intro', null); + d3.select('.preset-search-input') + .on('keydown.intro', null) + .on('keyup.intro', checkPresetSearch); - context.history().on('change.intro', function() { - continueTo(clickAddField); - }); + reveal('.preset-search-input', + t('intro.areas.search_playground', { preset: playgroundPreset.name() }) + ); + + context.history().on('change.intro', null); + } + }); + + function checkPresetSearch() { + var first = d3.select('.preset-list-item:first-child'); + + if (first.classed('preset-leisure-playground')) { + reveal(first.select('.preset-list-button').node(), + t('intro.areas.choose_playground', { preset: playgroundPreset.name() }), + { duration: 300 } + ); + + d3.select('.preset-search-input') + .on('keydown.intro', eventCancel, true) + .on('keyup.intro', null); + + context.history().on('change.intro', function() { + continueTo(clickAddField); + }); + } } function continueTo(nextStep) { - context.on('exit.intro', null); + context.on('enter.intro', null); context.history().on('change.intro', null); - d3.select('.preset-search-input').on('keydown.intro', null); + d3.select('.preset-search-input').on('keydown.intro keyup.intro', null); nextStep(); } } function clickAddField() { - context.on('exit.intro', function() { - return chapter.restart(); - }); + if (!areaId || !context.hasEntity(areaId)) { + return addArea(); + } + var ids = context.selectedIDs(); + if (context.mode().id !== 'select' || !ids.length || ids[0] !== areaId) { + return searchPresets(); + } timeout(function() { + // reset pane, in case user somehow happened to change it.. + d3.select('.inspector-wrap .panewrap').style('right', '0%'); + reveal('.more-fields .combobox-input', t('intro.areas.add_field'), { duration: 300 } @@ -180,7 +225,11 @@ export function uiIntroArea(context, reveal) { .on('click.intro', function() { continueTo(chooseDescriptionField); }); - }, 300); // after editor pane visible + }, 400); // after editor pane visible + + context.on('exit.intro', function() { + return continueTo(searchPresets); + }); function continueTo(nextStep) { d3.select('.more-fields .combobox-input').on('click.intro', null); @@ -191,9 +240,13 @@ export function uiIntroArea(context, reveal) { function chooseDescriptionField() { - context.on('exit.intro', function() { - return chapter.restart(); - }); + if (!areaId || !context.hasEntity(areaId)) { + return addArea(); + } + var ids = context.selectedIDs(); + if (context.mode().id !== 'select' || !ids.length || ids[0] !== areaId) { + return searchPresets(); + } reveal('div.combobox', t('intro.areas.choose_field', { field: descriptionField.label() }), @@ -203,13 +256,18 @@ export function uiIntroArea(context, reveal) { d3.select('div.combobox') .on('click.intro', function() { timeout(function() { - if (d3.select('.form-field-description').empty()) + if (d3.select('.form-field-description').empty()) { continueTo(retryChooseDescription); - else + } else { continueTo(describePlayground); - }, 300); + } + }, 300); // after description field added. }); + context.on('exit.intro', function() { + return continueTo(searchPresets); + }); + function continueTo(nextStep) { d3.select('div.combobox').on('click.intro', null); context.on('exit.intro', null); @@ -219,6 +277,17 @@ export function uiIntroArea(context, reveal) { function describePlayground() { + if (!areaId || !context.hasEntity(areaId)) { + return addArea(); + } + var ids = context.selectedIDs(); + if (context.mode().id !== 'select' || !ids.length || ids[0] !== areaId) { + return searchPresets(); + } + + // reset pane, in case user happened to change it.. + d3.select('.inspector-wrap .panewrap').style('right', '0%'); + context.on('exit.intro', function() { continueTo(play); }); @@ -236,9 +305,16 @@ export function uiIntroArea(context, reveal) { function retryChooseDescription() { - context.on('exit.intro', function() { - return chapter.restart(); - }); + if (!areaId || !context.hasEntity(areaId)) { + return addArea(); + } + var ids = context.selectedIDs(); + if (context.mode().id !== 'select' || !ids.length || ids[0] !== areaId) { + return searchPresets(); + } + + // reset pane, in case user happened to change it.. + d3.select('.inspector-wrap .panewrap').style('right', '0%'); reveal('.entity-editor-pane', t('intro.areas.retry_add_field', { field: descriptionField.label() }), { @@ -246,6 +322,10 @@ export function uiIntroArea(context, reveal) { buttonCallback: function() { continueTo(clickAddField); } }); + context.on('exit.intro', function() { + return continueTo(searchPresets); + }); + function continueTo(nextStep) { context.on('exit.intro', null); nextStep(); @@ -273,8 +353,7 @@ export function uiIntroArea(context, reveal) { chapter.exit = function() { timeouts.forEach(window.clearTimeout); - context.on('enter.intro', null); - context.on('exit.intro', null); + context.on('enter.intro exit.intro', null); context.map().on('move.intro drawn.intro', null); context.history().on('change.intro', null); d3.select('.preset-search-input').on('keydown.intro keyup.intro', null); diff --git a/modules/ui/intro/building.js b/modules/ui/intro/building.js index 1c13c5daa..b62fce0ff 100644 --- a/modules/ui/intro/building.js +++ b/modules/ui/intro/building.js @@ -1,7 +1,7 @@ import * as d3 from 'd3'; import _ from 'lodash'; import { t } from '../../util/locale'; -import { modeBrowse } from '../../modes/browse'; +import { modeBrowse, modeSelect } from '../../modes'; import { utilRebind } from '../../util/rebind'; import { icon, pad, isMostlySquare, selectMenuItem, transitionTime } from './helper'; @@ -49,9 +49,9 @@ export function uiIntroBuilding(context, reveal) { function addHouse() { - houseId = null; - tankId = null; + context.enter(modeBrowse(context)); context.history().reset('initial'); + houseId = null; var msec = transitionTime(house, context.map().center()); if (msec) { reveal(null, null, { duration: 0 }); } @@ -67,9 +67,6 @@ export function uiIntroBuilding(context, reveal) { .append('use') .attr('xlink:href', '#building-images'); - houseId = null; - context.history().reset('initial'); - context.on('enter.intro', function(mode) { if (mode.id !== 'add-area') return; continueTo(startHouse); @@ -85,7 +82,7 @@ export function uiIntroBuilding(context, reveal) { function startHouse() { if (context.mode().id !== 'add-area') { - return chapter.restart(); + return continueTo(addHouse); } houseId = null; @@ -100,7 +97,7 @@ export function uiIntroBuilding(context, reveal) { context.on('enter.intro', function(mode) { if (mode.id !== 'draw-area') return chapter.restart(); - continueTo(drawHouse); + continueTo(continueHouse); }); }, 550); // after easing @@ -113,12 +110,13 @@ export function uiIntroBuilding(context, reveal) { } - function drawHouse() { + function continueHouse() { if (context.mode().id !== 'draw-area') { - return chapter.restart(); + return continueTo(addHouse); } houseId = null; + revealHouse(house, t('intro.buildings.continue_building')); context.map().on('move.intro drawn.intro', function() { @@ -175,51 +173,83 @@ export function uiIntroBuilding(context, reveal) { function chooseCategoryBuilding() { - if (context.mode().id !== 'select') { - return chapter.restart(); + if (!houseId || !context.hasEntity(houseId)) { + return addHouse(); + } + var ids = context.selectedIDs(); + if (context.mode().id !== 'select' || !ids.length || ids[0] !== houseId) { + context.enter(modeSelect(context, [houseId])); } - context.on('exit.intro', function() { - return chapter.restart(); - }); - - var button = d3.select('.preset-category-building .preset-list-button'); - if (button.empty()) return chapter.restart(); - timeout(function() { + // reset pane, in case user somehow happened to change it.. + d3.select('.inspector-wrap .panewrap').style('right', '-100%'); + + var button = d3.select('.preset-category-building .preset-list-button'); + reveal(button.node(), t('intro.buildings.choose_category_building', { category: buildingCatetory.name() }) ); - button.on('click.intro', function() { continueTo(choosePresetHouse); }); - }, 500); + + button.on('click.intro', function() { + continueTo(choosePresetHouse); + }); + + }, 400); // after preset list pane visible.. + + + context.on('enter.intro', function(mode) { + if (!houseId || !context.hasEntity(houseId)) { + return continueTo(addHouse); + } + var ids = context.selectedIDs(); + if (mode.id !== 'select' || !ids.length || ids[0] !== houseId) { + return continueTo(chooseCategoryBuilding); + } + }); function continueTo(nextStep) { d3.select('.preset-list-button').on('click.intro', null); - context.on('exit.intro', null); + context.on('enter.intro', null); nextStep(); } } function choosePresetHouse() { - if (context.mode().id !== 'select') { - return chapter.restart(); + if (!houseId || !context.hasEntity(houseId)) { + return addHouse(); + } + var ids = context.selectedIDs(); + if (context.mode().id !== 'select' || !ids.length || ids[0] !== houseId) { + context.enter(modeSelect(context, [houseId])); } - context.on('exit.intro', function() { - return chapter.restart(); - }); - - var button = d3.select('.preset-building-house .preset-list-button'); - if (button.empty()) return chapter.restart(); - timeout(function() { + // reset pane, in case user somehow happened to change it.. + d3.select('.inspector-wrap .panewrap').style('right', '-100%'); + + var button = d3.select('.preset-building-house .preset-list-button'); + reveal(button.node(), t('intro.buildings.choose_preset_house', { preset: housePreset.name() }), { duration: 300 } ); - button.on('click.intro', function() { continueTo(closeEditorHouse); }); - }, 300); + + button.on('click.intro', function() { + continueTo(closeEditorHouse); + }); + }, 400); // after preset list pane visible.. + + context.on('enter.intro', function(mode) { + if (!houseId || !context.hasEntity(houseId)) { + return continueTo(addHouse); + } + var ids = context.selectedIDs(); + if (mode.id !== 'select' || !ids.length || ids[0] !== houseId) { + return continueTo(chooseCategoryBuilding); + } + }); function continueTo(nextStep) { d3.select('.preset-list-button').on('click.intro', null); @@ -230,8 +260,12 @@ export function uiIntroBuilding(context, reveal) { function closeEditorHouse() { - if (context.mode().id !== 'select') { - return chapter.restart(); + if (!houseId || !context.hasEntity(houseId)) { + return addHouse(); + } + var ids = context.selectedIDs(); + if (context.mode().id !== 'select' || !ids.length || ids[0] !== houseId) { + context.enter(modeSelect(context, [houseId])); } context.history().checkpoint('hasHouse'); @@ -379,8 +413,9 @@ export function uiIntroBuilding(context, reveal) { function addTank() { - tankId = null; + context.enter(modeBrowse(context)); context.history().reset('doneSquare'); + tankId = null; var msec = transitionTime(tank, context.map().center()); if (msec) { reveal(null, null, { duration: 0 }); } @@ -420,7 +455,7 @@ export function uiIntroBuilding(context, reveal) { context.on('enter.intro', function(mode) { if (mode.id !== 'draw-area') return chapter.restart(); - continueTo(drawTank); + continueTo(continueTank); }); }, 550); // after easing @@ -433,11 +468,13 @@ export function uiIntroBuilding(context, reveal) { } - function drawTank() { + function continueTank() { if (context.mode().id !== 'draw-area') { return continueTo(addTank); } + tankId = null; + revealTank(tank, t('intro.buildings.continue_tank')); context.map().on('move.intro drawn.intro', function() { @@ -445,12 +482,14 @@ export function uiIntroBuilding(context, reveal) { }); context.on('enter.intro', function(mode) { - if (mode.id === 'draw-area') + if (mode.id === 'draw-area') { return; - else if (mode.id === 'select') + } else if (mode.id === 'select') { + tankId = context.selectedIDs()[0]; return continueTo(searchPresetTank); - else + } else { return continueTo(addTank); + } }); function continueTo(nextStep) { @@ -462,64 +501,89 @@ export function uiIntroBuilding(context, reveal) { function searchPresetTank() { - if (context.mode().id !== 'select') { - return continueTo(addTank); + if (!tankId || !context.hasEntity(tankId)) { + return addTank(); + } + var ids = context.selectedIDs(); + if (context.mode().id !== 'select' || !ids.length || ids[0] !== tankId) { + context.enter(modeSelect(context, [tankId])); } - context.on('exit.intro', function() { - return continueTo(addTank); - }); - - d3.select('.preset-search-input') - .on('keyup.intro', checkPresetSearch); - timeout(function() { + // reset pane, in case user somehow happened to change it.. + d3.select('.inspector-wrap .panewrap').style('right', '-100%'); + + d3.select('.preset-search-input') + .on('keydown.intro', null) + .on('keyup.intro', checkPresetSearch); + reveal('.preset-search-input', t('intro.buildings.search_tank', { preset: tankPreset.name() }) ); - }, 500); + }, 400); // after preset list pane visible.. - function continueTo(nextStep) { - context.on('exit.intro', null); - d3.select('.preset-search-input').on('keyup.intro', null); - nextStep(); - } - } + context.on('enter.intro', function(mode) { + if (!tankId || !context.hasEntity(tankId)) { + return continueTo(addTank); + } + var ids = context.selectedIDs(); + if (mode.id !== 'select' || !ids.length || ids[0] !== tankId) { + // keep the user's area selected.. + context.enter(modeSelect(context, [tankId])); - function checkPresetSearch() { - var first = d3.select('.preset-list-item:first-child'); + // reset pane, in case user somehow happened to change it.. + d3.select('.inspector-wrap .panewrap').style('right', '-100%'); - if (first.classed('preset-man_made-storage_tank')) { - reveal(first.select('.preset-list-button').node(), - t('intro.buildings.choose_tank', { preset: tankPreset.name() }), - { duration: 300 } - ); + d3.select('.preset-search-input') + .on('keydown.intro', null) + .on('keyup.intro', checkPresetSearch); - d3.select('.preset-search-input') - .on('keydown.intro', eventCancel, true) - .on('keyup.intro', null); + reveal('.preset-search-input', + t('intro.buildings.search_tank', { preset: tankPreset.name() }) + ); - context.history().on('change.intro', function() { - continueTo(closeEditorTank); - }); + context.history().on('change.intro', null); + } + }); + + function checkPresetSearch() { + var first = d3.select('.preset-list-item:first-child'); + + if (first.classed('preset-man_made-storage_tank')) { + reveal(first.select('.preset-list-button').node(), + t('intro.buildings.choose_tank', { preset: tankPreset.name() }), + { duration: 300 } + ); + + d3.select('.preset-search-input') + .on('keydown.intro', eventCancel, true) + .on('keyup.intro', null); + + context.history().on('change.intro', function() { + continueTo(closeEditorTank); + }); + } } function continueTo(nextStep) { - context.on('exit.intro', null); + context.on('enter.intro', null); context.history().on('change.intro', null); - d3.select('.preset-search-input').on('keydown.intro', null); + d3.select('.preset-search-input').on('keydown.intro keyup.intro', null); nextStep(); } } function closeEditorTank() { - if (context.mode().id !== 'select') { - return continueTo(addTank); + if (!tankId || !context.hasEntity(tankId)) { + return addTank(); + } + var ids = context.selectedIDs(); + if (context.mode().id !== 'select' || !ids.length || ids[0] !== tankId) { + context.enter(modeSelect(context, [tankId])); } - tankId = context.mode().selectedIDs()[0]; context.history().checkpoint('hasTank'); context.on('exit.intro', function() { @@ -560,6 +624,7 @@ export function uiIntroBuilding(context, reveal) { }); revealTank(tank, t('intro.buildings.rightclick_tank')); + context.map().on('move.intro drawn.intro', function() { revealTank(tank, t('intro.buildings.rightclick_tank'), { duration: 0 }); }); @@ -668,8 +733,7 @@ export function uiIntroBuilding(context, reveal) { chapter.exit = function() { timeouts.forEach(window.clearTimeout); - context.on('enter.intro', null); - context.on('exit.intro', null); + context.on('enter.intro exit.intro', null); context.map().on('move.intro drawn.intro', null); context.history().on('change.intro', null); d3.select('.preset-search-input').on('keydown.intro keyup.intro', null); diff --git a/modules/ui/intro/line.js b/modules/ui/intro/line.js index 8b09e66be..fa276a50e 100644 --- a/modules/ui/intro/line.js +++ b/modules/ui/intro/line.js @@ -50,6 +50,7 @@ export function uiIntroLine(context, reveal) { function addLine() { + context.enter(modeBrowse(context)); context.history().reset('initial'); var msec = transitionTime(tulipRoadStart, context.map().center()); @@ -1047,8 +1048,7 @@ export function uiIntroLine(context, reveal) { chapter.exit = function() { timeouts.forEach(window.clearTimeout); d3.select(window).on('mousedown.intro', null, true); - context.on('enter.intro', null); - context.on('exit.intro', null); + context.on('enter.intro exit.intro', null); context.map().on('move.intro drawn.intro', null); context.history().on('change.intro', null); d3.select('.preset-list-button').on('click.intro', null); diff --git a/modules/ui/intro/navigation.js b/modules/ui/intro/navigation.js index d433c0a88..f3f261459 100644 --- a/modules/ui/intro/navigation.js +++ b/modules/ui/intro/navigation.js @@ -10,7 +10,6 @@ export function uiIntroNavigation(context, reveal) { timeouts = [], hallId = 'n2061', townHall = [-85.63591, 41.94285], - townHallPreset = context.presets().item('amenity/townhall'), springStreetId = 'w397', springStreetEndId = 'n1834', springStreet = [-85.63582, 41.94255]; @@ -50,6 +49,7 @@ export function uiIntroNavigation(context, reveal) { function dragMap() { + context.enter(modeBrowse(context)); context.history().reset('initial'); var msec = transitionTime(townHall, context.map().center()); @@ -212,6 +212,11 @@ export function uiIntroNavigation(context, reveal) { var onClick = function() { continueTo(presetTownHall); }; + reveal('.entity-editor-pane', + t('intro.navigation.editor_townhall'), + { buttonText: t('intro.ok'), buttonCallback: onClick } + ); + context.on('exit.intro', function() { continueTo(clickTownHall); }); @@ -222,11 +227,6 @@ export function uiIntroNavigation(context, reveal) { } }); - reveal('.entity-editor-pane', - t('intro.navigation.editor_townhall'), - { buttonText: t('intro.ok'), buttonCallback: onClick } - ); - function continueTo(nextStep) { context.on('exit.intro', null); context.history().on('change.intro', null); @@ -238,6 +238,13 @@ export function uiIntroNavigation(context, reveal) { function presetTownHall() { if (!isTownHallSelected()) return clickTownHall(); + // reset pane, in case user happened to change it.. + d3.select('.inspector-wrap .panewrap').style('right', '0%'); + + // preset match, in case the user happened to change it. + var entity = context.entity(context.selectedIDs()[0]); + var preset = context.presets().match(entity, context.graph()); + var onClick = function() { continueTo(fieldsTownHall); }; context.on('exit.intro', function() { @@ -251,7 +258,7 @@ export function uiIntroNavigation(context, reveal) { }); reveal('.inspector-body .preset-list-item.inspector-inner', - t('intro.navigation.preset_townhall', { preset: townHallPreset.name() }), + t('intro.navigation.preset_townhall', { preset: preset.name() }), { buttonText: t('intro.ok'), buttonCallback: onClick } ); @@ -266,8 +273,16 @@ export function uiIntroNavigation(context, reveal) { function fieldsTownHall() { if (!isTownHallSelected()) return clickTownHall(); + // reset pane, in case user happened to change it.. + d3.select('.inspector-wrap .panewrap').style('right', '0%'); + var onClick = function() { continueTo(closeTownHall); }; + reveal('.inspector-body .inspector-preset', + t('intro.navigation.fields_townhall'), + { buttonText: t('intro.ok'), buttonCallback: onClick } + ); + context.on('exit.intro', function() { continueTo(clickTownHall); }); @@ -278,11 +293,6 @@ export function uiIntroNavigation(context, reveal) { } }); - reveal('.inspector-body .inspector-preset', - t('intro.navigation.fields_townhall'), - { buttonText: t('intro.ok'), buttonCallback: onClick } - ); - function continueTo(nextStep) { context.on('exit.intro', null); context.history().on('change.intro', null); @@ -294,16 +304,6 @@ export function uiIntroNavigation(context, reveal) { function closeTownHall() { if (!isTownHallSelected()) return clickTownHall(); - context.on('exit.intro', function() { - continueTo(searchStreet); - }); - - context.history().on('change.intro', function() { - if (!context.hasEntity(hallId)) { - continueTo(clickTownHall); - } - }); - var selector = '.entity-editor-pane button.preset-close svg use'; var href = d3.select(selector).attr('href') || '#icon-close'; @@ -311,9 +311,12 @@ export function uiIntroNavigation(context, reveal) { t('intro.navigation.close_townhall', { button: icon(href, 'pre-text') }) ); + context.on('exit.intro', function() { + continueTo(searchStreet); + }); + function continueTo(nextStep) { context.on('exit.intro', null); - context.history().on('change.intro', null); nextStep(); } } @@ -395,7 +398,11 @@ export function uiIntroNavigation(context, reveal) { }); context.on('enter.intro', function(mode) { - if (mode.id !== 'select') { + if (!context.hasEntity(springStreetId)) { + return continueTo(searchStreet); + } + var ids = context.selectedIDs(); + if (mode.id !== 'select' || !ids.length || ids[0] !== springStreetId) { // keep Spring Street selected.. context.enter(modeSelect(context, [springStreetId])); } @@ -457,13 +464,10 @@ export function uiIntroNavigation(context, reveal) { chapter.exit = function() { timeouts.forEach(window.clearTimeout); - d3.select(window).on('mouseup.intro', null, true); + context.on('enter.intro exit.intro', null); context.map().on('move.intro drawn.intro', null); - context.on('enter.intro', null); - context.on('exit.intro', null); - d3.select('.search-header input') - .on('keydown.intro', null) - .on('keyup.intro', null); + context.history().on('change.intro', null); + d3.select('.search-header input').on('keydown.intro keyup.intro', null); }; diff --git a/modules/ui/intro/point.js b/modules/ui/intro/point.js index 9ec9beedb..7e39d81a5 100644 --- a/modules/ui/intro/point.js +++ b/modules/ui/intro/point.js @@ -1,5 +1,6 @@ import * as d3 from 'd3'; import { t, textDirection } from '../../util/locale'; +import { modeBrowse, modeSelect } from '../../modes'; import { utilRebind } from '../../util/rebind'; import { icon, pointBox, pad, selectMenuItem, transitionTime } from './helper'; @@ -30,6 +31,7 @@ export function uiIntroPoint(context, reveal) { function addPoint() { + context.enter(modeBrowse(context)); context.history().reset('initial'); var msec = transitionTime(intersection, context.map().center()); @@ -76,6 +78,7 @@ export function uiIntroPoint(context, reveal) { context.on('enter.intro', function(mode) { if (mode.id !== 'select') return chapter.restart(); + pointId = context.mode().selectedIDs()[0]; continueTo(searchPreset); }); @@ -88,58 +91,73 @@ export function uiIntroPoint(context, reveal) { function searchPreset() { - if (context.mode().id !== 'select') { - return chapter.restart(); + if (context.mode().id !== 'select' || !pointId || !context.hasEntity(pointId)) { + return addPoint(); } - pointId = context.mode().selectedIDs()[0]; - - context.on('exit.intro', function() { - return chapter.restart(); - }); - d3.select('.preset-search-input') + .on('keydown.intro', null) .on('keyup.intro', checkPresetSearch); - timeout(function() { - reveal('.preset-search-input', - t('intro.points.search_cafe', { preset: cafePreset.name() }) - ); - }, 500); - } + reveal('.preset-search-input', + t('intro.points.search_cafe', { preset: cafePreset.name() }) + ); + + context.on('enter.intro', function(mode) { + if (!pointId || !context.hasEntity(pointId)) { + return continueTo(addPoint); + } + + var ids = context.selectedIDs(); + if (mode.id !== 'select' || !ids.length || ids[0] !== pointId) { + // keep the user's point selected.. + context.enter(modeSelect(context, [pointId])); + + d3.select('.preset-search-input') + .on('keydown.intro', null) + .on('keyup.intro', checkPresetSearch); + + reveal('.preset-search-input', + t('intro.points.search_cafe', { preset: cafePreset.name() }) + ); + + context.history().on('change.intro', null); + } + }); - function checkPresetSearch() { - var first = d3.select('.preset-list-item:first-child'); + function checkPresetSearch() { + var first = d3.select('.preset-list-item:first-child'); - if (first.classed('preset-amenity-cafe')) { - reveal(first.select('.preset-list-button').node(), - t('intro.points.choose_cafe', { preset: cafePreset.name() }), - { duration: 300 } - ); + if (first.classed('preset-amenity-cafe')) { + d3.select('.preset-search-input') + .on('keydown.intro', eventCancel, true) + .on('keyup.intro', null); - d3.select('.preset-search-input') - .on('keydown.intro', eventCancel, true) - .on('keyup.intro', null); + reveal(first.select('.preset-list-button').node(), + t('intro.points.choose_cafe', { preset: cafePreset.name() }), + { duration: 300 } + ); - context.history().on('change.intro', function() { - continueTo(aboutFeatureEditor); - }); + context.history().on('change.intro', function() { + continueTo(aboutFeatureEditor); + }); + } } function continueTo(nextStep) { - context.on('exit.intro', null); + context.on('enter.intro', null); context.history().on('change.intro', null); - d3.select('.preset-search-input').on('keydown.intro', null); + d3.select('.preset-search-input').on('keydown.intro keyup.intro', null); nextStep(); } } function aboutFeatureEditor() { - context.on('exit.intro', function() { - return chapter.restart(); - }); + if (context.mode().id !== 'select' || !pointId || !context.hasEntity(pointId)) { + return addPoint(); + } timeout(function() { reveal('.entity-editor-pane', t('intro.points.feature_editor'), { @@ -149,6 +167,11 @@ export function uiIntroPoint(context, reveal) { }); }, 400); + context.on('exit.intro', function() { + // if user leaves select mode here, just continue with the tutorial. + continueTo(reselectPoint); + }); + function continueTo(nextStep) { context.on('exit.intro', null); nextStep(); @@ -157,13 +180,12 @@ export function uiIntroPoint(context, reveal) { function addName() { - context.on('exit.intro', function() { - return chapter.restart(); - }); + if (context.mode().id !== 'select' || !pointId || !context.hasEntity(pointId)) { + return addPoint(); + } - context.history().on('change.intro', function() { - continueTo(addCloseEditor); - }); + // reset pane, in case user happened to change it.. + d3.select('.inspector-wrap .panewrap').style('right', '0%'); timeout(function() { reveal('.entity-editor-pane', t('intro.points.add_name'), @@ -171,6 +193,15 @@ export function uiIntroPoint(context, reveal) { ); }, 400); + context.history().on('change.intro', function() { + continueTo(addCloseEditor); + }); + + context.on('exit.intro', function() { + // if user leaves select mode here, just continue with the tutorial. + continueTo(reselectPoint); + }); + function continueTo(nextStep) { context.on('exit.intro', null); context.history().on('change.intro', null); @@ -180,12 +211,18 @@ export function uiIntroPoint(context, reveal) { function addCloseEditor() { + // reset pane, in case user happened to change it.. + d3.select('.inspector-wrap .panewrap').style('right', '0%'); + + var selector = '.entity-editor-pane button.preset-close svg use'; + var href = d3.select(selector).attr('href') || '#icon-close'; + context.on('exit.intro', function() { continueTo(reselectPoint); }); reveal('.entity-editor-pane', - t('intro.points.add_close', { button: icon('#icon-apply', 'pre-text') }) + t('intro.points.add_close', { button: icon(href, 'pre-text') }) ); function continueTo(nextStep) { @@ -200,6 +237,8 @@ export function uiIntroPoint(context, reveal) { var entity = context.hasEntity(pointId); if (!entity) return chapter.restart(); + context.enter(modeBrowse(context)); + var msec = transitionTime(entity.loc, context.map().center()); if (msec) { reveal(null, null, { duration: 0 }); } context.map().centerEase(entity.loc, msec); @@ -231,6 +270,13 @@ export function uiIntroPoint(context, reveal) { function updatePoint() { + if (context.mode().id !== 'select' || !pointId || !context.hasEntity(pointId)) { + return continueTo(reselectPoint); + } + + // reset pane, in case user happened to untag the point.. + d3.select('.inspector-wrap .panewrap').style('right', '0%'); + context.on('exit.intro', function() { continueTo(reselectPoint); }); @@ -254,10 +300,13 @@ export function uiIntroPoint(context, reveal) { function updateCloseEditor() { - if (context.mode().id !== 'select') { + if (context.mode().id !== 'select' || !pointId || !context.hasEntity(pointId)) { return continueTo(reselectPoint); } + // reset pane, in case user happened to change it.. + d3.select('.inspector-wrap .panewrap').style('right', '0%'); + context.on('exit.intro', function() { continueTo(rightClickPoint); }); @@ -280,6 +329,8 @@ export function uiIntroPoint(context, reveal) { var entity = context.hasEntity(pointId); if (!entity) return chapter.restart(); + context.enter(modeBrowse(context)); + var box = pointBox(entity.loc, context); reveal(box, t('intro.points.rightclick')); @@ -339,8 +390,9 @@ export function uiIntroPoint(context, reveal) { }); context.history().on('change.intro', function(changed) { - if (changed.deleted().length) + if (changed.deleted().length) { continueTo(undo); + } }); function continueTo(nextStep) { @@ -388,8 +440,7 @@ export function uiIntroPoint(context, reveal) { chapter.exit = function() { timeouts.forEach(window.clearTimeout); - context.on('exit.intro', null); - context.on('enter.intro', null); + context.on('enter.intro exit.intro', null); context.map().on('move.intro drawn.intro', null); context.history().on('change.intro', null); d3.select('.preset-search-input').on('keydown.intro keyup.intro', null); diff --git a/modules/ui/intro/welcome.js b/modules/ui/intro/welcome.js index dd516569a..3564e66d7 100644 --- a/modules/ui/intro/welcome.js +++ b/modules/ui/intro/welcome.js @@ -14,14 +14,14 @@ export function uiIntroWelcome(context, reveal) { function welcome() { context.map().centerZoom([-85.63591, 41.94285], 19); - reveal('.intro-nav-wrap', + reveal('.intro-nav-wrap .chapter-welcome', t('intro.welcome.welcome'), { buttonText: t('intro.ok'), buttonCallback: practice } ); } function practice() { - reveal('.intro-nav-wrap', + reveal('.intro-nav-wrap .chapter-welcome', t('intro.welcome.practice'), { buttonText: t('intro.ok'), buttonCallback: chapters } );