├── .editorconfig
├── .gitignore
├── .travis.yml
├── example.html
├── index.js
├── license
├── package.json
├── readme.md
└── test.js
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | end_of_line = lf
5 | insert_final_newline = true
6 | indent_style = space
7 | indent_size = 2
8 | trim_trailing_whitespace = true
9 | insert_final_newline = true
10 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | #### joe made this: https://goel.io/joe
2 |
3 | #####=== SublimeText ===#####
4 | # cache files for sublime text
5 | *.tmlanguage.cache
6 | *.tmPreferences.cache
7 | *.stTheme.cache
8 |
9 | # workspace files are user-specific
10 | *.sublime-workspace
11 |
12 | # project files should be checked into the repository, unless a significant
13 | # proportion of contributors will probably not be using SublimeText
14 | # *.sublime-project
15 |
16 | # sftp configuration file
17 | sftp-config.json
18 |
19 | #####=== Node ===#####
20 |
21 | # Logs
22 | logs
23 | *.log
24 |
25 | # Runtime data
26 | pids
27 | *.pid
28 | *.seed
29 |
30 | # Directory for instrumented libs generated by jscoverage/JSCover
31 | lib-cov
32 |
33 | # Coverage directory used by tools like istanbul
34 | coverage
35 |
36 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
37 | .grunt
38 |
39 | # node-waf configuration
40 | .lock-wscript
41 |
42 | # Compiled binary addons (http://nodejs.org/api/addons.html)
43 | build/Release
44 |
45 | # Dependency directory
46 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git-
47 | node_modules
48 |
49 | # Debug log from npm
50 | npm-debug.log
51 |
52 | #####=== OSX ===#####
53 | .DS_Store
54 | .AppleDouble
55 | .LSOverride
56 |
57 | # Icon must end with two \r
58 | Icon
59 |
60 | # Thumbnails
61 | ._*
62 |
63 | # Files that might appear on external disk
64 | .Spotlight-V100
65 | .Trashes
66 |
67 | # Directories potentially created on remote AFP share
68 | .AppleDB
69 | .AppleDesktop
70 | Network Trash Folder
71 | Temporary Items
72 | .apdisk
73 |
74 | #####=== Linux ===#####
75 | *~
76 |
77 | # KDE directory preferences
78 | .directory
79 |
80 | # Linux trash folder which might appear on any partition or disk
81 | .Trash-*
82 |
83 |
84 | yarn.lock
85 |
86 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - 'stable'
4 | sudo: false
5 |
--------------------------------------------------------------------------------
/example.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | example
5 |
6 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | Hola
33 |
34 |
35 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const electron = require('electron');
4 |
5 | const DOM_VK_A = 0x41; // (65) "A" key.
6 | const DOM_VK_C = 0x43; // (67) "C" key.
7 | const DOM_VK_V = 0x56; // (86) "V" key.
8 | const DOM_VK_X = 0x58; // (88) "X" key.
9 | const DOM_VK_Z = 0x5A; // (90) "Z" key.
10 |
11 | const menuTemplate = [{
12 | label: 'Undo',
13 | role: 'undo'
14 | }, {
15 | label: 'Redo',
16 | role: 'redo'
17 | }, {
18 | type: 'separator'
19 | }, {
20 | label: 'Cut',
21 | role: 'cut'
22 | }, {
23 | label: 'Copy',
24 | role: 'copy'
25 | }, {
26 | label: 'Paste',
27 | role: 'paste'
28 | }, {
29 | type: 'separator'
30 | }, {
31 | label: 'Select all',
32 | role: 'selectall'
33 | }];
34 |
35 | function action(name, evt) {
36 | const win = electron.remote.getCurrentWindow();
37 | win.webContents[name]();
38 | evt.preventDefault();
39 | return false;
40 | }
41 |
42 | function defaultIsEditable(node) {
43 | return node.matches('input, textarea, [contenteditable]');
44 | }
45 |
46 | function mkInputMenu(isEditable = defaultIsEditable) {
47 | function inputMenu(ctx, next) {
48 | let node = ctx.elm;
49 |
50 | while (node) {
51 | if (isEditable(node)) {
52 | [].push.apply(ctx.menu, menuTemplate);
53 | break;
54 | }
55 | node = node.parentElement;
56 | }
57 | next();
58 | }
59 |
60 | function handleInputShortcuts(evt) {
61 | const c = evt.keyCode;
62 | const ctrlDown = evt.ctrlKey || evt.metaKey; // OSX support
63 | const altDown = evt.altKey;
64 | const shiftDown = evt.shiftKey;
65 |
66 | if (altDown) {
67 | return true;
68 | }
69 |
70 | if (!isEditable(evt.target)) {
71 | return true;
72 | }
73 |
74 | if (ctrlDown && !shiftDown && c === DOM_VK_C) {
75 | return action('copy', evt);
76 | }
77 |
78 | if (ctrlDown && !shiftDown && c === DOM_VK_V) {
79 | return action('paste', evt);
80 | }
81 |
82 | if (ctrlDown && !shiftDown && c === DOM_VK_X) {
83 | return action('cut', evt);
84 | }
85 |
86 | if (ctrlDown && !shiftDown && c === DOM_VK_A) {
87 | return action('selectAll', evt);
88 | }
89 |
90 | if (ctrlDown && !shiftDown && c === DOM_VK_Z) {
91 | return action('undo', evt);
92 | }
93 |
94 | if (ctrlDown && shiftDown && c === DOM_VK_Z) {
95 | return action('redo', evt);
96 | }
97 |
98 | return true;
99 | }
100 |
101 | function registerShortcuts() {
102 | if (document.body) {
103 | document.body.addEventListener('keydown', handleInputShortcuts);
104 | } else {
105 | document.addEventListener('DOMContentLoaded', () => {
106 | document.body.addEventListener('keydown', handleInputShortcuts);
107 | });
108 | }
109 | }
110 |
111 | inputMenu.registerShortcuts = registerShortcuts;
112 | return inputMenu;
113 | }
114 |
115 | const defaultInputMenu = mkInputMenu();
116 | defaultInputMenu.mkInputMenu = mkInputMenu;
117 | defaultInputMenu.defaultIsEditable = defaultIsEditable;
118 | module.exports = defaultInputMenu;
119 |
--------------------------------------------------------------------------------
/license:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 parro-it
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
19 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
21 | OR OTHER DEALINGS IN THE SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "electron-input-menu",
3 | "version": "2.1.0",
4 | "description": "Context menu for electron input elements.",
5 | "repository": "parro-it/electron-input-menu",
6 | "license": "MIT",
7 | "author": "andrea@parro.it",
8 | "scripts": {
9 | "test": "xo",
10 | "start": "electron test.js"
11 | },
12 | "keywords": [
13 | "electron",
14 | "input",
15 | "contextmenu",
16 | "shortcuts"
17 | ],
18 | "eslintConfig": {
19 | "extends": [
20 | "js",
21 | "features"
22 | ]
23 | },
24 | "devDependencies": {
25 | "electron-contextmenu-middleware": "^1.0.0",
26 | "electron-prebuilt": "^1.1.1",
27 | "xo": "^0.17.1"
28 | },
29 | "files": [
30 | "index.js"
31 | ],
32 | "xo": {
33 | "envs": [
34 | "browser",
35 | "node"
36 | ]
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # electron-input-menu
2 |
3 | [](https://greenkeeper.io/)
4 |
5 | > Context menu for [electron](https://github.com/atom/electron) input elements.
6 |
7 | [](http://travis-ci.org/parro-it/electron-input-menu)
8 | [](https://npmjs.org/package/electron-input-menu)
9 | [](https://npmjs.org/package/electron-input-menu)
10 |
11 | # Installation
12 |
13 | ```bash
14 | npm install --save electron-input-menu
15 | ```
16 |
17 | # Usage
18 |
19 | This module expose a middleware for [electron-contextmenu-middleware](https://github.com/parro-it/electron-contextmenu-middleware).
20 |
21 | To use input context menu, you have to require this module and `electron-contextmenu-middleware` in `renderer` process and then mount this module as a middleware.
22 |
23 | ```js
24 | const inputMenu = require('electron-input-menu');
25 | const context = require('electron-contextmenu-middleware');
26 |
27 | context.use(inputMenu);
28 |
29 | context.activate();
30 | ```
31 |
32 | # Keyboard shortcuts
33 |
34 | `electron-input-menu` can also register shortcuts on DOM `document` object to handle copy, paste, cut, selectAll, undo and redo action. This is useful if your app doesn't provide an "Edit" menu that can handle this shortcuts.
35 |
36 | To activate the shortcuts, call the `registerShortcuts` method in renderer process.
37 |
38 | ```js
39 | const inputMenu = require('electron-input-menu');
40 | inputMenu.registerShortcuts();
41 | ```
42 |
43 |
44 | # Related projects
45 |
46 | * [electron-contextmenu-middleware](https://github.com/parro-it/electron-contextmenu-middleware) - Build `electron` context menus composing multiple middlewares functions.
47 |
48 | * [debug-menu](https://github.com/parro-it/debug-menu) - Chrome-like "inspect element" context-menu.
49 |
50 |
51 |
52 | # License
53 |
54 | The MIT License (MIT)
55 |
56 | Copyright (c) 2016 parro-it
57 |
--------------------------------------------------------------------------------
/test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | const electron = require('electron');
3 |
4 | electron.app.on('ready', () => {
5 | const win = new electron.BrowserWindow({
6 | show: true
7 | });
8 | const empty = electron.Menu.buildFromTemplate([]);
9 | win.setMenu(empty);
10 | electron.Menu.setApplicationMenu(empty);
11 | win.loadURL(`file://${__dirname}/example.html`);
12 | win.webContents.openDevTools();
13 | });
14 |
--------------------------------------------------------------------------------