@webcoder49/code-input 2.5.0 → 2.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +9 -126
  3. package/code-input.css +71 -33
  4. package/code-input.d.ts +135 -59
  5. package/code-input.js +201 -110
  6. package/code-input.min.css +1 -1
  7. package/code-input.min.js +12 -1
  8. package/docs/LICENSE +3 -0
  9. package/docs/LICENSE.CC-BY-SA-4.0 +116 -0
  10. package/docs/LICENSE.CC0-1.0 +30 -0
  11. package/docs/README.md +5 -0
  12. package/docs/_index.md +308 -0
  13. package/docs/i18n/_index.md +52 -0
  14. package/docs/interface/_index.md +3 -0
  15. package/docs/interface/css/_index.md +12 -0
  16. package/docs/interface/forms/_index.md +17 -0
  17. package/docs/interface/js/_index.md +11 -0
  18. package/docs/modules-and-frameworks/_index.md +3 -0
  19. package/docs/modules-and-frameworks/custom/_index.md +9 -0
  20. package/docs/modules-and-frameworks/hljs/_index.md +13 -0
  21. package/docs/modules-and-frameworks/hljs/esm/_index.md +71 -0
  22. package/docs/modules-and-frameworks/hljs/nuxt/_index.md +250 -0
  23. package/docs/modules-and-frameworks/hljs/nuxt/nuxt-demo-screenshot.png +0 -0
  24. package/docs/modules-and-frameworks/hljs/vue/_index.md +233 -0
  25. package/docs/modules-and-frameworks/hljs/vue/vue-demo-screenshot.png +0 -0
  26. package/docs/modules-and-frameworks/prism/_index.md +14 -0
  27. package/docs/plugins/_index.md +676 -0
  28. package/docs/plugins/new/_index.md +52 -0
  29. package/docs/theory/_index.md +9 -0
  30. package/esm/.code-input.mjs.kate-swp +0 -0
  31. package/esm/README.md +23 -0
  32. package/esm/code-input.mjs +2 -0
  33. package/package.json +83 -7
  34. package/plugins/README.md +2 -0
  35. package/plugins/auto-close-brackets.js +25 -7
  36. package/plugins/auto-close-brackets.min.js +1 -1
  37. package/plugins/autocomplete.js +6 -6
  38. package/plugins/autocomplete.min.js +1 -1
  39. package/plugins/autodetect.js +4 -2
  40. package/plugins/autodetect.min.js +1 -1
  41. package/plugins/find-and-replace.css +0 -4
  42. package/plugins/find-and-replace.js +34 -8
  43. package/plugins/find-and-replace.min.css +1 -1
  44. package/plugins/find-and-replace.min.js +1 -1
  45. package/plugins/go-to-line.css +10 -5
  46. package/plugins/go-to-line.js +43 -6
  47. package/plugins/go-to-line.min.css +1 -1
  48. package/plugins/go-to-line.min.js +1 -1
  49. package/plugins/indent.js +29 -4
  50. package/plugins/indent.min.js +1 -1
  51. package/plugins/prism-line-numbers.css +14 -5
  52. package/plugins/prism-line-numbers.min.css +1 -1
  53. package/plugins/select-token-callbacks.js +3 -1
  54. package/plugins/select-token-callbacks.min.js +1 -1
  55. package/plugins/special-chars.css +13 -1
  56. package/plugins/special-chars.js +14 -4
  57. package/plugins/special-chars.min.css +1 -1
  58. package/plugins/special-chars.min.js +1 -1
  59. package/plugins/test.js +22 -7
  60. package/plugins/test.min.js +1 -1
  61. package/.github/workflows/minify.yml +0 -22
  62. package/.github/workflows/npm-publish.yml +0 -21
  63. package/CODE_OF_CONDUCT.md +0 -130
  64. package/CONTRIBUTING.md +0 -35
  65. package/tests/hljs.html +0 -55
  66. package/tests/i18n.html +0 -197
  67. package/tests/prism-match-braces-compatibility.js +0 -215
  68. package/tests/prism-match-braces-compatibility.min.js +0 -1
  69. package/tests/prism.html +0 -54
  70. package/tests/tester.js +0 -593
  71. package/tests/tester.min.js +0 -21
@@ -0,0 +1,52 @@
1
+ +++
2
+ title = 'Creating your own code-input Plugin to add functionality'
3
+ +++
4
+
5
+ # Creating your own code-input Plugin to add functionality
6
+
7
+ If you're writing some code that depends on the code-input editor and isn't very useful independent of it, or integrates other code with code-input, writing a plugin's often the way to go. You can even choose to contribute it back to the code-input library!
8
+
9
+ A very useful source of reference is the code-input.d.ts file in code-input.js' source code, which defines the public JavaScript interface of the code-input.js library including code-input elements.
10
+
11
+ Start with this code, which is also available as the `test` plugin. Afterwards, construct and pass a `new TestPlugin()` into the array when you register a code-input.js template, like any other code-input plugin:
12
+ ```javascript
13
+ const TestPlugin = class extends codeInput.Plugin {
14
+ instructions = {
15
+ beforeHighlight: "before highlight",
16
+ afterHighlight: "after highlight",
17
+ beforeElementsAdded: "before elements added",
18
+ afterElementsAdded: "after elements added",
19
+ attributeChanged: (name, oldValue, newValue) => `${name}: '${oldValue}'>'${newValue}'`
20
+ };
21
+
22
+ constructor(instructionTranslations = {}) {
23
+ super(["testattr"]);
24
+ // Array of observed attributes as parameter
25
+
26
+ // instructionTranslations, instructions, and the addTranslations
27
+ // call need not be present if this plugin uses no localisable
28
+ // text.
29
+ this.addTranslations(this.instructions, instructionTranslations);
30
+ }
31
+ /* Runs before code is highlighted; Params: codeInput element) */
32
+ beforeHighlight(codeInput) {
33
+ console.log(codeInput, this.instructions.beforeHighlight);
34
+ }
35
+ /* Runs after code is highlighted; Params: codeInput element) */
36
+ afterHighlight(codeInput) {
37
+ console.log(codeInput, this.instructions.afterHighlight);
38
+ }
39
+ /* Runs before elements are added into a `code-input`; Params: codeInput element) */
40
+ beforeElementsAdded(codeInput) {
41
+ console.log(codeInput, this.instructions.beforeElementsAdded);
42
+ }
43
+ /* Runs after elements are added into a `code-input` (useful for adding events to the textarea); Params: codeInput element) */
44
+ afterElementsAdded(codeInput) {
45
+ console.log(codeInput, this.instructions.afterElementsAdded);
46
+ }
47
+ /* Runs when an observed attribute of a `code-input` is changed (you must add the attribute name in the constructor); Params: codeInput element, name attribute name, oldValue previous value of attribute, newValue changed value of attribute) */
48
+ attributeChanged(codeInput, name, oldValue, newValue) {
49
+ console.log(codeInput, this.instructions.attriibuteChanged(name, oldValue, newValue));
50
+ }
51
+ };
52
+ ```
@@ -0,0 +1,9 @@
1
+ +++
2
+ title = 'How code-input.js works Behind The Scenes'
3
+ +++
4
+
5
+ # How `code-input.js` works Behind The Scenes
6
+
7
+ > Contributors: 2021 Oliver Geer
8
+
9
+ Bearing in mind that it will teach you to make your own version of the core of <code>code-input.js</code> but you should use the library itself if you want more stability, please see [this CSS-Tricks article](https://css-tricks.com/creating-an-editable-textarea-that-supports-syntax-highlighted-code). It was written by the founder of the library just before development started, so doesn't contain all bugfixes but does contain the core theory and how to create a minimal `code-input` yourself.
Binary file
package/esm/README.md ADDED
@@ -0,0 +1,23 @@
1
+ # Autogenerated ECMAScript Modules
2
+
3
+ ## Using
4
+
5
+ If you are using Yarn, NPM, or a similar package manager, the files should have been generated before being uploaded to the package repository, or on `pack` if the package manager is fetching from Git.
6
+
7
+ Otherwise, after changing directory to the one containing this file:
8
+
9
+ - If you have Node.js installed, run `node generate.mjs`.
10
+ - If you don't have Node.js installed but are on a POSIX-like system with `bash`/`zsh`, run `sh ./generate.sh`.
11
+ - If neither of the above are true, install Node.js or (slightly harder; look online) a POSIX/"Linux" compatible shell.
12
+
13
+ ## Extra Information
14
+
15
+ When code-input was started, it was written and tested only to be imported directly via a `<script>` tag, and it assigned an object to a global `codeInput` variable containing all its functionality. As plugins were added, they were implemented as similar but separate `<script>` tags. However, this limits where `codeInput` can be used, making it difficult to integrate with many larger JavaScript projects and frameworks, and causes code duplication when multiple plugins use the same code.
16
+
17
+ To fix these, code-input is gaining support for ECMAScript Modules (ESM), a standard way to import modules and export from them with JavaScript. ESM can be used directly in NPM/Yarn-led environments, bundled for inclusion in a `<script>` tag in a backwards-compatible way, or imported as a module into a web browser which supports it natively.
18
+
19
+ To ensure backwards compatibility, in the first stage of the transition a process to auto-generate ESM-compatible files from the existing JavaScript files will be created, so existing `<script>` tag users are unaffected.
20
+
21
+ Later in the second stage, `code-input`'s daily-edited source code may be relocated to ESM, using these generated files, and the direct importable files would be produced by a bundler.
22
+
23
+ However, refactoring the core would need quite a lot of work and testing, and the first stage suffices for compatibility with all the examples. This directory will exist from the first stage until the second stage, containing the tools to generate ESM files. After the second stage, it would likely be repurposed as the main source code directory, containing the same files which would become the main developed ones.
@@ -0,0 +1,2 @@
1
+ // NOTICE: This code is @generated from code outside the esm directory. Please do not edit it to contribute!
2
+
package/package.json CHANGED
@@ -1,10 +1,84 @@
1
1
  {
2
2
  "name": "@webcoder49/code-input",
3
- "version": "2.5.0",
4
- "description": "Fully customisable, editable syntax-highlighted textareas.",
3
+ "version": "2.6.0",
4
+ "description": "An editable &lt;textarea&gt; that supports *any* syntax highlighting algorithm, for code or something else. Also, added plugins.",
5
5
  "browser": "code-input.js",
6
+ "exports": {
7
+ ".": {
8
+ "import": "./esm/code-input.mjs"
9
+ },
10
+ "./code-input.mjs": {
11
+ "import": "./esm/code-input.mjs"
12
+ },
13
+ "./templates/hljs.mjs": {
14
+ "import": "./esm/templates/hljs.mjs"
15
+ },
16
+ "./templates/prism.mjs": {
17
+ "import": "./esm/templates/prism.mjs"
18
+ },
19
+ "./plugins/auto-close-brackets.mjs": {
20
+ "import": "./esm/plugins/auto-close-brackets.mjs"
21
+ },
22
+ "./plugins/autocomplete.mjs": {
23
+ "import": "./esm/plugins/autocomplete.mjs"
24
+ },
25
+ "./plugins/autodetect.mjs": {
26
+ "import": "./esm/plugins/autodetect.mjs"
27
+ },
28
+ "./plugins/find-and-replace.mjs": {
29
+ "import": "./esm/plugins/find-and-replace.mjs"
30
+ },
31
+ "./plugins/go-to-line.mjs": {
32
+ "import": "./esm/plugins/go-to-line.mjs"
33
+ },
34
+ "./plugins/indent.mjs": {
35
+ "import": "./esm/plugins/indent.mjs"
36
+ },
37
+ "./plugins/select-token-callbacks.mjs": {
38
+ "import": "./esm/plugins/select-token-callbacks.mjs"
39
+ },
40
+ "./plugins/special-chars.mjs": {
41
+ "import": "./esm/plugins/special-chars.mjs"
42
+ },
43
+ "./plugins/test.mjs": {
44
+ "import": "./esm/plugins/test.mjs"
45
+ },
46
+ "./code-input.js": "./code-input.js",
47
+ "./plugins/auto-close-brackets.js": "./plugins/auto-close-brackets.js",
48
+ "./plugins/autocomplete.js": "./plugins/autocomplete.js",
49
+ "./plugins/autodetect.js": "./plugins/autodetect.js",
50
+ "./plugins/find-and-replace.js": "./plugins/find-and-replace.js",
51
+ "./plugins/go-to-line.js": "./plugins/go-to-line.js",
52
+ "./plugins/indent.js": "./plugins/indent.js",
53
+ "./plugins/select-token-callbacks.js": "./plugins/select-token-callbacks.js",
54
+ "./plugins/special-chars.js": "./plugins/special-chars.js",
55
+ "./plugins/test.js": "./plugins/test.js",
56
+ "./code-input.min.js": "./code-input.min.js",
57
+ "./plugins/auto-close-brackets.min.js": "./plugins/auto-close-brackets.min.js",
58
+ "./plugins/autocomplete.min.js": "./plugins/autocomplete.min.js",
59
+ "./plugins/autodetect.min.js": "./plugins/autodetect.min.js",
60
+ "./plugins/find-and-replace.min.js": "./plugins/find-and-replace.min.js",
61
+ "./plugins/go-to-line.min.js": "./plugins/go-to-line.min.js",
62
+ "./plugins/indent.min.js": "./plugins/indent.min.js",
63
+ "./plugins/select-token-callbacks.min.js": "./plugins/select-token-callbacks.min.js",
64
+ "./plugins/special-chars.min.js": "./plugins/special-chars.min.js",
65
+ "./plugins/test.min.js": "./plugins/test.min.js",
66
+ "./code-input.css": "./code-input.css",
67
+ "./plugins/autocomplete.css": "./plugins/autocomplete.css",
68
+ "./plugins/find-and-replace.css": "./plugins/find-and-replace.css",
69
+ "./plugins/go-to-line.css": "./plugins/go-to-line.css",
70
+ "./plugins/prism-line-numbers.css": "./plugins/prism-line-numbers.css",
71
+ "./plugins/special-chars.css": "./plugins/special-chars.css",
72
+ "./code-input.min.css": "./code-input.min.css",
73
+ "./plugins/autocomplete.min.css": "./plugins/autocomplete.min.css",
74
+ "./plugins/find-and-replace.min.css": "./plugins/find-and-replace.min.css",
75
+ "./plugins/go-to-line.min.css": "./plugins/go-to-line.min.css",
76
+ "./plugins/prism-line-numbers.min.css": "./plugins/prism-line-numbers.min.css",
77
+ "./plugins/special-chars.min.css": "./plugins/special-chars.min.css"
78
+ },
6
79
  "scripts": {
7
- "test": "echo \"This is a front-end library, not a Node library. Please see the README for how to use.\" && exit 1"
80
+ "test": "echo \"This is a front-end library, not a Node library. Please see https://code-input-js.org for how to use.\" && exit 1",
81
+ "prepack": "cd esm ; node generate.mjs ; cd .."
8
82
  },
9
83
  "repository": {
10
84
  "type": "git",
@@ -16,16 +90,18 @@
16
90
  "highlight",
17
91
  "textarea",
18
92
  "editable",
19
- "web-components"
93
+ "web-components",
94
+ "code-editor",
95
+ "text-editor"
20
96
  ],
21
97
  "author": {
22
- "name": "WebCoder49",
98
+ "name": "Oliver Geer and contributors",
23
99
  "email": "hi@webcoder49.dev",
24
- "url": "https://webcoder49.dev/"
100
+ "url": "https://oliver.geer.im/"
25
101
  },
26
102
  "license": "MIT",
27
103
  "bugs": {
28
104
  "url": "https://github.com/WebCoder49/code-input/issues"
29
105
  },
30
- "homepage": "https://github.com/WebCoder49/code-input#readme"
106
+ "homepage": "https://code-input-js.org/"
31
107
  }
package/plugins/README.md CHANGED
@@ -61,6 +61,8 @@ Files: [prism-line-numbers.css](./prism-line-numbers.css) (NO JS FILE)
61
61
  Render special characters and control characters as a symbol
62
62
  with their hex code.
63
63
 
64
+ **Please note: This plugin is known to contain bugs, especially when used with highlight.js and/or other plugins. Please bear this in mind and look at the Issues if you want more details; fixes for the bugs are planned but not prioritised as much as those used in more common plugins or the core library.**
65
+
64
66
  Files: [special-chars.js](./special-chars.js) / [special-chars.css](./special-chars.css)
65
67
 
66
68
  [🚀 *CodePen Demo*](https://codepen.io/WebCoder49/pen/jOeYJbm)
@@ -3,6 +3,8 @@
3
3
  * is activated for.
4
4
  * Files: auto-close-brackets.js
5
5
  */
6
+ "use strict";
7
+
6
8
  codeInput.plugins.AutoCloseBrackets = class extends codeInput.Plugin {
7
9
  bracketPairs = [];
8
10
  bracketsOpenedStack = []; // Each item [closing bracket string, opening bracket location] Innermost at right so can know which brackets should be ignored when retyped
@@ -19,13 +21,17 @@ codeInput.plugins.AutoCloseBrackets = class extends codeInput.Plugin {
19
21
 
20
22
  /* Add keystroke events */
21
23
  afterElementsAdded(codeInput) {
22
- codeInput.textareaElement.addEventListener('keydown', (event) => { this.checkBackspace(codeInput, event) });
23
- codeInput.textareaElement.addEventListener('beforeinput', (event) => { this.checkBrackets(codeInput, event); });
24
+ codeInput.pluginData.autoCloseBrackets = { automatedKeypresses: false};
25
+ codeInput.textareaElement.addEventListener('keydown', (event) => { this.checkBackspace(codeInput, event); });
26
+ codeInput.textareaElement.addEventListener('beforeinput', (event) => { this.checkClosingBracket(codeInput, event); });
27
+ codeInput.textareaElement.addEventListener('input', (event) => { this.checkOpeningBracket(codeInput, event); });
24
28
  }
25
29
 
26
- /* Deal with the automatic creation of closing bracket when opening brackets are typed, and the ability to "retype" a closing
27
- bracket where one has already been placed. */
28
- checkBrackets(codeInput, event) {
30
+ /* Deal with the ability to "retype" a closing bracket where one has already
31
+ been placed. Runs before input so newly typing a closing bracket can be
32
+ prevented.*/
33
+ checkClosingBracket(codeInput, event) {
34
+ if(codeInput.pluginData.autoCloseBrackets.automatedKeypresses) return;
29
35
  if(event.data == codeInput.textareaElement.value[codeInput.textareaElement.selectionStart]) {
30
36
  // Check if a closing bracket is typed
31
37
  for(let openingBracket in this.bracketPairs) {
@@ -37,11 +43,22 @@ codeInput.plugins.AutoCloseBrackets = class extends codeInput.Plugin {
37
43
  break;
38
44
  }
39
45
  }
40
- } else if(event.data in this.bracketPairs) {
46
+ }
47
+ }
48
+
49
+ /* Deal with the automatic creation of closing bracket when opening brackets are typed. Runs after input for consistency between browsers. */
50
+ checkOpeningBracket(codeInput, event) {
51
+ if(codeInput.pluginData.autoCloseBrackets.automatedKeypresses) return;
52
+ if(event.data in this.bracketPairs) {
41
53
  // Opening bracket typed; Create bracket pair
42
54
  let closingBracket = this.bracketPairs[event.data];
43
55
  // Insert the closing bracket
56
+ // automatedKeypresses property to prevent keypresses being captured
57
+ // by this plugin during automated input as some browsers
58
+ // (e.g. GNOME Web) do.
59
+ codeInput.pluginData.autoCloseBrackets.automatedKeypresses = true;
44
60
  document.execCommand("insertText", false, closingBracket);
61
+ codeInput.pluginData.autoCloseBrackets.automatedKeypresses = false;
45
62
  // Move caret before the inserted closing bracket
46
63
  codeInput.textareaElement.selectionStart = codeInput.textareaElement.selectionEnd -= 1;
47
64
  }
@@ -49,6 +66,7 @@ codeInput.plugins.AutoCloseBrackets = class extends codeInput.Plugin {
49
66
 
50
67
  /* Deal with cases where a backspace deleting an opening bracket deletes the closing bracket straight after it as well */
51
68
  checkBackspace(codeInput, event) {
69
+ if(codeInput.pluginData.autoCloseBrackets.automatedKeypresses) return;
52
70
  if(event.key == "Backspace" && codeInput.textareaElement.selectionStart == codeInput.textareaElement.selectionEnd) {
53
71
  let closingBracket = this.bracketPairs[codeInput.textareaElement.value[codeInput.textareaElement.selectionStart-1]];
54
72
  if(closingBracket != undefined && codeInput.textareaElement.value[codeInput.textareaElement.selectionStart] == closingBracket) {
@@ -58,4 +76,4 @@ codeInput.plugins.AutoCloseBrackets = class extends codeInput.Plugin {
58
76
  }
59
77
  }
60
78
  }
61
- }
79
+ }
@@ -1 +1 @@
1
- codeInput.plugins.AutoCloseBrackets=class extends codeInput.Plugin{bracketPairs=[];bracketsOpenedStack=[];constructor(a={"(":")","[":"]","{":"}",'"':"\""}){super([]),this.bracketPairs=a}afterElementsAdded(a){a.textareaElement.addEventListener("keydown",b=>{this.checkBackspace(a,b)}),a.textareaElement.addEventListener("beforeinput",b=>{this.checkBrackets(a,b)})}checkBrackets(a,b){if(b.data==a.textareaElement.value[a.textareaElement.selectionStart])for(let c in this.bracketPairs){let d=this.bracketPairs[c];if(b.data==d){a.textareaElement.selectionStart=a.textareaElement.selectionEnd+=1,b.preventDefault();break}}else if(b.data in this.bracketPairs){let c=this.bracketPairs[b.data];document.execCommand("insertText",!1,c),a.textareaElement.selectionStart=a.textareaElement.selectionEnd-=1}}checkBackspace(a,b){if("Backspace"==b.key&&a.textareaElement.selectionStart==a.textareaElement.selectionEnd){let b=this.bracketPairs[a.textareaElement.value[a.textareaElement.selectionStart-1]];b!=null&&a.textareaElement.value[a.textareaElement.selectionStart]==b&&(a.textareaElement.selectionEnd=a.textareaElement.selectionStart+1,a.textareaElement.selectionStart-=1)}}};
1
+ "use strict";codeInput.plugins.AutoCloseBrackets=class extends codeInput.Plugin{bracketPairs=[];bracketsOpenedStack=[];constructor(a={"(":")","[":"]","{":"}",'"':"\""}){super([]),this.bracketPairs=a}afterElementsAdded(a){a.pluginData.autoCloseBrackets={automatedKeypresses:!1},a.textareaElement.addEventListener("keydown",b=>{this.checkBackspace(a,b)}),a.textareaElement.addEventListener("beforeinput",b=>{this.checkClosingBracket(a,b)}),a.textareaElement.addEventListener("input",b=>{this.checkOpeningBracket(a,b)})}checkClosingBracket(a,b){if(!a.pluginData.autoCloseBrackets.automatedKeypresses&&b.data==a.textareaElement.value[a.textareaElement.selectionStart])for(let c in this.bracketPairs){let d=this.bracketPairs[c];if(b.data==d){a.textareaElement.selectionStart=a.textareaElement.selectionEnd+=1,b.preventDefault();break}}}checkOpeningBracket(a,b){if(!a.pluginData.autoCloseBrackets.automatedKeypresses&&b.data in this.bracketPairs){let c=this.bracketPairs[b.data];a.pluginData.autoCloseBrackets.automatedKeypresses=!0,document.execCommand("insertText",!1,c),a.pluginData.autoCloseBrackets.automatedKeypresses=!1,a.textareaElement.selectionStart=a.textareaElement.selectionEnd-=1}}checkBackspace(a,b){if(!a.pluginData.autoCloseBrackets.automatedKeypresses&&"Backspace"==b.key&&a.textareaElement.selectionStart==a.textareaElement.selectionEnd){let b=this.bracketPairs[a.textareaElement.value[a.textareaElement.selectionStart-1]];null!=b&&a.textareaElement.value[a.textareaElement.selectionStart]==b&&(a.textareaElement.selectionEnd=a.textareaElement.selectionStart+1,a.textareaElement.selectionStart-=1)}}};
@@ -2,6 +2,8 @@
2
2
  * Display a popup under the caret using the text in the code-input element. This works well with autocomplete suggestions.
3
3
  * Files: autocomplete.js / autocomplete.css
4
4
  */
5
+ "use strict";
6
+
5
7
  codeInput.plugins.Autocomplete = class extends codeInput.Plugin {
6
8
  /**
7
9
  * Pass in a function to create a plugin that displays the popup that takes in (popup element, textarea, textarea.selectionEnd).
@@ -20,7 +22,7 @@ codeInput.plugins.Autocomplete = class extends codeInput.Plugin {
20
22
  popupElem.style.left = caretCoords.left + "px";
21
23
 
22
24
  if(!onlyScrolled) {
23
- this.updatePopupCallback(popupElem, textarea, textarea.selectionEnd);
25
+ this.updatePopupCallback(popupElem, textarea, textarea.selectionEnd, textarea.selectionStart);
24
26
  }
25
27
  }
26
28
  /* Create the popup element */
@@ -30,10 +32,8 @@ codeInput.plugins.Autocomplete = class extends codeInput.Plugin {
30
32
  codeInput.appendChild(popupElem);
31
33
 
32
34
  let testPosPre = document.createElement("pre");
33
- popupElem.setAttribute("inert", true); // Invisible to keyboard navigation
34
- popupElem.setAttribute("tabindex", -1); // Invisible to keyboard navigation
35
35
  testPosPre.setAttribute("aria-hidden", true); // Hide for screen readers
36
- if(codeInput.template.preElementStyled) {
36
+ if(codeInput.templateObject.preElementStyled) {
37
37
  testPosPre.classList.add("code-input_autocomplete_testpos");
38
38
  codeInput.appendChild(testPosPre); // Styled like first pre, but first pre found to update
39
39
  } else {
@@ -45,7 +45,7 @@ codeInput.plugins.Autocomplete = class extends codeInput.Plugin {
45
45
 
46
46
  let textarea = codeInput.textareaElement;
47
47
  textarea.addEventListener("input", () => { this.updatePopup(codeInput, false)});
48
- textarea.addEventListener("click", () => { this.updatePopup(codeInput, false)});
48
+ textarea.addEventListener("selectionchange", () => { this.updatePopup(codeInput, false)});
49
49
  }
50
50
  /**
51
51
  * Return the coordinates of the caret in a code-input
@@ -85,4 +85,4 @@ codeInput.plugins.Autocomplete = class extends codeInput.Plugin {
85
85
  return {"top": afterSpan.offsetTop - textarea.scrollTop, "left": afterSpan.offsetLeft - textarea.scrollLeft};
86
86
  }
87
87
  updatePopupCallback = function() {};
88
- }
88
+ }
@@ -1 +1 @@
1
- codeInput.plugins.Autocomplete=class extends codeInput.Plugin{constructor(a){super([]),this.updatePopupCallback=a}updatePopup(a,b){let c=a.textareaElement,d=this.getCaretCoordinates(a,c,c.selectionEnd,b),e=a.querySelector(".code-input_autocomplete_popup");e.style.top=d.top+"px",e.style.left=d.left+"px",b||this.updatePopupCallback(e,c,c.selectionEnd)}afterElementsAdded(a){let b=document.createElement("div");b.classList.add("code-input_autocomplete_popup"),a.appendChild(b);let c=document.createElement("pre");if(b.setAttribute("inert",!0),b.setAttribute("tabindex",-1),c.setAttribute("aria-hidden",!0),a.template.preElementStyled)c.classList.add("code-input_autocomplete_testpos"),a.appendChild(c);else{let b=document.createElement("code");b.classList.add("code-input_autocomplete_testpos"),c.appendChild(b),a.appendChild(c)}let d=a.textareaElement;d.addEventListener("input",()=>{this.updatePopup(a,!1)}),d.addEventListener("click",()=>{this.updatePopup(a,!1)})}getCaretCoordinates(a,b,c,d){let e;if(d){let d=a.querySelector(".code-input_autocomplete_testpos").querySelectorAll("span");if(2>d.length)return this.getCaretCoordinates(a,b,c,!1);e=d[1]}else{let d=a.querySelector(".code-input_autocomplete_testpos"),f=document.createElement("span");for(f.textContent=b.value.substring(0,c),e=document.createElement("span"),e.textContent=".";d.firstChild;)d.removeChild(d.firstChild);d.appendChild(f),d.appendChild(e)}return{top:e.offsetTop-b.scrollTop,left:e.offsetLeft-b.scrollLeft}}updatePopupCallback=function(){}};
1
+ "use strict";codeInput.plugins.Autocomplete=class extends codeInput.Plugin{constructor(a){super([]),this.updatePopupCallback=a}updatePopup(a,b){let c=a.textareaElement,d=this.getCaretCoordinates(a,c,c.selectionEnd,b),e=a.querySelector(".code-input_autocomplete_popup");e.style.top=d.top+"px",e.style.left=d.left+"px",b||this.updatePopupCallback(e,c,c.selectionEnd,c.selectionStart)}afterElementsAdded(a){let b=document.createElement("div");b.classList.add("code-input_autocomplete_popup"),a.appendChild(b);let c=document.createElement("pre");if(c.setAttribute("aria-hidden",!0),a.templateObject.preElementStyled)c.classList.add("code-input_autocomplete_testpos"),a.appendChild(c);else{let b=document.createElement("code");b.classList.add("code-input_autocomplete_testpos"),c.appendChild(b),a.appendChild(c)}let d=a.textareaElement;d.addEventListener("input",()=>{this.updatePopup(a,!1)}),d.addEventListener("selectionchange",()=>{this.updatePopup(a,!1)})}getCaretCoordinates(a,b,c,d){let e;if(d){let d=a.querySelector(".code-input_autocomplete_testpos").querySelectorAll("span");if(2>d.length)return this.getCaretCoordinates(a,b,c,!1);e=d[1]}else{let d=a.querySelector(".code-input_autocomplete_testpos"),f=document.createElement("span");for(f.textContent=b.value.substring(0,c),e=document.createElement("span"),e.textContent=".";d.firstChild;)d.removeChild(d.firstChild);d.appendChild(f),d.appendChild(e)}return{top:e.offsetTop-b.scrollTop,left:e.offsetLeft-b.scrollLeft}}updatePopupCallback=function(){}};
@@ -3,6 +3,8 @@
3
3
  * autodetect capabilities. Works with highlight.js only.
4
4
  * Files: autodetect.js
5
5
  */
6
+ "use strict";
7
+
6
8
  codeInput.plugins.Autodetect = class extends codeInput.Plugin {
7
9
  constructor() {
8
10
  super([]); // No observed attributes
@@ -17,7 +19,7 @@ codeInput.plugins.Autodetect = class extends codeInput.Plugin {
17
19
  afterHighlight(codeInput) {
18
20
  let langClass = codeInput.codeElement.className || codeInput.preElement.className;
19
21
  let lang = langClass.match(/lang(\w|-)*/i)[0]; // Get word starting with lang...; Get outer bracket
20
- lang = lang.split("-")[1];
22
+ lang = lang.match(/(?<=-)(\w|-)*/i)[0];
21
23
  if(lang == "undefined") {
22
24
  codeInput.removeAttribute("language");
23
25
  codeInput.removeAttribute("lang");
@@ -25,4 +27,4 @@ codeInput.plugins.Autodetect = class extends codeInput.Plugin {
25
27
  codeInput.setAttribute("language", lang);
26
28
  }
27
29
  }
28
- }
30
+ }
@@ -1 +1 @@
1
- codeInput.plugins.Autodetect=class extends codeInput.Plugin{constructor(){super([])}beforeHighlight(a){let b=a.codeElement;b.className="",b.parentElement.className=""}afterHighlight(a){let b=a.codeElement.className||a.preElement.className,c=b.match(/lang(\w|-)*/i)[0];c=c.split("-")[1],"undefined"==c?(a.removeAttribute("language"),a.removeAttribute("lang")):a.setAttribute("language",c)}};
1
+ "use strict";codeInput.plugins.Autodetect=class extends codeInput.Plugin{constructor(){super([])}beforeHighlight(a){let b=a.codeElement;b.className="",b.parentElement.className=""}afterHighlight(a){let b=a.codeElement.className||a.preElement.className,c=b.match(/lang(\w|-)*/i)[0];c=c.match(/(?<=-)(\w|-)*/i)[0],"undefined"==c?(a.removeAttribute("language"),a.removeAttribute("lang")):a.setAttribute("language",c)}};
@@ -60,10 +60,6 @@
60
60
  border: 0;
61
61
  }
62
62
 
63
- .code-input_find-and-replace_dialog input:hover {
64
- outline: none;
65
- }
66
-
67
63
  .code-input_find-and-replace_dialog input.code-input_find-and-replace_error {
68
64
  color: #ff0000aa;
69
65
  }
@@ -2,6 +2,8 @@
2
2
  * Add Find-and-Replace (Ctrl+F for find, Ctrl+H for replace by default) functionality to the code editor.
3
3
  * Files: find-and-replace.js / find-and-replace.css
4
4
  */
5
+ "use strict";
6
+
5
7
  codeInput.plugins.FindAndReplace = class extends codeInput.Plugin {
6
8
  useCtrlF = false;
7
9
  useCtrlH = false;
@@ -31,8 +33,8 @@ codeInput.plugins.FindAndReplace = class extends codeInput.Plugin {
31
33
 
32
34
  /**
33
35
  * Create a find-and-replace command plugin to pass into a template
34
- * @param {boolean} useCtrlF Should Ctrl+F be overriden for find-and-replace find functionality? If not, you can trigger it yourself using (instance of this plugin)`.showPrompt(code-input element, false)`.
35
- * @param {boolean} useCtrlH Should Ctrl+H be overriden for find-and-replace replace functionality? If not, you can trigger it yourself using (instance of this plugin)`.showPrompt(code-input element, true)`.
36
+ * @param {boolean} useCtrlF Should Ctrl+F be overriden for find-and-replace find functionality? Either way, you can also trigger it yourself using (instance of this plugin)`.showPrompt(code-input element, false)`.
37
+ * @param {boolean} useCtrlH Should Ctrl+H be overriden for find-and-replace replace functionality? Either way, you can also trigger it yourself using (instance of this plugin)`.showPrompt(code-input element, true)`.
36
38
  * @param {Object} instructionTranslations: user interface string keys mapped to translated versions for localisation. Look at the find-and-replace.js source code for the English text and available keys.
37
39
  */
38
40
  constructor(useCtrlF = true, useCtrlH = true, instructionTranslations = {}) {
@@ -192,6 +194,7 @@ codeInput.plugins.FindAndReplace = class extends codeInput.Plugin {
192
194
  const findInput = document.createElement('input');
193
195
  const findCaseSensitiveCheckbox = document.createElement('input');
194
196
  const findRegExpCheckbox = document.createElement('input');
197
+ // TODO in next major version: use more semantic HTML element than code
195
198
  const matchDescription = document.createElement('code');
196
199
  matchDescription.setAttribute("aria-live", "assertive"); // Screen reader must read the number of matches found.
197
200
 
@@ -204,7 +207,11 @@ codeInput.plugins.FindAndReplace = class extends codeInput.Plugin {
204
207
  const findPreviousButton = document.createElement('button');
205
208
  const replaceButton = document.createElement('button');
206
209
  const replaceAllButton = document.createElement('button');
210
+
211
+ // TODO: Make a button element (semantic HTML for accessibility) in next major version
207
212
  const cancel = document.createElement('span');
213
+ cancel.setAttribute("role", "button");
214
+ cancel.setAttribute("aria-label", this.instructions.closeDialog);
208
215
  cancel.setAttribute("tabindex", 0); // Visible to keyboard navigation
209
216
  cancel.setAttribute("title", this.instructions.closeDialog);
210
217
 
@@ -234,7 +241,7 @@ codeInput.plugins.FindAndReplace = class extends codeInput.Plugin {
234
241
  findRegExpCheckbox.title = this.instructions.findRegExp;
235
242
  findRegExpCheckbox.classList.add("code-input_find-and-replace_reg-exp-checkbox");
236
243
 
237
- matchDescription.textContent = "Search for matches in your code.";
244
+ matchDescription.textContent = this.instructions.start;
238
245
  matchDescription.classList.add("code-input_find-and-replace_match-description");
239
246
 
240
247
 
@@ -243,8 +250,10 @@ codeInput.plugins.FindAndReplace = class extends codeInput.Plugin {
243
250
  replaceInput.placeholder = this.instructions.replacePlaceholder;
244
251
  findNextButton.innerText = "↓";
245
252
  findNextButton.title = this.instructions.findNext;
253
+ findNextButton.setAttribute("aria-label", this.instructions.findNext);
246
254
  findPreviousButton.innerText = "↑";
247
255
  findPreviousButton.title = this.instructions.findPrevious;
256
+ findNextButton.setAttribute("aria-label", this.instructions.findPrevious);
248
257
  replaceButton.className = 'code-input_find-and-replace_button-hidden';
249
258
  replaceButton.innerText = this.instructions.replaceActionShort;
250
259
  replaceButton.title = this.instructions.replaceAction;
@@ -617,11 +626,28 @@ codeInput.plugins.FindAndReplace.FindMatchState = class {
617
626
  }
618
627
  }
619
628
 
620
- /* Highlight a match from the find functionality given its start and end indexes in the text.
621
- Start from the currentElement as this function is recursive. Use the matchID in the class name
629
+ /* Highlight a match from the find functionality given its start and end indexes in the text.
630
+ Start from the currentElement. Use the matchID in the class name
622
631
  of the match so different matches can be identified.
623
- This code is similar to codeInput.plugins.SelectTokenCallbacks.SelectedTokenState.updateSelectedTokens*/
632
+ */
624
633
  highlightMatch(matchID, currentElement, startIndex, endIndex) {
634
+ const lines = currentElement.textContent.substring(startIndex, endIndex).split("\n");
635
+ let lineStartIndex = startIndex;
636
+ for(let i = 0; i < lines.length; i++) {
637
+ if(i == 0) {
638
+ this.highlightMatchNewlineOnlyAtStart(matchID, currentElement, lineStartIndex, lineStartIndex+lines[i].length);
639
+ } else {
640
+ // Include previous newline character too
641
+ this.highlightMatchNewlineOnlyAtStart(matchID, currentElement, lineStartIndex-1, lineStartIndex+lines[i].length);
642
+ }
643
+
644
+ lineStartIndex += lines[i].length + 1; // +1 for newline character
645
+ }
646
+ }
647
+
648
+ /* Same as highlightMatch, but assumes any newlines in the
649
+ match are at the startIndex (for simpler code). */
650
+ highlightMatchNewlineOnlyAtStart(matchID, currentElement, startIndex, endIndex) {
625
651
  for(let i = 0; i < currentElement.childNodes.length; i++) {
626
652
  let childElement = currentElement.childNodes[i];
627
653
  let childText = childElement.textContent;
@@ -670,7 +696,7 @@ codeInput.plugins.FindAndReplace.FindMatchState = class {
670
696
  i++; // An extra element has been added
671
697
  return;
672
698
  } else {
673
- this.highlightMatch(matchID, childElement, 0, endIndex);
699
+ this.highlightMatchNewlineOnlyAtStart(matchID, childElement, 0, endIndex);
674
700
  }
675
701
 
676
702
  // Match ended - nothing to do after backtracking
@@ -729,7 +755,7 @@ codeInput.plugins.FindAndReplace.FindMatchState = class {
729
755
  i++; // An extra element has been added
730
756
  }
731
757
  } else {
732
- this.highlightMatch(matchID, childElement, startIndex, endIndex);
758
+ this.highlightMatchNewlineOnlyAtStart(matchID, childElement, startIndex, endIndex);
733
759
  }
734
760
 
735
761
  if(childText.length > endIndex) {
@@ -1 +1 @@
1
- .code-input_find-and-replace_find-match{color:inherit;text-shadow:none!important;background-color:#ff0!important}.code-input_find-and-replace_find-match-focused,.code-input_find-and-replace_find-match-focused *{background-color:#f80!important;color:#000!important}.code-input_find-and-replace_start-newline::before{content:"⤶"}@keyframes code-input_find-and-replace_roll-in{0%{opacity:0;transform:translateY(-34px)}100%{opacity:1;transform:translateY(0)}}@keyframes code-input_find-and-replace_roll-out{0%{opacity:1;top:0}100%{opacity:0;top:-34px}}.code-input_find-and-replace_dialog{position:absolute;top:0;right:14px;padding:6px;padding-top:8px;border:solid 1px #00000044;background-color:#fff;border-radius:6px;box-shadow:0 .2em 1em .2em rgba(0,0,0,.16)}.code-input_find-and-replace_dialog:not(.code-input_find-and-replace_hidden-dialog){animation:code-input_find-and-replace_roll-in .2s;opacity:1;pointer-events:all}.code-input_find-and-replace_dialog.code-input_find-and-replace_hidden-dialog{animation:code-input_find-and-replace_roll-out .2s;opacity:0;pointer-events:none}.code-input_find-and-replace_dialog input::placeholder{font-size:80%}.code-input_find-and-replace_dialog input{position:relative;width:240px;height:32px;top:-3px;font-size:large;color:#000000aa;border:0}.code-input_find-and-replace_dialog input:hover{outline:0}.code-input_find-and-replace_dialog input.code-input_find-and-replace_error{color:#ff0000aa}.code-input_find-and-replace_dialog button,.code-input_find-and-replace_dialog input[type=checkbox]{display:inline-block;line-height:24px;font-size:22px;cursor:pointer;appearance:none;width:min-content;margin:5px;padding:5px;border:0;background-color:#ddd;text-align:center;color:#000;vertical-align:top}.code-input_find-and-replace_dialog input[type=checkbox].code-input_find-and-replace_case-sensitive-checkbox::before{content:"Aa"}.code-input_find-and-replace_dialog input[type=checkbox].code-input_find-and-replace_reg-exp-checkbox::before{content:".*"}.code-input_find-and-replace_dialog button:hover,.code-input_find-and-replace_dialog input[type=checkbox]:hover{background-color:#bbb}.code-input_find-and-replace_dialog input[type=checkbox]:checked{background-color:#222;color:#fff}.code-input_find-and-replace_match-description{display:block;color:#444}.code-input_find-and-replace_dialog button,.code-input_find-and-replace_dialog details summary{cursor:pointer}.code-input_find-and-replace_dialog button.code-input_find-and-replace_button-hidden{opacity:0;pointer-events:none}.code-input_find-and-replace_dialog span{display:block;float:right;margin:5px;padding:5px;width:24px;line-height:24px;font-family:system-ui;font-size:22px;font-weight:500;text-align:center;border-radius:50%;color:#000;opacity:.6}.code-input_find-and-replace_dialog span:before{content:"\00d7"}.code-input_find-and-replace_dialog span:hover{opacity:.8;background-color:#00000018}
1
+ .code-input_find-and-replace_find-match{color:inherit;text-shadow:none!important;background-color:#ff0!important}.code-input_find-and-replace_find-match-focused,.code-input_find-and-replace_find-match-focused *{background-color:#f80!important;color:#000!important}.code-input_find-and-replace_start-newline::before{content:"⤶"}@keyframes code-input_find-and-replace_roll-in{0%{opacity:0;transform:translateY(-34px)}100%{opacity:1;transform:translateY(0)}}@keyframes code-input_find-and-replace_roll-out{0%{opacity:1;top:0}100%{opacity:0;top:-34px}}.code-input_find-and-replace_dialog{position:absolute;top:0;right:14px;padding:6px;padding-top:8px;border:solid 1px #00000044;background-color:#fff;border-radius:6px;box-shadow:0 .2em 1em .2em rgba(0,0,0,.16)}.code-input_find-and-replace_dialog:not(.code-input_find-and-replace_hidden-dialog){animation:code-input_find-and-replace_roll-in .2s;opacity:1;pointer-events:all}.code-input_find-and-replace_dialog.code-input_find-and-replace_hidden-dialog{animation:code-input_find-and-replace_roll-out .2s;opacity:0;pointer-events:none}.code-input_find-and-replace_dialog input::placeholder{font-size:80%}.code-input_find-and-replace_dialog input{position:relative;width:240px;height:32px;top:-3px;font-size:large;color:#000000aa;border:0}.code-input_find-and-replace_dialog input.code-input_find-and-replace_error{color:#ff0000aa}.code-input_find-and-replace_dialog button,.code-input_find-and-replace_dialog input[type=checkbox]{display:inline-block;line-height:24px;font-size:22px;cursor:pointer;appearance:none;width:min-content;margin:5px;padding:5px;border:0;background-color:#ddd;text-align:center;color:#000;vertical-align:top}.code-input_find-and-replace_dialog input[type=checkbox].code-input_find-and-replace_case-sensitive-checkbox::before{content:"Aa"}.code-input_find-and-replace_dialog input[type=checkbox].code-input_find-and-replace_reg-exp-checkbox::before{content:".*"}.code-input_find-and-replace_dialog button:hover,.code-input_find-and-replace_dialog input[type=checkbox]:hover{background-color:#bbb}.code-input_find-and-replace_dialog input[type=checkbox]:checked{background-color:#222;color:#fff}.code-input_find-and-replace_match-description{display:block;color:#444}.code-input_find-and-replace_dialog button,.code-input_find-and-replace_dialog details summary{cursor:pointer}.code-input_find-and-replace_dialog button.code-input_find-and-replace_button-hidden{opacity:0;pointer-events:none}.code-input_find-and-replace_dialog span{display:block;float:right;margin:5px;padding:5px;width:24px;line-height:24px;font-family:system-ui;font-size:22px;font-weight:500;text-align:center;border-radius:50%;color:#000;opacity:.6}.code-input_find-and-replace_dialog span:before{content:"\00d7"}.code-input_find-and-replace_dialog span:hover{opacity:.8;background-color:#00000018}
@@ -1 +1 @@
1
- codeInput.plugins.FindAndReplace=class extends codeInput.Plugin{useCtrlF=!1;useCtrlH=!1;findMatchesOnValueChange=!0;instructions={start:"Search for matches in your code.",none:"No matches",oneFound:"1 match found.",matchIndex:(a,b)=>`${a} of ${b} matches.`,error:a=>`Error: ${a}`,infiniteLoopError:"Causes an infinite loop",closeDialog:"Close Dialog and Return to Editor",findPlaceholder:"Find",findCaseSensitive:"Match Case Sensitive",findRegExp:"Use JavaScript Regular Expression",replaceTitle:"Replace",replacePlaceholder:"Replace with",findNext:"Find Next Occurrence",findPrevious:"Find Previous Occurrence",replaceActionShort:"Replace",replaceAction:"Replace This Occurrence",replaceAllActionShort:"Replace All",replaceAllAction:"Replace All Occurrences"};constructor(a=!0,b=!0,c={}){super([]),this.useCtrlF=a,this.useCtrlH=b,this.addTranslations(this.instructions,c)}afterElementsAdded(a){const b=a.textareaElement;this.useCtrlF&&b.addEventListener("keydown",b=>{this.checkCtrlF(a,b)}),this.useCtrlH&&b.addEventListener("keydown",b=>{this.checkCtrlH(a,b)})}afterHighlight(a){a.pluginData.findAndReplace==null||a.pluginData.findAndReplace.dialog==null||a.pluginData.findAndReplace.dialog.classList.contains("code-input_find-and-replace_hidden-dialog")||(a.pluginData.findAndReplace.dialog.findMatchState.rehighlightMatches(),this.updateMatchDescription(a.pluginData.findAndReplace.dialog),0==a.pluginData.findAndReplace.dialog.findMatchState.numMatches&&a.pluginData.findAndReplace.dialog.findInput.classList.add("code-input_find-and-replace_error"))}text2RegExp(a,b,c){return new RegExp(c?a:a.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),b?"g":"gi")}updateMatchDescription(a){a.matchDescription.textContent=0==a.findInput.value.length?this.instructions.start:0>=a.findMatchState.numMatches?this.instructions.none:1==a.findMatchState.numMatches?this.instructions.oneFound:this.instructions.matchIndex(a.findMatchState.focusedMatchID+1,a.findMatchState.numMatches)}updateFindMatches(a){let b=a.findInput.value;setTimeout(()=>{if(b==a.findInput.value){if(a.findMatchState.clearMatches(),0<b.length){try{a.findMatchState.updateMatches(this.text2RegExp(a.findInput.value,a.findCaseSensitiveCheckbox.checked,a.findRegExpCheckbox.checked))}catch(b){if(b instanceof SyntaxError){a.findInput.classList.add("code-input_find-and-replace_error");let c=b.message.split(": ");return void(a.matchDescription.textContent=this.instructions.error(c[c.length-1]))}throw b}0<a.findMatchState.numMatches?a.findInput.classList.remove("code-input_find-and-replace_error"):a.findInput.classList.add("code-input_find-and-replace_error")}this.updateMatchDescription(a)}},100)}checkFindPrompt(a,b,c){"Enter"==c.key&&(a.findMatchState.nextMatch(),this.updateMatchDescription(a))}checkReplacePrompt(a,b,c){"Enter"==c.key&&(a.findMatchState.replaceOnce(a.replaceInput.value),a.replaceInput.focus(),this.updateMatchDescription(a))}cancelPrompt(a,b,c){c.preventDefault(),this.findMatchesOnValueChange=!1,a.findInput.focus(),a.findInput.selectionStart=0,a.findInput.selectionEnd=a.findInput.value.length,document.execCommand("insertText",!1,a.findInput.value),this.findMatchesOnValueChange=!0,a.textarea.focus(),a.setAttribute("inert",!0),a.setAttribute("tabindex",-1),a.setAttribute("aria-hidden",!0),0<a.findMatchState.numMatches?(b.textareaElement.selectionStart=a.findMatchState.matchStartIndexes[a.findMatchState.focusedMatchID],b.textareaElement.selectionEnd=a.findMatchState.matchEndIndexes[a.findMatchState.focusedMatchID]):(b.textareaElement.selectionStart=a.selectionStart,b.textareaElement.selectionEnd=a.selectionEnd),a.findMatchState.clearMatches(),a.classList.add("code-input_find-and-replace_hidden-dialog")}showPrompt(a,b){let c;if(null==a.pluginData.findAndReplace||null==a.pluginData.findAndReplace.dialog){const d=a.textareaElement;c=document.createElement("div");const e=document.createElement("input"),f=document.createElement("input"),g=document.createElement("input"),h=document.createElement("code");h.setAttribute("aria-live","assertive");const i=document.createElement("input"),j=document.createElement("details"),k=document.createElement("summary"),l=document.createElement("div"),m=document.createElement("button"),n=document.createElement("button"),o=document.createElement("button"),p=document.createElement("button"),q=document.createElement("span");if(q.setAttribute("tabindex",0),q.setAttribute("title",this.instructions.closeDialog),l.appendChild(m),l.appendChild(n),l.appendChild(o),l.appendChild(p),l.appendChild(q),c.appendChild(l),c.appendChild(e),c.appendChild(g),c.appendChild(f),c.appendChild(h),j.appendChild(k),j.appendChild(i),c.appendChild(j),c.className="code-input_find-and-replace_dialog",e.spellcheck=!1,e.placeholder=this.instructions.findPlaceholder,f.setAttribute("type","checkbox"),f.title=this.instructions.findCaseSensitive,f.classList.add("code-input_find-and-replace_case-sensitive-checkbox"),g.setAttribute("type","checkbox"),g.title=this.instructions.findRegExp,g.classList.add("code-input_find-and-replace_reg-exp-checkbox"),h.textContent="Search for matches in your code.",h.classList.add("code-input_find-and-replace_match-description"),k.innerText=this.instructions.replaceTitle,i.spellcheck=!1,i.placeholder=this.instructions.replacePlaceholder,m.innerText="\u2193",m.title=this.instructions.findNext,n.innerText="\u2191",n.title=this.instructions.findPrevious,o.className="code-input_find-and-replace_button-hidden",o.innerText=this.instructions.replaceActionShort,o.title=this.instructions.replaceAction,o.addEventListener("focus",()=>{j.setAttribute("open",!0)}),p.className="code-input_find-and-replace_button-hidden",p.innerText=this.instructions.replaceAllActionShort,p.title=this.instructions.replaceAllAction,p.addEventListener("focus",()=>{j.setAttribute("open",!0)}),m.addEventListener("click",a=>{a.preventDefault(),c.findMatchState.nextMatch(),this.updateMatchDescription(c)}),n.addEventListener("click",()=>{event.preventDefault(),c.findMatchState.previousMatch(),this.updateMatchDescription(c)}),o.addEventListener("click",a=>{a.preventDefault(),c.findMatchState.replaceOnce(i.value),c.focus()}),p.addEventListener("click",a=>{a.preventDefault(),c.findMatchState.replaceAll(i.value),p.focus()}),j.addEventListener("toggle",()=>{o.classList.toggle("code-input_find-and-replace_button-hidden"),p.classList.toggle("code-input_find-and-replace_button-hidden")}),c.findMatchState=new codeInput.plugins.FindAndReplace.FindMatchState(a),c.codeInput=a,c.textarea=d,c.findInput=e,c.findCaseSensitiveCheckbox=f,c.findRegExpCheckbox=g,c.matchDescription=h,c.replaceInput=i,c.replaceDropdown=j,this.checkCtrlH&&e.addEventListener("keydown",a=>{a.ctrlKey&&"h"==a.key&&(a.preventDefault(),j.setAttribute("open",!0))}),e.addEventListener("keypress",a=>{"Enter"==a.key&&a.preventDefault()}),i.addEventListener("keypress",a=>{"Enter"==a.key&&a.preventDefault()}),i.addEventListener("input",()=>{c.classList.contains("code-input_find-and-replace_hidden-dialog")?this.showPrompt(c.codeInput,!0):!c.replaceDropdown.hasAttribute("open")&&c.replaceDropdown.setAttribute("open",!0)}),c.addEventListener("keyup",b=>{"Escape"==b.key&&this.cancelPrompt(c,a,b)}),e.addEventListener("keyup",b=>{this.checkFindPrompt(c,a,b)}),e.addEventListener("input",()=>{this.findMatchesOnValueChange&&this.updateFindMatches(c),c.classList.contains("code-input_find-and-replace_hidden-dialog")&&this.showPrompt(c.codeInput,!1)}),f.addEventListener("click",()=>{this.updateFindMatches(c)}),g.addEventListener("click",()=>{this.updateFindMatches(c)}),i.addEventListener("keyup",b=>{this.checkReplacePrompt(c,a,b),i.focus()}),q.addEventListener("click",b=>{this.cancelPrompt(c,a,b)}),q.addEventListener("keypress",b=>{("Space"==b.key||"Enter"==b.key)&&this.cancelPrompt(c,a,b)}),a.dialogContainerElement.appendChild(c),a.pluginData.findAndReplace={dialog:c},e.focus(),b&&j.setAttribute("open",!0),c.selectionStart=a.textareaElement.selectionStart,c.selectionEnd=a.textareaElement.selectionEnd,c.selectionStart<c.selectionEnd){let b=a.textareaElement.value.substring(c.selectionStart,c.selectionEnd);c.findInput.focus(),c.findInput.selectionStart=0,c.findInput.selectionEnd=c.findInput.value.length,document.execCommand("insertText",!1,b)}}else c=a.pluginData.findAndReplace.dialog,c.classList.remove("code-input_find-and-replace_hidden-dialog"),c.removeAttribute("inert"),c.setAttribute("tabindex",0),c.removeAttribute("aria-hidden"),c.findInput.focus(),b?c.replaceDropdown.setAttribute("open",!0):c.replaceDropdown.removeAttribute("open");if(c.selectionStart=a.textareaElement.selectionStart,c.selectionEnd=a.textareaElement.selectionEnd,c.selectionStart<c.selectionEnd){let b=a.textareaElement.value.substring(c.selectionStart,c.selectionEnd);c.findInput.focus(),c.findInput.selectionStart=0,c.findInput.selectionEnd=c.findInput.value.length,document.execCommand("insertText",!1,b)}this.updateFindMatches(c)}checkCtrlF(a,b){b.ctrlKey&&"f"==b.key&&(b.preventDefault(),this.showPrompt(a,!1))}checkCtrlH(a,b){b.ctrlKey&&"h"==b.key&&(b.preventDefault(),this.showPrompt(a,!0))}};const CODE_INPUT_FIND_AND_REPLACE_MATCH_BLOCK_SIZE=500;codeInput.plugins.FindAndReplace.FindMatchState=class{codeInput=null;lastValue=null;lastSearchRegexp=null;numMatches=0;focusedMatchID=0;matchStartIndexes=[];matchEndIndexes=[];focusedMatchStartIndex=0;matchBlocksHighlighted=[];constructor(a){this.focusedMatchStartIndex=a.textareaElement.selectionStart,this.codeInput=a}clearMatches(){this.numMatches=0,this.matchStartIndexes=[],this.matchEndIndexes=[];let a=this.codeInput.codeElement.querySelectorAll(".code-input_find-and-replace_temporary-span");for(let b=0;b<a.length;b++)a[b].parentElement.replaceChild(new Text(a[b].textContent),a[b]);let b=this.codeInput.codeElement.querySelectorAll(".code-input_find-and-replace_find-match");for(let a=0;a<b.length;a++)b[a].removeAttribute("data-code-input_find-and-replace_match-id"),b[a].classList.remove("code-input_find-and-replace_find-match"),b[a].classList.remove("code-input_find-and-replace_find-match-focused")}updateMatches(a){var b=Math.floor;this.lastSearchRegexp=a,this.lastValue=this.codeInput.value;let c,d=0;this.matchStartIndexes=[],this.matchEndIndexes=[],this.matchBlocksHighlighted=[];let e=b(this.focusedMatchID/CODE_INPUT_FIND_AND_REPLACE_MATCH_BLOCK_SIZE);for(let b=0;b<e;b++)this.matchBlocksHighlighted.push(!1);for(this.matchBlocksHighlighted.push(!0);null!==(c=a.exec(this.codeInput.value));){let a=c[0];if(0==a.length)throw SyntaxError(this.instructions.infiniteLoopError);let e=b(d/CODE_INPUT_FIND_AND_REPLACE_MATCH_BLOCK_SIZE);this.matchBlocksHighlighted.length<e&&this.matchBlocksHighlighted.push(!1),this.matchBlocksHighlighted[e]&&this.highlightMatch(d,this.codeInput.codeElement,c.index,c.index+a.length),this.matchStartIndexes.push(c.index),this.matchEndIndexes.push(c.index+a.length),d++}this.numMatches=d,0<this.numMatches&&this.focusMatch()}rehighlightMatches(){this.updateMatches(this.lastSearchRegexp),this.focusMatch()}replaceOnce(a){0<this.numMatches&&a!=this.codeInput.value.substring(0,this.matchStartIndexes[this.focusedMatchID],this.matchEndIndexes[this.focusedMatchID])&&(this.focusedMatchStartIndex+=a.length,this.codeInput.handleEventsFromTextarea=!1,this.codeInput.textareaElement.focus(),this.codeInput.textareaElement.selectionStart=this.matchStartIndexes[this.focusedMatchID],this.codeInput.textareaElement.selectionEnd=this.matchEndIndexes[this.focusedMatchID],document.execCommand("insertText",!1,a),this.codeInput.handleEventsFromTextarea=!0)}replaceAll(a){const b=a.length;let c=0;for(let d=0;d<this.numMatches;d++)this.codeInput.handleEventsFromTextarea=!1,this.codeInput.textareaElement.focus(),this.codeInput.textareaElement.selectionStart=this.matchStartIndexes[d]+c,this.codeInput.textareaElement.selectionEnd=this.matchEndIndexes[d]+c,c+=b-(this.matchEndIndexes[d]-this.matchStartIndexes[d]),document.execCommand("insertText",!1,a),this.codeInput.handleEventsFromTextarea=!0}nextMatch(){this.focusMatch((this.focusedMatchID+1)%this.numMatches)}previousMatch(){this.focusMatch((this.focusedMatchID+this.numMatches-1)%this.numMatches)}focusMatch(a=void 0){if(a===void 0){for(a=0;a<this.matchStartIndexes.length&&this.matchStartIndexes[a]<this.focusedMatchStartIndex;)a++;a>=this.matchStartIndexes.length&&(a=0)}this.focusedMatchStartIndex=this.matchStartIndexes[a],this.focusedMatchID=a;let b=this.codeInput.codeElement.querySelectorAll(".code-input_find-and-replace_find-match-focused");for(let c=0;c<b.length;c++)b[c].classList.remove("code-input_find-and-replace_find-match-focused");let c=Math.floor(a/CODE_INPUT_FIND_AND_REPLACE_MATCH_BLOCK_SIZE);if(!this.matchBlocksHighlighted[c]){this.matchBlocksHighlighted[c]=!0;for(let a=CODE_INPUT_FIND_AND_REPLACE_MATCH_BLOCK_SIZE*c;a<CODE_INPUT_FIND_AND_REPLACE_MATCH_BLOCK_SIZE*(c+1);a++)this.highlightMatch(a,this.codeInput.codeElement,this.matchStartIndexes[a],this.matchEndIndexes[a])}let d=this.codeInput.codeElement.querySelectorAll(`.code-input_find-and-replace_find-match[data-code-input_find-and-replace_match-id="${a}"]`);for(let b=0;b<d.length;b++)d[b].classList.add("code-input_find-and-replace_find-match-focused");0<d.length&&this.codeInput.scrollTo(d[0].offsetLeft-this.codeInput.offsetWidth/2,d[0].offsetTop-this.codeInput.offsetHeight/2)}highlightMatch(a,b,c,d){for(let e=0;e<b.childNodes.length;e++){let f=b.childNodes[e],g=f.textContent,h=!1;if(3==f.nodeType){if(e+1<b.childNodes.length&&3==b.childNodes[e+1].nodeType){b.childNodes[e+1].textContent=f.textContent+b.childNodes[e+1].textContent,b.removeChild(f),e--;continue}h=!0;let a=document.createElement("span");a.textContent=g,a.classList.add("code-input_find-and-replace_temporary-span"),b.replaceChild(a,f),f=a}if(0>=c){if(g.length>=d){if(h){let b=document.createElement("span");b.classList.add("code-input_find-and-replace_find-match"),b.setAttribute("data-code-input_find-and-replace_match-id",a),b.classList.add("code-input_find-and-replace_temporary-span"),b.textContent=g.substring(0,d),"\n"==b.textContent[0]&&b.classList.add("code-input_find-and-replace_start-newline");let c=g.substring(d);return f.textContent=c,f.insertAdjacentElement("beforebegin",b),void e++}return void this.highlightMatch(a,f,0,d)}f.classList.add("code-input_find-and-replace_find-match"),f.setAttribute("data-code-input_find-and-replace_match-id",a),"\n"==f.textContent[0]&&f.classList.add("code-input_find-and-replace_start-newline")}else if(g.length>c){if(!h)this.highlightMatch(a,f,c,d);else if(g.length>d){let b=document.createElement("span");b.classList.add("code-input_find-and-replace_temporary-span"),b.textContent=g.substring(0,c);let h=g.substring(c,d);f.textContent=h,f.classList.add("code-input_find-and-replace_find-match"),f.setAttribute("data-code-input_find-and-replace_match-id",a),"\n"==f.textContent[0]&&f.classList.add("code-input_find-and-replace_start-newline");let i=document.createElement("span");i.classList.add("code-input_find-and-replace_temporary-span"),i.textContent=g.substring(d),f.insertAdjacentElement("beforebegin",b),f.insertAdjacentElement("afterend",i),e++}else{let b=g.substring(0,c);f.textContent=b;let d=document.createElement("span");d.classList.add("code-input_find-and-replace_find-match"),d.setAttribute("data-code-input_find-and-replace_match-id",a),d.classList.add("code-input_find-and-replace_temporary-span"),d.textContent=g.substring(c),"\n"==d.textContent[0]&&d.classList.add("code-input_find-and-replace_start-newline"),f.insertAdjacentElement("afterend",d),e++}if(g.length>d)return}c-=g.length,d-=g.length}}};
1
+ "use strict";codeInput.plugins.FindAndReplace=class extends codeInput.Plugin{useCtrlF=!1;useCtrlH=!1;findMatchesOnValueChange=!0;instructions={start:"Search for matches in your code.",none:"No matches",oneFound:"1 match found.",matchIndex:(a,b)=>`${a} of ${b} matches.`,error:a=>`Error: ${a}`,infiniteLoopError:"Causes an infinite loop",closeDialog:"Close Dialog and Return to Editor",findPlaceholder:"Find",findCaseSensitive:"Match Case Sensitive",findRegExp:"Use JavaScript Regular Expression",replaceTitle:"Replace",replacePlaceholder:"Replace with",findNext:"Find Next Occurrence",findPrevious:"Find Previous Occurrence",replaceActionShort:"Replace",replaceAction:"Replace This Occurrence",replaceAllActionShort:"Replace All",replaceAllAction:"Replace All Occurrences"};constructor(a=!0,b=!0,c={}){super([]),this.useCtrlF=a,this.useCtrlH=b,this.addTranslations(this.instructions,c)}afterElementsAdded(a){const b=a.textareaElement;this.useCtrlF&&b.addEventListener("keydown",b=>{this.checkCtrlF(a,b)}),this.useCtrlH&&b.addEventListener("keydown",b=>{this.checkCtrlH(a,b)})}afterHighlight(a){a.pluginData.findAndReplace==null||a.pluginData.findAndReplace.dialog==null||a.pluginData.findAndReplace.dialog.classList.contains("code-input_find-and-replace_hidden-dialog")||(a.pluginData.findAndReplace.dialog.findMatchState.rehighlightMatches(),this.updateMatchDescription(a.pluginData.findAndReplace.dialog),0==a.pluginData.findAndReplace.dialog.findMatchState.numMatches&&a.pluginData.findAndReplace.dialog.findInput.classList.add("code-input_find-and-replace_error"))}text2RegExp(a,b,c){return new RegExp(c?a:a.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),b?"g":"gi")}updateMatchDescription(a){a.matchDescription.textContent=0==a.findInput.value.length?this.instructions.start:0>=a.findMatchState.numMatches?this.instructions.none:1==a.findMatchState.numMatches?this.instructions.oneFound:this.instructions.matchIndex(a.findMatchState.focusedMatchID+1,a.findMatchState.numMatches)}updateFindMatches(a){let b=a.findInput.value;setTimeout(()=>{if(b==a.findInput.value){if(a.findMatchState.clearMatches(),0<b.length){try{a.findMatchState.updateMatches(this.text2RegExp(a.findInput.value,a.findCaseSensitiveCheckbox.checked,a.findRegExpCheckbox.checked))}catch(b){if(b instanceof SyntaxError){a.findInput.classList.add("code-input_find-and-replace_error");let c=b.message.split(": ");return void(a.matchDescription.textContent=this.instructions.error(c[c.length-1]))}throw b}0<a.findMatchState.numMatches?a.findInput.classList.remove("code-input_find-and-replace_error"):a.findInput.classList.add("code-input_find-and-replace_error")}this.updateMatchDescription(a)}},100)}checkFindPrompt(a,b,c){"Enter"==c.key&&(a.findMatchState.nextMatch(),this.updateMatchDescription(a))}checkReplacePrompt(a,b,c){"Enter"==c.key&&(a.findMatchState.replaceOnce(a.replaceInput.value),a.replaceInput.focus(),this.updateMatchDescription(a))}cancelPrompt(a,b,c){c.preventDefault(),this.findMatchesOnValueChange=!1,a.findInput.focus(),a.findInput.selectionStart=0,a.findInput.selectionEnd=a.findInput.value.length,document.execCommand("insertText",!1,a.findInput.value),this.findMatchesOnValueChange=!0,a.textarea.focus(),a.setAttribute("inert",!0),a.setAttribute("tabindex",-1),a.setAttribute("aria-hidden",!0),0<a.findMatchState.numMatches?(b.textareaElement.selectionStart=a.findMatchState.matchStartIndexes[a.findMatchState.focusedMatchID],b.textareaElement.selectionEnd=a.findMatchState.matchEndIndexes[a.findMatchState.focusedMatchID]):(b.textareaElement.selectionStart=a.selectionStart,b.textareaElement.selectionEnd=a.selectionEnd),a.findMatchState.clearMatches(),a.classList.add("code-input_find-and-replace_hidden-dialog")}showPrompt(a,b){let c;if(null==a.pluginData.findAndReplace||null==a.pluginData.findAndReplace.dialog){const d=a.textareaElement;c=document.createElement("div");const e=document.createElement("input"),f=document.createElement("input"),g=document.createElement("input"),h=document.createElement("code");h.setAttribute("aria-live","assertive");const i=document.createElement("input"),j=document.createElement("details"),k=document.createElement("summary"),l=document.createElement("div"),m=document.createElement("button"),n=document.createElement("button"),o=document.createElement("button"),p=document.createElement("button"),q=document.createElement("span");if(q.setAttribute("role","button"),q.setAttribute("aria-label",this.instructions.closeDialog),q.setAttribute("tabindex",0),q.setAttribute("title",this.instructions.closeDialog),l.appendChild(m),l.appendChild(n),l.appendChild(o),l.appendChild(p),l.appendChild(q),c.appendChild(l),c.appendChild(e),c.appendChild(g),c.appendChild(f),c.appendChild(h),j.appendChild(k),j.appendChild(i),c.appendChild(j),c.className="code-input_find-and-replace_dialog",e.spellcheck=!1,e.placeholder=this.instructions.findPlaceholder,f.setAttribute("type","checkbox"),f.title=this.instructions.findCaseSensitive,f.classList.add("code-input_find-and-replace_case-sensitive-checkbox"),g.setAttribute("type","checkbox"),g.title=this.instructions.findRegExp,g.classList.add("code-input_find-and-replace_reg-exp-checkbox"),h.textContent=this.instructions.start,h.classList.add("code-input_find-and-replace_match-description"),k.innerText=this.instructions.replaceTitle,i.spellcheck=!1,i.placeholder=this.instructions.replacePlaceholder,m.innerText="\u2193",m.title=this.instructions.findNext,m.setAttribute("aria-label",this.instructions.findNext),n.innerText="\u2191",n.title=this.instructions.findPrevious,m.setAttribute("aria-label",this.instructions.findPrevious),o.className="code-input_find-and-replace_button-hidden",o.innerText=this.instructions.replaceActionShort,o.title=this.instructions.replaceAction,o.addEventListener("focus",()=>{j.setAttribute("open",!0)}),p.className="code-input_find-and-replace_button-hidden",p.innerText=this.instructions.replaceAllActionShort,p.title=this.instructions.replaceAllAction,p.addEventListener("focus",()=>{j.setAttribute("open",!0)}),m.addEventListener("click",a=>{a.preventDefault(),c.findMatchState.nextMatch(),this.updateMatchDescription(c)}),n.addEventListener("click",()=>{event.preventDefault(),c.findMatchState.previousMatch(),this.updateMatchDescription(c)}),o.addEventListener("click",a=>{a.preventDefault(),c.findMatchState.replaceOnce(i.value),c.focus()}),p.addEventListener("click",a=>{a.preventDefault(),c.findMatchState.replaceAll(i.value),p.focus()}),j.addEventListener("toggle",()=>{o.classList.toggle("code-input_find-and-replace_button-hidden"),p.classList.toggle("code-input_find-and-replace_button-hidden")}),c.findMatchState=new codeInput.plugins.FindAndReplace.FindMatchState(a),c.codeInput=a,c.textarea=d,c.findInput=e,c.findCaseSensitiveCheckbox=f,c.findRegExpCheckbox=g,c.matchDescription=h,c.replaceInput=i,c.replaceDropdown=j,this.checkCtrlH&&e.addEventListener("keydown",a=>{a.ctrlKey&&"h"==a.key&&(a.preventDefault(),j.setAttribute("open",!0))}),e.addEventListener("keypress",a=>{"Enter"==a.key&&a.preventDefault()}),i.addEventListener("keypress",a=>{"Enter"==a.key&&a.preventDefault()}),i.addEventListener("input",()=>{c.classList.contains("code-input_find-and-replace_hidden-dialog")?this.showPrompt(c.codeInput,!0):!c.replaceDropdown.hasAttribute("open")&&c.replaceDropdown.setAttribute("open",!0)}),c.addEventListener("keyup",b=>{"Escape"==b.key&&this.cancelPrompt(c,a,b)}),e.addEventListener("keyup",b=>{this.checkFindPrompt(c,a,b)}),e.addEventListener("input",()=>{this.findMatchesOnValueChange&&this.updateFindMatches(c),c.classList.contains("code-input_find-and-replace_hidden-dialog")&&this.showPrompt(c.codeInput,!1)}),f.addEventListener("click",()=>{this.updateFindMatches(c)}),g.addEventListener("click",()=>{this.updateFindMatches(c)}),i.addEventListener("keyup",b=>{this.checkReplacePrompt(c,a,b),i.focus()}),q.addEventListener("click",b=>{this.cancelPrompt(c,a,b)}),q.addEventListener("keypress",b=>{("Space"==b.key||"Enter"==b.key)&&this.cancelPrompt(c,a,b)}),a.dialogContainerElement.appendChild(c),a.pluginData.findAndReplace={dialog:c},e.focus(),b&&j.setAttribute("open",!0),c.selectionStart=a.textareaElement.selectionStart,c.selectionEnd=a.textareaElement.selectionEnd,c.selectionStart<c.selectionEnd){let b=a.textareaElement.value.substring(c.selectionStart,c.selectionEnd);c.findInput.focus(),c.findInput.selectionStart=0,c.findInput.selectionEnd=c.findInput.value.length,document.execCommand("insertText",!1,b)}}else c=a.pluginData.findAndReplace.dialog,c.classList.remove("code-input_find-and-replace_hidden-dialog"),c.removeAttribute("inert"),c.setAttribute("tabindex",0),c.removeAttribute("aria-hidden"),c.findInput.focus(),b?c.replaceDropdown.setAttribute("open",!0):c.replaceDropdown.removeAttribute("open");if(c.selectionStart=a.textareaElement.selectionStart,c.selectionEnd=a.textareaElement.selectionEnd,c.selectionStart<c.selectionEnd){let b=a.textareaElement.value.substring(c.selectionStart,c.selectionEnd);c.findInput.focus(),c.findInput.selectionStart=0,c.findInput.selectionEnd=c.findInput.value.length,document.execCommand("insertText",!1,b)}this.updateFindMatches(c)}checkCtrlF(a,b){b.ctrlKey&&"f"==b.key&&(b.preventDefault(),this.showPrompt(a,!1))}checkCtrlH(a,b){b.ctrlKey&&"h"==b.key&&(b.preventDefault(),this.showPrompt(a,!0))}};const CODE_INPUT_FIND_AND_REPLACE_MATCH_BLOCK_SIZE=500;codeInput.plugins.FindAndReplace.FindMatchState=class{codeInput=null;lastValue=null;lastSearchRegexp=null;numMatches=0;focusedMatchID=0;matchStartIndexes=[];matchEndIndexes=[];focusedMatchStartIndex=0;matchBlocksHighlighted=[];constructor(a){this.focusedMatchStartIndex=a.textareaElement.selectionStart,this.codeInput=a}clearMatches(){this.numMatches=0,this.matchStartIndexes=[],this.matchEndIndexes=[];let a=this.codeInput.codeElement.querySelectorAll(".code-input_find-and-replace_temporary-span");for(let b=0;b<a.length;b++)a[b].parentElement.replaceChild(new Text(a[b].textContent),a[b]);let b=this.codeInput.codeElement.querySelectorAll(".code-input_find-and-replace_find-match");for(let a=0;a<b.length;a++)b[a].removeAttribute("data-code-input_find-and-replace_match-id"),b[a].classList.remove("code-input_find-and-replace_find-match"),b[a].classList.remove("code-input_find-and-replace_find-match-focused")}updateMatches(a){var b=Math.floor;this.lastSearchRegexp=a,this.lastValue=this.codeInput.value;let c,d=0;this.matchStartIndexes=[],this.matchEndIndexes=[],this.matchBlocksHighlighted=[];let e=b(this.focusedMatchID/CODE_INPUT_FIND_AND_REPLACE_MATCH_BLOCK_SIZE);for(let b=0;b<e;b++)this.matchBlocksHighlighted.push(!1);for(this.matchBlocksHighlighted.push(!0);null!==(c=a.exec(this.codeInput.value));){let a=c[0];if(0==a.length)throw SyntaxError(this.instructions.infiniteLoopError);let e=b(d/CODE_INPUT_FIND_AND_REPLACE_MATCH_BLOCK_SIZE);this.matchBlocksHighlighted.length<e&&this.matchBlocksHighlighted.push(!1),this.matchBlocksHighlighted[e]&&this.highlightMatch(d,this.codeInput.codeElement,c.index,c.index+a.length),this.matchStartIndexes.push(c.index),this.matchEndIndexes.push(c.index+a.length),d++}this.numMatches=d,0<this.numMatches&&this.focusMatch()}rehighlightMatches(){this.updateMatches(this.lastSearchRegexp),this.focusMatch()}replaceOnce(a){0<this.numMatches&&a!=this.codeInput.value.substring(0,this.matchStartIndexes[this.focusedMatchID],this.matchEndIndexes[this.focusedMatchID])&&(this.focusedMatchStartIndex+=a.length,this.codeInput.handleEventsFromTextarea=!1,this.codeInput.textareaElement.focus(),this.codeInput.textareaElement.selectionStart=this.matchStartIndexes[this.focusedMatchID],this.codeInput.textareaElement.selectionEnd=this.matchEndIndexes[this.focusedMatchID],document.execCommand("insertText",!1,a),this.codeInput.handleEventsFromTextarea=!0)}replaceAll(a){const b=a.length;let c=0;for(let d=0;d<this.numMatches;d++)this.codeInput.handleEventsFromTextarea=!1,this.codeInput.textareaElement.focus(),this.codeInput.textareaElement.selectionStart=this.matchStartIndexes[d]+c,this.codeInput.textareaElement.selectionEnd=this.matchEndIndexes[d]+c,c+=b-(this.matchEndIndexes[d]-this.matchStartIndexes[d]),document.execCommand("insertText",!1,a),this.codeInput.handleEventsFromTextarea=!0}nextMatch(){this.focusMatch((this.focusedMatchID+1)%this.numMatches)}previousMatch(){this.focusMatch((this.focusedMatchID+this.numMatches-1)%this.numMatches)}focusMatch(a=void 0){if(a===void 0){for(a=0;a<this.matchStartIndexes.length&&this.matchStartIndexes[a]<this.focusedMatchStartIndex;)a++;a>=this.matchStartIndexes.length&&(a=0)}this.focusedMatchStartIndex=this.matchStartIndexes[a],this.focusedMatchID=a;let b=this.codeInput.codeElement.querySelectorAll(".code-input_find-and-replace_find-match-focused");for(let c=0;c<b.length;c++)b[c].classList.remove("code-input_find-and-replace_find-match-focused");let c=Math.floor(a/CODE_INPUT_FIND_AND_REPLACE_MATCH_BLOCK_SIZE);if(!this.matchBlocksHighlighted[c]){this.matchBlocksHighlighted[c]=!0;for(let a=CODE_INPUT_FIND_AND_REPLACE_MATCH_BLOCK_SIZE*c;a<CODE_INPUT_FIND_AND_REPLACE_MATCH_BLOCK_SIZE*(c+1);a++)this.highlightMatch(a,this.codeInput.codeElement,this.matchStartIndexes[a],this.matchEndIndexes[a])}let d=this.codeInput.codeElement.querySelectorAll(`.code-input_find-and-replace_find-match[data-code-input_find-and-replace_match-id="${a}"]`);for(let b=0;b<d.length;b++)d[b].classList.add("code-input_find-and-replace_find-match-focused");0<d.length&&this.codeInput.scrollTo(d[0].offsetLeft-this.codeInput.offsetWidth/2,d[0].offsetTop-this.codeInput.offsetHeight/2)}highlightMatch(a,b,c,d){const e=b.textContent.substring(c,d).split("\n");let f=c;for(let g=0;g<e.length;g++)0==g?this.highlightMatchNewlineOnlyAtStart(a,b,f,f+e[g].length):this.highlightMatchNewlineOnlyAtStart(a,b,f-1,f+e[g].length),f+=e[g].length+1}highlightMatchNewlineOnlyAtStart(a,b,c,d){for(let e=0;e<b.childNodes.length;e++){let f=b.childNodes[e],g=f.textContent,h=!1;if(3==f.nodeType){if(e+1<b.childNodes.length&&3==b.childNodes[e+1].nodeType){b.childNodes[e+1].textContent=f.textContent+b.childNodes[e+1].textContent,b.removeChild(f),e--;continue}h=!0;let a=document.createElement("span");a.textContent=g,a.classList.add("code-input_find-and-replace_temporary-span"),b.replaceChild(a,f),f=a}if(0>=c){if(g.length>=d){if(h){let b=document.createElement("span");b.classList.add("code-input_find-and-replace_find-match"),b.setAttribute("data-code-input_find-and-replace_match-id",a),b.classList.add("code-input_find-and-replace_temporary-span"),b.textContent=g.substring(0,d),"\n"==b.textContent[0]&&b.classList.add("code-input_find-and-replace_start-newline");let c=g.substring(d);return f.textContent=c,f.insertAdjacentElement("beforebegin",b),void e++}return void this.highlightMatchNewlineOnlyAtStart(a,f,0,d)}f.classList.add("code-input_find-and-replace_find-match"),f.setAttribute("data-code-input_find-and-replace_match-id",a),"\n"==f.textContent[0]&&f.classList.add("code-input_find-and-replace_start-newline")}else if(g.length>c){if(!h)this.highlightMatchNewlineOnlyAtStart(a,f,c,d);else if(g.length>d){let b=document.createElement("span");b.classList.add("code-input_find-and-replace_temporary-span"),b.textContent=g.substring(0,c);let h=g.substring(c,d);f.textContent=h,f.classList.add("code-input_find-and-replace_find-match"),f.setAttribute("data-code-input_find-and-replace_match-id",a),"\n"==f.textContent[0]&&f.classList.add("code-input_find-and-replace_start-newline");let i=document.createElement("span");i.classList.add("code-input_find-and-replace_temporary-span"),i.textContent=g.substring(d),f.insertAdjacentElement("beforebegin",b),f.insertAdjacentElement("afterend",i),e++}else{let b=g.substring(0,c);f.textContent=b;let d=document.createElement("span");d.classList.add("code-input_find-and-replace_find-match"),d.setAttribute("data-code-input_find-and-replace_match-id",a),d.classList.add("code-input_find-and-replace_temporary-span"),d.textContent=g.substring(c),"\n"==d.textContent[0]&&d.classList.add("code-input_find-and-replace_start-newline"),f.insertAdjacentElement("afterend",d),e++}if(g.length>d)return}c-=g.length,d-=g.length}}};