@webcoder49/code-input 2.5.1 → 2.6.2

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 (93) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +9 -126
  3. package/code-input.css +70 -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/README.md +23 -0
  31. package/esm/code-input.d.mts +154 -0
  32. package/esm/code-input.mjs +997 -0
  33. package/esm/plugins/auto-close-brackets.d.mts +15 -0
  34. package/esm/plugins/auto-close-brackets.mjs +84 -0
  35. package/esm/plugins/autocomplete.d.mts +14 -0
  36. package/esm/plugins/autocomplete.mjs +93 -0
  37. package/esm/plugins/autodetect.d.mts +11 -0
  38. package/esm/plugins/autodetect.mjs +35 -0
  39. package/esm/plugins/find-and-replace.d.mts +43 -0
  40. package/esm/plugins/find-and-replace.mjs +777 -0
  41. package/esm/plugins/go-to-line.d.mts +29 -0
  42. package/esm/plugins/go-to-line.mjs +217 -0
  43. package/esm/plugins/indent.d.mts +22 -0
  44. package/esm/plugins/indent.mjs +359 -0
  45. package/esm/plugins/select-token-callbacks.d.mts +51 -0
  46. package/esm/plugins/select-token-callbacks.mjs +296 -0
  47. package/esm/plugins/special-chars.d.mts +25 -0
  48. package/esm/plugins/special-chars.mjs +207 -0
  49. package/esm/plugins/test.d.mts +16 -0
  50. package/esm/plugins/test.mjs +56 -0
  51. package/esm/templates/hljs.d.mts +16 -0
  52. package/esm/templates/hljs.mjs +28 -0
  53. package/esm/templates/prism.d.mts +16 -0
  54. package/esm/templates/prism.mjs +25 -0
  55. package/package.json +83 -7
  56. package/plugins/README.md +2 -0
  57. package/plugins/auto-close-brackets.js +2 -0
  58. package/plugins/auto-close-brackets.min.js +1 -1
  59. package/plugins/autocomplete.js +6 -6
  60. package/plugins/autocomplete.min.js +1 -1
  61. package/plugins/autodetect.js +4 -2
  62. package/plugins/autodetect.min.js +1 -1
  63. package/plugins/find-and-replace.css +0 -4
  64. package/plugins/find-and-replace.js +28 -8
  65. package/plugins/find-and-replace.min.css +1 -1
  66. package/plugins/find-and-replace.min.js +1 -1
  67. package/plugins/go-to-line.css +10 -5
  68. package/plugins/go-to-line.js +39 -6
  69. package/plugins/go-to-line.min.css +1 -1
  70. package/plugins/go-to-line.min.js +1 -1
  71. package/plugins/indent.js +4 -2
  72. package/plugins/indent.min.js +1 -1
  73. package/plugins/prism-line-numbers.css +14 -5
  74. package/plugins/prism-line-numbers.min.css +1 -1
  75. package/plugins/select-token-callbacks.js +3 -1
  76. package/plugins/select-token-callbacks.min.js +1 -1
  77. package/plugins/special-chars.css +13 -1
  78. package/plugins/special-chars.js +14 -4
  79. package/plugins/special-chars.min.css +1 -1
  80. package/plugins/special-chars.min.js +1 -1
  81. package/plugins/test.js +22 -7
  82. package/plugins/test.min.js +1 -1
  83. package/.github/workflows/minify.yml +0 -22
  84. package/.github/workflows/npm-publish.yml +0 -21
  85. package/CODE_OF_CONDUCT.md +0 -130
  86. package/CONTRIBUTING.md +0 -35
  87. package/tests/hljs.html +0 -55
  88. package/tests/i18n.html +0 -197
  89. package/tests/prism-match-braces-compatibility.js +0 -215
  90. package/tests/prism-match-braces-compatibility.min.js +0 -1
  91. package/tests/prism.html +0 -54
  92. package/tests/tester.js +0 -600
  93. package/tests/tester.min.js +0 -21
@@ -0,0 +1,676 @@
1
+ +++
2
+ title = "Adding Extra Functionality With code-input.js' Plugins"
3
+ +++
4
+
5
+ # Adding Extra Functionality With `code-input.js`' Plugins
6
+
7
+ Right now, you can only add one plugin of each type (e.g. one SelectTokenCallbacks plugin) to a code-input template, and cannot remove or add plugins after registering the template. This is hoped to be fixed in major version 3 of code-input.js, but is not regularly needed and can usually be worked around. [If you need it, let us know!](https://github.com/WebCoder49/code-input/issues/118)
8
+
9
+ ## Learn by Example
10
+ {{< playground >}}
11
+
12
+ ### Plugins for Any Highlighter
13
+
14
+ #### `AutoCloseBrackets`: Add closing brackets automatically when opening ones are typed {#playground-preset-auto-close-brackets}
15
+
16
+ ```
17
+ <!DOCTYPE html>
18
+ <html>
19
+ <body>
20
+ <!--For convenience, this demo uses files from JSDelivr CDN; for more privacy and security download and host them yourself.-->
21
+
22
+ <!--Prism+code-input-->
23
+ <script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/components/prism-core.min.js" data-manual></script><!--Remove data-manual if also using Prism normally-->
24
+ <script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/plugins/autoloader/prism-autoloader.min.js"></script>
25
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/themes/prism.min.css"></link>
26
+ <script src="https://cdn.jsdelivr.net/gh/WebCoder49/code-input@2.6/code-input.min.js"></script>
27
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/WebCoder49/code-input@2.6/code-input.min.css">
28
+
29
+ <!--Import-->
30
+ <script src="https://cdn.jsdelivr.net/gh/WebCoder49/code-input@2.6/plugins/auto-close-brackets.min.js"></script>
31
+ <!--Not necessary, but works very well with the Indent plugin-->
32
+ <script src="https://cdn.jsdelivr.net/gh/WebCoder49/code-input@2.6/plugins/indent.min.js"></script>
33
+
34
+ <script>
35
+ codeInput.registerTemplate("syntax-highlighted", new codeInput.templates.Prism(Prism, [
36
+ // Pass at register
37
+ new codeInput.plugins.AutoCloseBrackets(
38
+ {"(": ")", "[": "]", "{": "}", '"': '"'} // Opening brackets mapped to closing brackets, default and example {"(": ")", "[": "]", "{": "}", '"': '"'}. All brackets must only be one character.
39
+ ),
40
+ // Not necessary, but works very well with the Indent plugin
41
+ // when the third parameter are the brackets which enclose an
42
+ // indented block.
43
+ new codeInput.plugins.Indent(false, 4, {"(": ")", "[": "]", "{": "}"})
44
+ ]));
45
+ </script>
46
+ <p>This uses both the auto-close brackets and indent plugins. Try typing some brackets / double quotes!</p>
47
+ <code-input language="javascript"></code-input>
48
+ </body>
49
+ </html>
50
+ ```
51
+
52
+ #### `Autocomplete`: Display a customisable popup next to the caret that can appear and disappear {#playground-preset-autocomplete}
53
+
54
+ ```
55
+ <!DOCTYPE html>
56
+ <html>
57
+ <body>
58
+ <!--For convenience, this demo uses files from JSDelivr CDN; for more privacy and security download and host them yourself.-->
59
+ <!--Prism+code-input-->
60
+ <script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/components/prism-core.min.js" data-manual></script><!--Remove data-manual if also using Prism normally-->
61
+ <script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/plugins/autoloader/prism-autoloader.min.js"></script>
62
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/themes/prism.min.css"></link>
63
+ <script src="https://cdn.jsdelivr.net/gh/WebCoder49/code-input@2.6/code-input.min.js"></script>
64
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/WebCoder49/code-input@2.6/code-input.min.css">
65
+
66
+ <!--Import-->
67
+ <script src="https://cdn.jsdelivr.net/gh/WebCoder49/code-input@2.6/plugins/autocomplete.min.js"></script>
68
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/WebCoder49/code-input@2.6/plugins/autocomplete.min.css">
69
+
70
+
71
+ <script>
72
+ // Create a function for autocompletion
73
+ var tags = ["!DOCTYPE html", "html", "head", "body", "title", "style", "script", "link", "meta", "h1", "h2", "h3", "h4", "h5", "h6", "em", "strong", "span", "section", "aside", "article", "div", "nav", "main", "ul", "ol", "li", "code-input"];
74
+ function updatePopup(popupElem, textarea, caretPos) {
75
+ // Takes in
76
+ // popupElem: an element under the caret which can be filled
77
+ // with autocompletion suggestion elements
78
+ // textarea: the editing element inside the code-input element
79
+ // (get the code-input element using textarea.parentElement; passed
80
+ // in for backwards compatibility)
81
+ // caretPos: the character index of the caret (typing cursor) in the
82
+ // contents
83
+ console.log(popupElem);
84
+ let list_ends_on_start_tag = textarea.value.substring(0, caretPos).split("<");
85
+ let start_tag = list_ends_on_start_tag[list_ends_on_start_tag.length-1];
86
+ if(start_tag[0] == "/") start_tag = start_tag.substr(1);
87
+ if(start_tag == "" || start_tag.includes(" ") || start_tag.includes(">")) {
88
+ popupElem.innerHTML = "";
89
+ return;
90
+ }
91
+ popupElem.innerText = "";
92
+ tags.forEach((tag) => {
93
+ if(tag.substring(0, start_tag.length) == start_tag) {
94
+ console.log(tag, tag.substring(0, start_tag.length));
95
+ let autocompleteButton = document.createElement("button");
96
+ autocompleteButton.innerHTML = "<i>" + tag.substring(0, start_tag.length) + "</i>" + tag.substring(start_tag.length, tag.length);
97
+ autocompleteButton.addEventListener("click", () => {
98
+ document.execCommand("insertText", false, tag.substring(start_tag.length, tag.length));
99
+ popupElem.innerHTML = ""; // On popup
100
+ });
101
+ popupElem.appendChild(autocompleteButton);
102
+ }
103
+ });
104
+
105
+ if(popupElem.firstElementChild != null) {
106
+ popupElem.firstElementChild.innerHTML += "[Tab]";
107
+ }
108
+ textarea.addEventListener("keydown", (event) => {
109
+ if(event.key == "Tab" && popupElem.firstElementChild != null) {
110
+ popupElem.firstElementChild.click();
111
+ event.preventDefault();
112
+ }
113
+ })
114
+ }
115
+ // Pass at register
116
+ codeInput.registerTemplate("syntax-highlighted", new codeInput.templates.Prism(Prism, [
117
+ new codeInput.plugins.Autocomplete(updatePopup) // See above
118
+ ]));
119
+ </script>
120
+ <p>Start typing some HTML tags to see the autocomplete in action. You can click an autocomplete suggestion, or press the Tab key to select the first.</p>
121
+ <code-input language="html"></code-input>
122
+ </body>
123
+ </html>
124
+ ```
125
+
126
+ #### `FindAndReplace`: Add an openable dialog to find and replace matches to a search term, including highlighting the matches {#playground-preset-find-and-replace}
127
+
128
+ ```
129
+ <!DOCTYPE html>
130
+ <html>
131
+ <body>
132
+ <!--For convenience, this demo uses files from JSDelivr CDN; for more privacy and security download and host them yourself.-->
133
+ <!--Prism+code-input-->
134
+ <script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/components/prism-core.min.js" data-manual></script><!--Remove data-manual if also using Prism normally-->
135
+ <script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/plugins/autoloader/prism-autoloader.min.js"></script>
136
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/themes/prism.min.css"></link>
137
+ <script src="https://cdn.jsdelivr.net/gh/WebCoder49/code-input@2.6/code-input.min.js"></script>
138
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/WebCoder49/code-input@2.6/code-input.min.css">
139
+
140
+ <!--Import-->
141
+ <script src="https://cdn.jsdelivr.net/gh/WebCoder49/code-input@2.6/plugins/find-and-replace.min.js"></script>
142
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/WebCoder49/code-input@2.6/plugins/find-and-replace.min.css"/>
143
+
144
+ <script>
145
+ let findAndReplacePlugin = new codeInput.plugins.FindAndReplace(
146
+ true, // 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)`.
147
+ true, // 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)`.
148
+ );
149
+ // Programatically opening the dialogs, to integrate with your user interface
150
+ function find() {
151
+ findAndReplacePlugin.showPrompt(document.querySelector("code-input"), false);
152
+ }
153
+ function replace() {
154
+ findAndReplacePlugin.showPrompt(document.querySelector("code-input"), true);
155
+ }
156
+ codeInput.registerTemplate("syntax-highlighted", new codeInput.templates.Prism(Prism, [
157
+ // Pass at register
158
+ findAndReplacePlugin
159
+ ]));
160
+ </script>
161
+ <p>When focused in the editor: Try Ctrl+F, or click <button onclick="find();">this</button> to find. Try Ctrl+H, or click <button onclick="replace();">this</button> to replace.</p>
162
+ <code-input language="markdown"># Hickory dickory dock
163
+ Hickory dickory dock.
164
+ The mouse ran up the clock.
165
+ The clock struck one,
166
+ The mouse ran down,
167
+ Hickory dickory dock.</code-input>
168
+ </body>
169
+ </html>
170
+ ```
171
+
172
+ #### `GoToLine`: Add an openable dialog to go to a specific line and potentially column number {#playground-preset-go-to-line}
173
+
174
+ ```
175
+ <!DOCTYPE html>
176
+ <html>
177
+ <body>
178
+ <!--For convenience, this demo uses files from JSDelivr CDN; for more privacy and security download and host them yourself.-->
179
+ <!--Prism+code-input-->
180
+ <script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/components/prism-core.min.js" data-manual></script><!--Remove data-manual if also using Prism normally-->
181
+ <script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/plugins/autoloader/prism-autoloader.min.js"></script>
182
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/themes/prism.min.css"></link>
183
+ <!--Not necessary, but works very well with the Prism line-numbers plugin-->
184
+ <script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/plugins/line-numbers/prism-line-numbers.min.js"></script>
185
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/plugins/line-numbers/prism-line-numbers.min.css">
186
+ <script src="https://cdn.jsdelivr.net/gh/WebCoder49/code-input@2.6/code-input.min.js"></script>
187
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/WebCoder49/code-input@2.6/code-input.min.css">
188
+
189
+ <!--Import-->
190
+ <script src="https://cdn.jsdelivr.net/gh/WebCoder49/code-input@2.6/plugins/go-to-line.min.js"></script>
191
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/WebCoder49/code-input@2.6/plugins/go-to-line.min.css"/>
192
+ <!--Not necessary, but works very well with the Prism line-numbers plugin-->
193
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/WebCoder49/code-input@2.6/plugins/prism-line-numbers.min.css"/>
194
+
195
+ <script>
196
+ let goToLinePlugin = new codeInput.plugins.GoToLine(
197
+ true, // Should Ctrl+G be overriden for go-to-line functionality? Either way, you can trigger it yourself using (instance of this plugin)`.showPrompt(code-input element)`.
198
+ );
199
+ // Programatically opening the dialogs, to integrate with your user interface
200
+ function goToLine() {
201
+ goToLinePlugin.showPrompt(document.querySelector("code-input"));
202
+ }
203
+ codeInput.registerTemplate("syntax-highlighted", new codeInput.templates.Prism(Prism, [
204
+ // Pass at register
205
+ goToLinePlugin
206
+ ]));
207
+ </script>
208
+ <p>Try Ctrl+G when focused in the editor, or click <button onclick="goToLine()">this button</button></p>
209
+ <code-input class="line-numbers" language="markdown"># Hickory dickory dock
210
+ Hickory dickory dock.
211
+ The mouse ran up the clock.
212
+ The clock struck one,
213
+ The mouse ran down,
214
+ Hickory dickory dock.</code-input>
215
+ </body>
216
+ </html>
217
+ ```
218
+
219
+ #### `Indent`: Make the Tab key and newlines after brackets do what you expect {#playground-preset-indent}
220
+
221
+ ```
222
+ <!DOCTYPE html>
223
+ <html>
224
+ <body>
225
+ <!--For convenience, this demo uses files from JSDelivr CDN; for more privacy and security download and host them yourself.-->
226
+ <!--Prism+code-input-->
227
+ <script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/components/prism-core.min.js" data-manual></script><!--Remove data-manual if also using Prism normally-->
228
+ <script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/plugins/autoloader/prism-autoloader.min.js"></script>
229
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/themes/prism.min.css"></link>
230
+ <script src="https://cdn.jsdelivr.net/gh/WebCoder49/code-input@2.6/code-input.min.js"></script>
231
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/WebCoder49/code-input@2.6/code-input.min.css">
232
+
233
+ <!--Import-->
234
+ <script src="https://cdn.jsdelivr.net/gh/WebCoder49/code-input@2.6/plugins/indent.min.js"></script>
235
+
236
+ <script>
237
+ // Programatically opening the dialogs, to integrate with your user interface
238
+ function goToLine() {
239
+ goToLinePlugin.showPrompt(document.querySelector("code-input"));
240
+ }
241
+ codeInput.registerTemplate("syntax-highlighted", new codeInput.templates.Prism(Prism, [
242
+ // Pass at register
243
+ new codeInput.plugins.Indent(
244
+ true, // Should the Tab key enter spaces rather than tabs? Defaults to false.
245
+ 4, // How many spaces is each tab character worth? Defaults to 4, and has no effect if the previous argument was true (in which case use CSS tab-width)
246
+ {"(": ")", "[": "]", "{": "}"}, // Opening brackets mapped to closing brackets, default and example {"(": ")", "[": "]", "{": "}"}. All brackets must only be one character, and this can be left as null to remove bracket-based indentation behaviour.
247
+ true, // Whether pressing the Escape key before (Shift+)Tab should make this keypress focus on a different element (Tab's default behaviour). You should always either enable this or use this plugin's disableTabIndentation and enableTabIndentation methods linked to other keyboard shortcuts, for accessibility.
248
+ )
249
+ ]));
250
+ </script>
251
+ <p>Try Tab or Shift+Tab when selecting or editing text.</p>
252
+ <code-input class="line-numbers" language="json">{
253
+ "hello": "world",
254
+ 1: 2,
255
+ "foo": {
256
+ "bar": "baz"
257
+ }
258
+ }</code-input>
259
+ </body>
260
+ </html>
261
+ ```
262
+
263
+ #### `SelectTokenCallbacks`: Handle which highlighted tokens are selected in the `code-input` element, e.g. for visual effects {#playground-preset-select-token-callbacks}
264
+
265
+ ```
266
+ <!DOCTYPE html>
267
+ <html>
268
+ <head>
269
+ <!--Prism+code-input-->
270
+ <script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/components/prism-core.min.js" data-manual></script><!--Remove data-manual if also using Prism normally-->
271
+ <script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/plugins/autoloader/prism-autoloader.min.js"></script>
272
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/themes/prism.min.css"></link>
273
+
274
+ <script>
275
+ // This code is here to show a very real-world use of
276
+ // SelectTokenCallbacks: transforming plugins from a highlighter
277
+ // that act on hover and click events to ones for editable code
278
+ // that act on text selection.
279
+
280
+ /* Modified from Prism.js v1.29.0's match-braces plugin.
281
+ to enable codeInput SelectTokenCallbacks compatibility. */
282
+
283
+ /* Licensed MIT
284
+ Copyright 2012 Lea Verou, 2025 Oliver Geer */
285
+
286
+ // Additions on lines 6-10, and lines 84-98.
287
+
288
+ // code-input modification: ADD
289
+ // Callbacks
290
+ let selectBrace;
291
+ let deselectAllBraces;
292
+ // END code-input modification
293
+ (function () {
294
+
295
+ if (typeof Prism === 'undefined' || typeof document === 'undefined') {
296
+ return;
297
+ }
298
+
299
+ function mapClassName(name) {
300
+ var customClass = Prism.plugins.customClass;
301
+ if (customClass) {
302
+ return customClass.apply(name, 'none');
303
+ } else {
304
+ return name;
305
+ }
306
+ }
307
+
308
+ var PARTNER = {
309
+ '(': ')',
310
+ '[': ']',
311
+ '{': '}',
312
+ };
313
+
314
+ // The names for brace types.
315
+ // These names have two purposes: 1) they can be used for styling and 2) they are used to pair braces. Only braces
316
+ // of the same type are paired.
317
+ var NAMES = {
318
+ '(': 'brace-round',
319
+ '[': 'brace-square',
320
+ '{': 'brace-curly',
321
+ };
322
+
323
+ // A map for brace aliases.
324
+ // This is useful for when some braces have a prefix/suffix as part of the punctuation token.
325
+ var BRACE_ALIAS_MAP = {
326
+ '${': '{', // JS template punctuation (e.g. `foo ${bar + 1}`)
327
+ };
328
+
329
+ var LEVEL_WARP = 12;
330
+
331
+ var pairIdCounter = 0;
332
+
333
+ var BRACE_ID_PATTERN = /^(pair-\d+-)(close|open)$/;
334
+
335
+ /**
336
+ * Returns the brace partner given one brace of a brace pair.
337
+ *
338
+ * @param {HTMLElement} brace
339
+ * @returns {HTMLElement}
340
+ */
341
+ function getPartnerBrace(brace) {
342
+ var match = BRACE_ID_PATTERN.exec(brace.id);
343
+ return document.querySelector('#' + match[1] + (match[2] == 'open' ? 'close' : 'open'));
344
+ }
345
+
346
+ /**
347
+ * @this {HTMLElement}
348
+ */
349
+ function hoverBrace() {
350
+ if (!Prism.util.isActive(this, 'brace-hover', true)) {
351
+ return;
352
+ }
353
+
354
+ [this, getPartnerBrace(this)].forEach(function (e) {
355
+ e.classList.add(mapClassName('brace-hover'));
356
+ });
357
+ }
358
+ /**
359
+ * @this {HTMLElement}
360
+ */
361
+ function leaveBrace() {
362
+ [this, getPartnerBrace(this)].forEach(function (e) {
363
+ e.classList.remove(mapClassName('brace-hover'));
364
+ });
365
+ }
366
+ // code-input modification: ADD
367
+ selectBrace = (token) => {
368
+ console.log("sB", token, BRACE_ID_PATTERN, BRACE_ID_PATTERN.test(token.id));
369
+ if(BRACE_ID_PATTERN.test(token.id)) { // Check it's a brace
370
+ hoverBrace.apply(token); // Move the brace from a this to a parameter
371
+ }
372
+ };
373
+ deselectAllBraces = (tokenContainer) => {
374
+ console.log("dAB", tokenContainer);
375
+ // Remove selected class
376
+ let selectedClassTokens = tokenContainer.getElementsByClassName(mapClassName('brace-hover'));
377
+ // Use it like a queue, because as elements have their class name removed they are live-removed from the collection.
378
+ while(selectedClassTokens.length > 0) {
379
+ selectedClassTokens[0].classList.remove(mapClassName('brace-hover'));
380
+ }
381
+ }; // Moves the brace from a this to a parameter
382
+ // end code-input modification
383
+ /**
384
+ * @this {HTMLElement}
385
+ */
386
+ function clickBrace() {
387
+ if (!Prism.util.isActive(this, 'brace-select', true)) {
388
+ return;
389
+ }
390
+
391
+ [this, getPartnerBrace(this)].forEach(function (e) {
392
+ e.classList.add(mapClassName('brace-selected'));
393
+ });
394
+ }
395
+
396
+ Prism.hooks.add('complete', function (env) {
397
+
398
+ /** @type {HTMLElement} */
399
+ var code = env.element;
400
+ var pre = code.parentElement;
401
+
402
+ if (!pre || pre.tagName != 'PRE') {
403
+ return;
404
+ }
405
+
406
+ // find the braces to match
407
+ /** @type {string[]} */
408
+ var toMatch = [];
409
+ if (Prism.util.isActive(code, 'match-braces')) {
410
+ toMatch.push('(', '[', '{');
411
+ }
412
+
413
+ if (toMatch.length == 0) {
414
+ // nothing to match
415
+ return;
416
+ }
417
+
418
+ if (!pre.__listenerAdded) {
419
+ // code blocks might be highlighted more than once
420
+ pre.addEventListener('mousedown', function removeBraceSelected() {
421
+ // the code element might have been replaced
422
+ var code = pre.querySelector('code');
423
+ var className = mapClassName('brace-selected');
424
+ Array.prototype.slice.call(code.querySelectorAll('.' + className)).forEach(function (e) {
425
+ e.classList.remove(className);
426
+ });
427
+ });
428
+ Object.defineProperty(pre, '__listenerAdded', { value: true });
429
+ }
430
+
431
+ /** @type {HTMLSpanElement[]} */
432
+ var punctuation = Array.prototype.slice.call(
433
+ code.querySelectorAll('span.' + mapClassName('token') + '.' + mapClassName('punctuation'))
434
+ );
435
+
436
+ /** @type {{ index: number, open: boolean, element: HTMLElement }[]} */
437
+ var allBraces = [];
438
+
439
+ toMatch.forEach(function (open) {
440
+ var close = PARTNER[open];
441
+ var name = mapClassName(NAMES[open]);
442
+
443
+ /** @type {[number, number][]} */
444
+ var pairs = [];
445
+ /** @type {number[]} */
446
+ var openStack = [];
447
+
448
+ for (var i = 0; i < punctuation.length; i++) {
449
+ var element = punctuation[i];
450
+ if (element.childElementCount == 0) {
451
+ var text = element.textContent;
452
+ text = BRACE_ALIAS_MAP[text] || text;
453
+ if (text === open) {
454
+ allBraces.push({ index: i, open: true, element: element });
455
+ element.classList.add(name);
456
+ element.classList.add(mapClassName('brace-open'));
457
+ openStack.push(i);
458
+ } else if (text === close) {
459
+ allBraces.push({ index: i, open: false, element: element });
460
+ element.classList.add(name);
461
+ element.classList.add(mapClassName('brace-close'));
462
+ if (openStack.length) {
463
+ pairs.push([i, openStack.pop()]);
464
+ }
465
+ }
466
+ }
467
+ }
468
+
469
+ pairs.forEach(function (pair) {
470
+ var pairId = 'pair-' + (pairIdCounter++) + '-';
471
+
472
+ var opening = punctuation[pair[0]];
473
+ var closing = punctuation[pair[1]];
474
+
475
+ opening.id = pairId + 'open';
476
+ closing.id = pairId + 'close';
477
+
478
+ [opening, closing].forEach(function (e) {
479
+ e.addEventListener('mouseenter', hoverBrace);
480
+ e.addEventListener('mouseleave', leaveBrace);
481
+ e.addEventListener('click', clickBrace);
482
+ });
483
+ });
484
+ });
485
+
486
+ var level = 0;
487
+ allBraces.sort(function (a, b) { return a.index - b.index; });
488
+ allBraces.forEach(function (brace) {
489
+ if (brace.open) {
490
+ brace.element.classList.add(mapClassName('brace-level-' + (level % LEVEL_WARP + 1)));
491
+ level++;
492
+ } else {
493
+ level = Math.max(0, level - 1);
494
+ brace.element.classList.add(mapClassName('brace-level-' + (level % LEVEL_WARP + 1)));
495
+ }
496
+ });
497
+ });
498
+
499
+ }());
500
+ </script>
501
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/plugins/match-braces/prism-match-braces.min.css"/>
502
+
503
+ <script src="https://cdn.jsdelivr.net/gh/WebCoder49/code-input@2.6/code-input.min.js"></script>
504
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/WebCoder49/code-input@2.6/code-input.min.css">
505
+
506
+ <!--Import-->
507
+ <script src="https://cdn.jsdelivr.net/gh/WebCoder49/code-input@2.6/plugins/select-token-callbacks.min.js"></script>
508
+ </head>
509
+ <body>
510
+ <!--For convenience, this demo uses files from JSDelivr CDN; for more privacy and security download and host them yourself.-->
511
+
512
+ <script>
513
+ codeInput.registerTemplate("syntax-highlighted", new codeInput.templates.Prism(Prism, [
514
+ // Pass at register
515
+ new codeInput.plugins.SelectTokenCallbacks(
516
+ // Set up the behaviour of tokens text-selected in the `<code-input>` element, and the exact definition of a token being text-selected.
517
+
518
+ // All parameters are optional. If you provide no arguments to the constructor, this will dynamically apply the "code-input_select-token-callbacks_selected" class to selected tokens only, for you to style via CSS.
519
+
520
+ new codeInput.plugins.SelectTokenCallbacks.TokenSelectorCallbacks(
521
+ // Pass any callbacks you want to customise the behaviour of selected tokens via JavaScript.
522
+ // (If the behaviour you want is just differently styling selected tokens _via CSS_, you should probably use the codeInput.plugins.SelectTokenCallbacks.TokenSelectorCallbacks.createClassSynchronisation(selectedClass) static method.)
523
+
524
+ selectBrace, // Runs multiple times when the text selection inside the code-input changes, each time inputting a single (part of the highlighted `<pre><code>`) token element that is selected in the new text selection.
525
+ deselectAllBraces // Each time the text selection inside the code-input changes, runs once before any tokenSelectedCallback calls, inputting the highlighted `<pre><code>`'s `<code>` element that contains all token elements.
526
+ ),
527
+ false, // If true, tokens will only be marked as selected when no text is selected but rather the caret is inside them (start of selection == end of selection). Default false.
528
+ true, // Whether the caret or text selection's end being just before the first character of a token means said token is selected. Default true.
529
+ true, // Whether the caret or text selection's start being just after the last character of a token means said token is selected. Default true.
530
+ false, // Whether temporary `<span>` elements should be created inside partially-selected tokens containing just the selected text and given the selected class. Default false.
531
+ true, // Whether tokens for which only some of their text is selected should be treated as selected. Default true.
532
+ true // Whether all parent tokens of selected tokens should be treated as selected. Default true.
533
+ )
534
+ ]));
535
+ </script>
536
+ <p>Try selecting some code with a bracket. This is just one demo use of this very flexible plugin, which lets you use more features from your highlighter (here, Prism.js' match-braces plugin)!</p>
537
+ <code-input class="match-braces" language="javascript">function hello() {
538
+ let data = {
539
+ "array": [
540
+ "world"
541
+ ]
542
+ };
543
+ console.log(data["array"][0]);
544
+ }</code-input>
545
+ </body>
546
+ </html>
547
+ ```
548
+
549
+ #### `SpecialChars`: Display a selection of characters as a colourful representation of their character codes {#playground-preset-special-chars}
550
+
551
+ ```
552
+ <!--
553
+ WARNING:
554
+
555
+ This plugin is currently unstable when used with other plugins,
556
+ Unicode characters, or highlight.js. I hope to fix much of this by
557
+ major version 3, and if you could help that would be amazing!
558
+
559
+ See https://github.com/WebCoder49/code-input/issues?q=is%3Aissue%20state%3Aopen%20specialchars
560
+ -->
561
+
562
+ <!DOCTYPE html>
563
+ <html>
564
+ <body>
565
+ <!--For convenience, this demo uses files from JSDelivr CDN; for more privacy and security download and host them yourself.-->
566
+ <!--Prism+code-input-->
567
+ <script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/components/prism-core.min.js" data-manual></script><!--Remove data-manual if also using Prism normally-->
568
+ <script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/plugins/autoloader/prism-autoloader.min.js"></script>
569
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/themes/prism.min.css"></link>
570
+ <script src="https://cdn.jsdelivr.net/gh/WebCoder49/code-input@2.6/code-input.min.js"></script>
571
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/WebCoder49/code-input@2.6/code-input.min.css">
572
+
573
+ <!--Import-->
574
+ <script src="https://cdn.jsdelivr.net/gh/WebCoder49/code-input@2.6/plugins/special-chars.min.js"></script>
575
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/WebCoder49/code-input@2.6/plugins/special-chars.min.css"></script>
576
+
577
+ <script>
578
+ codeInput.registerTemplate("syntax-highlighted", new codeInput.templates.Prism(Prism, [
579
+ // Pass at register
580
+ new codeInput.plugins.SpecialChars(
581
+ true, // Whether or not to give special characters custom background colors based on their hex code. Defaults to false.
582
+ true, // If true, forces the color of the hex code to inherit from syntax highlighting. If false, the base color of the `pre code` element is used to give contrast to the small characters. Defaults to false.
583
+ /(?!\n)(?!\t)[\u{0000}-\u{001F}]|[\u{007F}-\u{009F}]|[\u{0200}-\u{FFFF}]/ug // The regular expression which matches special characters. Defaults to many non-renderable ASCII characters (which characters are renderable depends on the browser and OS).
584
+ )
585
+ ]));
586
+ </script>
587
+ <code-input class="line-numbers" language="json"></code-input>
588
+ <script>
589
+ window.addEventListener("load", function() {
590
+ document.querySelector("code-input").value += "[\n";
591
+ for(let i = 0; i < 256; i++) {
592
+ document.querySelector("code-input").value += ` ${String.fromCharCode(i)},\n`;
593
+ }
594
+ document.querySelector("code-input").value += "]\n";
595
+ });
596
+ </script>
597
+ </body>
598
+ </html>
599
+ ```
600
+
601
+
602
+
603
+ ### Plugins for highlight.js Only
604
+
605
+ #### `Autodetect`: Auto-detect the programming language live {#playground-preset-autodetect}
606
+
607
+ ```
608
+ <!DOCTYPE html>
609
+ <html>
610
+ <body>
611
+ <!--For convenience, this demo uses files from JSDelivr CDN; for more privacy and security download and host them yourself.-->
612
+ <!--highlight.js+code-input-->
613
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/styles/default.min.css">
614
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/highlight.min.js"></script>
615
+ <script src="https://cdn.jsdelivr.net/gh/WebCoder49/code-input@2.6/code-input.min.js"></script>
616
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/WebCoder49/code-input@2.6/code-input.min.css">
617
+
618
+
619
+ <!--Import-->
620
+ <script src="https://cdn.jsdelivr.net/gh/WebCoder49/code-input@2.6/plugins/autodetect.min.js"></script>
621
+
622
+ <script>
623
+ codeInput.registerTemplate("syntax-highlighted", new codeInput.templates.Hljs(hljs, [
624
+ // Pass at register
625
+ new codeInput.plugins.Autodetect()
626
+ ]));
627
+ </script>
628
+ <p>Start typing code of any language. <st;;;rong>Detected language: <span id="language"></span></strong>. Inaccurate language detection should be reported to <a target="_blank" href="highlightjs.org">highlight.js</a>, not code-input-js.</p>
629
+ <code-input oninput="document.getElementById('language').textContent = this.getAttribute('language');"></code-input>
630
+ <p></p>
631
+ </body>
632
+ </html>
633
+ ```
634
+
635
+ ### Plugins for Prism.js Only
636
+
637
+ #### `PrismLineNumbers`: Add visible line numbers from Prism.js' plugin of the same name {#playground-preset-prism-line-numbers}
638
+
639
+ ```
640
+ <!DOCTYPE html>
641
+ <html>
642
+ <body>
643
+ <!--For convenience, this demo uses files from JSDelivr CDN; for more privacy and security download and host them yourself.-->
644
+ <!--Prism+code-input-->
645
+ <script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/components/prism-core.min.js" data-manual></script><!--Remove data-manual if also using Prism normally-->
646
+ <script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/plugins/autoloader/prism-autoloader.min.js"></script>
647
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/themes/prism.min.css"></link>
648
+ <script src="https://cdn.jsdelivr.net/gh/WebCoder49/code-input@2.6/code-input.min.js"></script>
649
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/WebCoder49/code-input@2.6/code-input.min.css">
650
+
651
+
652
+ <!--Import-->
653
+ <script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/plugins/line-numbers/prism-line-numbers.min.js"></script>
654
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/plugins/line-numbers/prism-line-numbers.min.css">
655
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/WebCoder49/code-input@2.6/plugins/prism-line-numbers.min.css"/>
656
+
657
+ <script>
658
+ codeInput.registerTemplate("syntax-highlighted", new codeInput.templates.Prism(Prism, [
659
+ // CSS only - don't pass here
660
+ ]));
661
+ </script>
662
+ <p>The lines are numbered!</p>
663
+ <code-input class="line-numbers" language="markdown"># Hickory dickory dock
664
+ Hickory dickory dock.
665
+ The mouse ran up the clock.
666
+ The clock struck one,
667
+ The mouse ran down,
668
+ Hickory dickory dock.</code-input>
669
+ </body>
670
+ </html>
671
+ ```
672
+
673
+ {{< /playground >}}
674
+
675
+ ## Translating plugin text
676
+ As shown above, some plugins contain user interfaces containing English text. If you provide translated versions, you can swap them out for different languages following [these instructions](../i18n#languages).