Fix issues with non-US keyboards and add key binding settings page (#2930)

Replaced the key manager by atom-keymap to support non-US keyboards and
dead key translation on macOS and Windows. In addition, a GUI for key
bindings was added.
This commit is contained in:
Felix Häusler 2022-01-29 15:14:19 +01:00 committed by GitHub
parent c959d185b2
commit 6b3ead958e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
41 changed files with 2078 additions and 1233 deletions

View File

@ -7,7 +7,6 @@ Usage: marktext [commands] [path ...]
--debug Enable debug mode
--safe Disable plugins and other user configuration
--dump-keyboard-layout Dump keyboard information
-n, --new-window Open a new window on second-instance
--user-data-dir Change the user data directory
--disable-gpu Disable GPU hardware acceleration

View File

@ -17,12 +17,13 @@ Here is an example:
- `Option` on macOS
- `Ctrl`
- `Shift`
- `Alt` and `AltGr` on Linux and Windows
- `Super` on Linux and Windows
- `Alt` (equal to `Option` on macOS)
Please don't bind `AltGr`, use `Cltr+Alt` instead.
## Available keys
- `0-9`, `A-Z`, `F1-F24` and punctuations
- `0-9`, `A-Z`, `F1-F24` and punctuations like `/` or `#`
- `Plus`, `Space`, `Tab`, `Backspace`, `Delete`, `Insert`, `Return/Enter`, `Esc`, `Home`, `End` and `PrintScreen`
- `Up`, `Down`, `Left` and `Right`
- `PageUp` and `PageDown`

View File

@ -62,11 +62,11 @@ MarkText key bindings for Linux. Please see [general key bindings](KEYBINDINGS.m
| `paragraph.math-formula` | <kbd>Ctrl</kbd>+<kbd>Alt</kbd>+<kbd>M</kbd> | Insert a math block |
| `paragraph.html-block` | <kbd>Ctrl</kbd>+<kbd>Alt</kbd>+<kbd>H</kbd> | Insert a HTML block |
| `paragraph.order-list` | <kbd>Ctrl</kbd>+<kbd>G</kbd> | Insert a ordered list |
| `paragraph.bullet-list` | <kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>G</kbd> | Insert a unordered list |
| `paragraph.bullet-list` | <kbd>Ctrl</kbd>+<kbd>H</kbd> | Insert a unordered list |
| `paragraph.task-list` | <kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>X</kbd> | Insert a task list |
| `paragraph.loose-list-item` | <kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>L</kbd> | Convert a list item to a loose list item |
| `paragraph.paragraph` | <kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>0</kbd> | Convert a heading to a paragraph |
| `paragraph.horizontal-line` | <kbd>Ctrl</kbd>+<kbd>H</kbd> | Add a horizontal line |
| `paragraph.horizontal-line` | <kbd>Ctrl</kbd>+<kbd>\_</kbd> | Add a horizontal line |
| `paragraph.front-matter` | <kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>Y</kbd> | Insert a YAML frontmatter block |
#### Format menu
@ -79,7 +79,7 @@ MarkText key bindings for Linux. Please see [general key bindings](KEYBINDINGS.m
| `format.superscript` | - | Change the selected text to underline |
| `format.subscript` | - | Change the selected text to underline |
| `format.highlight` | <kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>H</kbd> | Highlight the selected text by <mark>tag</mark> |
| `format.inline-code` | <kbd>Ctrl</kbd>+<kbd>`</kbd> | Change the selected text to inline code |
| `format.inline-code` | <kbd>Ctrl</kbd>+<kbd>Y</kbd> | Change the selected text to inline code |
| `format.inline-math` | <kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>M</kbd> | Change the selected text to inline math |
| `format.strike` | <kbd>Ctrl</kbd>+<kbd>D</kbd> | Strike through the selected text |
| `format.hyperlink` | <kbd>Ctrl</kbd>+<kbd>L</kbd> | Insert a hyperlink |
@ -136,4 +136,4 @@ MarkText key bindings for Linux. Please see [general key bindings](KEYBINDINGS.m
| Id | Default | Description |
| ----------------- | ---------------------------- | ---------------------- |
| `file.quick-open` | <kbd>Ctrl</kbd>+<kbd>P</kbd> | Open quick open dialog |
| `file.quick-open` | <kbd>Ctrl</kbd>+<kbd>P</kbd> | Show quick open dialog |

View File

@ -6,12 +6,12 @@ MarkText key bindings for macOS. Please see [general key bindings](KEYBINDINGS.m
#### MarkText menu
| Id | Default | Description |
| ------------------ | ---------------------------------------------- | -------------------------------------- |
| `mt.hide` | <kbd>Command</kbd>+<kbd>H</kbd> | Hide MarkText |
| `mt.hide-others` | <kbd>Command</kbd>+<kbd>Alt</kbd>+<kbd>H</kbd> | Hide all other windows except MarkText |
| `file.preferences` | <kbd>Command</kbd>+<kbd>,</kbd> | Open settings window |
| `file.quit` | <kbd>Command</kbd>+<kbd>Q</kbd> | Quit MarkText |
| Id | Default | Description |
| ------------------ | ------------------------------------------------- | -------------------------------------- |
| `mt.hide` | <kbd>Command</kbd>+<kbd>H</kbd> | Hide MarkText |
| `mt.hide-others` | <kbd>Command</kbd>+<kbd>Option</kbd>+<kbd>H</kbd> | Hide all other windows except MarkText |
| `file.preferences` | <kbd>Command</kbd>+<kbd>,</kbd> | Open settings window |
| `file.quit` | <kbd>Command</kbd>+<kbd>Q</kbd> | Quit MarkText |
#### File menu
@ -31,51 +31,51 @@ MarkText key bindings for macOS. Please see [general key bindings](KEYBINDINGS.m
#### Edit menu
| Id | Default | Description |
|:------------------------ | ------------------------------------------------ | ----------------------------------------------- |
| `edit.undo` | <kbd>Command</kbd>+<kbd>Z</kbd> | Undo last operation |
| `edit.redo` | <kbd>Command</kbd>+<kbd>Shift</kbd>+<kbd>Z</kbd> | Redo last operation |
| `edit.cut` | <kbd>Command</kbd>+<kbd>X</kbd> | Cut selected text |
| `edit.copy` | <kbd>Command</kbd>+<kbd>C</kbd> | Copy selected text |
| `edit.paste` | <kbd>Command</kbd>+<kbd>V</kbd> | Paste text |
| `edit.copy-as-markdown` | <kbd>Command</kbd>+<kbd>Shift</kbd>+<kbd>C</kbd> | Copy selected text as markdown |
| `edit.copy-as-html` | - | Copy selected text as html |
| `edit.paste-as-plaintext` | <kbd>Command</kbd>+<kbd>Shift</kbd>+<kbd>V</kbd> | Copy selected text as plaintext |
| `edit.select-all` | <kbd>Command</kbd>+<kbd>A</kbd> | Select all text of the document |
| `edit.duplicate` | <kbd>Command</kbd>+<kbd>Alt</kbd>+<kbd>P</kbd> | Duplicate the current paragraph |
| `edit.create-paragraph` | <kbd>Command</kbd>+<kbd>Shift</kbd>+<kbd>N</kbd> | Create a new paragraph after the current one |
| `edit.delete-paragraph` | <kbd>Command</kbd>+<kbd>Shift</kbd>+<kbd>D</kbd> | Delete current paragraph |
| `edit.find` | <kbd>Command</kbd>+<kbd>F</kbd> | Find information in the document |
| `edit.find-next` | <kbd>Cmd</kbd>+<kbd>G</kbd> | Continue the search and find the next match |
| `edit.find-previous` | <kbd>Shift</kbd>+<kbd>Cmd</kbd>+<kbd>G</kbd> | Continue the search and find the previous match |
| `edit.replace` | <kbd>Command</kbd>+<kbd>Alt</kbd>+<kbd>F</kbd> | Replace the information with a replacement |
| `edit.find-in-folder` | <kbd>Command</kbd>+<kbd>Shift</kbd>+<kbd>F</kbd> | Find files contain the keyword in opend folder |
| `edit.screenshot` | <kbd>Command</kbd>+<kbd>Alt</kbd>+<kbd>A</kbd> | Get the screenshot |
| Id | Default | Description |
|:------------------------- | ------------------------------------------------- | ----------------------------------------------- |
| `edit.undo` | <kbd>Command</kbd>+<kbd>Z</kbd> | Undo last operation |
| `edit.redo` | <kbd>Command</kbd>+<kbd>Shift</kbd>+<kbd>Z</kbd> | Redo last operation |
| `edit.cut` | <kbd>Command</kbd>+<kbd>X</kbd> | Cut selected text |
| `edit.copy` | <kbd>Command</kbd>+<kbd>C</kbd> | Copy selected text |
| `edit.paste` | <kbd>Command</kbd>+<kbd>V</kbd> | Paste text |
| `edit.copy-as-markdown` | <kbd>Command</kbd>+<kbd>Shift</kbd>+<kbd>C</kbd> | Copy selected text as markdown |
| `edit.copy-as-html` | - | Copy selected text as html |
| `edit.paste-as-plaintext` | <kbd>Command</kbd>+<kbd>Shift</kbd>+<kbd>V</kbd> | Copy selected text as plaintext |
| `edit.select-all` | <kbd>Command</kbd>+<kbd>A</kbd> | Select all text of the document |
| `edit.duplicate` | <kbd>Command</kbd>+<kbd>Option</kbd>+<kbd>P</kbd> | Duplicate the current paragraph |
| `edit.create-paragraph` | <kbd>Command</kbd>+<kbd>Shift</kbd>+<kbd>N</kbd> | Create a new paragraph after the current one |
| `edit.delete-paragraph` | <kbd>Command</kbd>+<kbd>Shift</kbd>+<kbd>D</kbd> | Delete current paragraph |
| `edit.find` | <kbd>Command</kbd>+<kbd>F</kbd> | Find information in the document |
| `edit.find-next` | <kbd>Cmd</kbd>+<kbd>G</kbd> | Continue the search and find the next match |
| `edit.find-previous` | <kbd>Shift</kbd>+<kbd>Cmd</kbd>+<kbd>G</kbd> | Continue the search and find the previous match |
| `edit.replace` | <kbd>Command</kbd>+<kbd>Option</kbd>+<kbd>F</kbd> | Replace the information with a replacement |
| `edit.find-in-folder` | <kbd>Command</kbd>+<kbd>Shift</kbd>+<kbd>F</kbd> | Find files contain the keyword in opend folder |
| `edit.screenshot` | <kbd>Command</kbd>+<kbd>Option</kbd>+<kbd>A</kbd> | Get the screenshot |
#### Paragraph menu
| Id | Default | Description |
| --------------------------- | ------------------------------------------------ | ---------------------------------------- |
| `paragraph.heading-1` | <kbd>Command</kbd>+<kbd>1</kbd> | Set line as heading 1 |
| `paragraph.heading-2` | <kbd>Command</kbd>+<kbd>2</kbd> | Set line as heading 2 |
| `paragraph.heading-3` | <kbd>Command</kbd>+<kbd>3</kbd> | Set line as heading 3 |
| `paragraph.heading-4` | <kbd>Command</kbd>+<kbd>4</kbd> | Set line as heading 4 |
| `paragraph.heading-5` | <kbd>Command</kbd>+<kbd>5</kbd> | Set line as heading 5 |
| `paragraph.heading-6` | <kbd>Command</kbd>+<kbd>6</kbd> | Set line as heading 6 |
| `paragraph.upgrade-heading` | <kbd>Command</kbd>+<kbd>=</kbd> | Upgrade a heading |
| `paragraph.degrade-heading` | <kbd>Command</kbd>+<kbd>-</kbd> | Degrade a heading |
| `paragraph.table` | <kbd>Command</kbd>+<kbd>Shift</kbd>+<kbd>T</kbd> | Insert a table |
| `paragraph.code-fence` | <kbd>Command</kbd>+<kbd>Alt</kbd>+<kbd>C</kbd> | Insert a code block |
| `paragraph.quote-block` | <kbd>Command</kbd>+<kbd>Alt</kbd>+<kbd>Q</kbd> | Insert a quote block |
| `paragraph.math-formula` | <kbd>Command</kbd>+<kbd>Alt</kbd>+<kbd>M</kbd> | Insert a math block |
| `paragraph.html-block` | <kbd>Command</kbd>+<kbd>Alt</kbd>+<kbd>J</kbd> | Insert a HTML block |
| `paragraph.order-list` | <kbd>Command</kbd>+<kbd>Alt</kbd>+<kbd>O</kbd> | Insert a ordered list |
| `paragraph.bullet-list` | <kbd>Command</kbd>+<kbd>Alt</kbd>+<kbd>U</kbd> | Insert a unordered list |
| `paragraph.task-list` | <kbd>Command</kbd>+<kbd>Alt</kbd>+<kbd>X</kbd> | Insert a task list |
| `paragraph.loose-list-item` | <kbd>Command</kbd>+<kbd>Alt</kbd>+<kbd>L</kbd> | Convert a list item to a loose list item |
| `paragraph.paragraph` | <kbd>Command</kbd>+<kbd>0</kbd> | Convert a heading to a paragraph |
| `paragraph.horizontal-line` | <kbd>Command</kbd>+<kbd>Alt</kbd>+<kbd>-</kbd> | Add a horizontal line |
| `paragraph.front-matter` | <kbd>Command</kbd>+<kbd>Alt</kbd>+<kbd>Y</kbd> | Insert a YAML frontmatter block |
| Id | Default | Description |
| --------------------------- | ------------------------------------------------- | ---------------------------------------- |
| `paragraph.heading-1` | <kbd>Command</kbd>+<kbd>1</kbd> | Set line as heading 1 |
| `paragraph.heading-2` | <kbd>Command</kbd>+<kbd>2</kbd> | Set line as heading 2 |
| `paragraph.heading-3` | <kbd>Command</kbd>+<kbd>3</kbd> | Set line as heading 3 |
| `paragraph.heading-4` | <kbd>Command</kbd>+<kbd>4</kbd> | Set line as heading 4 |
| `paragraph.heading-5` | <kbd>Command</kbd>+<kbd>5</kbd> | Set line as heading 5 |
| `paragraph.heading-6` | <kbd>Command</kbd>+<kbd>6</kbd> | Set line as heading 6 |
| `paragraph.upgrade-heading` | <kbd>Command</kbd>+<kbd>=</kbd> | Upgrade a heading |
| `paragraph.degrade-heading` | <kbd>Command</kbd>+<kbd>-</kbd> | Degrade a heading |
| `paragraph.table` | <kbd>Command</kbd>+<kbd>Shift</kbd>+<kbd>T</kbd> | Insert a table |
| `paragraph.code-fence` | <kbd>Command</kbd>+<kbd>Option</kbd>+<kbd>C</kbd> | Insert a code block |
| `paragraph.quote-block` | <kbd>Command</kbd>+<kbd>Option</kbd>+<kbd>Q</kbd> | Insert a quote block |
| `paragraph.math-formula` | <kbd>Command</kbd>+<kbd>Option</kbd>+<kbd>M</kbd> | Insert a math block |
| `paragraph.html-block` | <kbd>Command</kbd>+<kbd>Option</kbd>+<kbd>J</kbd> | Insert a HTML block |
| `paragraph.order-list` | <kbd>Command</kbd>+<kbd>Option</kbd>+<kbd>O</kbd> | Insert a ordered list |
| `paragraph.bullet-list` | <kbd>Command</kbd>+<kbd>Option</kbd>+<kbd>U</kbd> | Insert a unordered list |
| `paragraph.task-list` | <kbd>Command</kbd>+<kbd>Option</kbd>+<kbd>X</kbd> | Insert a task list |
| `paragraph.loose-list-item` | <kbd>Command</kbd>+<kbd>Option</kbd>+<kbd>L</kbd> | Convert a list item to a loose list item |
| `paragraph.paragraph` | <kbd>Command</kbd>+<kbd>0</kbd> | Convert a heading to a paragraph |
| `paragraph.horizontal-line` | <kbd>Command</kbd>+<kbd>Option</kbd>+<kbd>-</kbd> | Add a horizontal line |
| `paragraph.front-matter` | <kbd>Command</kbd>+<kbd>Option</kbd>+<kbd>Y</kbd> | Insert a YAML frontmatter block |
#### Format menu
@ -106,18 +106,18 @@ MarkText key bindings for macOS. Please see [general key bindings](KEYBINDINGS.m
#### View menu
| Id | Default | Description |
| ----------------------- | ------------------------------------------------ | ---------------------------------------- |
| `view.command-palette` | <kbd>Command</kbd>+<kbd>Shift</kbd>+<kbd>P</kbd> | Toggle command palette |
| `view.source-code-mode` | <kbd>Command</kbd>+<kbd>Alt</kbd>+<kbd>S</kbd> | Switch to source code mode |
| `view.typewriter-mode` | <kbd>Command</kbd>+<kbd>Alt</kbd>+<kbd>T</kbd> | Enable typewriter mode |
| `view.focus-mode` | <kbd>Command</kbd>+<kbd>Shift</kbd>+<kbd>J</kbd> | Enable focus mode |
| `view.toggle-sidebar` | <kbd>Command</kbd>+<kbd>J</kbd> | Toggle sidebar |
| `view.toggle-tabbar` | <kbd>Command</kbd>+<kbd>Alt</kbd>+<kbd>B</kbd> | Toggle tabbar |
| `view.toggle-toc` . | <kbd>Command</kbd>+<kbd>K</kbd> | Toggle table of contents |
| `view.toggle-dev-tools` | <kbd>Command</kbd>+<kbd>Alt</kbd>+<kbd>I</kbd> | Toggle developer tools (debug mode only) |
| `view.dev-reload` | <kbd>Command</kbd>+<kbd>Alt</kbd>+<kbd>R</kbd> | Reload window (debug mode only) |
| `view.reload-images` | <kbd>Command</kbd>+<kbd>R</kbd> | Reload images |
| Id | Default | Description |
| ----------------------- | ------------------------------------------------- | ---------------------------------------- |
| `view.command-palette` | <kbd>Command</kbd>+<kbd>Shift</kbd>+<kbd>P</kbd> | Toggle command palette |
| `view.source-code-mode` | <kbd>Command</kbd>+<kbd>Option</kbd>+<kbd>S</kbd> | Switch to source code mode |
| `view.typewriter-mode` | <kbd>Command</kbd>+<kbd>Option</kbd>+<kbd>T</kbd> | Enable typewriter mode |
| `view.focus-mode` | <kbd>Command</kbd>+<kbd>Shift</kbd>+<kbd>J</kbd> | Enable focus mode |
| `view.toggle-sidebar` | <kbd>Command</kbd>+<kbd>J</kbd> | Toggle sidebar |
| `view.toggle-tabbar` | <kbd>Command</kbd>+<kbd>Option</kbd>+<kbd>B</kbd> | Toggle tabbar |
| `view.toggle-toc` . | <kbd>Command</kbd>+<kbd>K</kbd> | Toggle table of contents |
| `view.toggle-dev-tools` | <kbd>Command</kbd>+<kbd>Option</kbd>+<kbd>I</kbd> | Toggle developer tools (debug mode only) |
| `view.dev-reload` | <kbd>Command</kbd>+<kbd>Option</kbd>+<kbd>R</kbd> | Reload window (debug mode only) |
| `view.reload-images` | <kbd>Command</kbd>+<kbd>R</kbd> | Reload images |
## Available key bindings

View File

@ -57,16 +57,16 @@ MarkText key bindings for Windows. Please see [general key bindings](KEYBINDINGS
| `paragraph.upgrade-heading` | <kbd>Ctrl</kbd>+<kbd>=</kbd> | Upgrade a heading |
| `paragraph.degrade-heading` | <kbd>Ctrl</kbd>+<kbd>-</kbd> | Degrade a heading |
| `paragraph.table` | <kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>T</kbd> | Insert a table |
| `paragraph.code-fence` | <kbd>Ctrl</kbd>+<kbd>Alt</kbd>+<kbd>C</kbd> | Insert a code block |
| `paragraph.quote-block` | <kbd>Ctrl</kbd>+<kbd>Alt</kbd>+<kbd>Q</kbd> | Insert a quote block |
| `paragraph.math-formula` | <kbd>Ctrl</kbd>+<kbd>Alt</kbd>+<kbd>M</kbd> | Insert a math block |
| `paragraph.code-fence` | <kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>K</kbd> | Insert a code block |
| `paragraph.quote-block` | <kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>Q</kbd> | Insert a quote block |
| `paragraph.math-formula` | <kbd>Ctrl</kbd>+<kbd>Alt</kbd>+<kbd>N</kbd> | Insert a math block |
| `paragraph.html-block` | <kbd>Ctrl</kbd>+<kbd>Alt</kbd>+<kbd>H</kbd> | Insert a HTML block |
| `paragraph.order-list` | <kbd>Ctrl</kbd>+<kbd>Alt</kbd>+<kbd>O</kbd> | Insert a ordered list |
| `paragraph.bullet-list` | <kbd>Ctrl</kbd>+<kbd>Alt</kbd>+<kbd>U</kbd> | Insert a unordered list |
| `paragraph.order-list` | <kbd>Ctrl</kbd>+<kbd>G</kbd> | Insert a ordered list |
| `paragraph.bullet-list` | <kbd>Ctrl</kbd>+<kbd>H</kbd> | Insert a unordered list |
| `paragraph.task-list` | <kbd>Ctrl</kbd>+<kbd>Alt</kbd>+<kbd>X</kbd> | Insert a task list |
| `paragraph.loose-list-item` | <kbd>Ctrl</kbd>+<kbd>Alt</kbd>+<kbd>L</kbd> | Convert a list item to a loose list item |
| `paragraph.paragraph` | <kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>0</kbd> | Convert a heading to a paragraph |
| `paragraph.horizontal-line` | <kbd>Ctrl</kbd>+<kbd>Alt</kbd>+<kbd>-</kbd> | Add a horizontal line |
| `paragraph.horizontal-line` | <kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>U</kbd> | Add a horizontal line |
| `paragraph.front-matter` | <kbd>Ctrl</kbd>+<kbd>Alt</kbd>+<kbd>Y</kbd> | Insert a YAML frontmatter block |
#### Format menu
@ -102,7 +102,7 @@ MarkText key bindings for Windows. Please see [general key bindings](KEYBINDINGS
| ----------------------- | --------------------------------------------- | ---------------------------------------- |
| `view.command-palette` | <kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>P</kbd> | Toggle command palette |
| `view.source-code-mode` | <kbd>Ctrl</kbd>+<kbd>E</kbd> | Switch to source code mode |
| `view.typewriter-mode` | <kbd>Ctrl</kbd>+<kbd>Alt</kbd>+<kbd>T</kbd> | Enable typewriter mode |
| `view.typewriter-mode` | <kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>G</kbd> | Enable typewriter mode |
| `view.focus-mode` | <kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>J</kbd> | Enable focus mode |
| `view.toggle-sidebar` | <kbd>Ctrl</kbd>+<kbd>J</kbd> | Toggle sidebar |
| `view.toggle-tabbar` | <kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>B</kbd> | Toggle tabbar |

View File

@ -12,9 +12,11 @@ files:
- "!**/node_modules/**/{CHANGELOG.md,README.md,README,readme.md,readme}"
- "!node_modules/css-b64-images/{draft.png,draft.xcf}"
- "!node_modules/dagre-d3-renderer/dist/demo/"
- "!node_modules/dagre-d3/dist/demo/"
- "!node_modules/dragula/resources"
- "!node_modules/**/*.js.map"
- "!node_modules/**/*.cjs.map"
- "!node_modules/**/*.mjs.map"
- "!node_modules/**/*.ts.map"
# Don't bundle build files
- "!node_modules/@felixrieseberg/spellchecker/bin"
@ -26,6 +28,16 @@ files:
- "!node_modules/fontmanager-redux/bin"
- "!node_modules/keyboard-layout/bin"
- "!node_modules/keytar/bin"
- "!node_modules/native-keymap/bin"
# Large source files that aren't needed
- "!node_modules/dagre-d3/dist/dagre-d3.min.js"
- "!node_modules/mermaid/dist/mermaid.js"
- "!node_modules/mermaid/dist/mermaid.min.js"
- "!node_modules/mermaid/dist/mermaid.esm.min.mjs"
- "!node_modules/katex/dist/katex.min.js"
- "!node_modules/katex/dist/katex.mjs"
- "!node_modules/vega/build-es5/"
- "!node_modules/vega-embed/build-es5/"
# Don't bundle Linux build files
- "!node_modules/@hfelix/spellchecker/build/Release/hunspell.a"
- "!node_modules/ced/build/Release/compact_enc_det.a"

View File

@ -33,23 +33,22 @@
"validate-licenses": "node tools/validateLicenses.js"
},
"dependencies": {
"@electron/remote": "^2.0.1",
"@hfelix/electron-localshortcut": "^3.1.1",
"@electron/remote": "^2.0.4",
"@hfelix/electron-localshortcut": "^4.0.0-rc.1",
"@hfelix/electron-spellchecker": "^2.0.0",
"@marktext/file-icons": "^1.0.6",
"@octokit/rest": "^18.12.0",
"arg": "^5.0.1",
"axios": "^0.24.0",
"axios": "^0.25.0",
"ced": "^2.0.0",
"chokidar": "^3.5.2",
"codemirror": "^5.65.0",
"chokidar": "^3.5.3",
"codemirror": "^5.65.1",
"command-exists": "^1.2.9",
"dayjs": "^1.10.7",
"dom-autoscroller": "^2.3.4",
"dompurify": "^2.3.4",
"dompurify": "^2.3.5",
"dragula": "^3.7.3",
"electron-is-accelerator": "^0.2.0",
"electron-log": "^4.4.4",
"electron-log": "^4.4.5",
"electron-store": "^8.0.1",
"electron-window-state": "^5.0.3",
"element-resize-detector": "^1.2.4",
@ -62,17 +61,17 @@
"github-markdown-css": "^3.0.1",
"html-tags": "^3.1.0",
"iconv-lite": "^0.6.3",
"iso-639-1": "^2.1.11",
"iso-639-1": "^2.1.12",
"joplin-turndown-plugin-gfm": "^1.0.12",
"katex": "^0.15.2",
"keyboard-layout": "^2.0.17",
"keytar": "^7.7.0",
"mermaid": "^8.13.10",
"minizlib": "^2.1.1",
"minizlib": "^2.1.2",
"native-keymap": "^3.1.1",
"plist": "^3.0.4",
"popper.js": "^1.16.1",
"prismjs": "^1.26.0",
"snabbdom": "^3.2.0",
"snabbdom": "^3.3.1",
"snabbdom-to-html": "^7.0.0",
"source-map-support": "^0.5.21",
"turndown": "^7.1.1",
@ -89,36 +88,36 @@
"webfontloader": "^1.6.28"
},
"devDependencies": {
"@babel/core": "^7.16.7",
"@babel/core": "^7.16.12",
"@babel/eslint-parser": "^7.16.5",
"@babel/plugin-proposal-class-properties": "^7.16.7",
"@babel/plugin-proposal-export-default-from": "^7.16.7",
"@babel/plugin-proposal-function-bind": "^7.16.7",
"@babel/plugin-syntax-class-properties": "^7.12.13",
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
"@babel/plugin-transform-runtime": "^7.16.8",
"@babel/preset-env": "^7.16.8",
"@babel/plugin-transform-runtime": "^7.16.10",
"@babel/preset-env": "^7.16.11",
"@babel/register": "^7.16.9",
"@babel/runtime": "^7.16.7",
"@markedjs/html-differ": "^4.0.0",
"@playwright/test": "^1.17.2",
"@playwright/test": "^1.18.1",
"babel-loader": "^8.2.3",
"babel-plugin-component": "^1.1.1",
"babel-plugin-istanbul": "^6.1.1",
"cfonts": "^2.10.0",
"chai": "^4.3.4",
"chai": "^4.3.6",
"chalk": "^4.1.2",
"cheerio": "^1.0.0-rc.10",
"copy-webpack-plugin": "^10.2.0",
"copy-webpack-plugin": "^10.2.1",
"cross-env": "^7.0.3",
"css-loader": "^6.5.1",
"del": "^6.0.0",
"devtron": "^1.4.0",
"dotenv": "^10.0.0",
"electron": "^15.3.4",
"electron-builder": "^22.14.8",
"electron": "^15.3.6",
"electron-builder": "^22.14.13",
"electron-devtools-installer": "^3.2.0",
"electron-rebuild": "^3.2.5",
"electron-rebuild": "^3.2.7",
"electron-updater": "^4.6.3",
"eslint": "^8.7.0",
"eslint-config-standard": "^16.0.3",
@ -129,30 +128,30 @@
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^6.0.0",
"eslint-plugin-standard": "^4.1.0",
"eslint-plugin-vue": "^8.2.0",
"eslint-plugin-vue": "^8.4.0",
"eslint-webpack-plugin": "^3.1.1",
"esm": "^3.2.25",
"file-loader": "^6.2.0",
"git-revision-webpack-plugin": "^5.0.0",
"html-webpack-plugin": "^5.5.0",
"imports-loader": "^0.8.0",
"karma": "^6.3.11",
"karma": "^6.3.12",
"karma-chai": "^0.1.0",
"karma-coverage": "^2.1.0",
"karma-electron": "^7.1.0",
"karma-mocha": "^2.0.1",
"karma-sourcemap-loader": "^0.3.8",
"karma-spec-reporter": "0.0.32",
"karma-spec-reporter": "0.0.33",
"karma-webpack": "^5.0.0",
"license-checker": "^25.0.1",
"listr": "^0.14.3",
"marked": "^1.2.9",
"mini-css-extract-plugin": "^2.5.1",
"mini-css-extract-plugin": "^2.5.3",
"mocha": "^8.4.0",
"node-fetch": "^2.6.6",
"node-loader": "^2.0.0",
"path-browserify": "^1.0.1",
"playwright": "^1.17.2",
"playwright": "^1.18.1",
"postcss": "^8.4.5",
"postcss-loader": "^6.2.1",
"postcss-preset-env": "^7.2.3",
@ -168,9 +167,9 @@
"vue-loader": "^15.9.8",
"vue-style-loader": "^4.1.3",
"vue-template-compiler": "^2.6.14",
"webpack": "^5.66.0",
"webpack": "^5.67.0",
"webpack-bundle-analyzer": "^4.5.0",
"webpack-cli": "^4.9.1",
"webpack-cli": "^4.9.2",
"webpack-dev-server": "^4.7.3",
"webpack-hot-middleware": "^2.25.1",
"webpack-merge": "^5.8.0"

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,32 @@
const isOsx = process.platform === 'darwin'
const _normalizeAccelerator = accelerator => {
return accelerator.toLowerCase()
.replace('commandorcontrol', isOsx ? 'cmd' : 'ctrl')
.replace('cmdorctrl', isOsx ? 'cmd' : 'ctrl')
.replace('control', 'ctrl')
.replace('meta', 'cmd') // meta := cmd (macOS only) or super
.replace('command', 'cmd')
.replace('option', 'alt')
}
export const isEqualAccelerator = (a, b) => {
a = _normalizeAccelerator(a)
b = _normalizeAccelerator(b)
const i1 = a.indexOf('+')
const i2 = b.indexOf('+')
if (i1 === -1 && i2 === -1) {
return a === b
} else if (i1 === -1 || i2 === -1) {
return false
}
const partsA = a.split('+')
const partsB = b.split('+')
if (partsA.length !== partsB.length || partsA.length <= 1) {
return false
}
const intersection = new Set([...partsA, ...partsB])
return intersection.size === partsB.length
}

View File

@ -9,6 +9,7 @@ import { isLinux, isOsx, isWindows } from '../config'
import parseArgs from '../cli/parser'
import { normalizeAndResolvePath } from '../filesystem'
import { normalizeMarkdownPath } from '../filesystem/markdown'
import { registerKeyboardListeners } from '../keyboard'
import { selectTheme } from '../menu/actions/theme'
import { dockMenu } from '../menu/templates'
import ensureDefaultDict from '../preferences/hunspell'
@ -427,6 +428,8 @@ class App {
}
_listenForIpcMain () {
registerKeyboardListeners()
ipcMain.on('app-create-editor-window', () => {
this._createEditorWindow()
})
@ -566,6 +569,18 @@ class App {
const { keybindings } = this._accessor
keybindings.openConfigInFileManager()
})
ipcMain.handle('mt::keybinding-get-pref-keybindings', () => {
const { keybindings } = this._accessor
const defaultKeybindings = keybindings.getDefaultKeybindings()
const userKeybindings = keybindings.getUserKeybindings()
return { defaultKeybindings, userKeybindings }
})
ipcMain.handle('mt::keybinding-save-user-keybindings', async (event, userKeybindings) => {
const { keybindings } = this._accessor
return await keybindings.setUserKeybindings(userKeybindings)
})
}
}

View File

@ -3,7 +3,6 @@ import { app } from 'electron'
import os from 'os'
import { isDirectory } from 'common/filesystem'
import parseArgs from './parser'
import { dumpKeyboardInformation } from '../keyboard'
import { getPath } from '../utils'
const write = s => process.stdout.write(s)
@ -24,7 +23,6 @@ const cli = () => {
--debug Enable debug mode
--safe Disable plugins and other user configuration
--dump-keyboard-layout Dump keyboard information
-n, --new-window Open a new window on second-instance
--user-data-dir Change the user data directory
--disable-gpu Disable GPU hardware acceleration
@ -44,11 +42,6 @@ const cli = () => {
process.exit(0)
}
if (args['--dump-keyboard-layout']) {
writeLine(dumpKeyboardInformation())
process.exit(0)
}
// Check for portable mode and ensure the user data path is absolute. We assume
// that the path is writable if not this lead to an application crash.
if (!args['--user-data-dir']) {

View File

@ -14,7 +14,6 @@ const parseArgs = (argv = null, permissive = true) => {
const spec = {
'--debug': Boolean,
'--safe': Boolean,
'--dump-keyboard-layout': Boolean,
'--new-window': Boolean,
'-n': '--new-window',

View File

@ -12,7 +12,7 @@ export const editorWinOptions = Object.freeze({
webSecurity: false
},
useContentSize: true,
show: true, // Show the window after the app is ready.
show: true,
frame: false,
titleBarStyle: 'hiddenInset',
zoomFactor: 1.0
@ -31,9 +31,7 @@ export const preferencesWinOptions = Object.freeze({
},
fullscreenable: false,
fullscreen: false,
resizable: false,
minimizable: false,
maximizable: false,
useContentSize: true,
show: true,
frame: false,

View File

@ -1,56 +1,76 @@
// import EventEmitter from 'events'
import { getCurrentKeyboardLayout, getCurrentKeyboardLanguage, getCurrentKeymap } from 'keyboard-layout'
import { ipcMain, shell } from 'electron'
import log from 'electron-log'
import EventEmitter from 'events'
import fsPromises from 'fs/promises'
import { getCurrentKeyboardLayout, getKeyMap, onDidChangeKeyboardLayout } from 'native-keymap'
import os from 'os'
import path from 'path'
export const getKeyboardLanguage = () => {
const lang = getCurrentKeyboardLanguage()
if (lang.length >= 2) {
return lang.substring(0, 2)
let currentKeyboardInfo = null
const loadKeyboardInfo = () => {
currentKeyboardInfo = {
layout: getCurrentKeyboardLayout(),
keymap: getKeyMap()
}
return lang
return currentKeyboardInfo
}
export const dumpKeyboardInformation = () => {
return `Layout: ${getCurrentKeyboardLayout()}\n` +
`Language: ${getCurrentKeyboardLanguage()}\n\n` +
JSON.stringify(getCurrentKeymap(), null, 2)
export const getKeyboardInfo = () => {
if (!currentKeyboardInfo) {
return loadKeyboardInfo()
}
return currentKeyboardInfo
}
export const getVirtualLetters = () => {
// Full list of supported virtual keys:
// https://github.com/parro-it/keyboardevent-from-electron-accelerator/blob/afdbd57bead1e139d7bd03c763778dce6ca8c35d/main.js#L104
const currentKeymap = getCurrentKeymap()
const vkeys = {}
for (const key in currentKeymap) {
// TODO(fxha): Possibly, we can fix more broken accelerators without apply a manually fix later.
if (!key.startsWith('Key')) {
continue
}
const unmodifiedKey = currentKeymap[key].unmodified
if (unmodifiedKey) {
// uppercase character / vkey name (A: KeyA)
vkeys[unmodifiedKey.toUpperCase()] = key
const KEYBOARD_LAYOUT_MONITOR_CHANNEL_ID = 'onDidChangeKeyboardLayout'
class KeyboardLayoutMonitor extends EventEmitter {
constructor () {
super()
this._isSubscribed = false
this._emitTimer = null
}
addListener (callback) {
this._ensureNativeListener()
this.on(KEYBOARD_LAYOUT_MONITOR_CHANNEL_ID, callback)
}
removeListener (callback) {
this.removeListener(KEYBOARD_LAYOUT_MONITOR_CHANNEL_ID, callback)
}
_ensureNativeListener () {
if (!this._isSubscribed) {
this._isSubscribed = true
onDidChangeKeyboardLayout(() => {
// The keyboard layout change event may be emitted multiple times.
clearTimeout(this._emitTimer)
this._emitTimer = setTimeout(() => {
this.emit(KEYBOARD_LAYOUT_MONITOR_CHANNEL_ID, loadKeyboardInfo())
this._emitTimer = null
}, 150)
})
}
}
return vkeys
}
// class KeyboardLayoutMonitor {
//
// constructor() {
// this._eventEmitter = new EventEmitter()
// this._subscription = null
// }
//
// onDidChangeCurrentKeyboardLayout (callback) {
// if (!this._subscription) {
// this._subscription = onDidChangeCurrentKeyboardLayout(layout => {
// this._eventEmitter.emit('onDidChangeCurrentKeyboardLayout', layout)
// })
// }
// this._eventEmitter.on('onDidChangeCurrentKeyboardLayout', callback)
// }
//
// }
//
// // TODO(@fxha): Reload ShortcutHandler on change
// export const keyboardLayoutMonitor = new KeyboardLayoutMonitor()
// Export a single-instance of the monitor.
export const keyboardLayoutMonitor = new KeyboardLayoutMonitor()
export const registerKeyboardListeners = () => {
ipcMain.handle('mt::keybinding-get-keyboard-info', async () => {
return getKeyboardInfo()
})
ipcMain.on('mt::keybinding-debug-dump-keyboard-info', async () => {
const dumpPath = path.join(os.tmpdir(), 'marktext_keyboard_info.json')
const content = JSON.stringify(getKeyboardInfo(), null, 2)
fsPromises.writeFile(dumpPath, content, 'utf8')
.then(() => {
console.log(`Keyboard information written to "${dumpPath}".`)
shell.openPath(dumpPath)
})
.catch(error => {
log.error('Error dumping keyboard information:', error)
})
})
}

View File

@ -1,9 +1,12 @@
// Key bindings for macOS.
// NOTE: Avoid pure `Option` aka `Alt` shortcuts on macOS because these are used to produce alternative characters on all letters and digits.
// Our current key manager will forbid the usage of these key combinations too.
export default new Map([
// MarkText menu
['mt.hide', 'Command+H'],
['mt.hide-others', 'Command+Alt+H'],
['mt.hide-others', 'Command+Option+H'],
['file.preferences', 'Command+,'], // located under MarkText menu in macOS only
// File menu
@ -30,15 +33,15 @@ export default new Map([
['edit.copy-as-html', ''],
['edit.paste-as-plaintext', 'Command+Shift+V'],
['edit.select-all', 'Command+A'],
['edit.duplicate', 'Command+Alt+D'],
['edit.duplicate', 'Command+Option+D'],
['edit.create-paragraph', 'Shift+Command+N'],
['edit.delete-paragraph', 'Shift+Command+D'],
['edit.find', 'Command+F'],
['edit.find-next', 'Cmd+G'],
['edit.find-previous', 'Cmd+Shift+G'],
['edit.replace', 'Command+Alt+F'],
['edit.replace', 'Command+Option+F'],
['edit.find-in-folder', 'Shift+Command+F'],
['edit.screenshot', 'Command+Alt+A'], // macOS only
['edit.screenshot', 'Command+Option+A'], // macOS only
// Paragraph menu
['paragraph.heading-1', 'Command+1'],
@ -50,17 +53,17 @@ export default new Map([
['paragraph.upgrade-heading', 'Command+='],
['paragraph.degrade-heading', 'Command+-'],
['paragraph.table', 'Command+Shift+T'],
['paragraph.code-fence', 'Command+Alt+C'],
['paragraph.quote-block', 'Command+Alt+Q'],
['paragraph.math-formula', 'Command+Alt+M'],
['paragraph.html-block', 'Command+Alt+J'],
['paragraph.order-list', 'Command+Alt+O'],
['paragraph.bullet-list', 'Command+Alt+U'],
['paragraph.task-list', 'Command+Alt+X'],
['paragraph.loose-list-item', 'Command+Alt+L'],
['paragraph.code-fence', 'Command+Option+C'],
['paragraph.quote-block', 'Command+Option+Q'],
['paragraph.math-formula', 'Command+Option+M'],
['paragraph.html-block', 'Command+Option+J'],
['paragraph.order-list', 'Command+Option+O'],
['paragraph.bullet-list', 'Command+Option+U'],
['paragraph.task-list', 'Command+Option+X'],
['paragraph.loose-list-item', 'Command+Option+L'],
['paragraph.paragraph', 'Command+0'],
['paragraph.horizontal-line', 'Command+Alt+-'],
['paragraph.front-matter', 'Command+Alt+Y'],
['paragraph.horizontal-line', 'Command+Option+-'],
['paragraph.front-matter', 'Command+Option+Y'],
// Format menu
['format.strong', 'Command+B'],
@ -85,14 +88,14 @@ export default new Map([
// View menu
['view.command-palette', 'Command+Shift+P'],
['view.source-code-mode', 'Command+Alt+S'],
['view.typewriter-mode', 'Command+Alt+T'],
['view.source-code-mode', 'Command+Option+S'],
['view.typewriter-mode', 'Command+Option+T'],
['view.focus-mode', 'Command+Shift+J'],
['view.toggle-sidebar', 'Command+J'],
['view.toggle-toc', 'Command+K'],
['view.toggle-tabbar', 'Command+Alt+B'],
['view.toggle-dev-tools', 'Command+Alt+I'],
['view.dev-reload', 'Command+Alt+R'],
['view.toggle-tabbar', 'Command+Option+B'],
['view.toggle-dev-tools', 'Command+Option+I'],
['view.dev-reload', 'Command+Option+R'],
['view.reload-images', 'Command+R'],
// ======== Not included in application menu ========================

View File

@ -1,6 +1,11 @@
// Key bindings for Linux.
// NOTE: Avoid `Ctrl+Alt` and `Alt` shortcuts on Linux because Ubuntu based OSs have reserved system shortcuts (see GH#2370).
// Binding shortcuts to these modifiers will result in odd behavior on Ubuntu.
// NOTE: Don't use `Ctrl+Shift+U` because it's used IBus for unicode support.
// NOTE: We can't determine the character for a dead key and no translation is provided. E.g. Ctrl+` (=Ctrl+Shift+´) on a
// none nodeadkeys german keyboard cannot be interpreted. In general don't bind default shortcuts to characters that
// can be produced with ^ or ` on any keyboard. --> ^, `, ", ~, ...
export default new Map([
// MarkText menu on macOS only
@ -57,11 +62,11 @@ export default new Map([
['paragraph.math-formula', 'Ctrl+Alt+M'],
['paragraph.html-block', 'Ctrl+Alt+H'],
['paragraph.order-list', 'Ctrl+G'],
['paragraph.bullet-list', 'Ctrl+Shift+U'],
['paragraph.bullet-list', 'Ctrl+H'],
['paragraph.task-list', 'Ctrl+Shift+X'],
['paragraph.loose-list-item', 'Ctrl+Shift+L'],
['paragraph.paragraph', 'Ctrl+Shift+0'],
['paragraph.horizontal-line', 'Ctrl+H'],
['paragraph.horizontal-line', 'Ctrl+_'], // Ctrl+Shift+-
['paragraph.front-matter', 'Ctrl+Shift+Y'],
// Format menu
@ -71,7 +76,7 @@ export default new Map([
['format.superscript', ''],
['format.subscript', ''],
['format.highlight', 'Ctrl+Shift+H'],
['format.inline-code', 'Ctrl+`'],
['format.inline-code', 'Ctrl+Y'],
['format.inline-math', 'Ctrl+Shift+M'],
['format.strike', 'Ctrl+D'],
['format.hyperlink', 'Ctrl+L'],

View File

@ -1,5 +1,9 @@
// Key bindings for Windows.
// NOTE: Avoid `Ctrl+Alt` and `AltGr` shortcuts on Windows because these are used to produce alternative characters.
// Unlike Linux, `Ctrl+Alt` is an alias to `AltGr` on Windows and will produce alternative characters too.
// We'll should try bind no keys to `Alt` "modifiers" because there are only a few key bindings available.
export default new Map([
// MarkText menu on macOS only
['mt.hide', ''],
@ -50,16 +54,16 @@ export default new Map([
['paragraph.upgrade-heading', 'Ctrl+='],
['paragraph.degrade-heading', 'Ctrl+-'],
['paragraph.table', 'Ctrl+Shift+T'],
['paragraph.code-fence', 'Ctrl+Alt+C'],
['paragraph.quote-block', 'Ctrl+Alt+Q'],
['paragraph.math-formula', 'Ctrl+Alt+M'],
['paragraph.code-fence', 'Ctrl+Shift+K'],
['paragraph.quote-block', 'Ctrl+Shift+Q'],
['paragraph.math-formula', 'Ctrl+Alt+N'],
['paragraph.html-block', 'Ctrl+Alt+H'],
['paragraph.order-list', 'Ctrl+Alt+O'],
['paragraph.bullet-list', 'Ctrl+Alt+U'],
['paragraph.order-list', 'Ctrl+G'],
['paragraph.bullet-list', 'Ctrl+H'],
['paragraph.task-list', 'Ctrl+Alt+X'],
['paragraph.loose-list-item', 'Ctrl+Alt+L'],
['paragraph.paragraph', 'Ctrl+Shift+0'],
['paragraph.horizontal-line', 'Ctrl+Alt+-'],
['paragraph.horizontal-line', 'Ctrl+Shift+U'],
['paragraph.front-matter', 'Ctrl+Alt+Y'],
// Format menu
@ -86,7 +90,7 @@ export default new Map([
// View menu
['view.command-palette', 'Ctrl+Shift+P'],
['view.source-code-mode', 'Ctrl+E'],
['view.typewriter-mode', 'Ctrl+Alt+T'],
['view.typewriter-mode', 'Ctrl+Shift+G'],
['view.focus-mode', 'Ctrl+Shift+J'],
['view.toggle-sidebar', 'Ctrl+J'],
['view.toggle-toc', 'Ctrl+K'],

View File

@ -1,20 +1,17 @@
import { shell, Menu } from 'electron'
import fs from 'fs'
import fsPromises from 'fs/promises'
import path from 'path'
import log from 'electron-log'
import isAccelerator from 'electron-is-accelerator'
import electronLocalshortcut from '@hfelix/electron-localshortcut'
import { electronLocalshortcut, isValidElectronAccelerator } from '@hfelix/electron-localshortcut'
import { isFile2 } from 'common/filesystem'
import { isEqualAccelerator } from 'common/keybinding'
import { isLinux, isOsx } from '../config'
import { getKeyboardLanguage, getVirtualLetters } from '../keyboard'
import { getKeyboardInfo, keyboardLayoutMonitor } from '../keyboard'
import keybindingsDarwin from './keybindingsDarwin'
import keybindingsLinux from './keybindingsLinux'
import keybindingsWindows from './keybindingsWindows'
// Problematic key bindings:
// Inline Code: Ctrl+` -> dead key
// Upgrade Heading: Ctrl+= -> points to Ctrl+Plus which is ok; Ctrl+Plus is broken
class Keybindings {
/**
* @param {string} userDataPath The user data path.
@ -22,11 +19,9 @@ class Keybindings {
constructor (userDataPath) {
this.configPath = path.join(userDataPath, 'keybindings.json')
this.keys = this._getOsKeyMap()
// Fix non-US keyboards
this.mnemonics = new Map()
this._fixLayout()
this.userKeybindings = new Map()
this.keys = this.getDefaultKeybindings()
this._prepareKeyMapper()
// Load user-defined keybindings
this._loadLocalKeybindings()
@ -44,23 +39,11 @@ class Keybindings {
for (const item of acceleratorMap) {
let { accelerator } = item
// Fix broken shortcuts because of dead keys or non-US keyboard problems. We bind the
// shortcut to another accelerator because of key mapping issues. E.g: 'Alt+/' is not
// available on a German keyboard, because you have to press 'Shift+7' to produce '/'.
// In this case we can remap the accelerator to 'Alt+7' or 'Ctrl+Shift+7'.
const acceleratorFix = this.mnemonics.get(accelerator)
if (acceleratorFix) {
accelerator = acceleratorFix
}
// Regisiter shortcuts on the BrowserWindow instead of using Chromium's native menu.
// This makes it possible to receive key down events before Chromium/Electron and we
// can handle reserved Chromium shortcuts. Afterwards prevent the default action of
// the event so the native menu is not triggered.
electronLocalshortcut.register(win, accelerator, () => {
if (global.MARKTEXT_DEBUG && process.env.MARKTEXT_DEBUG_KEYBOARD) {
console.log(`You pressed ${accelerator}`)
}
callMenuCallback(item, win)
return true // prevent default action
})
@ -76,9 +59,7 @@ class Keybindings {
.catch(err => console.error(err))
}
// --- private --------------------------------
_getOsKeyMap () {
getDefaultKeybindings () {
if (isOsx) {
return keybindingsDarwin
} else if (isLinux) {
@ -87,58 +68,50 @@ class Keybindings {
return keybindingsWindows
}
_fixLayout () {
// Fix wrong virtual key mapping on non-QWERTY layouts
electronLocalshortcut.updateVirtualKeys(getVirtualLetters())
// Fix broken shortcuts and dead keys
const lang = getKeyboardLanguage()
switch (lang) {
// Fix inline code
case 'ch':
case 'de':
case 'dk':
case 'fi':
case 'no':
case 'se':
this._fixInlineCode()
if (!isOsx) {
this._fixDeadKey()
}
break
// Fix dead key only
case 'es':
case 'fr':
case 'hr':
case 'it':
case 'pl':
case 'pt':
if (!isOsx) {
this._fixDeadKey()
}
break
// Custom layouts
case 'bg':
if (!isOsx) {
this.mnemonics.set('CmdOrCtrl+/', 'CmdOrCtrl+8')
this._fixInlineCode()
}
break
}
/**
* Returns all user key bindings.
*
* @returns {Map<String, String>} User key bindings.
*/
getUserKeybindings () {
return this.userKeybindings
}
_fixDeadKey () {
this.mnemonics.set('CmdOrCtrl+/', 'CmdOrCtrl+7')
/**
* Sets and saves the given user key bindings on disk.
*
* @param {Map<String, String>} userKeybindings New user key bindings.
* @returns {Promise<Boolean>}
*/
async setUserKeybindings (userKeybindings) {
this.userKeybindings = new Map(userKeybindings)
return this._saveUserKeybindings()
}
// Fix dead backquote key on layouts like German
_fixInlineCode () {
if (isOsx) {
this.keys.set('format.inline-code', 'Cmd+Shift+B')
} else {
this.keys.set('format.inline-code', 'Ctrl+Alt+B')
// --- private --------------------------------
_prepareKeyMapper () {
// Update the key mapper to prevent problems on non-US keyboards.
const { layout, keymap } = getKeyboardInfo()
electronLocalshortcut.setKeyboardLayout(layout, keymap)
// Notify key mapper when the keyboard layout was changed.
keyboardLayoutMonitor.addListener(({ layout, keymap }) => {
if (global.MARKTEXT_DEBUG && process.env.MARKTEXT_DEBUG_KEYBOARD) {
console.log('[DEBUG] Keyboard layout changed:\n', layout)
}
electronLocalshortcut.setKeyboardLayout(layout, keymap)
})
}
async _saveUserKeybindings () {
const { configPath, userKeybindings } = this
try {
const userKeybindingJson = JSON.stringify(Object.fromEntries(userKeybindings), null, 2)
await fsPromises.writeFile(configPath, userKeybindingJson, 'utf8')
return true
} catch (_) {
return false
}
}
@ -147,14 +120,9 @@ class Keybindings {
return
}
let json
try {
json = JSON.parse(fs.readFileSync(this.configPath, 'utf8'))
} catch (_) {
json = null
}
if (!json || typeof json !== 'object') {
log.warn('Invalid keybindings.json configuration.')
const rawUserKeybindings = this._loadUserKeybindingsFromDisk()
if (!rawUserKeybindings) {
log.warn('Invalid keybinding configuration: failed to load or parse file.')
return
}
@ -165,15 +133,17 @@ class Keybindings {
// }
const userAccelerators = new Map()
for (const key in json) {
for (const key in rawUserKeybindings) {
if (this.keys.has(key)) {
const value = json[key]
const value = rawUserKeybindings[key]
if (typeof value === 'string') {
if (value.length === 0) {
// Unset key
userAccelerators.set(key, '')
} else if (isAccelerator(value)) {
} else if (isValidElectronAccelerator(value)) {
userAccelerators.set(key, value)
} else {
console.error(`[WARNING] "${value}" is not a valid accelerator.`)
}
}
}
@ -182,7 +152,7 @@ class Keybindings {
// Check for duplicate user shortcuts
for (const [keyA, valueA] of userAccelerators) {
for (const [keyB, valueB] of userAccelerators) {
if (valueA !== '' && keyA !== keyB && this._isEqualAccelerator(valueA, valueB)) {
if (valueA !== '' && keyA !== keyB && isEqualAccelerator(valueA, valueB)) {
const err = `Invalid keybindings.json configuration: Duplicate value for "${keyA}" and "${keyB}"!`
console.log(err)
log.error(err)
@ -201,10 +171,18 @@ class Keybindings {
// Check for duplicate shortcuts
for (const [userKey, userValue] of userAccelerators) {
for (const [key, value] of accelerators) {
if (this._isEqualAccelerator(value, userValue)) {
// This is a workaround to unset key bindings that the user used in `keybindings.json` before
// proper settings. Keep this for now, but add the ID to the users key binding that we show the
// right bindings in settings.
if (isEqualAccelerator(value, userValue)) {
// Unset default key
accelerators.set(key, '')
// This entry is actually unset because the user used the accelerator.
if (userAccelerators.get(key) == null) {
userAccelerators.set(key, '')
}
// A accelerator should only exist once in the default map.
break
}
@ -214,27 +192,21 @@ class Keybindings {
// Update key bindings
this.keys = accelerators
// Save user keybindings for settings
this.userKeybindings = userAccelerators
}
_isEqualAccelerator (a, b) {
a = a.toLowerCase().replace('cmdorctrl', 'ctrl').replace('command', 'ctrl')
b = b.toLowerCase().replace('cmdorctrl', 'ctrl').replace('command', 'ctrl')
const i1 = a.indexOf('+')
const i2 = b.indexOf('+')
if (i1 === -1 && i2 === -1) {
return a === b
} else if (i1 === -1 || i2 === -1) {
return false
_loadUserKeybindingsFromDisk () {
try {
const obj = JSON.parse(fs.readFileSync(this.configPath, 'utf8'))
if (typeof obj !== 'object') {
return null
}
return obj
} catch (_) {
return null
}
const keysA = a.split('+')
const keysB = b.split('+')
if (keysA.length !== keysB.length) {
return false
}
const intersection = new Set([...keysA, ...keysB])
return intersection.size === keysB.length
}
}

View File

@ -32,6 +32,24 @@ export const edit = (win, type) => {
}
}
export const nativeCut = win => {
if (win) {
win.webContents.cut()
}
}
export const nativeCopy = win => {
if (win) {
win.webContents.copy()
}
}
export const nativePaste = win => {
if (win) {
win.webContents.paste()
}
}
export const screenshot = win => {
ipcMain.emit('screen-capture', win)
}

View File

@ -550,6 +550,12 @@ export const closeTab = win => {
}
}
export const closeWindow = win => {
if (win) {
win.close()
}
}
export const save = win => {
if (win && win.webContents) {
win.webContents.send('mt::editor-ask-file-save')

View File

@ -1,4 +1,15 @@
import { ipcMain } from 'electron'
import { ipcMain, Menu } from 'electron'
import { isOsx } from '../../config'
export const minimizeWindow = win => {
if (win) {
if (isOsx) {
Menu.sendActionToFirstResponder('performMiniaturize:')
} else {
win.minimize()
}
}
}
export const toggleAlwaysOnTop = win => {
if (win) {

View File

@ -21,15 +21,21 @@ export default function (keybindings) {
}, {
label: 'Cut',
accelerator: keybindings.getAccelerator('edit.cut'),
role: 'cut'
click (menuItem, browserWindow) {
actions.nativeCut(browserWindow)
}
}, {
label: 'Copy',
accelerator: keybindings.getAccelerator('edit.copy'),
role: 'copy'
click (menuItem, browserWindow) {
actions.nativeCopy(browserWindow)
}
}, {
label: 'Paste',
accelerator: keybindings.getAccelerator('edit.paste'),
role: 'paste'
click (menuItem, browserWindow) {
actions.nativePaste(browserWindow)
}
}, {
type: 'separator'
}, {

View File

@ -162,7 +162,9 @@ export default function (keybindings, userPreference, recentlyUsedFiles) {
}, {
label: 'Close Window',
accelerator: keybindings.getAccelerator('file.close-window'),
role: 'close'
click (menuItem, browserWindow) {
actions.closeWindow(browserWindow)
}
}, {
type: 'separator',
visible: !isOsx

View File

@ -1,7 +1,9 @@
import { app } from 'electron'
import { app, Menu } from 'electron'
import { showAboutDialog } from '../actions/help'
import * as actions from '../actions/marktext'
// macOS only menu.
export default function (keybindings) {
return {
label: 'MarkText',
@ -32,14 +34,20 @@ export default function (keybindings) {
}, {
label: 'Hide MarkText',
accelerator: keybindings.getAccelerator('mt.hide'),
role: 'hide'
click () {
Menu.sendActionToFirstResponder('hide:')
}
}, {
label: 'Hide Others',
accelerator: keybindings.getAccelerator('mt.hide-others'),
role: 'hideothers'
click () {
Menu.sendActionToFirstResponder('hideOtherApplications:')
}
}, {
label: 'Show All',
role: 'unhide'
click () {
Menu.sendActionToFirstResponder('unhideAllApplications:')
}
}, {
type: 'separator'
}, {

View File

@ -1,4 +1,5 @@
import { toggleAlwaysOnTop } from '../actions/window'
import { Menu } from 'electron'
import { minimizeWindow, toggleAlwaysOnTop } from '../actions/window'
import { zoomIn, zoomOut } from '../../windows/utils'
import { isOsx } from '../../config'
@ -9,7 +10,9 @@ export default function (keybindings) {
submenu: [{
label: 'Minimize',
accelerator: keybindings.getAccelerator('window.minimize'),
role: 'minimize'
click (menuItem, browserWindow) {
minimizeWindow(browserWindow)
}
}, {
id: 'alwaysOnTopMenuItem',
label: 'Always on Top',
@ -48,7 +51,9 @@ export default function (keybindings) {
if (isOsx) {
menu.submenu.push({
label: 'Bring All to Front',
role: 'front'
click () {
Menu.sendActionToFirstResponder('arrangeInFront:')
}
})
}
return menu

View File

@ -182,6 +182,9 @@ class EditorWindow extends BaseWindow {
mainWindowState.manage(win)
// Disable application menu shortcuts because we want to handle key bindings yourself.
win.webContents.setIgnoreMenuShortcuts(true)
// Delay load files and directories after the current control flow.
setTimeout(() => {
if (rootDirectory) {

View File

@ -1,7 +1,7 @@
import path from 'path'
import { BrowserWindow, ipcMain } from 'electron'
import { enable as remoteEnable } from '@electron/remote/main'
import electronLocalshortcut from '@hfelix/electron-localshortcut'
import { electronLocalshortcut } from '@hfelix/electron-localshortcut'
import BaseWindow, { WindowLifecycle, WindowType } from './base'
import { centerWindowOptions } from './utils'
import { TITLE_BAR_HEIGHT, preferencesWinOptions, isLinux, isOsx } from '../config'

View File

@ -43,6 +43,8 @@ class Clipboard {
eventCenter.attachDOMEvent(document.body, 'copy', docCopyCutHandler)
}
// TODO: `document.execCommand` is deprecated!
copyAsMarkdown () {
this._copyType = 'copyAsMarkdown'
document.execCommand('copy')

View File

@ -1,7 +1,7 @@
import loadRenderer from '../../renderers'
import { CLASS_OR_ID, PREVIEW_DOMPURIFY_CONFIG } from '../../config'
import { conflict, mixins, camelToSnake, sanitize } from '../../utils'
import { patch, toVNode, toHTML, h, addNStoVNodeSvgChildren } from './snabbdom'
import { patch, toVNode, toHTML, h } from './snabbdom'
import { beginRules } from '../rules'
import renderInlines from './renderInlines'
import renderBlock from './renderBlock'
@ -176,7 +176,6 @@ class StateRender {
const children = blocks.map(block => {
return this.renderBlock(null, block, activeBlocks, matches, true)
})
addNStoVNodeSvgChildren(children)
const newVdom = h(selector, children)
const rootDom = document.querySelector(selector) || this.container
const oldVdom = toVNode(rootDom)

View File

@ -29,21 +29,3 @@ export const htmlToVNode = html => { // helper function for convert html to vnod
return toVNode(wrapper).children
}
const addNS = ({ data, children, sel }) => {
data.ns = 'http://www.w3.org/2000/svg'
if (sel !== 'foreignObject' && children !== undefined) {
for (const vNode of children) {
if (vNode.data === undefined) continue
addNS(vNode)
}
}
}
export const addNStoVNodeSvgChildren = (children = []) => {
for (const vNode of children) {
if (vNode.data === undefined) continue
if (vNode.sel.startsWith('svg')) addNS(vNode)
addNStoVNodeSvgChildren(vNode.children)
}
}

View File

@ -0,0 +1,119 @@
const commandDescriptions = Object.freeze({
// ============================================
// # Key binding descriptions
// #
'mt.hide': 'MarkText: Hide MarkText',
'mt.hide-others': 'MarkText: Hide Others',
'file.new-file': 'File: New Window',
'file.new-tab': 'File: New Tab',
'file.open-file': 'File: Open file',
'file.open-folder': 'File: Open Folder',
'file.save': 'File: Save',
'file.save-as': 'File: Save As...',
'file.move-file': 'File: Move...',
'file.rename-file': 'File: Rename...',
'file.quick-open': 'File: Show quick open dialog',
'file.print': 'File: Print current Tab',
'file.preferences': 'MarkText: Preferences',
'file.close-tab': 'File: Close current Tab',
'file.close-window': 'File: Close Window',
'file.quit': 'MarkText: Quit',
'edit.undo': 'Edit: Undo',
'edit.redo': 'Edit: Redo',
'edit.cut': 'Edit: Cut',
'edit.copy': 'Edit: Copy',
'edit.paste': 'Edit: Paste',
'edit.copy-as-markdown': 'Edit: Copy as Markdown',
'edit.copy-as-html': 'Edit: Copy as HTML',
'edit.paste-as-plaintext': 'Edit: Paste as Plain Text',
'edit.select-all': 'Edit: Select All',
'edit.duplicate': 'Edit: Duplicate',
'edit.create-paragraph': 'Edit: Create Paragraph',
'edit.delete-paragraph': 'Edit: Delete Paragraph',
'edit.find': 'Edit: Find',
'edit.find-next': 'Edit: Find Next',
'edit.find-previous': 'Edit: Find Previous',
'edit.replace': 'Edit: Replace',
'edit.find-in-folder': 'Edit: Find in Folder',
'edit.screenshot': 'Edit: Make Screenshot',
'paragraph.heading-1': 'Paragraph: Transform into Heading 1',
'paragraph.heading-2': 'Paragraph: Transform into Heading 2',
'paragraph.heading-3': 'Paragraph: Transform into Heading 3',
'paragraph.heading-4': 'Paragraph: Transform into Heading 4',
'paragraph.heading-5': 'Paragraph: Transform into Heading 5',
'paragraph.heading-6': 'Paragraph: Transform into Heading 6',
'paragraph.upgrade-heading': 'Paragraph: Upgrade Heading',
'paragraph.degrade-heading': 'Paragraph: Degrade Heading',
'paragraph.table': 'Paragraph: Create Table',
'paragraph.code-fence': 'Paragraph: Transform into Code Fence',
'paragraph.quote-block': 'Paragraph: Transform into Quote Block',
'paragraph.math-formula': 'Paragraph: Transform into Math Formula',
'paragraph.html-block': 'Paragraph: Transform into HTML Block',
'paragraph.order-list': 'Paragraph: Transform into Order List',
'paragraph.bullet-list': 'Paragraph: Transform into Bullet List',
'paragraph.task-list': 'Paragraph: Transform into Task List',
'paragraph.loose-list-item': 'Paragraph: Convert to Loose List Item',
'paragraph.paragraph': 'Paragraph: Create new Paragraph',
'paragraph.horizontal-line': 'Paragraph: Insert Horizontal Line',
'paragraph.front-matter': 'Paragraph: Insert Front Matter',
'format.strong': 'Format: Strong',
'format.emphasis': 'Format: Emphasis',
'format.underline': 'Format: Underline',
'format.superscript': 'Format: Superscript',
'format.subscript': 'Format: Subscript',
'format.highlight': 'Format: Highlight',
'format.inline-code': 'Format: Inline Code',
'format.inline-math': 'Format: Inline Math',
'format.strike': 'Format: Strike',
'format.hyperlink': 'Format: Hyperlink',
'format.image': 'Format: Insert Image',
'format.clear-format': 'Format: Clear Format',
'window.minimize': 'Window: Minimize',
'window.toggle-always-on-top': 'Window: Always on Top',
'window.zoom-in': 'Window: Zoom In',
'window.zoom-out': 'Window: Zoom Out',
'window.toggle-full-screen': 'Window: Toggle Full Screen',
'view.command-palette': 'View: Show Command Palette',
'view.source-code-mode': 'View: Toggle Source Code Mode',
'view.typewriter-mode': 'View: Toggle Typewriter Mode',
'view.focus-mode': 'View: Focus Mode',
'view.toggle-sidebar': 'View: Toggle Sidebar',
'view.toggle-toc': 'View: Toggle Table of Content',
'view.toggle-tabbar': 'View: Toggle Tabs',
'view.toggle-dev-tools': 'View: Show Developer Tools (Debug)',
'view.dev-reload': 'View: Reload Window (Debug)',
'tabs.cycle-forward': 'Misc: Cycle Tabs Forward',
'tabs.cycle-backward': 'Misc: Cycle Tabs Backward',
'tabs.switch-to-left': 'Misc: Switch tab to the left',
'tabs.switch-to-right': 'Misc: Switch tab to the right',
'tabs.switch-to-first': 'Misc: Switch tab to the 1st',
'tabs.switch-to-second': 'Misc: Switch tab to the 2st',
'tabs.switch-to-third': 'Misc: Switch tab to the 3st',
'tabs.switch-to-fourth': 'Misc: Switch tab to the 4st',
'tabs.switch-to-fifth': 'Misc: Switch tab to the 5st',
'tabs.switch-to-sixth': 'Misc: Switch tab to the 6st',
'tabs.switch-to-seventh': 'Misc: Switch tab to the 7st',
'tabs.switch-to-eighth': 'Misc: Switch tab to the 8st',
'tabs.switch-to-ninth': 'Misc: Switch tab to the 9st',
'tabs.switch-to-tenth': 'Misc: Switch tab to the 10st',
// ============================================
// # Additional command descriptions
// #
'file.toggle-auto-save': 'File: Toggle Auto Save',
'file.import-file': 'File: Import...',
'file.export-file': 'File: Export...',
'file.zoom': 'Window: Zoom...',
'file.check-update': 'MarkText: Check for Updates...',
'paragraph.reset-paragraph': 'Paragraph: Transform into Paragraph',
'window.change-theme': 'Theme: Change Theme...',
'view.text-direction': 'View: Set Text Direction',
'docs.user-guide': 'MarkText: End User Guide',
'docs.markdown-syntax': 'MarkText: Markdown Syntax Guide'
})
export default id => {
return commandDescriptions[id]
}

View File

@ -4,6 +4,7 @@ import { getCurrentWindow } from '@electron/remote'
import bus from '../bus'
import { delay, isOsx } from '@/util'
import { isUpdatable } from './utils'
import getCommandDescriptionById from './descriptions'
export { default as FileEncodingCommand } from './fileEncoding'
export { default as LineEndingCommand } from './lineEnding'
@ -38,56 +39,47 @@ const commands = [
{
id: 'file.new-tab',
description: 'File: New Tab',
execute: async () => {
ipcRenderer.emit('mt::new-untitled-tab', null)
}
}, {
id: 'file.new-file',
description: 'File: New Window',
execute: async () => {
ipcRenderer.send('mt::cmd-new-editor-window')
}
}, {
id: 'file.open-file',
description: 'File: Open file',
execute: async () => {
ipcRenderer.send('mt::cmd-open-file')
}
}, {
id: 'file.open-folder',
description: 'File: Open Folder',
execute: async () => {
ipcRenderer.send('mt::cmd-open-folder')
}
}, {
id: 'file.save',
description: 'File: Save',
execute: async () => {
ipcRenderer.emit('mt::editor-ask-file-save', null)
}
}, {
id: 'file.save-as',
description: 'File: Save As...',
execute: async () => {
ipcRenderer.emit('mt::editor-ask-file-save-as', null)
}
}, {
id: 'file.print',
description: 'File: Print current Tab',
execute: async () => {
await delay(50)
bus.$emit('showExportDialog', 'print')
}
}, {
id: 'file.close-tab',
description: 'File: Close current Tab',
execute: async () => {
ipcRenderer.emit('mt::editor-close-tab', null)
}
}, {
id: 'file.close-window',
description: 'File: Close Window',
execute: async () => {
ipcRenderer.send('mt::cmd-close-window')
}
@ -95,32 +87,27 @@ const commands = [
{
id: 'file.toggle-auto-save',
description: 'File: Toggle Auto Save',
execute: async () => {
ipcRenderer.send('mt::cmd-toggle-autosave')
}
}, {
id: 'file.move-file',
description: 'File: Move...',
execute: async () => {
ipcRenderer.emit('mt::editor-move-file', null)
}
}, {
id: 'file.rename-file',
description: 'File: Rename...',
execute: async () => {
await delay(50)
ipcRenderer.emit('mt::editor-rename-file', null)
}
}, {
id: 'file.import-file',
description: 'File: Import...',
execute: async () => {
ipcRenderer.send('mt::cmd-import-file')
}
}, {
id: 'file.export-file',
description: 'File: Export...',
subcommands: [{
id: 'file.export-file-html',
description: 'HTML',
@ -143,7 +130,6 @@ const commands = [
{
id: 'edit.undo',
description: 'Edit: Undo',
execute: async () => {
focusEditorAndExecute(
() => bus.$emit('undo', 'undo')
@ -151,7 +137,6 @@ const commands = [
}
}, {
id: 'edit.redo',
description: 'Edit: Redo',
execute: async () => {
focusEditorAndExecute(
() => bus.$emit('redo', 'redo')
@ -159,7 +144,6 @@ const commands = [
}
}, {
id: 'edit.duplicate',
description: 'Edit: Duplicate',
execute: async () => {
focusEditorAndExecute(
() => bus.$emit('duplicate', 'duplicate')
@ -167,7 +151,6 @@ const commands = [
}
}, {
id: 'edit.create-paragraph',
description: 'Edit: Create Paragraph',
execute: async () => {
focusEditorAndExecute(
() => bus.$emit('createParagraph', 'createParagraph')
@ -175,7 +158,6 @@ const commands = [
}
}, {
id: 'edit.delete-paragraph',
description: 'Edit: Delete Paragraph',
execute: async () => {
focusEditorAndExecute(
() => bus.$emit('deleteParagraph', 'deleteParagraph')
@ -183,7 +165,6 @@ const commands = [
}
}, {
id: 'edit.find',
description: 'Edit: Find',
execute: async () => {
await delay(150)
bus.$emit('find', 'find')
@ -207,14 +188,12 @@ const commands = [
// },
{
id: 'edit.replace',
description: 'Edit: Replace',
execute: async () => {
await delay(150)
bus.$emit('replace', 'replace')
}
}, {
id: 'edit.find-in-folder',
description: 'Edit: Find in Folder',
execute: async () => {
await delay(150)
ipcRenderer.emit('mt::editor-edit-action', null, 'findInFolder')
@ -226,7 +205,6 @@ const commands = [
{
id: 'paragraph.heading-1',
description: 'Paragraph: Transform into Heading 1',
execute: async () => {
focusEditorAndExecute(
() => bus.$emit('paragraph', 'heading 1')
@ -234,7 +212,6 @@ const commands = [
}
}, {
id: 'paragraph.heading-2',
description: 'Paragraph: Transform into Heading 2',
execute: async () => {
focusEditorAndExecute(
() => bus.$emit('paragraph', 'heading 2')
@ -242,7 +219,6 @@ const commands = [
}
}, {
id: 'paragraph.heading-3',
description: 'Paragraph: Transform into Heading 3',
execute: async () => {
focusEditorAndExecute(
() => bus.$emit('paragraph', 'heading 3')
@ -250,7 +226,6 @@ const commands = [
}
}, {
id: 'paragraph.heading-4',
description: 'Paragraph: Transform into Heading 4',
execute: async () => {
focusEditorAndExecute(
() => bus.$emit('paragraph', 'heading 4')
@ -258,7 +233,6 @@ const commands = [
}
}, {
id: 'paragraph.heading-5',
description: 'Paragraph: Transform into Heading 5',
execute: async () => {
focusEditorAndExecute(
() => bus.$emit('paragraph', 'heading 5')
@ -266,7 +240,6 @@ const commands = [
}
}, {
id: 'paragraph.heading-6',
description: 'Paragraph: Transform into Heading 6',
execute: async () => {
focusEditorAndExecute(
() => bus.$emit('paragraph', 'heading 6')
@ -274,7 +247,6 @@ const commands = [
}
}, {
id: 'paragraph.upgrade-heading',
description: 'Paragraph: Upgrade Heading',
execute: async () => {
focusEditorAndExecute(
() => bus.$emit('paragraph', 'upgrade heading')
@ -282,7 +254,6 @@ const commands = [
}
}, {
id: 'paragraph.degrade-heading',
description: 'Paragraph: Degrade Heading',
execute: async () => {
focusEditorAndExecute(
() => bus.$emit('paragraph', 'degrade heading')
@ -290,7 +261,6 @@ const commands = [
}
}, {
id: 'paragraph.table',
description: 'Paragraph: Create Table',
execute: async () => {
focusEditorAndExecute(
() => bus.$emit('paragraph', 'table')
@ -298,7 +268,6 @@ const commands = [
}
}, {
id: 'paragraph.code-fence',
description: 'Paragraph: Transform into Code Fence',
execute: async () => {
focusEditorAndExecute(
() => bus.$emit('paragraph', 'pre')
@ -306,7 +275,6 @@ const commands = [
}
}, {
id: 'paragraph.quote-block',
description: 'Paragraph: Transform into Quote Block',
execute: async () => {
focusEditorAndExecute(
() => bus.$emit('paragraph', 'blockquote')
@ -314,7 +282,6 @@ const commands = [
}
}, {
id: 'paragraph.math-formula',
description: 'Paragraph: Transform into Math Formula',
execute: async () => {
focusEditorAndExecute(
() => bus.$emit('paragraph', 'mathblock')
@ -322,7 +289,6 @@ const commands = [
}
}, {
id: 'paragraph.html-block',
description: 'Paragraph: Transform into HTML Block',
execute: async () => {
focusEditorAndExecute(
() => bus.$emit('paragraph', 'html')
@ -330,7 +296,6 @@ const commands = [
}
}, {
id: 'paragraph.order-list',
description: 'Paragraph: Transform into Order List',
execute: async () => {
focusEditorAndExecute(
() => bus.$emit('paragraph', 'ol-bullet')
@ -338,7 +303,6 @@ const commands = [
}
}, {
id: 'paragraph.bullet-list',
description: 'Paragraph: Transform into Bullet List',
execute: async () => {
focusEditorAndExecute(
() => bus.$emit('paragraph', 'ul-bullet')
@ -346,7 +310,6 @@ const commands = [
}
}, {
id: 'paragraph.task-list',
description: 'Paragraph: Transform into Task List',
execute: async () => {
focusEditorAndExecute(
() => bus.$emit('paragraph', 'ul-task')
@ -354,7 +317,6 @@ const commands = [
}
}, {
id: 'paragraph.loose-list-item',
description: 'Paragraph: Convert to Loose List Item',
execute: async () => {
focusEditorAndExecute(
() => bus.$emit('paragraph', 'loose-list-item')
@ -362,7 +324,6 @@ const commands = [
}
}, {
id: 'paragraph.paragraph',
description: 'Paragraph: Create new Paragraph',
execute: async () => {
focusEditorAndExecute(
() => bus.$emit('paragraph', 'paragraph')
@ -370,7 +331,6 @@ const commands = [
}
}, {
id: 'paragraph.reset-paragraph',
description: 'Paragraph: Transform into Paragraph',
execute: async () => {
focusEditorAndExecute(
() => bus.$emit('paragraph', 'reset-to-paragraph')
@ -378,7 +338,6 @@ const commands = [
}
}, {
id: 'paragraph.horizontal-line',
description: 'Paragraph: Insert Horizontal Line',
execute: async () => {
focusEditorAndExecute(
() => bus.$emit('paragraph', 'hr')
@ -386,7 +345,6 @@ const commands = [
}
}, {
id: 'paragraph.front-matter',
description: 'Paragraph: Insert Front Matter',
execute: async () => {
focusEditorAndExecute(
() => bus.$emit('paragraph', 'front-matter')
@ -401,7 +359,6 @@ const commands = [
{
id: 'format.strong',
description: 'Format: Strong',
execute: async () => {
focusEditorAndExecute(
() => bus.$emit('format', 'strong')
@ -409,7 +366,6 @@ const commands = [
}
}, {
id: 'format.emphasis',
description: 'Format: Emphasis',
execute: async () => {
focusEditorAndExecute(
() => bus.$emit('format', 'em')
@ -417,7 +373,6 @@ const commands = [
}
}, {
id: 'format.underline',
description: 'Format: Underline',
execute: async () => {
focusEditorAndExecute(
() => bus.$emit('format', 'u')
@ -425,7 +380,6 @@ const commands = [
}
}, {
id: 'format.highlight',
description: 'Format: Highlight',
execute: async () => {
focusEditorAndExecute(
() => bus.$emit('format', 'mark')
@ -433,7 +387,6 @@ const commands = [
}
}, {
id: 'format.superscript',
description: 'Format: Superscript',
execute: async () => {
focusEditorAndExecute(
() => bus.$emit('format', 'sup')
@ -441,7 +394,6 @@ const commands = [
}
}, {
id: 'format.subscript',
description: 'Format: Subscript',
execute: async () => {
focusEditorAndExecute(
() => bus.$emit('format', 'sub')
@ -449,7 +401,6 @@ const commands = [
}
}, {
id: 'format.inline-code',
description: 'Format: Inline Code',
execute: async () => {
focusEditorAndExecute(
() => bus.$emit('format', 'inline_code')
@ -457,7 +408,6 @@ const commands = [
}
}, {
id: 'format.inline-math',
description: 'Format: Inline Math',
execute: async () => {
focusEditorAndExecute(
() => bus.$emit('format', 'inline_math')
@ -465,7 +415,6 @@ const commands = [
}
}, {
id: 'format.strike',
description: 'Format: Strike',
execute: async () => {
focusEditorAndExecute(
() => bus.$emit('format', 'del')
@ -473,7 +422,6 @@ const commands = [
}
}, {
id: 'format.hyperlink',
description: 'Format: Hyperlink',
execute: async () => {
focusEditorAndExecute(
() => bus.$emit('format', 'link')
@ -481,7 +429,6 @@ const commands = [
}
}, {
id: 'format.image',
description: 'Format: Insert Image',
execute: async () => {
focusEditorAndExecute(
() => bus.$emit('format', 'image')
@ -489,7 +436,6 @@ const commands = [
}
}, {
id: 'format.clear-format',
description: 'Format: Clear Format',
execute: async () => {
focusEditorAndExecute(
() => bus.$emit('format', 'clear')
@ -502,19 +448,16 @@ const commands = [
{
id: 'window.minimize',
description: 'Window: Minimize',
execute: async () => {
getCurrentWindow().minimize()
}
}, {
id: 'window.toggle-always-on-top',
description: 'Window: Always on Top',
execute: async () => {
ipcRenderer.send('mt::window-toggle-always-on-top')
}
}, {
id: 'window.toggle-full-screen',
description: 'Window: Toggle Full Screen',
execute: async () => {
const win = getCurrentWindow()
win.setFullScreen(!win.isFullScreen())
@ -523,7 +466,6 @@ const commands = [
{
id: 'file.zoom',
description: 'Window: Zoom...',
shortcut: [(isOsx ? 'Cmd' : 'Ctrl'), 'Scroll'],
subcommands: [{
id: 'file.zoom-0',
@ -584,7 +526,6 @@ const commands = [
{
id: 'window.change-theme',
description: 'Theme: Change Theme',
subcommands: [{
id: 'window.change-theme-light',
description: 'Cadmium Light',
@ -620,13 +561,11 @@ const commands = [
{
id: 'view.source-code-mode',
description: 'View: Toggle Source Code Mode',
execute: async () => {
bus.$emit('view:toggle-view-entry', 'sourceCode')
}
}, {
id: 'view.typewriter-mode',
description: 'View: Toggle Typewriter Mode',
execute: async () => {
focusEditorAndExecute(
() => bus.$emit('view:toggle-view-entry', 'typewriter')
@ -634,7 +573,6 @@ const commands = [
}
}, {
id: 'view.focus-mode',
description: 'View: Focus Mode',
execute: async () => {
focusEditorAndExecute(
() => bus.$emit('view:toggle-view-entry', 'focus')
@ -642,13 +580,11 @@ const commands = [
}
}, {
id: 'view.toggle-sidebar',
description: 'View: Toggle Sidebar',
execute: async () => {
bus.$emit('view:toggle-view-layout-entry', 'showSideBar')
}
}, {
id: 'view.toggle-tabbar',
description: 'View: Toggle Tabs',
execute: async () => {
bus.$emit('view:toggle-view-layout-entry', 'showTabBar')
}
@ -656,7 +592,6 @@ const commands = [
{
id: 'view.text-direction',
description: 'View: Set Text Direction',
subcommands: [{
id: 'view.text-direction-ltr',
description: 'Left to Right',
@ -676,25 +611,21 @@ const commands = [
{
id: 'file.preferences',
description: 'MarkText: Preferences',
execute: async () => {
ipcRenderer.send('mt::open-setting-window')
}
}, {
id: 'file.quit',
description: 'MarkText: Quit',
execute: async () => {
ipcRenderer.send('mt::app-try-quit')
}
}, {
id: 'docs.user-guide',
description: 'MarkText: End User Guide',
execute: async () => {
shell.openExternal('https://github.com/marktext/marktext/blob/master/docs/README.md')
}
}, {
id: 'docs.markdown-syntax',
description: 'MarkText: Markdown Syntax Guide',
execute: async () => {
shell.openExternal('https://github.com/marktext/marktext/blob/master/docs/MARKDOWN_SYNTAX.md')
}
@ -705,13 +636,11 @@ const commands = [
{
id: 'tabs.cycle-forward',
description: 'Misc: Cycle Tabs Forward',
execute: async () => {
ipcRenderer.emit('mt::tabs-cycle-right', null)
}
}, {
id: 'tabs.cycle-backward',
description: 'Misc: Cycle Tabs Backward',
execute: async () => {
ipcRenderer.emit('mt::tabs-cycle-left', null)
}
@ -721,7 +650,6 @@ const commands = [
if (isUpdatable()) {
commands.push({
id: 'file.check-update',
description: 'MarkText: Check for Updates',
execute: async () => {
ipcRenderer.send('mt::check-for-update')
}
@ -731,11 +659,18 @@ if (isUpdatable()) {
if (isOsx) {
commands.push({
id: 'edit.screenshot',
description: 'Edit: Make Screenshot',
execute: async () => {
ipcRenderer.send('mt::make-screenshot')
}
})
}
// Complete all command descriptions.
for (const item of commands) {
const { id, description } = item
if (id && !description) {
item.description = getCommandDescriptionById(id)
}
}
export default commands

View File

@ -1005,7 +1005,11 @@ export default {
},
handleSelectAll () {
if (this.editor && !this.sourceCode && (this.editor.hasFocus() || this.editor.contentState.selectedTableCells)) {
if (this.sourceCode) {
return
}
if (this.editor && (this.editor.hasFocus() || this.editor.contentState.selectedTableCells)) {
this.editor.selectAll()
} else {
const activeElement = document.activeElement

View File

@ -247,8 +247,19 @@ export default {
},
handleSelectAll () {
if (this.sourceCode && this.editor) {
if (!this.sourceCode) {
return
}
const { editor } = this
if (editor && editor.hasFocus()) {
this.editor.execCommand('selectAll')
} else {
const activeElement = document.activeElement
const nodeName = activeElement.nodeName
if (nodeName === 'INPUT' || nodeName === 'TEXTAREA') {
activeElement.select()
}
}
},

View File

@ -61,7 +61,7 @@ export default {
<style>
.pref-container {
--prefSideBarWidth: 320px;
--prefSideBarWidth: 280px;
width: 100vw;
height: 100vh;

View File

@ -22,9 +22,8 @@
<script>
import { shell } from 'electron'
import fontManager from 'fontmanager-redux'
// Example font objects:
// Example of fontmanager-redux objects:
// {
// path: '/Library/Fonts/Arial.ttf',
// postscriptName: 'ArialMT',
@ -101,6 +100,8 @@ export default {
}
},
mounted () {
// Delay load native library because it's not needed for the editor and causes a delay.
const fontManager = require('fontmanager-redux')
const { onlyMonospace } = this
const buf = fontManager.getAvailableFontsSync()
.filter(f => f.family && (!onlyMonospace || (onlyMonospace && f.monospace)))

View File

@ -0,0 +1,144 @@
import { ipcRenderer } from 'electron'
import { isEqualAccelerator } from 'common/keybinding'
import getCommandDescriptionById from '@/commands/descriptions'
import { isOsx } from '@/util'
const SHORTCUT_TYPE_DEFAULT = 0
const SHORTCUT_TYPE_USER = 1
const getShortcutDescriptionById = id => {
const description = getCommandDescriptionById(id)
if (!description) {
return id
}
return description
}
export default class KeybindingConfigurator {
/**
* ctor
*
* @param {Map<String, String>} defaultKeybindings
* @param {Map<String, String>} userKeybindings
*/
constructor (defaultKeybindings, userKeybindings) {
this.defaultKeybindings = defaultKeybindings
this.keybindingList = this._buildUiKeybindingList(defaultKeybindings, userKeybindings)
this.isDirty = false
}
_buildUiKeybindingList (defaultKeybindings, userKeybindings) {
const uiKeybindings = []
for (const [id] of defaultKeybindings) {
if (!isOsx && id.startsWith('mt.')) {
// Skip MarkText menu that is only available on macOS.
continue
}
uiKeybindings.push(this._toUiKeybinding(id, defaultKeybindings, userKeybindings))
}
uiKeybindings.sort((a, b) => a.description.localeCompare(b.description))
return uiKeybindings
}
_toUiKeybinding (id, defaultKeybindings, userKeybindings) {
const description = getShortcutDescriptionById(id)
const userAccelerator = userKeybindings.get(id)
let type = SHORTCUT_TYPE_DEFAULT
// Overwrite accelerator if key is present (empty string unset old binding).
let accelerator
if (userAccelerator != null) {
type = SHORTCUT_TYPE_USER
accelerator = userAccelerator
} else {
accelerator = defaultKeybindings.get(id)
}
return { id, description, accelerator, type }
}
getKeybindings () {
return this.keybindingList
}
async save () {
if (!this.isDirty) {
return true
}
const userKeybindings = this._getUserKeybindingMap()
const result = await ipcRenderer.invoke('mt::keybinding-save-user-keybindings', userKeybindings)
if (result) {
this.isDirty = false
return true
}
return false
}
_getUserKeybindingMap () {
const userKeybindings = new Map()
for (const entry of this.keybindingList) {
const { id, accelerator, type } = entry
if (type !== SHORTCUT_TYPE_DEFAULT) {
userKeybindings.set(id, accelerator)
}
}
return userKeybindings
}
change (id, accelerator) {
const entry = this.keybindingList.find(entry => entry.id === id)
if (!entry) {
return false
}
if (accelerator && this._isDuplicate(accelerator)) {
return false
}
entry.accelerator = accelerator
entry.type = this._isDefaultBinding(id, accelerator)
? SHORTCUT_TYPE_DEFAULT
: SHORTCUT_TYPE_USER
this.isDirty = true
return true
}
unbind (id) {
return this.change(id, '')
}
resetToDefault (id) {
const accelerator = this.defaultKeybindings.get(id)
if (accelerator == null) { // allow empty string
return false
}
return this.change(id, accelerator)
}
async resetAll () {
const { defaultKeybindings, keybindingList } = this
for (const entry of keybindingList) {
const defaultAccelerator = defaultKeybindings.get(entry.id)
if (defaultAccelerator) {
entry.accelerator = defaultAccelerator
} else {
entry.accelerator = ''
}
entry.type = SHORTCUT_TYPE_DEFAULT
}
this.isDirty = true
return this.save()
}
getDefaultAccelerator (id) {
return this.defaultKeybindings.get(id)
}
_isDuplicate (accelerator) {
return accelerator !== '' && this.keybindingList.findIndex(entry => isEqualAccelerator(entry.accelerator, accelerator)) !== -1
}
_isDefaultBinding (id, accelerator) {
return this.defaultKeybindings.get(id) === accelerator
}
}

View File

@ -1,38 +1,168 @@
<template>
<div class="pref-keybindings">
<h4>Key Bindings</h4>
<div class="keybinding-info">
<span>
MarkText shortcuts can be customized by editing a configuration file named <code>keybindings.json</code>.
More information how to use custom key bindings can be found <span class="link" @click="openKeybindingsDocumentation">online</span>.
All changes require a restart.
</span>
<section class="keybindings">
<div class="text">
Customize MarkText shortcuts and click on the save button below to apply all changes (requires a restart).
All available and default key binding can be found <a class="link" @click="openKeybindingWiki">online</a>.
</div>
<el-table
:data="keybindingList"
style="width: 100%"
>
<el-table-column prop="description" label="Description">
</el-table-column>
<el-table-column prop="accelerator" label="Key Combination" width="220">
</el-table-column>
<el-table-column fixed="right" label="Options" width="90">
<template slot-scope="scope">
<el-button @click="handleEditClick(scope.$index, scope.row)" type="text" size="small" title="Edit">
<i class="el-icon-edit"></i>
</el-button>
<el-button @click="handleResetClick(scope.$index, scope.row)" type="text" size="small" title="Reset">
<i class="el-icon-refresh-right"></i>
</el-button>
<el-button @click="handleUnbindClick(scope.$index, scope.row)" type="text" size="small" title="Unbind">
<i class="el-icon-delete"></i>
</el-button>
</template>
</el-table-column>
</el-table>
</section>
<section class="footer">
<separator></separator>
<el-button size="medium" @click="openKeybindingsFile">Open keybindings.json</el-button>
</div>
<el-button size="medium" @click="saveKeybindings">Save</el-button>
<el-button size="medium" @click="restoreDefaults">Restore default key bindings</el-button>
</section>
<section v-if="showDebugTools" class="keyboard-debug">
<separator></separator>
<div><strong>Debug options:</strong></div>
<el-button size="medium" @click="dumpKeyboardInformation">Dump keyboard information</el-button>
</section>
<key-input-dialog
:showWithId="selectedShortcutId"
:onCommit="onKeybinding"
></key-input-dialog>
</div>
</template>
<script>
import { ipcRenderer, shell } from 'electron'
import log from 'electron-log'
import { setKeyboardLayout } from '@hfelix/electron-localshortcut'
import Compound from '../common/compound'
import Separator from '../common/separator'
import KeyInputDialog from './key-input-dialog.vue'
import KeybindingConfigurator from './KeybindingConfigurator'
import notice from '@/services/notification'
export default {
components: {
Compound,
Separator
Separator,
KeyInputDialog
},
data () {
return {}
return {
showDebugTools: false,
keybindingConfigurator: null,
selectedShortcutId: null,
keybindingList: []
}
},
mounted () {
ipcRenderer.invoke('mt::keybinding-get-keyboard-info')
.then(({ layout, keymap }) => {
// Update the key mapper to prevent problems on non-US keyboards.
setKeyboardLayout(layout, keymap)
})
.catch(error => log.error('Error while loading keyboard information for settings:', error))
ipcRenderer.invoke('mt::keybinding-get-pref-keybindings')
.then(({ defaultKeybindings, userKeybindings }) => {
this.keybindingConfigurator = new KeybindingConfigurator(defaultKeybindings, userKeybindings)
this.keybindingList = this.keybindingConfigurator.getKeybindings()
})
.catch(error => log.error('Error while loading keyboard information for settings:', error))
// Show keyboard debugging tools which has been moved from CLI because we
// need an active window on Windows.
this.showDebugTools = global.marktext.env.debug
},
unmounted () {
this.keybindingList = []
this.keybindingConfigurator = null
},
methods: {
openKeybindingsDocumentation () {
openKeybindingWiki () {
shell.openExternal('https://github.com/marktext/marktext/blob/master/docs/KEYBINDINGS.md')
},
openKeybindingsFile () {
ipcRenderer.send('mt::open-keybindings-config')
saveKeybindings () {
if (this.keybindingConfigurator && this.keybindingList.length > 0) {
this.keybindingConfigurator.save()
.then(success => {
if (!success) {
notice.notify({
title: 'Failed to save',
type: 'error',
message: 'An unexpected error occurred while saving.'
})
}
})
.catch(error => log.error(error))
}
},
restoreDefaults () {
this.keybindingConfigurator.resetAll()
.then(success => {
if (!success) {
notice.notify({
title: 'Failed to save',
type: 'error',
message: 'An unexpected error occurred while saving.'
})
}
})
.catch(error => log.error(error))
},
handleEditClick (index, entry) {
if (index >= 0 && entry) {
this.selectedShortcutId = entry.id
}
},
handleResetClick (index, entry) {
const { keybindingConfigurator } = this
const { id } = entry
const success = keybindingConfigurator.resetToDefault(id)
if (!success) {
this.handleDuplicateShortcut(id, keybindingConfigurator.getDefaultAccelerator(id))
}
},
handleUnbindClick (index, entry) {
this.keybindingConfigurator.unbind(entry.id)
},
onKeybinding (value) {
const selectedId = this.selectedShortcutId
if (value && selectedId) {
const success = this.keybindingConfigurator.change(selectedId, value)
if (!success) {
this.handleDuplicateShortcut(selectedId, value)
}
}
this.selectedShortcutId = null
},
handleDuplicateShortcut (id, accelerator) {
notice.notify({
title: 'Shortcut already in use',
type: 'warning',
message: `The shortcut "${accelerator}" is already in use. Please unset the shortcut and try again.`
})
},
dumpKeyboardInformation () {
ipcRenderer.send('mt::keybinding-debug-dump-keyboard-info')
}
}
}
@ -40,10 +170,17 @@ export default {
<style scoped>
.pref-keybindings {
& .keybinding-info {
& .keyboard-debug,
& .keybindings {
font-size: 14px;
margin: 20px 0;
color: var(--editorColor);
& .link {
cursor: pointer;
}
}
& .keybindings > div.text {
margin-bottom: 10px;
}
& .link {
color: var(--themeColor);
@ -53,4 +190,59 @@ export default {
font-size: 13px;
}
}
.el-table, .el-table__expanded-cell {
background: var(--editorBgColor);
}
.el-table button {
padding: 2px 2px;
margin: 4px 0px;
color: var(--themeColor);
background: none;
border: none;
}
.el-table button:not(:last-child) {
margin-right: 4px;
}
.el-table button:hover,
.el-table button:active {
opacity: 0.9;
background: none;
}
</style>
<style>
.pref-keybindings .el-table table {
margin: 0;
border: none;
}
.pref-keybindings .el-table th,
.pref-keybindings .el-table tr {
background: var(--editorBgColor);
}
.pref-keybindings .el-table th.el-table__cell.is-leaf,
.pref-keybindings .el-table th,
.pref-keybindings .el-table td {
border: none;
}
.pref-keybindings .el-table th.el-table__cell.is-leaf:last-child,
.pref-keybindings .el-table th:last-child,
.pref-keybindings .el-table td:last-child {
border-right: 1px solid var(--tableBorderColor);
}
.pref-keybindings .el-table--border::after,
.pref-keybindings .el-table--group::after,
.pref-keybindings .el-table::before,
.pref-keybindings .el-table__fixed-right::before,
.pref-keybindings .el-table__fixed::before {
background: var(--tableBorderColor);
}
.pref-keybindings .el-table__body tr.hover-row.current-row>td,
.pref-keybindings .el-table__body tr.hover-row.el-table__row--striped.current-row>td,
.pref-keybindings .el-table__body tr.hover-row.el-table__row--striped>td,
.pref-keybindings .el-table__body tr.hover-row>td {
background: var(--selectionColor);
}
.pref-keybindings .el-table .el-table__cell {
padding: 2px 0;
margin: 0;
}
</style>

View File

@ -0,0 +1,239 @@
<template>
<div class="key-input-dialog">
<div v-if="showKeyInputDialog" class="input-overlay"></div>
<el-dialog
:visible.sync="showKeyInputDialog"
:show-close="false"
:modal="false"
@close="cancelKeybinding"
custom-class="ag-dialog-table"
width="350px"
>
<div slot="title" class="key-input-wrapper">
<div class="input-wrapper">
<input
tabindex="0"
type="text"
ref="intputTextbox"
v-model="keybindingInputValue"
class="input-textbox"
@keydown="handleKeyDown"
@keyup="handleKeyUp"
:placeholder="placeholderText"
>
</div>
<div class="footer">
<div class="descriptions">Press Enter to continue or ESC to exit.</div>
<div
v-show="!isKeybindingValid"
class="invalid-keybinding"
>
Current key combination cannot be bound!
</div>
</div>
</div>
</el-dialog>
</div>
</template>
<script>
import {
isCompositionEvent,
isValidElectronAccelerator,
getAcceleratorFromKeyboardEvent
} from '@hfelix/electron-localshortcut'
export default {
data () {
this.needCommitOnClose = true
this.currentKeybinding = null
this.defaultPlaceholderText = 'Press a key combination'
return {
showKeyInputDialog: false,
placeholderText: this.defaultPlaceholderText,
isKeybindingValid: true,
keybindingInputValue: ''
}
},
props: {
onCommit: Function,
showWithId: {
type: String,
default: null
}
},
watch: {
showWithId: function (value, oldValue) {
if (value !== oldValue) {
if (value) {
this.handleShow()
} else {
this.cancelKeybinding()
}
}
}
},
methods: {
handleShow () {
this.needCommitOnClose = true
this.showKeyInputDialog = true
this.$nextTick(() => {
this.$refs.intputTextbox.focus()
})
},
handleDialogClose () {
this.currentKeybinding = null
this.isKeybindingValid = true
this.keybindingInputValue = ''
this.showKeyInputDialog = false
},
handleKeyDown (event) {
event.preventDefault()
event.stopPropagation()
if (isCompositionEvent(event)) {
// FIXME: You can still write in the textbox while composition.
return
} else if (this.isRawKeyCode(event, 'Escape')) {
this.cancelKeybinding()
return
} else if (this.isRawKeyCode(event, 'Enter')) {
this.saveKeybinding()
return
}
const keybinding = getAcceleratorFromKeyboardEvent(event)
this.currentKeybinding = keybinding
// Verify whether the given key binding is valid for Electron.
this.isKeybindingValid = keybinding.isValid && isValidElectronAccelerator(keybinding.accelerator)
this.keybindingInputValue = keybinding.accelerator
},
handleKeyUp (event) {
event.preventDefault()
event.stopPropagation()
},
cancelKeybinding () {
// Don't commit twice if the user clicks on the background.
if (this.needCommitOnClose) {
this.needCommitOnClose = false
this.onCommit(null)
this.handleDialogClose()
}
},
saveKeybinding () {
if (!this.currentKeybinding) {
this.cancelKeybinding()
return
}
const { accelerator, isValid } = this.currentKeybinding
if (!isValid) {
// TODO: Show shake animation on error text.
return
}
this.needCommitOnClose = false
this.onCommit(accelerator)
this.handleDialogClose()
},
isRawKeyCode (event, keyCode) {
const { code, ctrlKey, altKey, shiftKey, metaKey } = event
return event && code === keyCode && !ctrlKey && !altKey && !shiftKey && !metaKey
}
}
}
</script>
<style scoped>
::-webkit-scrollbar {
display: none;
}
.key-input-wrapper {
position: absolute;
display: flex;
flex-direction: column;
align-items: center;
width: 500px;
height: auto;
top: 0;
left: 50%;
transform: translateX(-50%);
padding: 8px;
margin: 0 auto;
margin-top: 8px;
box-sizing: border-box;
color: var(--editorColor);
background: var(--floatBgColor);
border: 1px solid var(--floatBorderColor);
border-radius: 4px;
box-shadow: 0 3px 8px 3px var(--floatShadow);
z-index: 10000;
}
.input-wrapper {
display: block;
width: 100%;
border: 1px solid var(--inputBgColor);
background: var(--inputBgColor);
border-radius: 3px;
}
input.input-textbox {
width: 100%;
height: 30px;
margin: 0 10px;
font-size: 14px;
color: var(--editorColor);
background: transparent;
outline: none;
border: none;
}
.footer {
font-size: 13px;
text-align: center;
& .description {
margin-top: 2px;
}
& .invalid-keybinding {
font-weight: bold;
}
}
.fade-enter-active, .fade-leave-active {
transition: opacity .2s;
}
.fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ {
opacity: 0;
}
.input-overlay {
position: fixed;
left: 0;
top: 0;
right: 0;
bottom: 0;
z-index: 100;
display: flex;
justify-content: center;
align-items: center;
font-size: 13px;
color: var(--editorColor);
background: rgba(0, 0, 0, 0.5);
}
</style>
<style>
.key-input-dialog .el-dialog,
.key-input-dialog .el-dialog.ag-dialog-table {
box-shadow: none !important;
border: none !important;
background: none !important;
}
.key-input-dialog .el-dialog__header {
margin-bottom: 20px;
padding: 0 !important;
}
.key-input-dialog .el-dialog__body {
display: none !important;
}
</style>

View File

@ -0,0 +1,111 @@
import { isEqualAccelerator } from 'common/keybinding'
const keys = [
'0',
'1',
'9',
'A',
'G',
'Z',
'F1',
'F5',
'F24',
'~',
'!',
'@',
'#',
'Plus',
'Space',
'Tab',
'Backspace',
'Delete',
'Insert',
'Return',
'Enter',
'Up',
'Down',
'Left',
'Right',
'Home',
'End',
'PageUp',
'PageDown',
'Escape',
'Esc',
'VolumeUp',
'VolumeDown',
'VolumeMute',
'MediaNextTrack',
'MediaPreviousTrack',
'MediaStop',
'MediaPlayPause',
'PrintScreen'
]
const modifiers = [
'Command',
'Cmd',
'Control',
'Ctrl',
'CommandOrControl',
'CmdOrCtrl',
'Alt',
'Option',
'AltGr',
'Shift'
]
describe('Test equal with basis keys', () => {
it('Match Ctrl+A', () => {
expect(isEqualAccelerator('Ctrl+A', 'A+Ctrl')).to.equal(true)
})
it('Match case insensitive with multiple modifiers', () => {
expect(isEqualAccelerator('Ctrl+Alt+A', 'ctrl+alt+a')).to.equal(true)
})
it('Match case insensitive with multiple modifiers and upper-case letter', () => {
expect(isEqualAccelerator('Ctrl+Shift+A', 'ctrl+shift+A')).to.equal(true)
})
it('Match mixed case with multiple modifiers', () => {
expect(isEqualAccelerator('Ctrl+a+shift', 'ctrl+Shift+a')).to.equal(true)
})
})
describe('Test not equal with basis keys', () => {
it('Mismatch Ctrl+A', () => {
expect(isEqualAccelerator('Ctrl+A', 'A+Ctrl+Alt')).to.equal(false)
})
it('Mismatch case insensitive with multiple modifiers', () => {
expect(isEqualAccelerator('Ctrl+A', 'ctrl+alt+a')).to.equal(false)
})
it('Mismatch letters only', () => {
expect(isEqualAccelerator('a', 'b')).to.equal(false)
})
it('Mismatch same modifiers but different key', () => {
expect(isEqualAccelerator('Ctrl+a+shift', 'ctrl+Shift+b')).to.equal(false)
})
})
describe('Test invalid accelerator', () => {
it('Ctrl+', () => {
expect(isEqualAccelerator('Ctrl+', 'Ctrl+Plus')).to.equal(false)
})
it('Ctrl++', () => {
expect(isEqualAccelerator('Ctrl++', 'Ctrl+Plus')).to.equal(false)
})
it('Emtpy accelerator 1', () => {
expect(isEqualAccelerator('', 'Ctrl+A')).to.equal(false)
})
it('Emtpy accelerator 2', () => {
expect(isEqualAccelerator('ctrl+Shift+b', '')).to.equal(false)
})
})
describe('Match all', () => {
modifiers.forEach(mod =>
keys.forEach(key => {
it(`Should match ${mod}+${key}`, () => {
expect(isEqualAccelerator(`${mod}+${key}`, `${key}+${mod}`)).to.equal(true)
})
})
)
})

484
yarn.lock
View File

@ -80,20 +80,20 @@
semver "^6.3.0"
source-map "^0.5.0"
"@babel/core@^7.16.7":
version "7.16.7"
resolved "https://registry.npmjs.org/@babel/core/-/core-7.16.7.tgz#db990f931f6d40cb9b87a0dc7d2adc749f1dcbcf"
integrity sha512-aeLaqcqThRNZYmbMqtulsetOQZ/5gbR/dWruUCJcpas4Qoyy+QeagfDsPdMrqwsPRDNxJvBlRiZxxX7THO7qtA==
"@babel/core@^7.16.12":
version "7.16.12"
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.16.12.tgz#5edc53c1b71e54881315923ae2aedea2522bb784"
integrity sha512-dK5PtG1uiN2ikk++5OzSYsitZKny4wOCD0nrO4TqnW4BVBTQ2NGS3NgilvT/TEyxTST7LNyWV/T4tXDoD3fOgg==
dependencies:
"@babel/code-frame" "^7.16.7"
"@babel/generator" "^7.16.7"
"@babel/generator" "^7.16.8"
"@babel/helper-compilation-targets" "^7.16.7"
"@babel/helper-module-transforms" "^7.16.7"
"@babel/helpers" "^7.16.7"
"@babel/parser" "^7.16.7"
"@babel/parser" "^7.16.12"
"@babel/template" "^7.16.7"
"@babel/traverse" "^7.16.7"
"@babel/types" "^7.16.7"
"@babel/traverse" "^7.16.10"
"@babel/types" "^7.16.8"
convert-source-map "^1.7.0"
debug "^4.1.0"
gensync "^1.0.0-beta.2"
@ -160,7 +160,7 @@
jsesc "^2.5.1"
source-map "^0.5.0"
"@babel/generator@^7.16.7", "@babel/generator@^7.16.8":
"@babel/generator@^7.16.8":
version "7.16.8"
resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.16.8.tgz#359d44d966b8cd059d543250ce79596f792f2ebe"
integrity sha512-1ojZwE9+lOXzcWdWmO6TbUzDfqLD39CmEhN8+2cX9XkDo5yW1OpgfejfliysR2AWLpMamTiOiAp/mtroaymhpw==
@ -230,6 +230,19 @@
"@babel/helper-replace-supers" "^7.16.0"
"@babel/helper-split-export-declaration" "^7.16.0"
"@babel/helper-create-class-features-plugin@^7.16.10":
version "7.16.10"
resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.16.10.tgz#8a6959b9cc818a88815ba3c5474619e9c0f2c21c"
integrity sha512-wDeej0pu3WN/ffTxMNCPW5UCiOav8IcLRxSIyp/9+IF2xJUM9h/OYjg0IJLHaL6F8oU8kqMz9nc1vryXhMsgXg==
dependencies:
"@babel/helper-annotate-as-pure" "^7.16.7"
"@babel/helper-environment-visitor" "^7.16.7"
"@babel/helper-function-name" "^7.16.7"
"@babel/helper-member-expression-to-functions" "^7.16.7"
"@babel/helper-optimise-call-expression" "^7.16.7"
"@babel/helper-replace-supers" "^7.16.7"
"@babel/helper-split-export-declaration" "^7.16.7"
"@babel/helper-create-class-features-plugin@^7.16.5":
version "7.16.5"
resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.16.5.tgz#5d1bcd096792c1ebec6249eebc6358eec55d0cad"
@ -758,6 +771,11 @@
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.16.4.tgz#d5f92f57cf2c74ffe9b37981c0e72fee7311372e"
integrity sha512-6V0qdPUaiVHH3RtZeLIsc+6pDhbYzHR8ogA8w+f+Wc77DuXto19g2QUwveINoS34Uw+W8/hQDGJCx+i4n7xcng==
"@babel/parser@^7.16.10", "@babel/parser@^7.16.12":
version "7.16.12"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.16.12.tgz#9474794f9a650cf5e2f892444227f98e28cdf8b6"
integrity sha512-VfaV15po8RiZssrkPweyvbGVSe4x2y+aciFCgn0n0/SJMR22cwofRV1mtnJQYcSB1wUTaA/X1LnA3es66MCO5A==
"@babel/parser@^7.16.5":
version "7.16.6"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.16.6.tgz#8f194828193e8fa79166f34a4b4e52f3e769a314"
@ -967,12 +985,12 @@
"@babel/helper-create-class-features-plugin" "^7.16.5"
"@babel/helper-plugin-utils" "^7.16.5"
"@babel/plugin-proposal-private-methods@^7.16.7":
version "7.16.7"
resolved "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.7.tgz#e418e3aa6f86edd6d327ce84eff188e479f571e0"
integrity sha512-7twV3pzhrRxSwHeIvFE6coPgvo+exNDOiGUMg39o2LiLo1Y+4aKpfkcLGcg1UHonzorCt7SNXnoMyCnnIOA8Sw==
"@babel/plugin-proposal-private-methods@^7.16.11":
version "7.16.11"
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.11.tgz#e8df108288555ff259f4527dbe84813aac3a1c50"
integrity sha512-F/2uAkPlXDr8+BHpZvo19w3hLFKge+k75XUprE6jaqKxjGkSYcK+4c+bup5PdW/7W/Rpjwql7FTVEDW+fRAQsw==
dependencies:
"@babel/helper-create-class-features-plugin" "^7.16.7"
"@babel/helper-create-class-features-plugin" "^7.16.10"
"@babel/helper-plugin-utils" "^7.16.7"
"@babel/plugin-proposal-private-property-in-object@^7.14.5":
@ -1067,6 +1085,13 @@
dependencies:
"@babel/helper-plugin-utils" "^7.8.0"
"@babel/plugin-syntax-jsx@^7.16.7":
version "7.16.7"
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.16.7.tgz#50b6571d13f764266a113d77c82b4a6508bbe665"
integrity sha512-Esxmk7YjA8QysKeT3VhTXvF6y77f/a91SIs4pWb4H2eWGQkCKFgQaG6hdoEVZtGsrAcb2K5BW66XsOErD4WU3Q==
dependencies:
"@babel/helper-plugin-utils" "^7.16.7"
"@babel/plugin-syntax-logical-assignment-operators@^7.10.4":
version "7.10.4"
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699"
@ -1333,6 +1358,17 @@
dependencies:
"@babel/helper-plugin-utils" "^7.16.7"
"@babel/plugin-transform-react-jsx@^7.14.5":
version "7.16.7"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.16.7.tgz#86a6a220552afd0e4e1f0388a68a372be7add0d4"
integrity sha512-8D16ye66fxiE8m890w0BpPpngG9o9OVBBy0gH2E+2AR7qMR2ZpTYJEqLxAsoroenMId0p/wMW+Blc0meDgu0Ag==
dependencies:
"@babel/helper-annotate-as-pure" "^7.16.7"
"@babel/helper-module-imports" "^7.16.7"
"@babel/helper-plugin-utils" "^7.16.7"
"@babel/plugin-syntax-jsx" "^7.16.7"
"@babel/types" "^7.16.7"
"@babel/plugin-transform-regenerator@^7.16.7":
version "7.16.7"
resolved "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.16.7.tgz#9e7576dc476cb89ccc5096fff7af659243b4adeb"
@ -1347,10 +1383,10 @@
dependencies:
"@babel/helper-plugin-utils" "^7.16.7"
"@babel/plugin-transform-runtime@^7.16.8":
version "7.16.8"
resolved "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.16.8.tgz#3339368701103edae708f0fba9e4bfb70a3e5872"
integrity sha512-6Kg2XHPFnIarNweZxmzbgYnnWsXxkx9WQUVk2sksBRL80lBC1RAQV3wQagWxdCHiYHqPN+oenwNIuttlYgIbQQ==
"@babel/plugin-transform-runtime@^7.16.10":
version "7.16.10"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.16.10.tgz#53d9fd3496daedce1dd99639097fa5d14f4c7c2c"
integrity sha512-9nwTiqETv2G7xI4RvXHNfpGdr8pAA+Q/YtN3yLK7OoK7n9OibVm/xymJ838a9A6E/IciOLPj82lZk0fW6O4O7w==
dependencies:
"@babel/helper-module-imports" "^7.16.7"
"@babel/helper-plugin-utils" "^7.16.7"
@ -1419,10 +1455,10 @@
"@babel/helper-create-regexp-features-plugin" "^7.16.7"
"@babel/helper-plugin-utils" "^7.16.7"
"@babel/preset-env@^7.16.8":
version "7.16.8"
resolved "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.16.8.tgz#e682fa0bcd1cf49621d64a8956318ddfb9a05af9"
integrity sha512-9rNKgVCdwHb3z1IlbMyft6yIXIeP3xz6vWvGaLHrJThuEIqWfHb0DNBH9VuTgnDfdbUDhkmkvMZS/YMCtP7Elg==
"@babel/preset-env@^7.16.11":
version "7.16.11"
resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.16.11.tgz#5dd88fd885fae36f88fd7c8342475c9f0abe2982"
integrity sha512-qcmWG8R7ZW6WBRPZK//y+E3Cli151B20W1Rv7ln27vuPaXU/8TKms6jFdiJtF7UDTxcrb7mZd88tAeK9LjdT8g==
dependencies:
"@babel/compat-data" "^7.16.8"
"@babel/helper-compilation-targets" "^7.16.7"
@ -1442,7 +1478,7 @@
"@babel/plugin-proposal-object-rest-spread" "^7.16.7"
"@babel/plugin-proposal-optional-catch-binding" "^7.16.7"
"@babel/plugin-proposal-optional-chaining" "^7.16.7"
"@babel/plugin-proposal-private-methods" "^7.16.7"
"@babel/plugin-proposal-private-methods" "^7.16.11"
"@babel/plugin-proposal-private-property-in-object" "^7.16.7"
"@babel/plugin-proposal-unicode-property-regex" "^7.16.7"
"@babel/plugin-syntax-async-generators" "^7.8.4"
@ -1601,6 +1637,22 @@
debug "^4.1.0"
globals "^11.1.0"
"@babel/traverse@^7.16.10":
version "7.16.10"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.16.10.tgz#448f940defbe95b5a8029975b051f75993e8239f"
integrity sha512-yzuaYXoRJBGMlBhsMJoUW7G1UmSb/eXr/JHYM/MsOJgavJibLwASijW7oXBdw3NQ6T0bW7Ty5P/VarOs9cHmqw==
dependencies:
"@babel/code-frame" "^7.16.7"
"@babel/generator" "^7.16.8"
"@babel/helper-environment-visitor" "^7.16.7"
"@babel/helper-function-name" "^7.16.7"
"@babel/helper-hoist-variables" "^7.16.7"
"@babel/helper-split-export-declaration" "^7.16.7"
"@babel/parser" "^7.16.10"
"@babel/types" "^7.16.8"
debug "^4.1.0"
globals "^11.1.0"
"@babel/traverse@^7.16.5":
version "7.16.5"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.16.5.tgz#d7d400a8229c714a59b87624fc67b0f1fbd4b2b3"
@ -1701,10 +1753,10 @@
global-agent "^3.0.0"
global-tunnel-ng "^2.7.1"
"@electron/remote@^2.0.1":
version "2.0.1"
resolved "https://registry.yarnpkg.com/@electron/remote/-/remote-2.0.1.tgz#810cbc595a21f0f94641eb2d7e8264063a3f84de"
integrity sha512-bGX4/yB2bPZwXm1DsxgoABgH0Cz7oFtXJgkerB8VrStYdTyvhGAULzNLRn9rVmeAuC3VUDXaXpZIlZAZHpsLIA==
"@electron/remote@^2.0.4":
version "2.0.4"
resolved "https://registry.yarnpkg.com/@electron/remote/-/remote-2.0.4.tgz#c3dae436aed79d1b8adcefc5a4963c06750ad5d8"
integrity sha512-8m2P/d2RH986PmMW5lKygbPEjEYJ7RgCe37Y8DQ1wujKMH6VjmLIB+Y+DP2SA611svCZc58TRSd8FraGvcfGZw==
"@electron/universal@1.0.5":
version "1.0.5"
@ -1737,15 +1789,12 @@
resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.2.tgz#30aa825f11d438671d585bd44e7fd564535fc210"
integrity sha512-82cpyJyKRoQoRi+14ibCeGPu0CwypgtBAdBhq1WfvagpCZNKqwXbKwXllYSMG91DhmG4jt9gN8eP6lGOtozuaw==
"@hfelix/electron-localshortcut@^3.1.1":
version "3.1.1"
resolved "https://registry.npmjs.org/@hfelix/electron-localshortcut/-/electron-localshortcut-3.1.1.tgz#97e2f200568bffd5a49b465830b84f76fbc1130d"
integrity sha512-0kXNL54CE4d6oaUjZJ0kWzIVhENDp9JB9cFJnREwkhbR+aKvzGKeT8yofmf5tq+cZcoLKyBPchDtJLNDls8j5w==
"@hfelix/electron-localshortcut@^4.0.0-rc.1":
version "4.0.0-rc.1"
resolved "https://registry.yarnpkg.com/@hfelix/electron-localshortcut/-/electron-localshortcut-4.0.0-rc.1.tgz#1d7801c32ddd2ad2785073b920dcd16f24c1e53a"
integrity sha512-rRiwMBPJkPe/aAuzjFcjuIokm8VsTTWsCPOHNsjrrLWhOy+/TCiwEmdspCguLt07e23oXMhbMLALE3N3NFJGTg==
dependencies:
"@hfelix/keyboardevent-from-electron-accelerator" "^1.1.1"
debug "^4.0.1"
electron-is-accelerator "^0.1.0"
keyboardevents-areequal "^0.2.1"
debug "^4.3.3"
"@hfelix/electron-spellchecker@^2.0.0":
version "2.0.0"
@ -1761,11 +1810,6 @@
lru-cache "^6.0.0"
p-throttle "^3.1.0"
"@hfelix/keyboardevent-from-electron-accelerator@^1.1.1":
version "1.1.1"
resolved "https://registry.npmjs.org/@hfelix/keyboardevent-from-electron-accelerator/-/keyboardevent-from-electron-accelerator-1.1.1.tgz#7e1d4fd913759c381b7919cc7faf4c0c641d457c"
integrity sha512-1eVkDSqoRQkF2FrPPia2EZ3310c0TvFKYvSuJbaxHpRKbI6eVHcVGKpmOSDli6Qdn3Bu0h7ozfgMZbAEBD+BLQ==
"@hfelix/spellchecker@^4.1.0":
version "4.1.0"
resolved "https://registry.yarnpkg.com/@hfelix/spellchecker/-/spellchecker-4.1.0.tgz#d569a7adefe43ba154688e4a6cac15303ace53e9"
@ -2000,10 +2044,10 @@
dependencies:
"@octokit/openapi-types" "^11.2.0"
"@playwright/test@^1.17.2":
version "1.17.2"
resolved "https://registry.npmjs.org/@playwright/test/-/test-1.17.2.tgz#0c67e329a28ffe43a79dc15a0e139dadd9cb250f"
integrity sha512-lxauaOlLNddQsgknCDJZEo8spTlSUF7gU4jXf0sUDLFsH/KE4ySe4SOPUGbtw+lCMrUfSbSRz0e7wnw5z78LNA==
"@playwright/test@^1.18.1":
version "1.18.1"
resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.18.1.tgz#efaa3aa9c7f8aebeb75cd45fd9737529e9b30fbd"
integrity sha512-v6jAM2GpRvf4MUvSLkrAXg101XT9mLu2X2NbCnEoj7GHBXwavDlAJDMwh4Hn8oipDxB6MS6FTcr7opXsIMNwrA==
dependencies:
"@babel/code-frame" "^7.14.5"
"@babel/core" "^7.14.8"
@ -2021,20 +2065,23 @@
"@babel/plugin-syntax-object-rest-spread" "^7.8.3"
"@babel/plugin-syntax-optional-catch-binding" "^7.8.3"
"@babel/plugin-transform-modules-commonjs" "^7.14.5"
"@babel/plugin-transform-react-jsx" "^7.14.5"
"@babel/preset-typescript" "^7.14.5"
babel-plugin-module-resolver "^4.1.0"
colors "1.4.0"
commander "^8.2.0"
debug "^4.1.1"
expect "=27.2.5"
jest-matcher-utils "=27.2.5"
jpeg-js "^0.4.2"
json5 "^2.2.0"
mime "^2.4.6"
minimatch "^3.0.3"
ms "^2.1.2"
open "^8.3.0"
pirates "^4.0.1"
pixelmatch "^5.2.1"
playwright-core "=1.17.2"
playwright-core "=1.18.1"
pngjs "^5.0.0"
rimraf "^3.0.2"
source-map-support "^0.4.18"
@ -2572,22 +2619,22 @@
"@webassemblyjs/ast" "1.11.1"
"@xtuc/long" "4.2.2"
"@webpack-cli/configtest@^1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@webpack-cli/configtest/-/configtest-1.1.0.tgz#8342bef0badfb7dfd3b576f2574ab80c725be043"
integrity sha512-ttOkEkoalEHa7RaFYpM0ErK1xc4twg3Am9hfHhL7MVqlHebnkYd2wuI/ZqTDj0cVzZho6PdinY0phFZV3O0Mzg==
"@webpack-cli/configtest@^1.1.1":
version "1.1.1"
resolved "https://registry.yarnpkg.com/@webpack-cli/configtest/-/configtest-1.1.1.tgz#9f53b1b7946a6efc2a749095a4f450e2932e8356"
integrity sha512-1FBc1f9G4P/AxMqIgfZgeOTuRnwZMten8E7zap5zgpPInnCrP8D4Q81+4CWIch8i/Nf7nXjP0v6CjjbHOrXhKg==
"@webpack-cli/info@^1.4.0":
version "1.4.0"
resolved "https://registry.yarnpkg.com/@webpack-cli/info/-/info-1.4.0.tgz#b9179c3227ab09cbbb149aa733475fcf99430223"
integrity sha512-F6b+Man0rwE4n0409FyAJHStYA5OIZERxmnUfLVwv0mc0V1wLad3V7jqRlMkgKBeAq07jUvglacNaa6g9lOpuw==
"@webpack-cli/info@^1.4.1":
version "1.4.1"
resolved "https://registry.yarnpkg.com/@webpack-cli/info/-/info-1.4.1.tgz#2360ea1710cbbb97ff156a3f0f24556e0fc1ebea"
integrity sha512-PKVGmazEq3oAo46Q63tpMr4HipI3OPfP7LiNOEJg963RMgT0rqheag28NCML0o3GIzA3DmxP1ZIAv9oTX1CUIA==
dependencies:
envinfo "^7.7.3"
"@webpack-cli/serve@^1.6.0":
version "1.6.0"
resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-1.6.0.tgz#2c275aa05c895eccebbfc34cfb223c6e8bd591a2"
integrity sha512-ZkVeqEmRpBV2GHvjjUZqEai2PpUbuq8Bqd//vEYsp63J8WyexI8ppCqVS3Zs0QADf6aWuPdU+0XsPI647PVlQA==
"@webpack-cli/serve@^1.6.1":
version "1.6.1"
resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-1.6.1.tgz#0de2875ac31b46b6c5bb1ae0a7d7f0ba5678dffe"
integrity sha512-gNGTiTrjEVQ0OcVnzsRSqTxaBSr+dmTfm+qJsCDluky8uhdLWep7Gcr62QsAKHTMxjCS/8nEITsmFAhfIx+QSw==
"@xtuc/ieee754@^1.2.0":
version "1.2.0"
@ -2841,10 +2888,10 @@ app-builder-bin@3.7.1:
resolved "https://registry.yarnpkg.com/app-builder-bin/-/app-builder-bin-3.7.1.tgz#cb0825c5e12efc85b196ac3ed9c89f076c61040e"
integrity sha512-ql93vEUq6WsstGXD+SBLSIQw6SNnhbDEM0swzgugytMxLp3rT24Ag/jcC80ZHxiPRTdew1niuR7P3/FCrDqIjw==
app-builder-lib@22.14.8:
version "22.14.8"
resolved "https://registry.yarnpkg.com/app-builder-lib/-/app-builder-lib-22.14.8.tgz#37137f45c5768d46a022d49b5577426264d3f19d"
integrity sha512-Lg3mvgR45LynhMVwVFIJgIfozaTBrcAJY3sGE3Mq5O7GVwYf0Ucdoi3mc6EqAhiyCerNznKfW9vCeL0E85vIog==
app-builder-lib@22.14.13:
version "22.14.13"
resolved "https://registry.yarnpkg.com/app-builder-lib/-/app-builder-lib-22.14.13.tgz#c1f5b6afc86596357598bb90b69eef06c7c2eeb3"
integrity sha512-SufmrtxU+D0Tn948fjEwAOlCN9757UXLkzzTWXMwZKR/5hisvgqeeBepWfphMIE6OkDGz0fbzEhL1P2Pty4XMg==
dependencies:
"7zip-bin" "~5.1.1"
"@develar/schema-utils" "~2.6.5"
@ -2852,13 +2899,13 @@ app-builder-lib@22.14.8:
"@malept/flatpak-bundler" "^0.4.0"
async-exit-hook "^2.0.1"
bluebird-lst "^1.0.9"
builder-util "22.14.7"
builder-util "22.14.13"
builder-util-runtime "8.9.2"
chromium-pickle-js "^0.2.0"
debug "^4.3.2"
ejs "^3.1.6"
electron-osx-sign "^0.5.0"
electron-publish "22.14.7"
electron-publish "22.14.13"
form-data "^4.0.0"
fs-extra "^10.0.0"
hosted-git-info "^4.0.2"
@ -3105,12 +3152,12 @@ autoprefixer@^10.4.2:
picocolors "^1.0.0"
postcss-value-parser "^4.2.0"
axios@^0.24.0:
version "0.24.0"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.24.0.tgz#804e6fa1e4b9c5288501dd9dff56a7a0940d20d6"
integrity sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA==
axios@^0.25.0:
version "0.25.0"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.25.0.tgz#349cfbb31331a9b4453190791760a8d35b093e0a"
integrity sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==
dependencies:
follow-redirects "^1.14.4"
follow-redirects "^1.14.7"
babel-helper-vue-jsx-merge-props@^2.0.0:
version "2.0.3"
@ -3152,6 +3199,17 @@ babel-plugin-istanbul@^6.1.1:
istanbul-lib-instrument "^5.0.4"
test-exclude "^6.0.0"
babel-plugin-module-resolver@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/babel-plugin-module-resolver/-/babel-plugin-module-resolver-4.1.0.tgz#22a4f32f7441727ec1fbf4967b863e1e3e9f33e2"
integrity sha512-MlX10UDheRr3lb3P0WcaIdtCSRlxdQsB1sBqL7W0raF070bGl1HQQq5K3T2vf2XAYie+ww+5AKC/WrkjRO2knA==
dependencies:
find-babel-config "^1.2.0"
glob "^7.1.6"
pkg-up "^3.1.0"
reselect "^4.0.0"
resolve "^1.13.1"
babel-plugin-polyfill-corejs2@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.0.tgz#407082d0d355ba565af24126fb6cb8e9115251fd"
@ -3466,10 +3524,10 @@ builder-util-runtime@8.9.2:
debug "^4.3.2"
sax "^1.2.4"
builder-util@22.14.7:
version "22.14.7"
resolved "https://registry.yarnpkg.com/builder-util/-/builder-util-22.14.7.tgz#bb445f6102ccab4e4fdc8dd57de9dda9bb672666"
integrity sha512-M8ql8WPW/P9UKsF00YZjiP5h29MYrJ3svJx5suszC5EGwIdAztIhFyXoXKI3hPtDaR5b6EoWD9nLa5/Gr+QToQ==
builder-util@22.14.13:
version "22.14.13"
resolved "https://registry.yarnpkg.com/builder-util/-/builder-util-22.14.13.tgz#41b5b7b4ee53aff4e09cc007fb144522598f3ce6"
integrity sha512-oePC/qrrUuerhmH5iaCJzPRAKlSBylrhzuAJmRQClTyWnZUv6jbaHh+VoHMbEiE661wrj2S2aV7/bQh12cj1OA==
dependencies:
"7zip-bin" "~5.1.1"
"@types/debug" "^4.1.6"
@ -3659,15 +3717,16 @@ cfonts@^2.10.0:
chalk "^4.1.2"
window-size "^1.1.1"
chai@^4.3.4:
version "4.3.4"
resolved "https://registry.yarnpkg.com/chai/-/chai-4.3.4.tgz#b55e655b31e1eac7099be4c08c21964fce2e6c49"
integrity sha512-yS5H68VYOCtN1cjfwumDSuzn/9c+yza4f3reKXlE5rUg7SFcCEy90gJvydNgOYtblyf4Zi6jIWRnXOgErta0KA==
chai@^4.3.6:
version "4.3.6"
resolved "https://registry.yarnpkg.com/chai/-/chai-4.3.6.tgz#ffe4ba2d9fa9d6680cc0b370adae709ec9011e9c"
integrity sha512-bbcp3YfHCUzMOvKqsztczerVgBKSsEijCySNlHHbX3VG1nskvqjz5Rfso1gGwD6w6oOV3eI60pKuMOV5MV7p3Q==
dependencies:
assertion-error "^1.1.0"
check-error "^1.0.2"
deep-eql "^3.0.1"
get-func-name "^2.0.0"
loupe "^2.3.1"
pathval "^1.1.1"
type-detect "^4.0.5"
@ -3787,6 +3846,21 @@ chokidar@^3.5.1, chokidar@^3.5.2:
optionalDependencies:
fsevents "~2.3.2"
chokidar@^3.5.3:
version "3.5.3"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd"
integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==
dependencies:
anymatch "~3.1.2"
braces "~3.0.2"
glob-parent "~5.1.2"
is-binary-path "~2.1.0"
is-glob "~4.0.1"
normalize-path "~3.0.0"
readdirp "~3.6.0"
optionalDependencies:
fsevents "~2.3.2"
chownr@^1.1.1:
version "1.1.4"
resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b"
@ -3968,10 +4042,10 @@ code-point-at@^1.0.0:
resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=
codemirror@^5.65.0:
version "5.65.0"
resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-5.65.0.tgz#50344359393579f526ca53797e510ff75477117f"
integrity sha512-gWEnHKEcz1Hyz7fsQWpK7P0sPI2/kSkRX2tc7DFA6TmZuDN75x/1ejnH/Pn8adYKrLEA1V2ww6L00GudHZbSKw==
codemirror@^5.65.1:
version "5.65.1"
resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-5.65.1.tgz#5988a812c974c467f964bcc1a00c944e373de502"
integrity sha512-s6aac+DD+4O2u1aBmdxhB7yz2XU7tG3snOyQ05Kxifahz7hoxnfxIRHxiCSEv3TUC38dIVH8G+lZH9UWSfGQxA==
collection-visit@^1.0.0:
version "1.0.0"
@ -4020,7 +4094,7 @@ colors@1.0.3:
resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b"
integrity sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=
colors@1.4.0, colors@^1.1.2, colors@^1.3.3:
colors@1.4.0:
version "1.4.0"
resolved "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78"
integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==
@ -4266,10 +4340,10 @@ copy-descriptor@^0.1.0:
resolved "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d"
integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=
copy-webpack-plugin@^10.2.0:
version "10.2.0"
resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-10.2.0.tgz#24c2d256953a55400a1ec66be4e0eccd1c4ae958"
integrity sha512-my6iXII95c78w14HzYCNya5TlJYa44lOppAge5GSTMM1SyDxNsVGCJvhP4/ld6snm8lzjn3XOonMZD6s1L86Og==
copy-webpack-plugin@^10.2.1:
version "10.2.1"
resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-10.2.1.tgz#115a41f913070ac236a1b576066204cbf35341a1"
integrity sha512-nr81NhCAIpAWXGCK5thrKmfCQ6GDY0L5RN0U+BnIn/7Us55+UCex5ANNsNKmIVtDRnk0Ecf+/kzp9SUVrrBMLg==
dependencies:
fast-glob "^3.2.7"
glob-parent "^6.0.1"
@ -5124,7 +5198,7 @@ debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8, debug@^2.6.9:
dependencies:
ms "2.0.0"
debug@4, debug@^4.0.1, debug@^4.1.0:
debug@4, debug@^4.1.0:
version "4.1.1"
resolved "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791"
integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==
@ -5152,7 +5226,7 @@ debug@^3.2.7:
dependencies:
ms "^2.1.1"
debug@^4.1.1, debug@~4.3.1, debug@~4.3.2:
debug@^4.1.1, debug@^4.3.3, debug@~4.3.1, debug@~4.3.2:
version "4.3.3"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664"
integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==
@ -5414,13 +5488,13 @@ dir-glob@^3.0.1:
dependencies:
path-type "^4.0.0"
dmg-builder@22.14.8:
version "22.14.8"
resolved "https://registry.yarnpkg.com/dmg-builder/-/dmg-builder-22.14.8.tgz#97c5265ca712a707f0d598777606cb7ef711c46d"
integrity sha512-Dui12ofMfFLoqMMPgU60OgUU1tG8orWkYIa+zmen6I74VO1b+ell+Fkcu95jlX7JiLyMSuhzmUcfBnCc4NTCaw==
dmg-builder@22.14.13:
version "22.14.13"
resolved "https://registry.yarnpkg.com/dmg-builder/-/dmg-builder-22.14.13.tgz#cc613f3c18e889b8777d525991fd52f50a564f8c"
integrity sha512-xNOugB6AbIRETeU2uID15sUfjdZZcKdxK8xkFnwIggsM00PJ12JxpLNPTjcRoUnfwj3WrPjilrO64vRMwNItQg==
dependencies:
app-builder-lib "22.14.8"
builder-util "22.14.7"
app-builder-lib "22.14.13"
builder-util "22.14.13"
builder-util-runtime "8.9.2"
fs-extra "^10.0.0"
iconv-lite "^0.6.2"
@ -5594,11 +5668,16 @@ domino@^2.1.6:
resolved "https://registry.yarnpkg.com/domino/-/domino-2.1.6.tgz#fe4ace4310526e5e7b9d12c7de01b7f485a57ffe"
integrity sha512-3VdM/SXBZX2omc9JF9nOPCtDaYQ67BGp5CoLpIQlO2KCAPETs8TcDHacF26jXadGbvUteZzRTeos2fhID5+ucQ==
dompurify@2.3.4, dompurify@^2.3.4:
dompurify@2.3.4:
version "2.3.4"
resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.3.4.tgz#1cf5cf0105ccb4debdf6db162525bd41e6ddacc6"
integrity sha512-6BVcgOAVFXjI0JTjEvZy901Rghm+7fDQOrNIcxB4+gdhj6Kwp6T9VBhBY/AbagKHJocRkDYGd6wvI+p4/10xtQ==
dompurify@^2.3.5:
version "2.3.5"
resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.3.5.tgz#c83ed5a3ae5ce23e52efe654ea052ffb358dd7e3"
integrity sha512-kD+f8qEaa42+mjdOpKeztu9Mfx5bv9gVLO6K9jRx4uGvh6Wv06Srn4jr1wPNY2OOUGGSKHNFN+A8MA3v0E0QAQ==
domready@1.0.8:
version "1.0.8"
resolved "https://registry.npmjs.org/domready/-/domready-1.0.8.tgz#91f252e597b65af77e745ae24dd0185d5e26d58c"
@ -5695,17 +5774,17 @@ ejs@^3.1.6:
dependencies:
jake "^10.6.1"
electron-builder@^22.14.8:
version "22.14.8"
resolved "https://registry.yarnpkg.com/electron-builder/-/electron-builder-22.14.8.tgz#f6d253700b1cf81c6c4132daefac4b12a3046c74"
integrity sha512-vfujO+XJiNI9mnppePEvukjqDvBu0n3mKtP0AgEgfQkB0JL3zh1qcWS/BpvB6SRjK6CoFZnOyyLrepcdtlhi7A==
electron-builder@^22.14.13:
version "22.14.13"
resolved "https://registry.yarnpkg.com/electron-builder/-/electron-builder-22.14.13.tgz#fd40564685cf5422a8f8d667940af3d3776f4fb8"
integrity sha512-3fgLxqF2TXVKiUPeg74O4V3l0l3j7ERLazo8sUbRkApw0+4iVAf2BJkHsHMaXiigsgCoEzK/F4/rB5rne/VAnw==
dependencies:
"@types/yargs" "^17.0.1"
app-builder-lib "22.14.8"
builder-util "22.14.7"
app-builder-lib "22.14.13"
builder-util "22.14.13"
builder-util-runtime "8.9.2"
chalk "^4.1.1"
dmg-builder "22.14.8"
dmg-builder "22.14.13"
fs-extra "^10.0.0"
is-ci "^3.0.0"
lazy-val "^1.0.5"
@ -5723,20 +5802,10 @@ electron-devtools-installer@^3.2.0:
tslib "^2.1.0"
unzip-crx-3 "^0.2.0"
electron-is-accelerator@^0.1.0:
version "0.1.2"
resolved "https://registry.npmjs.org/electron-is-accelerator/-/electron-is-accelerator-0.1.2.tgz#509e510c26a56b55e17f863a4b04e111846ab27b"
integrity sha1-UJ5RDCala1Xhf4Y6SwThEYRqsns=
electron-is-accelerator@^0.2.0:
version "0.2.0"
resolved "https://registry.npmjs.org/electron-is-accelerator/-/electron-is-accelerator-0.2.0.tgz#8768feb2eb64ded6bcb98936853a4a6dcf6bfb46"
integrity sha512-jml8EDK0x1xuPCr8ZWr+tuCL9RwfR4lee+WhLID2WZ0ygGSlnkumF6K1zw05CgnkDvHuKhFV6/NrSDI87QWAfA==
electron-log@^4.4.4:
version "4.4.4"
resolved "https://registry.npmjs.org/electron-log/-/electron-log-4.4.4.tgz#df893ae9ae8c21781a585eea50ce7836ac3e0fe7"
integrity sha512-jcNtrVmKXG+CHchLo/jnjjQ9K4/ORguWD23H2nqApTwisQ4Qo3IRQtLiorubajX0Uxg76Xm/Yt+eNfQMoHVr5w==
electron-log@^4.4.5:
version "4.4.5"
resolved "https://registry.yarnpkg.com/electron-log/-/electron-log-4.4.5.tgz#5fcfd0c2dc5fbda915ee0a9d802705dc57930786"
integrity sha512-Cfa2CKnwBhlUfIl/qr2GF5SCqfoA9yPBqTJ6/wPs+PEn36M2+EZ3RpGSaOhYQ1BZpolL1CWyeu3gMG8epLl3Ng==
electron-osx-sign@^0.5.0:
version "0.5.0"
@ -5750,31 +5819,31 @@ electron-osx-sign@^0.5.0:
minimist "^1.2.0"
plist "^3.0.1"
electron-publish@22.14.7:
version "22.14.7"
resolved "https://registry.yarnpkg.com/electron-publish/-/electron-publish-22.14.7.tgz#5fb3a4278fdb7873c5a282152b909fe9814a4102"
integrity sha512-sqZX/64k0B7sQeaDzFDE6m7r2zOtFgdmWAFnkv10bLlbHagkH9AkwwcjiGBpIto7mUBp89ntL7Ij5QFvldqI4Q==
electron-publish@22.14.13:
version "22.14.13"
resolved "https://registry.yarnpkg.com/electron-publish/-/electron-publish-22.14.13.tgz#8b71e6975af8cc6ac5b21f293ade23f8704047c7"
integrity sha512-0oP3QiNj3e8ewOaEpEJV/o6Zrmy2VarVvZ/bH7kyO/S/aJf9x8vQsKVWpsdmSiZ5DJEHgarFIXrnO0ZQf0P9iQ==
dependencies:
"@types/fs-extra" "^9.0.11"
builder-util "22.14.7"
builder-util "22.14.13"
builder-util-runtime "8.9.2"
chalk "^4.1.1"
fs-extra "^10.0.0"
lazy-val "^1.0.5"
mime "^2.5.2"
electron-rebuild@^3.2.5:
version "3.2.5"
resolved "https://registry.yarnpkg.com/electron-rebuild/-/electron-rebuild-3.2.5.tgz#a9e82b4259aac33ad449f6959de68ded2c5679f8"
integrity sha512-U9dKi10V9w/BdIVB8a8dTKYLK3Q1d2WZ+Yo5qfM3XX/O4jI7KpnwgvWgGoVv0jTWPC2NlebF00ffWS/8NfUAtA==
electron-rebuild@^3.2.7:
version "3.2.7"
resolved "https://registry.yarnpkg.com/electron-rebuild/-/electron-rebuild-3.2.7.tgz#0f56c1cc99a6fec0a5b990532283c2a8c838c19b"
integrity sha512-WvaW1EgRinDQ61khHFZfx30rkPQG5ItaOT0wrI7iJv9A3SbghriQGfZQfHZs25fWLBe6/vkv05LOqg6aDw6Wzw==
dependencies:
"@malept/cross-spawn-promise" "^2.0.0"
colors "^1.3.3"
chalk "^4.0.0"
debug "^4.1.1"
detect-libc "^1.0.3"
fs-extra "^10.0.0"
got "^11.7.0"
lzma-native "^8.0.1"
lzma-native "^8.0.5"
node-abi "^3.0.0"
node-api-version "^0.1.4"
node-gyp "^8.4.0"
@ -5823,10 +5892,10 @@ electron-window-state@^5.0.3:
jsonfile "^4.0.0"
mkdirp "^0.5.1"
electron@^15.3.4:
version "15.3.4"
resolved "https://registry.yarnpkg.com/electron/-/electron-15.3.4.tgz#811e8872f4500b88ad49e005cbe8f93e10676f6d"
integrity sha512-GLTE+UEKw1pJehkgpLgXtsHhYqSPp6skSNY1bxnY3dDYBrsPlP3nTEO9YQY2p4eHk+uxFVTXOVy5afcu9fIZ9A==
electron@^15.3.6:
version "15.3.6"
resolved "https://registry.yarnpkg.com/electron/-/electron-15.3.6.tgz#19b9aee1e063b1983b3d7f535567d90e0e1b4d04"
integrity sha512-mOOTcZH/Vlq9GP3B8G3aMvZQ4eZyCjUZZpLccABqsPyLUMEixcdx750DQ7M+iHYyo0BWxj/JuHblzQXgNnPkfg==
dependencies:
"@electron/get" "^1.13.0"
"@types/node" "^14.6.2"
@ -6157,10 +6226,10 @@ eslint-plugin-standard@^4.1.0:
resolved "https://registry.yarnpkg.com/eslint-plugin-standard/-/eslint-plugin-standard-4.1.0.tgz#0c3bf3a67e853f8bbbc580fb4945fbf16f41b7c5"
integrity sha512-ZL7+QRixjTR6/528YNGyDotyffm5OQst/sGxKDwGb9Uqs4In5Egi4+jbobhqJoyoCM6/7v/1A5fhQ7ScMtDjaQ==
eslint-plugin-vue@^8.2.0:
version "8.2.0"
resolved "https://registry.yarnpkg.com/eslint-plugin-vue/-/eslint-plugin-vue-8.2.0.tgz#b404bc10e3f43b2b7aad4ebb3b38090a58040202"
integrity sha512-cLIdTuOAMXyHeQ4drYKcZfoyzdwdBpH279X8/N0DgmotEI9yFKb5O/cAgoie/CkQZCH/MOmh0xw/KEfS90zY2A==
eslint-plugin-vue@^8.4.0:
version "8.4.0"
resolved "https://registry.yarnpkg.com/eslint-plugin-vue/-/eslint-plugin-vue-8.4.0.tgz#16e59b356386b4428fb7d886b6d8ee5df2bbc09d"
integrity sha512-Ga96QRG8GA9AyzKtEDxqYRCMt/VJM4SLkcNmm4FvUiFBE4jpaBr25unRBi9iVmHLYhA9EZ/4I+jD8n1vfWzyAA==
dependencies:
eslint-utils "^3.0.0"
natural-compare "^1.4.0"
@ -6678,6 +6747,14 @@ finalhandler@1.1.2, finalhandler@~1.1.2:
statuses "~1.5.0"
unpipe "~1.0.0"
find-babel-config@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/find-babel-config/-/find-babel-config-1.2.0.tgz#a9b7b317eb5b9860cda9d54740a8c8337a2283a2"
integrity sha512-jB2CHJeqy6a820ssiqwrKMeyC6nNdmrcgkKWJWmpoxpE8RKciYJXCcXRq1h2AzCo5I5BJeN2tkGEO3hLTuePRA==
dependencies:
json5 "^0.5.1"
path-exists "^3.0.0"
find-cache-dir@^2.0.0:
version "2.1.0"
resolved "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz#8d0f94cd13fe43c6c7c261a0d86115ca918c05f7"
@ -6763,10 +6840,10 @@ follow-redirects@^1.0.0:
dependencies:
debug "^3.0.0"
follow-redirects@^1.14.4:
version "1.14.5"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.5.tgz#f09a5848981d3c772b5392309778523f8d85c381"
integrity sha512-wtphSXy7d4/OR+MvIFbCVBDzZ5520qV8XfPklSN5QtxuMUJZ+b0Wnst1e1lCDocfzuCkHqj8k0FpZqO+UIaKNA==
follow-redirects@^1.14.7:
version "1.14.7"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.7.tgz#2004c02eb9436eee9a21446a6477debf17e81685"
integrity sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ==
fontmanager-redux@^1.1.0:
version "1.1.0"
@ -8200,10 +8277,10 @@ isexe@^2.0.0:
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=
iso-639-1@^2.1.11:
version "2.1.11"
resolved "https://registry.yarnpkg.com/iso-639-1/-/iso-639-1-2.1.11.tgz#a928a7c71025321258bd46e03ae85e49ded5dbdc"
integrity sha512-WDF2XWfw1GuPvjn3YEn1+gFGF+72ZltVcjNhaWwmgvveN+rTy3XzWYwgIp/Y8CSZYclNvJ4Vqeh5byubiXCzPw==
iso-639-1@^2.1.12:
version "2.1.12"
resolved "https://registry.yarnpkg.com/iso-639-1/-/iso-639-1-2.1.12.tgz#3893075f50506e98e6243398a5d83ea0f6355524"
integrity sha512-XuThg6XyPBj4RpXtsLbgbJPww6cQeSoiVQWJprM72f1ZTEV/1oeTMzU+dUY+SMPkHfIM5CfaliR4veTVtdXRKg==
isobject@^2.0.0, isobject@^2.1.0:
version "2.1.0"
@ -8460,6 +8537,11 @@ json-stringify-safe@^5.0.1:
resolved "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=
json5@^0.5.1:
version "0.5.1"
resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821"
integrity sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=
json5@^1.0.1:
version "1.0.1"
resolved "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe"
@ -8551,12 +8633,12 @@ karma-sourcemap-loader@^0.3.8:
dependencies:
graceful-fs "^4.1.2"
karma-spec-reporter@0.0.32:
version "0.0.32"
resolved "https://registry.npmjs.org/karma-spec-reporter/-/karma-spec-reporter-0.0.32.tgz#2e9c7207ea726771260259f82becb543209e440a"
integrity sha1-LpxyB+pyZ3EmAln4K+y1QyCeRAo=
karma-spec-reporter@0.0.33:
version "0.0.33"
resolved "https://registry.yarnpkg.com/karma-spec-reporter/-/karma-spec-reporter-0.0.33.tgz#5b2712c3eaff7ae50dbd6ad4e5fb59befd740a96"
integrity sha512-xRVevDUkiIVhKbDQ3CmeGEpyzA4b3HeVl95Sx5yJAvurpdKUSYF6ZEbQOqKJ7vrtDniABV1hyFez9KX9+7ruBA==
dependencies:
colors "^1.1.2"
colors "1.4.0"
karma-webpack@^5.0.0:
version "5.0.0"
@ -8567,10 +8649,10 @@ karma-webpack@^5.0.0:
minimatch "^3.0.4"
webpack-merge "^4.1.5"
karma@^6.3.11:
version "6.3.11"
resolved "https://registry.npmjs.org/karma/-/karma-6.3.11.tgz#2c2fb09f1a9f52e1a0739adeedace2a68d4c0d34"
integrity sha512-QGUh4yXgizzDNPLB5nWTvP+wysKexngbyLVWFOyikB661hpa2RZLf5anZQzqliWtAQuYVep0ot0D1U7UQKpsxQ==
karma@^6.3.12:
version "6.3.12"
resolved "https://registry.yarnpkg.com/karma/-/karma-6.3.12.tgz#fe6347f027385fc16da1a9bb87d766e2d25981c6"
integrity sha512-qwIG+oB2YmHx4hjvYSRMNzL3YWAJ9baHaLAxiP7biFNkfpwYTUTtPck0joFpucalNLzMr+7z/FX1uY/kl8DV9A==
dependencies:
body-parser "^1.19.0"
braces "^3.0.2"
@ -8611,11 +8693,6 @@ keyboard-layout@^2.0.17:
event-kit "^2.0.0"
nan "^2.13.2"
keyboardevents-areequal@^0.2.1:
version "0.2.2"
resolved "https://registry.npmjs.org/keyboardevents-areequal/-/keyboardevents-areequal-0.2.2.tgz#88191ec738ce9f7591c25e9056de928b40277194"
integrity sha512-Nv+Kr33T0mEjxR500q+I6IWisOQ0lK1GGOncV0kWE6n4KFmpcu7RUX5/2B0EUtX51Cb0HjZ9VJsSY3u4cBa0kw==
keypress@0.1.x:
version "0.1.0"
resolved "https://registry.npmjs.org/keypress/-/keypress-0.1.0.tgz#4a3188d4291b66b4f65edb99f806aa9ae293592a"
@ -8944,6 +9021,13 @@ longest@^1.0.1:
resolved "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097"
integrity sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=
loupe@^2.3.1:
version "2.3.1"
resolved "https://registry.yarnpkg.com/loupe/-/loupe-2.3.1.tgz#a2e1192c9f452e4e85089766da10ac8288383947"
integrity sha512-EN1D3jyVmaX4tnajVlfbREU4axL647hLec1h/PXAb8CPDMJiYitcWF2UeLVNttRqaIqQs4x+mRvXf+d+TlDrCA==
dependencies:
get-func-name "^2.0.0"
lower-case-first@^1.0.0:
version "1.0.2"
resolved "https://registry.npmjs.org/lower-case-first/-/lower-case-first-1.0.2.tgz#e5da7c26f29a7073be02d52bac9980e5922adfa1"
@ -8995,10 +9079,10 @@ lru-cache@^6.0.0:
dependencies:
yallist "^4.0.0"
lzma-native@^8.0.1:
version "8.0.1"
resolved "https://registry.yarnpkg.com/lzma-native/-/lzma-native-8.0.1.tgz#8569e2f88de461a9a2469ac9d8183637c387d682"
integrity sha512-Ryr9X3yDVZhRYOxR8QhUBCNe6GdEfy9BvFDIFtUvEkocvSvnrYt9lRm6FR1z0eQn0QSMenrgrDIJRMgUf9zsKQ==
lzma-native@^8.0.5:
version "8.0.6"
resolved "https://registry.yarnpkg.com/lzma-native/-/lzma-native-8.0.6.tgz#3ea456209d643bafd9b5d911781bdf0b396b2665"
integrity sha512-09xfg67mkL2Lz20PrrDeNYZxzeW7ADtpYFbwSQh9U8+76RIzx5QsJBMy8qikv3hbUPfpy6hqwxt6FcGK81g9AA==
dependencies:
node-addon-api "^3.1.0"
node-gyp-build "^4.2.1"
@ -9240,10 +9324,10 @@ mimic-response@^3.1.0:
resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9"
integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==
mini-css-extract-plugin@^2.5.1:
version "2.5.1"
resolved "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.5.1.tgz#af8c7c40d08251f165ac3e046a5cae9d2c1a58c8"
integrity sha512-CRC6E2yedNjfOA3nQjpqAkpnranxhxmilhBPYtldnXcPT/QZb3aJFzvt0pp8W1jhuLR/E0zDa+QEHuC/HhhaLQ==
mini-css-extract-plugin@^2.5.3:
version "2.5.3"
resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-2.5.3.tgz#c5c79f9b22ce9b4f164e9492267358dbe35376d9"
integrity sha512-YseMB8cs8U/KCaAGQoqYmfUuhhGW0a9p9XvWXrxVOkE3/IiISTLw4ALNt7JR5B2eYauFM+PQGSbXMDmVbR7Tfw==
dependencies:
schema-utils "^4.0.0"
@ -9310,7 +9394,7 @@ minipass@^3.0.0, minipass@^3.1.0, minipass@^3.1.1, minipass@^3.1.3:
dependencies:
yallist "^4.0.0"
minizlib@^2.0.0, minizlib@^2.1.1:
minizlib@^2.0.0, minizlib@^2.1.1, minizlib@^2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931"
integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==
@ -9466,6 +9550,11 @@ napi-build-utils@^1.0.1:
resolved "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz#b1fddc0b2c46e380a0b7a76f984dd47c41a13806"
integrity sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==
native-keymap@^3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/native-keymap/-/native-keymap-3.1.1.tgz#edecdc763129eb97754c0651e8f7da89a2b78958"
integrity sha512-q6I3VBGW0dMxTvL2gXWkkl8Ofdlt56RxlPL/lknA8HjgXCpZ/esukuZGV+sGS1xif1muTM3gTnv2PGf4SxHovA==
natural-compare@^1.4.0:
version "1.4.0"
resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
@ -10228,10 +10317,10 @@ pkg-up@^3.1.0:
dependencies:
find-up "^3.0.0"
playwright-core@=1.17.2:
version "1.17.2"
resolved "https://registry.npmjs.org/playwright-core/-/playwright-core-1.17.2.tgz#916254fa8fb3eb76c160b5c2e06bc979d6ec2cf8"
integrity sha512-TCYIt2UNHvqGxvD79bBjBv9osDLAH1gn7AZD5kRpMNQJG6BAmJt8B4Ek8fzdKmCQOnHf9ASJmcYRszoIZxcdVA==
playwright-core@=1.18.1:
version "1.18.1"
resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.18.1.tgz#a5cf3f212d10692382e2acd1f7bc8c9ff9bbb849"
integrity sha512-NALGl8R1GHzGLlhUApmpmfh6M1rrrPcDTygWvhTbprxwGB9qd/j9DRwyn4HTQcUB6o0/VOpo46fH9ez3+D/Rog==
dependencies:
commander "^8.2.0"
debug "^4.1.1"
@ -10250,12 +10339,12 @@ playwright-core@=1.17.2:
yauzl "^2.10.0"
yazl "^2.5.1"
playwright@^1.17.2:
version "1.17.2"
resolved "https://registry.npmjs.org/playwright/-/playwright-1.17.2.tgz#918b9a7e43ac8640fa3e2162ce0cb8b395c55fb7"
integrity sha512-u1HZmVoeLCLptNcpuOyp5KfBzsdsLxE9CReK82i/p8j5i7EPqtY3fX77SMHqDGeO7tLBSYk2a6eFDVlQfSSANg==
playwright@^1.18.1:
version "1.18.1"
resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.18.1.tgz#45c2ca6ee25c44e336985de9b51955727b5f17cf"
integrity sha512-8EaX9EtbtAoMq5tnzIsoA3b/V86V/6Mq2skuOU4qEw+5OVxs1lwesDwmjy/RVU1Qfx5UuwSQzhp45wyH22oa+A==
dependencies:
playwright-core "=1.17.2"
playwright-core "=1.18.1"
plist@^3.0.1:
version "3.0.1"
@ -11119,6 +11208,11 @@ requires-port@^1.0.0:
resolved "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=
reselect@^4.0.0:
version "4.1.5"
resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.1.5.tgz#852c361247198da6756d07d9296c2b51eddb79f6"
integrity sha512-uVdlz8J7OO+ASpBYoz1Zypgx0KasCY20H+N8JD13oUMtPvSHQuscrHop4KbXrbsBcdB9Ds7lVK7eRkBIfO43vQ==
resize-observer-polyfill@^1.5.0:
version "1.5.1"
resolved "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464"
@ -11151,7 +11245,7 @@ resolve-url@^0.2.1:
resolved "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=
resolve@^1.1.10:
resolve@^1.1.10, resolve@^1.13.1:
version "1.22.0"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.0.tgz#5e0b8c67c15df57a89bdbabe603a002f21731198"
integrity sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==
@ -11626,10 +11720,10 @@ snabbdom-to-html@^7.0.0:
object-assign "^4.1.0"
parse-sel "^1.0.0"
snabbdom@^3.2.0:
version "3.2.0"
resolved "https://registry.npmjs.org/snabbdom/-/snabbdom-3.2.0.tgz#8ea6b2517739a7d9ca82df3f181d052adf1ca5ad"
integrity sha512-UWyfm8WbaFmbmYLC33pe5fawBfExhynkMDoZqQ8ehlHDwkxrgIOpWhKf5PaacLUW1n+Uwu5N5HND6mESU7cMlw==
snabbdom@^3.3.1:
version "3.3.1"
resolved "https://registry.yarnpkg.com/snabbdom/-/snabbdom-3.3.1.tgz#a2fb9a1c85cc19d6dc11c4c5e4c78cbbbaafff1f"
integrity sha512-FR9u20dCkktPd+qbedqwYNjMXzYhizhqlKTQzYZimLNeCJY0/5qgs0DtLVSmzIEL1bN3Dyb9sQpiHGCxUjyLnQ==
snake-case@^2.1.0:
version "2.1.0"
@ -13343,15 +13437,15 @@ webpack-bundle-analyzer@^4.5.0:
sirv "^1.0.7"
ws "^7.3.1"
webpack-cli@^4.9.1:
version "4.9.1"
resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-4.9.1.tgz#b64be825e2d1b130f285c314caa3b1ba9a4632b3"
integrity sha512-JYRFVuyFpzDxMDB+v/nanUdQYcZtqFPGzmlW4s+UkPMFhSpfRNmf1z4AwYcHJVdvEFAM7FFCQdNTpsBYhDLusQ==
webpack-cli@^4.9.2:
version "4.9.2"
resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-4.9.2.tgz#77c1adaea020c3f9e2db8aad8ea78d235c83659d"
integrity sha512-m3/AACnBBzK/kMTcxWHcZFPrw/eQuY4Df1TxvIWfWM2x7mRqBQCqKEd96oCUa9jkapLBaFfRce33eGDb4Pr7YQ==
dependencies:
"@discoveryjs/json-ext" "^0.5.0"
"@webpack-cli/configtest" "^1.1.0"
"@webpack-cli/info" "^1.4.0"
"@webpack-cli/serve" "^1.6.0"
"@webpack-cli/configtest" "^1.1.1"
"@webpack-cli/info" "^1.4.1"
"@webpack-cli/serve" "^1.6.1"
colorette "^2.0.14"
commander "^7.0.0"
execa "^5.0.0"
@ -13432,15 +13526,15 @@ webpack-merge@^5.7.3, webpack-merge@^5.8.0:
clone-deep "^4.0.1"
wildcard "^2.0.0"
webpack-sources@^3.2.2:
version "3.2.2"
resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.2.tgz#d88e3741833efec57c4c789b6010db9977545260"
integrity sha512-cp5qdmHnu5T8wRg2G3vZZHoJPN14aqQ89SyQ11NpGH5zEMDCclt49rzo+MaRazk7/UeILhAI+/sEtcM+7Fr0nw==
webpack-sources@^3.2.3:
version "3.2.3"
resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde"
integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==
webpack@^5.66.0:
version "5.66.0"
resolved "https://registry.npmjs.org/webpack/-/webpack-5.66.0.tgz#789bf36287f407fc92b3e2d6f978ddff1bfc2dbb"
integrity sha512-NJNtGT7IKpGzdW7Iwpn/09OXz9inIkeIQ/ibY6B+MdV1x6+uReqz/5z1L89ezWnpPDWpXF0TY5PCYKQdWVn8Vg==
webpack@^5.67.0:
version "5.67.0"
resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.67.0.tgz#cb43ca2aad5f7cc81c4cd36b626e6b819805dbfd"
integrity sha512-LjFbfMh89xBDpUMgA1W9Ur6Rn/gnr2Cq1jjHFPo4v6a79/ypznSYbAyPgGhwsxBtMIaEmDD1oJoA7BEYw/Fbrw==
dependencies:
"@types/eslint-scope" "^3.7.0"
"@types/estree" "^0.0.50"
@ -13465,7 +13559,7 @@ webpack@^5.66.0:
tapable "^2.1.1"
terser-webpack-plugin "^5.1.3"
watchpack "^2.3.1"
webpack-sources "^3.2.2"
webpack-sources "^3.2.3"
websocket-driver@>=0.5.1, websocket-driver@^0.7.4:
version "0.7.4"