UNPKG

yy-menu

Version:

A traditional menu system for web apps inspired by Electron

1,737 lines (1,487 loc) 51.6 kB
// modules are defined as an array // [ module function, map of requires ] // // map of requires is short require name -> numeric require // // anything defined in a previous bundle is accessed via the // orig method which is the require for previous bundles parcelRequire = (function (modules, cache, entry, globalName) { // Save the require from previous bundle to this closure if any var previousRequire = typeof parcelRequire === 'function' && parcelRequire; var nodeRequire = typeof require === 'function' && require; function newRequire(name, jumped) { if (!cache[name]) { if (!modules[name]) { // if we cannot find the module within our internal map or // cache jump to the current global require ie. the last bundle // that was added to the page. var currentRequire = typeof parcelRequire === 'function' && parcelRequire; if (!jumped && currentRequire) { return currentRequire(name, true); } // If there are other bundles on this page the require from the // previous one is saved to 'previousRequire'. Repeat this as // many times as there are bundles until the module is found or // we exhaust the require chain. if (previousRequire) { return previousRequire(name, true); } // Try the node require function if it exists. if (nodeRequire && typeof name === 'string') { return nodeRequire(name); } var err = new Error('Cannot find module \'' + name + '\''); err.code = 'MODULE_NOT_FOUND'; throw err; } localRequire.resolve = resolve; localRequire.cache = {}; var module = cache[name] = new newRequire.Module(name); modules[name][0].call(module.exports, localRequire, module, module.exports, this); } return cache[name].exports; function localRequire(x){ return newRequire(localRequire.resolve(x)); } function resolve(x){ return modules[name][1][x] || x; } } function Module(moduleName) { this.id = moduleName; this.bundle = newRequire; this.exports = {}; } newRequire.isParcelRequire = true; newRequire.Module = Module; newRequire.modules = modules; newRequire.cache = cache; newRequire.parent = previousRequire; newRequire.register = function (id, exports) { modules[id] = [function (require, module) { module.exports = exports; }, {}]; }; var error; for (var i = 0; i < entry.length; i++) { try { newRequire(entry[i]); } catch (e) { // Save first error but execute all entries if (!error) { error = e; } } } if (entry.length) { // Expose entry point to Node, AMD or browser globals // Based on https://github.com/ForbesLindesay/umd/blob/master/template.js var mainExports = newRequire(entry[entry.length - 1]); // CommonJS if (typeof exports === "object" && typeof module !== "undefined") { module.exports = mainExports; // RequireJS } else if (typeof define === "function" && define.amd) { define(function () { return mainExports; }); // <script> } else if (globalName) { this[globalName] = mainExports; } } // Override the current require with this new one parcelRequire = newRequire; if (error) { // throw error from earlier, _after updating parcelRequire_ throw error; } return newRequire; })({"../src/config.js":[function(require,module,exports) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.config = void 0; var config = { /** * application menu container styles * @type {object} */ ApplicationContainerStyle: { 'z-index': 999999, 'position': 'absolute', 'top': 0, 'left': 0, 'user-select': 'none', 'font-size': '0.85em' }, /** * application menu-bar styles * @type {object} */ ApplicationMenuStyle: { 'display': 'flex', 'position': 'relative', 'flex-direction': 'row', 'color': 'black', 'backgroundColor': 'rgb(230,230,230)', 'width': '100vw', 'border': 'none', 'box-shadow': 'unset', 'outline': 'none' }, /** * application menu entry styles * @type {object} */ ApplicationMenuRowStyle: { 'padding': '0.25em 0.5em', 'margin': 0, 'line-height': '1em' }, /** * lower-level menu window styles * @type {object} */ MenuStyle: { 'flex-direction': 'column', 'position': 'absolute', 'user-select': 'none', 'color': 'black', 'z-index': 999999, 'backgroundColor': 'white', 'border': '1px solid rgba(0,0,0,0.5)', 'boxShadow': '1px 3px 3px rgba(0,0,0,0.25)' }, /** * lower-level menu row styles * @type {object} */ RowStyle: { 'display': 'flex', 'padding': '0.25em 1.5em 0.25em', 'line-height': '1.5em' }, /** * lower-level menu accelerator styles * @type {object} */ AcceleratorStyle: { 'opacity': 0.5 }, /** * lower-level menu separator styles * @type {object} */ SeparatorStyle: { 'border-bottom': '1px solid rgba(0,0,0,0.1)', 'margin': '0.5em 0' }, /** * accelerator key styles * NOTE: accelerator keys must use text-decoration as its used as a toggle in the code * @type {object} */ AcceleratorKeyStyle: { 'text-decoration': 'underline', 'text-decoration-color': 'rgba(0,0,0,0.5)' }, /** * minimum column width in pixels for checked and arrow in the lower-level menus * @type {number} */ MinimumColumnWidth: 20, /** * CSS background style for selected MenuItems * NOTE: unselected have 'transparent' style * @type {string} */ SelectedBackgroundStyle: 'rgba(0,0,0,0.1)', /** * number of pixels to overlap child menus * @type {number} */ Overlap: 5, /** * time in milliseconds to wait for submenu to open when mouse hovers * @param {number} */ SubmenuOpenDelay: 500 }; exports.config = config; },{}],"../src/html.js":[function(require,module,exports) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.html = html; function html(options) { options = options || {}; var object = document.createElement(options.type || 'div'); if (options.parent) { options.parent.appendChild(object); } if (options.styles) { for (var style in options.styles) { object.style[style] = options.styles[style]; } } if (options.html) { object.innerHTML = options.html; } return object; } },{}],"../src/localAccelerator.js":[function(require,module,exports) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.localAccelerator = void 0; function _createForOfIteratorHelper(o, allowArrayLike) { var it; if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = o[Symbol.iterator](); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; } /** * Handles all keyboard input for the menu and user-registered keys */ var localAccelerator = { init: function init() { if (!localAccelerator.menuKeys) { localAccelerator.menuKeys = {}; localAccelerator.keys = {}; document.body.addEventListener('keydown', function (e) { return localAccelerator.keydown(localAccelerator, e); }); document.body.addEventListener('keyup', function (e) { return localAccelerator.keyup(localAccelerator, e); }); } }, /** * clear all user-registered keys */ clearKeys: function clearKeys() { localAccelerator.keys = {}; }, /** * Register a shortcut key for use by an open menu * @param {KeyCodes} letter * @param {MenuItem} menuItem * @param {boolean} applicationMenu * @private */ registerMenuShortcut: function registerMenuShortcut(letter, menuItem) { if (letter) { var keyCode = (menuItem.menu.applicationMenu ? 'alt+' : '') + letter; localAccelerator.menuKeys[localAccelerator.prepareKey(keyCode)] = function (e) { menuItem.handleClick(e); e.stopPropagation(); e.preventDefault(); }; } }, /** * Register special shortcut keys for menu * @param {MenuItem} menuItem * @private */ registerMenuSpecial: function registerMenuSpecial(menu) { localAccelerator.menuKeys['escape'] = function () { return menu.closeAll(); }; localAccelerator.menuKeys['enter'] = function (e) { return menu.enter(e); }; localAccelerator.menuKeys['space'] = function (e) { return menu.enter(e); }; localAccelerator.menuKeys['arrowright'] = function (e) { return menu.move(e, 'right'); }; localAccelerator.menuKeys['arrowleft'] = function (e) { return menu.move(e, 'left'); }; localAccelerator.menuKeys['arrowup'] = function (e) { return menu.move(e, 'up'); }; localAccelerator.menuKeys['arrowdown'] = function (e) { return menu.move(e, 'down'); }; }, /** * special key registration for alt * @param {function} pressed * @param {function} released * @private */ registerAlt: function registerAlt(pressed, released) { localAccelerator.alt = { pressed: pressed, released: released }; }, /** * Removes menu shortcuts * @private */ unregisterMenuShortcuts: function unregisterMenuShortcuts() { localAccelerator.menuKeys = {}; }, /** * Keycodes definition. In the form of modifier[+modifier...]+key * <p>For example: ctrl+shift+e</p> * <p>KeyCodes are case insensitive (i.e., shift+a is the same as Shift+A). And spaces are removed</p> * <p>You can assign more than one key to the same shortcut by using a | between the keys (e.g., 'shift+a | ctrl+a')</p> * <pre> * Modifiers: * ctrl, alt, shift, meta, (ctrl aliases: command, control, commandorcontrol) * </pre> * <pre> * Keys: * escape, 0-9, minus, equal, backspace, tab, a-z, backetleft, bracketright, semicolon, quote, * backquote, backslash, comma, period, slash, numpadmultiply, space, capslock, f1-f24, pause, * scrolllock, printscreen, home, arrowup, arrowleft, arrowright, arrowdown, pageup, pagedown, * end, insert, delete, enter, shiftleft, shiftright, ctrlleft, ctrlright, altleft, altright, shiftleft, * shiftright, numlock, numpad... * </pre> * For OS-specific codes and a more detailed explanation see {@link https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/code}. Also note that 'Digit' and 'Key' are removed from the code to make it easier to type. * * @typedef {string} localAccelerator~KeyCodes */ /** * translate a user-provided keycode * @param {KeyCodes} keyCode * @return {KeyCodes} formatted and sorted keyCode * @private */ prepareKey: function prepareKey(keyCode) { var keys = []; var split; keyCode += ''; if (keyCode.length > 1 && keyCode.indexOf('|') !== -1) { split = keyCode.split('|'); } else { split = [keyCode]; } var _iterator = _createForOfIteratorHelper(split), _step; try { for (_iterator.s(); !(_step = _iterator.n()).done;) { var code = _step.value; var key = ''; var modifiers = []; code = code.toLowerCase().replace(' ', ''); if (code.indexOf('+') !== -1) { var _split = code.split('+'); for (var i = 0; i < _split.length - 1; i++) { var modifier = _split[i]; modifier = modifier.replace('commandorcontrol', 'ctrl'); modifier = modifier.replace('command', 'ctrl'); modifier = modifier.replace('control', 'ctrl'); modifiers.push(modifier); } modifiers = modifiers.sort(function (a, b) { return a[0] > b[0] ? 1 : a[0] < b[0] ? -1 : 0; }); var _iterator2 = _createForOfIteratorHelper(modifiers), _step2; try { for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) { var part = _step2.value; key += part + '+'; } } catch (err) { _iterator2.e(err); } finally { _iterator2.f(); } key += _split[_split.length - 1]; } else { key = code; } keys.push(key); } } catch (err) { _iterator.e(err); } finally { _iterator.f(); } return keys; }, /** * Make the KeyCode pretty for printing on the menu * @param {KeyCode} keyCode * @return {string} * @private */ prettifyKey: function prettifyKey(keyCode) { var key = ''; var codes = localAccelerator.prepareKey(keyCode); for (var i = 0; i < codes.length; i++) { var _keyCode = codes[i]; if (_keyCode.indexOf('+') !== -1) { var split = _keyCode.toLowerCase().split('+'); for (var _i = 0; _i < split.length - 1; _i++) { var modifier = split[_i]; key += modifier[0].toUpperCase() + modifier.substr(1) + '+'; } key += split[split.length - 1].toUpperCase(); } else { key = _keyCode.toUpperCase(); } if (i !== codes.length - 1) { key += ' or '; } } return key; }, /** * register a key as a global accelerator * @param {KeyCodes} keyCode (e.g., Ctrl+shift+E) * @param {function} callback */ register: function register(keyCode, callback) { var keys = localAccelerator.prepareKey(keyCode); var _iterator3 = _createForOfIteratorHelper(keys), _step3; try { for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) { var key = _step3.value; localAccelerator.keys[key] = function (e) { callback(e); e.preventDefault(); e.stopPropagation(); }; } } catch (err) { _iterator3.e(err); } finally { _iterator3.f(); } }, keyup: function keyup(accelerator, e) { if (localAccelerator.alt && (e.code === 'AltLeft' || e.code === 'AltRight')) { localAccelerator.alt.released(); localAccelerator.alt.isPressed = false; } }, keydown: function keydown(accelerator, e) { if (localAccelerator.alt && !localAccelerator.alt.isPressed && (e.code === 'AltLeft' || e.code === 'AltRight')) { localAccelerator.alt.pressed(); localAccelerator.alt.isPressed = true; e.preventDefault(); } var modifiers = []; if (e.altKey) { modifiers.push('alt'); } if (e.ctrlKey) { modifiers.push('ctrl'); } if (e.metaKey) { modifiers.push('meta'); } if (e.shiftKey) { modifiers.push('shift'); } var keyCode = ''; for (var _i2 = 0, _modifiers = modifiers; _i2 < _modifiers.length; _i2++) { var modifier = _modifiers[_i2]; keyCode += modifier + '+'; } var translate = e.code.toLowerCase(); translate = translate.replace('digit', ''); translate = translate.replace('key', ''); keyCode += translate; if (localAccelerator.menuKeys[keyCode]) { localAccelerator.menuKeys[keyCode](e, localAccelerator); } else if (localAccelerator.keys[keyCode]) { localAccelerator.keys[keyCode](e, localAccelerator); } } }; exports.localAccelerator = localAccelerator; },{}],"../src/MenuItem.js":[function(require,module,exports) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.MenuItem = void 0; var _html = require("./html"); var _config = require("./config"); var _localAccelerator = require("./localAccelerator"); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } var MenuItem = /*#__PURE__*/function () { /** * @param {object} options * @param {string} [options.label] label for menu entry may include accelerator by placing & before letter) * @param {string} [options.type] separator, checkbox, or undefined * @param {object} [options.styles] additional CSS styles to apply to this MenuItem * @param {string} [options.accelerator] see Accelerator for inputs (e.g., ctrl+shift+A) * @param {MenuItem} [options.submenu] attaches a submenu (and changes type to submenu) * @param {boolean} [options.checked] check the checkbox */ function MenuItem(options) { var _this = this; _classCallCheck(this, MenuItem); _localAccelerator.localAccelerator.init(); options = options || {}; this.styles = options.styles; this.div = (0, _html.html)(); this.type = options.type; this.click = options.click; if (this.type === 'separator') { this.applyConfig(_config.config.SeparatorStyle); } else { this._checked = options.checked; this.createChecked(options.checked); this.text = options.label || '&nbsp;&nbsp;&nbsp;'; this.createShortcut(); this.createAccelerator(options.accelerator); this.createSubmenu(options.submenu); if (options.submenu) { this.submenu = options.submenu; this.submenu.applyConfig(_config.config.MenuStyle); } this.applyConfig(_config.config.RowStyle); this.div.addEventListener('mousedown', function (e) { return _this.handleClick(e); }); this.div.addEventListener('touchstart', function (e) { return _this.handleClick(e); }); this.div.addEventListener('mouseenter', function () { return _this.mouseenter(); }); this.div.addEventListener('mouseleave', function () { return _this.mouseleave(); }); } } /** * The click callback * @callback MenuItem~ClickCallback * @param {InputEvent} e */ _createClass(MenuItem, [{ key: "mouseenter", value: function mouseenter() { var _this2 = this; if (!this.submenu || this.menu.showing !== this) { this.div.style.backgroundColor = _config.config.SelectedBackgroundStyle; if (this.submenu && (!this.menu.applicationMenu || this.menu.showing)) { this.submenuTimeout = setTimeout(function () { _this2.submenuTimeout = null; _this2.submenu.show(_this2); }, this.menu.applicationMenu ? 0 : _config.config.SubmenuOpenDelay); } } } }, { key: "mouseleave", value: function mouseleave() { if (!this.submenu || this.menu.showing !== this) { if (this.submenuTimeout) { clearTimeout(this.submenuTimeout); this.submenuTimeout = null; } this.div.style.backgroundColor = 'transparent'; } } }, { key: "applyConfig", value: function applyConfig(base) { var styles = {}; for (var style in base) { styles[style] = base[style]; } if (this.styles) { for (var _style in this.styles) { styles[_style] = this.styles[_style]; } } for (var _style2 in styles) { this.div.style[_style2] = styles[_style2]; } } }, { key: "createChecked", value: function createChecked(checked) { this.check = (0, _html.html)({ parent: this.div, html: checked ? '&#10004;' : '' }); } }, { key: "createShortcut", value: function createShortcut() { if (this.type !== 'separator') { var text = this.text; this.label = (0, _html.html)({ parent: this.div }); var current = (0, _html.html)({ parent: this.label, type: 'span' }); if (text.indexOf('&') !== -1) { var i = 0; do { var letter = text[i]; if (letter === '&') { i++; this.shortcutSpan = (0, _html.html)({ parent: this.label, type: 'span', html: text[i], styles: _config.config.AcceleratorKeyStyle }); current = (0, _html.html)({ parent: this.label, type: 'span' }); } else { current.innerHTML += letter; } i++; } while (i < text.length); } else { this.label.innerHTML = text; } } } }, { key: "showShortcut", value: function showShortcut() { if (this.shortcutSpan) { this.shortcutSpan.style.textDecoration = 'underline'; } } }, { key: "hideShortcut", value: function hideShortcut() { if (this.shortcutSpan) { this.shortcutSpan.style.textDecoration = 'none'; } } }, { key: "createAccelerator", value: function createAccelerator(accelerator) { var _this3 = this; this.accelerator = (0, _html.html)({ parent: this.div, html: accelerator ? _localAccelerator.localAccelerator.prettifyKey(accelerator) : '', styles: _config.config.AcceleratorStyle }); if (accelerator) { _localAccelerator.localAccelerator.register(accelerator, function (e) { return _this3.click(e); }); } } }, { key: "createSubmenu", value: function createSubmenu(submenu) { this.arrow = (0, _html.html)({ parent: this.div, html: submenu ? '&#9658;' : '' }); } }, { key: "closeAll", value: function closeAll() { var menu = this.menu; _localAccelerator.localAccelerator.unregisterMenuShortcuts(); while (menu && !menu.applicationMenu) { if (menu.showing) { menu.showing.div.style.backgroundColor = 'transparent'; menu.showing = null; } menu.div.remove(); menu = menu.menu; } if (menu.showing) { menu.showing.div.style.background = 'transparent'; menu.showing = null; menu.hideAccelerators(); } } }, { key: "handleClick", value: function handleClick(e) { if (this.submenu) { if (this.submenuTimeout) { clearTimeout(this.submenuTimeout); this.submenuTimeout = null; } this.submenu.show(this); this.div.style.backgroundColor = _config.config.SelectedBackgroundStyle; if (typeof e !== 'undefined' && this.menu.applicationMenu && document.activeElement !== this.menu.div) { this.menu.div.focus(); } if (e) { e.preventDefault(); } } else if (this.type === 'checkbox') { this.checked = !this.checked; this.closeAll(); } else { this.closeAll(); } if (this.click) { this.click(e, this); } } }, { key: "checked", get: function get() { return this._checked; }, set: function set(value) { this._checked = value; this.check.innerHTML = this._checked ? '&#10004;' : ''; } }]); return MenuItem; }(); exports.MenuItem = MenuItem; },{"./html":"../src/html.js","./config":"../src/config.js","./localAccelerator":"../src/localAccelerator.js"}],"../src/Menu.js":[function(require,module,exports) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Menu = void 0; var _config = require("./config"); var _MenuItem = require("./MenuItem"); var _localAccelerator = require("./localAccelerator"); var _html = require("./html"); function _createForOfIteratorHelper(o, allowArrayLike) { var it; if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = o[Symbol.iterator](); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } var _application; var Menu = /*#__PURE__*/function () { /** * creates a menu bar * @param {object} [options] * @param {object} [options.styles] additional CSS styles for menu */ function Menu(options) { _classCallCheck(this, Menu); options = options || {}; this.div = document.createElement('div'); this.styles = options.styles; this.children = []; this.applyConfig(_config.config.MenuStyle); this.div.tabIndex = -1; } /** * append a MenuItem to the Menu * @param {MenuItem} menuItem */ _createClass(Menu, [{ key: "append", value: function append(menuItem) { if (menuItem.submenu) { menuItem.submenu.menu = this; } menuItem.menu = this; this.div.appendChild(menuItem.div); if (menuItem.type !== 'separator') { this.children.push(menuItem); } } /** * inserts a MenuItem into the Menu * @param {number} pos * @param {MenuItem} menuItem */ }, { key: "insert", value: function insert(pos, menuItem) { if (pos >= this.div.childNodes.length) { this.append(menuItem); } else { if (menuItem.submenu) { menuItem.submenu.menu = this; } menuItem.menu = this; this.div.insertBefore(menuItem.div, this.div.childNodes[pos]); if (menuItem.type !== 'separator') { this.children.splice(pos, 0, menuItem); } } } }, { key: "hide", value: function hide() { var current = this.menu.showing; while (current && current.submenu) { current.div.style.backgroundColor = 'transparent'; current.submenu.div.remove(); var next = current.submenu.showing; if (next) { current.submenu.showing.div.style.backgroundColor = 'transparent'; current.submenu.showing = null; } current = next; } } }, { key: "show", value: function show(menuItem) { _localAccelerator.localAccelerator.unregisterMenuShortcuts(); if (this.menu && this.menu.showing === menuItem) { this.hide(); this.menu.showing = null; this.div.remove(); this.menu.showAccelerators(); } else { if (this.menu) { if (this.menu.showing && this.menu.children.indexOf(menuItem) !== -1) { this.hide(); } this.menu.showing = menuItem; this.menu.hideAccelerators(); } var div = menuItem.div; var parent = this.menu.div; if (this.menu.applicationMenu) { this.div.style.left = div.offsetLeft + 'px'; this.div.style.top = div.offsetTop + div.offsetHeight + 'px'; } else { this.div.style.left = parent.offsetLeft + parent.offsetWidth - _config.config.Overlap + 'px'; this.div.style.top = parent.offsetTop + div.offsetTop - _config.config.Overlap + 'px'; } this.attached = menuItem; this.showAccelerators(); this.getApplicationDiv().appendChild(this.div); var label = 0, accelerator = 0, arrow = 0, checked = 0; var _iterator = _createForOfIteratorHelper(this.children), _step; try { for (_iterator.s(); !(_step = _iterator.n()).done;) { var child = _step.value; child.check.style.width = 'auto'; child.label.style.width = 'auto'; child.accelerator.style.width = 'auto'; child.arrow.style.width = 'auto'; if (child.type === 'checkbox') { checked = _config.config.MinimumColumnWidth; } if (child.submenu) { arrow = _config.config.MinimumColumnWidth; } } } catch (err) { _iterator.e(err); } finally { _iterator.f(); } var _iterator2 = _createForOfIteratorHelper(this.children), _step2; try { for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) { var _child = _step2.value; var childLabel = _child.label.offsetWidth * 2; label = childLabel > label ? childLabel : label; var childAccelerator = _child.accelerator.offsetWidth; accelerator = childAccelerator > accelerator ? childAccelerator : accelerator; if (_child.submenu) { arrow = _child.arrow.offsetWidth; } } } catch (err) { _iterator2.e(err); } finally { _iterator2.f(); } var _iterator3 = _createForOfIteratorHelper(this.children), _step3; try { for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) { var _child2 = _step3.value; _child2.check.style.width = checked + 'px'; _child2.label.style.width = label + 'px'; _child2.accelerator.style.width = accelerator + 'px'; _child2.arrow.style.width = arrow + 'px'; } } catch (err) { _iterator3.e(err); } finally { _iterator3.f(); } if (this.div.offsetLeft + this.div.offsetWidth > window.innerWidth) { this.div.style.left = window.innerWidth - this.div.offsetWidth + 'px'; } if (this.div.offsetTop + this.div.offsetHeight > window.innerHeight) { this.div.style.top = window.innerHeight - this.div.offsetHeight + 'px'; } _application.menu.div.focus(); } } }, { key: "applyConfig", value: function applyConfig(base) { var styles = {}; for (var style in base) { styles[style] = base[style]; } if (this.styles) { for (var _style in this.styles) { styles[_style] = this.styles[_style]; } } for (var _style2 in styles) { this.div.style[_style2] = styles[_style2]; } } }, { key: "showAccelerators", value: function showAccelerators() { var _iterator4 = _createForOfIteratorHelper(this.children), _step4; try { for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) { var child = _step4.value; child.showShortcut(); if (child.type !== 'separator') { var index = child.text.indexOf('&'); if (index !== -1) { _localAccelerator.localAccelerator.registerMenuShortcut(child.text[index + 1], child); } } } } catch (err) { _iterator4.e(err); } finally { _iterator4.f(); } if (!this.applicationMenu) { _localAccelerator.localAccelerator.registerMenuSpecial(this); } } }, { key: "hideAccelerators", value: function hideAccelerators() { var _iterator5 = _createForOfIteratorHelper(this.children), _step5; try { for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) { var child = _step5.value; child.hideShortcut(); } } catch (err) { _iterator5.e(err); } finally { _iterator5.f(); } } }, { key: "closeAll", value: function closeAll() { _localAccelerator.localAccelerator.unregisterMenuShortcuts(); var application = _application.menu; if (application.showing) { var menu = application; while (menu.showing) { menu = menu.showing.submenu; } while (menu && !menu.applicationMenu) { if (menu.showing) { menu.showing.div.style.backgroundColor = 'transparent'; menu.showing = null; } menu.div.remove(); menu = menu.menu; } if (menu) { menu.showing.div.style.background = 'transparent'; menu.showing = null; menu.hideAccelerators(); } } } }, { key: "getApplicationDiv", value: function getApplicationDiv() { return _application; } /** * move selector to the next child pane * @param {string} direction (left or right) * @private */ }, { key: "moveChild", value: function moveChild(direction) { var index; if (direction === 'left') { var parent = this.selector.menu.menu; index = parent.children.indexOf(parent.showing); index--; index = index < 0 ? parent.children.length - 1 : index; parent.children[index].handleClick(); } else { var _parent = this.selector.menu.menu; var selector = _parent.showing; while (!_parent.applicationMenu) { selector.handleClick(); selector.div.style.backgroundColor = 'transparent'; _parent = _parent.menu; selector = _parent.showing; } index = _parent.children.indexOf(selector); index++; index = index === _parent.children.length ? 0 : index; _parent.children[index].handleClick(); } this.selector = null; } /** * move selector right and left * @param {MouseEvent} e * @param {string} direction * @private */ }, { key: "horizontalSelector", value: function horizontalSelector(e, direction) { if (direction === 'right') { if (this.selector.submenu) { this.selector.handleClick(e); this.selector.submenu.selector = this.selector.submenu.children[0]; this.selector.submenu.selector.div.style.backgroundColor = _config.config.SelectedBackgroundStyle; this.selector = null; } else { this.moveChild(direction); } } else if (direction === 'left') { if (!this.selector.menu.menu.applicationMenu) { this.selector.menu.attached.handleClick(e); this.selector.menu.menu.selector = this.selector.menu.attached; this.selector = null; } else { this.moveChild(direction); } } e.stopPropagation(); e.preventDefault(); } /** * move the selector in the menu * @param {KeyboardEvent} e * @param {string} direction (left, right, up, down) * @private */ }, { key: "move", value: function move(e, direction) { if (this.selector) { this.selector.div.style.backgroundColor = 'transparent'; var index = this.children.indexOf(this.selector); if (direction === 'down') { index++; index = index === this.children.length ? 0 : index; } else if (direction === 'up') { index--; index = index < 0 ? this.children.length - 1 : index; } else { return this.horizontalSelector(e, direction); } this.selector = this.children[index]; } else { if (direction === 'up') { this.selector = this.children[this.children.length - 1]; } else { this.selector = this.children[0]; } } this.selector.div.style.backgroundColor = _config.config.SelectedBackgroundStyle; e.preventDefault(); e.stopPropagation(); } /** * click the selector with keyboard * @private */ }, { key: "enter", value: function enter(e) { if (this.selector) { this.selector.handleClick(e); e.preventDefault(); e.stopPropagation(); } } /** * array containing the menu's items * @property {MenuItems[]} items * @readonly */ }, { key: "showApplicationAccelerators", /** * show application menu accelerators when alt is pressed * @private */ value: function showApplicationAccelerators() { var _this = this; this.hideAccelerators(); _localAccelerator.localAccelerator.registerAlt(function () { if (!_this.showing) { _this.showAccelerators(); } }, function () { _this.hideAccelerators(); }); } /** * sets active application Menu (and removes any existing application menus) * @param {Menu} menu * @param {HTMLElement} [parent=document.body] */ }, { key: "items", get: function get() { return this.children; } }], [{ key: "setApplicationMenu", value: function setApplicationMenu(menu) { var parent = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : document.body; _localAccelerator.localAccelerator.init(); if (_application) { _application.remove(); } _application = (0, _html.html)({ parent: parent, styles: _config.config.ApplicationContainerStyle }); _application.menu = menu; menu.applyConfig(_config.config.ApplicationMenuStyle); var _iterator6 = _createForOfIteratorHelper(menu.children), _step6; try { for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) { var child = _step6.value; child.applyConfig(_config.config.ApplicationMenuRowStyle); if (child.arrow) { child.arrow.style.display = 'none'; } menu.div.appendChild(child.div); } } catch (err) { _iterator6.e(err); } finally { _iterator6.f(); } _application.appendChild(menu.div); menu.applicationMenu = true; menu.div.tabIndex = -1; // don't let menu bar focus unless windows are open (this fixes a focus bug) menu.div.addEventListener('focus', function () { if (!menu.showing) { menu.div.blur(); } }); // close all windows if menu is no longer the focus menu.div.addEventListener('blur', function () { if (menu.showing) { menu.closeAll(); } }); menu.showApplicationAccelerators(); } /** * use this to change the default config settings across all menus * @type {config} */ }, { key: "config", get: function get() { return _config.config; } /** * MenuItem definition * @type {MenuItem} */ }, { key: "MenuItem", get: function get() { return _MenuItem.MenuItem; } }]); return Menu; }(); exports.Menu = Menu; },{"./config":"../src/config.js","./MenuItem":"../src/MenuItem.js","./localAccelerator":"../src/localAccelerator.js","./html":"../src/html.js"}],"../src/index.js":[function(require,module,exports) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "Menu", { enumerable: true, get: function () { return _Menu.Menu; } }); Object.defineProperty(exports, "MenuItem", { enumerable: true, get: function () { return _MenuItem.MenuItem; } }); Object.defineProperty(exports, "localAccelerator", { enumerable: true, get: function () { return _localAccelerator.localAccelerator; } }); var _Menu = require("./Menu"); var _MenuItem = require("./MenuItem"); var _localAccelerator = require("./localAccelerator"); },{"./Menu":"../src/Menu.js","./MenuItem":"../src/MenuItem.js","./localAccelerator":"../src/localAccelerator.js"}],"code.js":[function(require,module,exports) { "use strict"; var _src = require("../src"); function test() { // change a Menu setting _src.Menu.config.SubmenuOpenDelay = 300; var menu = new _src.Menu(); var file = new _src.Menu(); file.append(new _src.MenuItem({ label: '&New...', accelerator: 'CommandOrControl+N', click: function click() { return console.log('new dialog open'); } })); file.append(new _src.MenuItem({ label: '&Save...', accelerator: 'CommandOrControl+S' })); file.insert(1, new _src.MenuItem({ label: '&Open...', accelerator: 'CommandOrControl+O', click: function click() { return console.log('open pressed'); } })); file.append(new _src.MenuItem({ type: 'separator' })); var autosave = new _src.MenuItem({ label: '&Autosave', type: 'checkbox', checked: false }); file.append(autosave); file.append(new _src.MenuItem({ type: 'separator' })); file.append(new _src.MenuItem({ label: 'E&xit' })); menu.append(new _src.MenuItem({ label: '&File', submenu: file })); var submenu = new _src.Menu(); submenu.append(new _src.MenuItem({ label: 'first', accelerator: 'ctrl+a | ctrl+b', click: function click() { return console.log('first pressed'); } })); submenu.append(new _src.MenuItem({ label: 'second' })); submenu.append(new _src.MenuItem({ label: 'third' })); submenu.append(new _src.MenuItem({ label: 'fourth' })); var subsubmenu = new _src.Menu(); subsubmenu.append(new _src.MenuItem({ label: 'first' })); subsubmenu.append(new _src.MenuItem({ label: 'second' })); submenu.append(new _src.MenuItem({ label: 'sub-submenu', submenu: subsubmenu })); var submenu2 = new _src.Menu(); submenu2.append(new _src.MenuItem({ label: 'first' })); submenu2.append(new _src.MenuItem({ label: 'second' })); submenu2.append(new _src.MenuItem({ label: 'third' })); submenu2.append(new _src.MenuItem({ label: 'fourth' })); var view = new _src.Menu(); view.append(new _src.MenuItem({ label: 'submenu &1', submenu: submenu })); view.append(new _src.MenuItem({ label: 'zoom &in', accelerator: 'CommandOrControl+=' })); view.append(new _src.MenuItem({ label: 'zoom &out', accelerator: 'CommandOrControl+-' })); view.append(new _src.MenuItem({ type: 'separator' })); view.append(new _src.MenuItem({ label: 'submenu &2', submenu: submenu2 })); menu.append(new _src.MenuItem({ label: '&View', submenu: view })); var help = new _src.Menu(); help.append(new _src.MenuItem({ label: 'About' })); menu.append(new _src.MenuItem({ label: '&Help', submenu: help })); _src.Menu.setApplicationMenu(menu); _src.localAccelerator.register('a', function () { return console.log('hi'); }); // test checked change autosave.checked = true; } window.onload = function () { test(); // require('fork-me-github')() // require('./highlight')() }; },{"../src":"../src/index.js"}],"../node_modules/parcel/src/builtins/hmr-runtime.js":[function(require,module,exports) { var global = arguments[3]; var OVERLAY_ID = '__parcel__error__overlay__'; var OldModule = module.bundle.Module; function Module(moduleName) { OldModule.call(this, moduleName); this.hot = { data: module.bundle.hotData, _acceptCallbacks: [], _disposeCallbacks: [], accept: function (fn) { this._acceptCallbacks.push(fn || function () {}); }, dispose: function (fn) { this._disposeCallbacks.push(fn); } }; module.bundle.hotData = null; } module.bundle.Module = Module; var checkedAssets, assetsToAccept; var parent = module.bundle.parent; if ((!parent || !parent.isParcelRequire) && typeof WebSocket !== 'undefined') { var hostname = "" || location.hostname; var protocol = location.protocol === 'https:' ? 'wss' : 'ws'; var ws = new WebSocket(protocol + '://' + hostname + ':' + "46307" + '/'); ws.onmessage = function (event) { checkedAssets = {}; assetsToAccept = []; var data = JSON.parse(event.data); if (data.type === 'update') { var handled = false; data.assets.forEach(function (asset) { if (!asset.isNew) { var didAccept = hmrAcceptCheck(global.parcelRequire, asset.id); if (didAccept) { handled = true; } } }); // Enable HMR for CSS by default. handled = handled || data.assets.every(function (asset) { return asset.type === 'css' && asset.generated.js; }); if (handled) { console.clear(); data.assets.forEach(function (asset) { hmrApply(global.parcelRequire, asset); }); assetsToAccept.forEach(function (v) { hmrAcceptRun(v[0], v[1]); }); } else if (location.reload) { // `location` global exists in a web worker context but lacks `.reload()` function. location.reload(); } } if (data.type === 'reload') { ws.close(); ws.onclose = function () { location.reload(); }; } if (data.type === 'error-resolved') { console.log('[parcel] ✨ Error resolved'); removeErrorOverlay(); } if (data.type === 'error') { console.error('[parcel] 🚨 ' + data.error.message + '\n' + data.error.stack); removeErrorOverlay(); var overlay = createErrorOverlay(data); document.body.appendChild(overlay); } }; } function removeErrorOverlay() { var overlay = document.getElementById(OVERLAY_ID); if (overlay) { overlay.remove(); } } function createErrorOverlay(data) { var overlay = document.createElement('div'); overlay.id = OVERLAY_ID; // html encode message and stack trace var message = document.createElement('div'); var stackTrace = document.createElement('pre'); message.innerText = data.error.message; stackTrace.innerText = data.error.stack; overlay.innerHTML = '<div style="background: black; font-size: 16px; color: white; position: fixed; height: 100%; width: 100%; top: 0px; left: 0px; padding: 30px; opacity: 0.85; font-family: Menlo, Consolas, monospace; z-index: 9999;">' + '<span style="background: red; padding: 2px 4px; border-radius: 2px;">ERROR</span>' + '<span style="top: 2px; margin-left: 5px; position: relative;">🚨</span>' + '<div style="font-size: 18px; font-weight: bold; margin-top: 20px;">' + message.innerHTML + '</div>' + '<pre>' + stackTrace.innerHTML + '</pre>' + '</div>'; return overlay; } function getParents(bundle, id) { var modules = bundle.modules; if (!modules) { return []; } var parents = []; var k, d, dep; for (k in modules) { for (d in modules[k][1]) { dep = modules[k][1][d]; if (dep === id || Array.isArray(dep) && dep[dep.length - 1] === id) { parents.push(k); } } } if (bundle.parent) { parents = parents.concat(getParents(bundle.parent, id)); } return parents; } function hmrApply(bund