modules/ui/shortcuts.js (225 lines of code) (raw):

import { select as d3_select } from 'd3-selection'; import { utilArrayUniq } from '@id-sdk/util'; import { fileFetcher } from '../core/file_fetcher'; import { t } from '../core/localizer'; import { svgIcon } from '../svg/icon'; import { uiCmd } from './cmd'; import { uiModal } from './modal'; import { utilDetect } from '../util/detect'; export function uiShortcuts(context) { var detected = utilDetect(); var _activeTab = 0; var _modalSelection; var _selection = d3_select(null); var _dataShortcuts; function shortcutsModal(_modalSelection) { _modalSelection.select('.modal') .classed('modal-shortcuts', true); var content = _modalSelection.select('.content'); content .append('div') .attr('class', 'modal-section') .append('h3') .html(t.html('shortcuts.title')); fileFetcher.get('shortcuts') .then(function(data) { _dataShortcuts = data; content.call(render); }) .catch(function() { /* ignore */ }); } function render(selection) { if (!_dataShortcuts) return; var wrapper = selection .selectAll('.wrapper') .data([0]); var wrapperEnter = wrapper .enter() .append('div') .attr('class', 'wrapper modal-section'); var tabsBar = wrapperEnter .append('div') .attr('class', 'tabs-bar'); var shortcutsList = wrapperEnter .append('div') .attr('class', 'shortcuts-list'); wrapper = wrapper.merge(wrapperEnter); var tabs = tabsBar .selectAll('.tab') .data(_dataShortcuts); var tabsEnter = tabs .enter() .append('a') .attr('class', 'tab') .attr('href', '#') .on('click', function (d3_event, d) { d3_event.preventDefault(); var i = _dataShortcuts.indexOf(d); _activeTab = i; render(selection); }); tabsEnter .append('span') .html(function (d) { return t.html(d.text); }); // Update wrapper.selectAll('.tab') .classed('active', function (d, i) { return i === _activeTab; }); var shortcuts = shortcutsList .selectAll('.shortcut-tab') .data(_dataShortcuts); var shortcutsEnter = shortcuts .enter() .append('div') .attr('class', function(d) { return 'shortcut-tab shortcut-tab-' + d.tab; }); var columnsEnter = shortcutsEnter .selectAll('.shortcut-column') .data(function (d) { return d.columns; }) .enter() .append('table') .attr('class', 'shortcut-column'); var rowsEnter = columnsEnter .selectAll('.shortcut-row') .data(function (d) { return d.rows; }) .enter() .append('tr') .attr('class', 'shortcut-row'); var sectionRows = rowsEnter .filter(function (d) { return !d.shortcuts; }); sectionRows .append('td'); sectionRows .append('td') .attr('class', 'shortcut-section') .append('h3') .html(function (d) { return t.html(d.text); }); var shortcutRows = rowsEnter .filter(function (d) { return d.shortcuts; }); var shortcutKeys = shortcutRows .append('td') .attr('class', 'shortcut-keys'); var modifierKeys = shortcutKeys .filter(function (d) { return d.modifiers; }); modifierKeys .selectAll('kbd.modifier') .data(function (d) { if (detected.os === 'win' && d.text === 'shortcuts.editing.commands.redo') { return ['⌘']; } else if (detected.os !== 'mac' && d.text === 'shortcuts.browsing.display_options.fullscreen') { return []; } else { return d.modifiers; } }) .enter() .each(function () { var selection = d3_select(this); selection .append('kbd') .attr('class', 'modifier') .html(function (d) { return uiCmd.display(d); }); selection .append('span') .html('+'); }); shortcutKeys .selectAll('kbd.shortcut') .data(function (d) { var arr = d.shortcuts; if (detected.os === 'win' && d.text === 'shortcuts.editing.commands.redo') { arr = ['Y']; } else if (detected.os !== 'mac' && d.text === 'shortcuts.browsing.display_options.fullscreen') { arr = ['F11']; } // replace translations arr = arr.map(function(s) { return uiCmd.display(s.indexOf('.') !== -1 ? t(s) : s); }); return utilArrayUniq(arr).map(function(s) { return { shortcut: s, separator: d.separator, suffix: d.suffix, rapid: d.rapid }; }); }) .enter() .each(function (d, i, nodes) { var selection = d3_select(this); var click = d.shortcut.toLowerCase().match(/(.*).click/); if (click && click[1]) { // replace "left_click", "right_click" with mouse icon selection .call(svgIcon('#iD-walkthrough-mouse-' + click[1], 'operation')); } else if (d.shortcut.toLowerCase() === 'long-press') { selection .call(svgIcon('#iD-walkthrough-longpress', 'longpress operation')); } else if (d.shortcut.toLowerCase() === 'tap') { selection .call(svgIcon('#iD-walkthrough-tap', 'tap operation')); } else { selection .append('kbd') .attr('class', 'shortcut') .html(function (d) { return d.shortcut; }); } if (i < nodes.length - 1) { selection .append('span') .html(d.separator || '\u00a0' + t.html('shortcuts.or') + '\u00a0'); } else if (i === nodes.length - 1 && d.suffix) { selection .append('span') .html(d.suffix); } if (d.rapid){ selection .append('svg') .lower() .attr('class', 'icon logo-rapid') .append('use') .attr('xlink:href', '#iD-logo-rapid') .attr('class', '#iD-logo-rapid'); } }); shortcutKeys .filter(function(d) { return d.gesture; }) .each(function () { var selection = d3_select(this); selection .append('span') .html('+'); selection .append('span') .attr('class', 'gesture') .html(function (d) { return t.html(d.gesture); }); }); shortcutRows .append('td') .attr('class', 'shortcut-desc') .html(function (d) { return d.text ? t.html(d.text) : '\u00a0'; }); // Update wrapper.selectAll('.shortcut-tab') .style('display', function (d, i) { return i === _activeTab ? 'flex' : 'none'; }); } return function(selection, show) { _selection = selection; if (show) { _modalSelection = uiModal(selection); _modalSelection.call(shortcutsModal); } else { context.keybinding() .on([t('shortcuts.toggle.key'), '?'], function () { if (context.container().selectAll('.modal-shortcuts').size()) { // already showing if (_modalSelection) { _modalSelection.close(); _modalSelection = null; } } else { _modalSelection = uiModal(_selection); _modalSelection.call(shortcutsModal); } }); } }; }