@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
package/tests/prism.html DELETED
@@ -1,54 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>code-input Tester</title>
7
- <!--Import Prism-->
8
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism.min.css">
9
- <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/prism.min.js"></script>
10
- <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/autoloader/prism-autoloader.min.js"></script>
11
- <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/line-numbers/prism-line-numbers.min.js"></script>
12
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/line-numbers/prism-line-numbers.min.css">
13
- <script src="prism-match-braces-compatibility.js"></script>
14
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/match-braces/prism-match-braces.min.css">
15
-
16
- <!--Import code-input-->
17
- <link rel="stylesheet" href="../code-input.css">
18
- <script src="../code-input.js"></script>
19
-
20
- <!--Import code-input plugins-->
21
- <script src="../plugins/auto-close-brackets.js"></script>
22
- <script src="../plugins/autocomplete.js"></script>
23
- <link rel="stylesheet" href="../plugins/autocomplete.css">
24
- <script src="../plugins/find-and-replace.js"></script>
25
- <link rel="stylesheet" href="../plugins/find-and-replace.css">
26
- <script src="../plugins/go-to-line.js"></script>
27
- <link rel="stylesheet" href="../plugins/go-to-line.css">
28
- <script src="../plugins/indent.js"></script>
29
- <link rel="stylesheet" href="../plugins/prism-line-numbers.css">
30
- <script src="../plugins/select-token-callbacks.js"></script>
31
- <script src="../plugins/special-chars.js"></script>
32
- <link rel="stylesheet" href="../plugins/special-chars.css">
33
-
34
- <script src="tester.js"></script>
35
- </head>
36
- <body>
37
- <h1>code-input Tester (Prism.js)</h1>
38
- <h2>If the page doesn't load, please reload it, and answer the questions in alert boxes.</h2>
39
- <h4><a href="hljs.html">Test for highlight.js</a></h4>
40
- <p>This page carries out automated tests for the code-input library to check that both the core components and the plugins work in some ways. It doesn't fully cover every scenario so you should test any code you change by hand, but it's good for quickly checking a wide range of functionality works.</p>
41
-
42
- <details id="collapse-results"><summary>Test Results (Click to Open)</summary><pre id="test-results"></pre></details>
43
- <form method="GET" class="match-braces line-numbers" action="https://google.com/search" target="_blank">
44
- <code-input name="q">console.log("Hello, World!");
45
- // A second line
46
- // A third line with &lt;html> tags</code-input>
47
- <input type="submit" value="Search Google For Code"/>
48
- </form>
49
-
50
- <script>
51
- beginTest(false);
52
- </script>
53
- </body>
54
- </html>
package/tests/tester.js DELETED
@@ -1,600 +0,0 @@
1
- /* This file contains the main code to test the code-input library with Prism.js and highlight.js. */
2
-
3
- /* --- Test running functions --- */
4
- var testsFailed = false;
5
-
6
- /* Add data to the tests list under a specific group and test description (usually the plugin name then the functionality description) */
7
- function testData(group, test, data) {
8
- let resultElem = document.getElementById("test-results");
9
- let groupElem = resultElem.querySelector("#test-"+group);
10
- if(groupElem == undefined) {
11
- groupElem = document.createElement("span");
12
- groupElem.innerHTML = `Group <b>${group}</b>:\n`
13
- groupElem.id = "test-" + group;
14
- resultElem.append(groupElem);
15
- }
16
- groupElem.innerHTML += `\t${test}: ${data}\n`;
17
- }
18
-
19
- /* Add a test to the tests list, saying if it has passed (passed parameter), and if it has failed giving a message (messageIfFailed parameter) */
20
- function testAssertion(group, test, passed, messageIfFailed) {
21
- let resultElem = document.getElementById("test-results");
22
- let groupElem = resultElem.querySelector("#test-"+group);
23
- if(groupElem == undefined) {
24
- groupElem = document.createElement("span");
25
- groupElem.innerHTML = `Group <b>${group}</b>:\n`
26
- groupElem.id = "test-" + group;
27
- resultElem.append(groupElem);
28
- }
29
- groupElem.innerHTML += `\t${test}: ${passed ? '<b style="color: darkgreen;">passed</b>' : '<b style="color: red;">failed</b> ('+messageIfFailed+')' }\n`;
30
-
31
- if(!passed) testsFailed = true;
32
- }
33
-
34
- /* Run a test that passes if the givenOutput == correctOutput */
35
- function assertEqual(group, test, givenOutput, correctOutput) {
36
- let equal = givenOutput == correctOutput;
37
- testAssertion(group, test, equal, "see console output");
38
- if(!equal) {
39
- console.error(group, test, givenOutput, "should be", correctOutput);
40
- }
41
- }
42
-
43
- /* Test whether adding text to the textarea (with keyboard events emitted, therefore interacting with plugins) gives the correct output and selection start/end. */
44
- function testAddingText(group, textarea, action, correctOutput, correctLengthToSelectionStart, correctLengthToSelectionEnd) {
45
- let origSelectionStart = textarea.selectionStart;
46
- let origValueBefore = textarea.value.substring(0, textarea.selectionStart);
47
- let origValueAfter = textarea.value.substring(textarea.selectionEnd);
48
- action(textarea);
49
-
50
- let correctOutputValue = origValueBefore+correctOutput+origValueAfter;
51
- assertEqual(group, "Text Output", textarea.value, correctOutputValue);
52
- assertEqual(group, "Code-Input Value JS Property Output", textarea.parentElement.value, correctOutputValue);
53
- assertEqual(group, "Selection Start", textarea.selectionStart, origSelectionStart+correctLengthToSelectionStart);
54
- assertEqual(group, "Selection End", textarea.selectionEnd, origSelectionStart+correctLengthToSelectionEnd);
55
- }
56
-
57
- /* --- Test helper functions --- */
58
-
59
- /* Assuming the textarea is focused, add the given text to it, emitting 'input' and 'beforeinput' keyboard events (and 'keydown'/'keyup' Enter on newlines, if enterEvents is true) which plugins can handle */
60
- function addText(textarea, text, enterEvents=false) {
61
- for(let i = 0; i < text.length; i++) {
62
- if(enterEvents && text[i] == "\n") {
63
- textarea.dispatchEvent(new KeyboardEvent("keydown", { "key": "Enter" }));
64
- textarea.dispatchEvent(new KeyboardEvent("keyup", { "key": "Enter" }));
65
- } else {
66
- let beforeInputEvt = new InputEvent("beforeinput", { "cancelable": true, "data": text[i] });
67
- textarea.dispatchEvent(beforeInputEvt);
68
- if(!beforeInputEvt.defaultPrevented) {
69
- textarea.dispatchEvent(new InputEvent("input", { "data": text[i] }));
70
- }
71
- }
72
- }
73
- }
74
-
75
- /* Emit the necessary events to simulate a backspace keypress in the textarea. */
76
- function backspace(textarea) {
77
- let keydownEvt = new KeyboardEvent("keydown", { "cancelable": true, "key": "Backspace" });
78
- textarea.dispatchEvent(keydownEvt);
79
- let keyupEvt = new KeyboardEvent("keyup", { "cancelable": true, "key": "Backspace" });
80
- textarea.dispatchEvent(keyupEvt);
81
- if(!keydownEvt.defaultPrevented) {
82
- if(textarea.selectionEnd == textarea.selectionStart) {
83
- textarea.selectionEnd = textarea.selectionStart;
84
- textarea.selectionStart--;
85
- }
86
- document.execCommand("delete", false, null);
87
- }
88
- }
89
-
90
- /* Move the caret numMovesRight characters to the right, in the textarea. */
91
- function move(textarea, numMovesRight) {
92
- textarea.selectionStart += numMovesRight;
93
- textarea.selectionEnd = textarea.selectionStart;
94
- }
95
-
96
- /* Wait in an asynchronous function for a specified number of milliseconds by using `await waitAsync(milliseconds)`. */
97
- function waitAsync(milliseconds) {
98
- return new Promise((resolve) => {
99
- setTimeout(() => {
100
- resolve();
101
- }, milliseconds);
102
- });
103
- }
104
-
105
- /* --- Running the tests --- */
106
-
107
- /* Start the test, for Prism.js if isHLJS is false, or for highlight.js if isHLJS is true. */
108
- function beginTest(isHLJS) {
109
- let codeInputElem = document.querySelector("code-input");
110
- if(isHLJS) {
111
- codeInput.registerTemplate("code-editor", codeInput.templates.hljs(hljs, [
112
- new codeInput.plugins.AutoCloseBrackets(),
113
- new codeInput.plugins.Autocomplete(function(popupElem, textarea, selectionEnd) {
114
- if(textarea.value.substring(selectionEnd-5, selectionEnd) == "popup") {
115
- // Show popup
116
- popupElem.style.display = "block";
117
- popupElem.innerHTML = "Here's your popup!";
118
- } else {
119
- popupElem.style.display = "none";
120
- }
121
- }),
122
- new codeInput.plugins.Autodetect(),
123
- new codeInput.plugins.FindAndReplace(),
124
- new codeInput.plugins.GoToLine(),
125
- new codeInput.plugins.Indent(true, 2),
126
- new codeInput.plugins.SelectTokenCallbacks(codeInput.plugins.SelectTokenCallbacks.TokenSelectorCallbacks.createClassSynchronisation("in-selection"), false, true, true, true, true, false),
127
- new codeInput.plugins.SpecialChars(true),
128
- ]));
129
- } else {
130
- codeInput.registerTemplate("code-editor", codeInput.templates.prism(Prism, [
131
- new codeInput.plugins.AutoCloseBrackets(),
132
- new codeInput.plugins.Autocomplete(function(popupElem, textarea, selectionEnd) {
133
- if(textarea.value.substring(selectionEnd-5, selectionEnd) == "popup") {
134
- // Show popup
135
- popupElem.style.display = "block";
136
- popupElem.innerHTML = "Here's your popup!";
137
- } else {
138
- popupElem.style.display = "none";
139
- }
140
- }),
141
- new codeInput.plugins.FindAndReplace(),
142
- new codeInput.plugins.GoToLine(),
143
- new codeInput.plugins.Indent(true, 2),
144
- new codeInput.plugins.SelectTokenCallbacks(new codeInput.plugins.SelectTokenCallbacks.TokenSelectorCallbacks(selectBrace, deselectAllBraces), true),
145
- new codeInput.plugins.SpecialChars(true),
146
- ]));
147
- }
148
- startLoad(codeInputElem, isHLJS);
149
- }
150
-
151
- /* Start loading the tests, using the codeInput load time as one of the tests. */
152
- function startLoad(codeInputElem, isHLJS) {
153
- let textarea;
154
- let timeToLoad = 0;
155
- let interval = window.setInterval(() => {
156
- textarea = codeInputElem.querySelector("textarea");
157
- if(textarea != null) window.clearInterval(interval);
158
- timeToLoad += 10;
159
- testData("TimeTaken", "Textarea Appears", timeToLoad+"ms (nearest 10)");
160
- startTests(textarea, isHLJS);
161
- }, 10);
162
- }
163
-
164
- /* Make input events work and be trusted in the inputElement - thanks for this SO answer: https://stackoverflow.com/a/49519772/21785620 */
165
- function allowInputEvents(inputElement, codeInputElement=undefined) {
166
- inputElement.addEventListener('input', function(e){
167
- if(!e.isTrusted){
168
- e.preventDefault();
169
- // Manually trigger
170
- // Prevent auto-close-brackets plugin recapturing the event
171
- // Needed because this interception is hacky.
172
- // TODO: Potentially plugin-agnostic way, probably automatedKeypresses var in core, won't be needed much but may be helpful extra feature.
173
- if(codeInputElement !== undefined) codeInputElement.pluginData.autoCloseBrackets.automatedKeypresses = true;
174
- document.execCommand("insertText", false, e.data);
175
- if(codeInputElement !== undefined) codeInputElement.pluginData.autoCloseBrackets.automatedKeypresses = false;
176
- }
177
- }, false);
178
- }
179
-
180
- /* Start the tests using the textarea inside the code-input element and whether highlight.js is being used (as the Autodetect plugin only works with highlight.js, for example) */
181
- async function startTests(textarea, isHLJS) {
182
- textarea.focus();
183
-
184
- codeInputElement = textarea.parentElement;
185
- allowInputEvents(textarea, codeInputElement);
186
-
187
- /*--- Tests for core functionality ---*/
188
-
189
- // Textarea's initial value should be correct.
190
- assertEqual("Core", "Initial Textarea Value", textarea.value, `console.log("Hello, World!");
191
- // A second line
192
- // A third line with <html> tags`);
193
- // Code element's displayed value, ignoring appearance with HTML tags, should be the initial value but HTML-escaped
194
- let renderedValue = codeInputElement.codeElement.innerHTML.replace(/<[^>]+>/g, "");
195
- assertEqual("Core", "Initial Rendered Value", renderedValue, `console.log("Hello, World!");
196
- // A second line
197
- // A third line with &lt;html&gt; tags
198
- `); // Extra newline so line numbers visible if enabled
199
-
200
-
201
- // Update code-input value with JavaScript, new value and num events should be correct.
202
- codeInputElement.value += `
203
- console.log("I've got another line!", 2 < 3, "should be true.");`;
204
-
205
- await waitAsync(50); // Wait for rendered value to update
206
-
207
- // Textarea's value once updated with JavaScript should be correct.
208
- assertEqual("Core", "JS-updated Textarea Value", textarea.value, `console.log("Hello, World!");
209
- // A second line
210
- // A third line with <html> tags
211
- console.log("I've got another line!", 2 < 3, "should be true.");`);
212
- // Code element's displayed value, ignoring appearance with HTML tags, should be the initial value but HTML-escaped
213
- renderedValue = codeInputElement.codeElement.innerHTML.replace(/<[^>]+>/g, "");
214
- assertEqual("Core", "JS-updated Rendered Value", renderedValue, `console.log("Hello, World!");
215
- // A second line
216
- // A third line with &lt;html&gt; tags
217
- console.log("I've got another line!", 2 &lt; 3, "should be true.");
218
- `); // Extra newline so line numbers visible if enabled
219
-
220
- // Event Listener Tests
221
- // Function type listeners
222
- let numTimesInputCalled = 0;
223
- let numTimesChangeCalled = 0;
224
-
225
- let inputListener = (evt) => {
226
- if(!evt.isTrusted) { // To prevent duplicate calling due to allowInputEvents hack
227
- numTimesInputCalled++;
228
- }
229
- };
230
- codeInputElement.addEventListener("input", inputListener);
231
- let changeListener = () => {
232
- numTimesChangeCalled++;
233
- };
234
- codeInputElement.addEventListener("change", changeListener);
235
-
236
- let inputDeletedListenerCalled = false;
237
- let deletedListener = () => {
238
- inputDeletedListenerCalled = true;
239
- };
240
- codeInputElement.addEventListener("input", deletedListener);
241
- codeInputElement.removeEventListener("input", deletedListener);
242
-
243
- // Make listeners be called
244
- textarea.focus(); // Focus textarea
245
- addText(textarea, " // Hi");
246
- textarea.blur(); // Unfocus textarea - calls change event
247
- textarea.focus();
248
-
249
- assertEqual("Core", "Function Event Listeners: Input Called Right Number of Times", numTimesInputCalled, 6);
250
- assertEqual("Core", "Function Event Listeners: Change Called Right Number of Times", numTimesChangeCalled, 1);
251
- testAssertion("Core", "Function Event Listeners: Input Removed Listener Not Called", !inputDeletedListenerCalled, "(code-input element).removeEventListener did not work.");
252
-
253
- codeInputElement.removeEventListener("input", inputListener);
254
- codeInputElement.removeEventListener("change", changeListener);
255
-
256
- // Repeat for Object type listeners
257
- numTimesInputCalled = 0;
258
- numTimesChangeCalled = 0;
259
- codeInputElement.addEventListener("input", {handleEvent: (evt) => {
260
- if(!evt.isTrusted) { // To prevent duplicate calling due to allowInputEvents hack
261
- numTimesInputCalled++;
262
- }
263
- }});
264
- codeInputElement.addEventListener("change", {handleEvent: () => {
265
- numTimesChangeCalled++;
266
- }});
267
-
268
- inputDeletedListenerCalled = false;
269
- deletedListener = {handleEvent: () => {
270
- inputDeletedListenerCalled = true;
271
- }};
272
- codeInputElement.addEventListener("input", deletedListener);
273
- codeInputElement.removeEventListener("input", deletedListener);
274
-
275
- // Make listeners be called
276
- textarea.focus(); // Focus textarea
277
- addText(textarea, " // Hi");
278
- textarea.blur(); // Unfocus textarea - calls change event
279
- textarea.focus();
280
-
281
- assertEqual("Core", "Object Event Listeners: Input Called Right Number of Times", numTimesInputCalled, 6);
282
- assertEqual("Core", "Object Event Listeners: Change Called Right Number of Times", numTimesChangeCalled, 1);
283
- testAssertion("Core", "Object Event Listeners: Input Removed Listener Not Called", !inputDeletedListenerCalled, "(code-input element).removeEventListener did not work.");
284
-
285
- // Changing language should be correct
286
- if(!isHLJS) {
287
- // Highlight.js has autodetect plugin that should make this fail, so don't run these tests with it.
288
- testAssertion("Core", "Language attribute Initial value",
289
- !codeInputElement.codeElement.classList.contains("language-javascript")
290
- && !codeInputElement.codeElement.classList.contains("language-html"),
291
- `Language unset but code element's class name is ${codeInputElement.codeElement.className}.`);
292
-
293
- codeInputElement.setAttribute("language", "HTML");
294
-
295
- await waitAsync(50); // Wait for attribute change to be handled
296
-
297
- testAssertion("Core", "Language attribute Changed value 1",
298
- codeInputElement.codeElement.classList.contains("language-html")
299
- && !codeInputElement.codeElement.classList.contains("language-javascript"),
300
- `Language set to HTML but code element's class name is ${codeInputElement.codeElement.className}.`);
301
-
302
- codeInputElement.setAttribute("language", "JavaScript");
303
-
304
- await waitAsync(50); // Wait for attribute change to be handled
305
-
306
- testAssertion("Core", "Language attribute Changed value 2",
307
- codeInputElement.codeElement.classList.contains("language-javascript")
308
- && !codeInputElement.codeElement.classList.contains("language-html"),
309
- `Language set to JavaScript but code element's class name is ${codeInputElement.codeElement.className}.`);
310
- }
311
-
312
- let formElement = codeInputElement.parentElement;
313
- formElement.reset();
314
-
315
- await waitAsync(50); // Wait for rendered value to update
316
-
317
- assertEqual("Core", "Form Reset resets Code-Input Value", codeInputElement.value, `console.log("Hello, World!");
318
- // A second line
319
- // A third line with <html> tags`);
320
- assertEqual("Core", "Form Reset resets Textarea Value", textarea.value, `console.log("Hello, World!");
321
- // A second line
322
- // A third line with <html> tags`);
323
- renderedValue = codeInputElement.codeElement.innerHTML.replace(/<[^>]+>/g, "");
324
- assertEqual("Core", "Form Reset resets Rendered Value", renderedValue, `console.log("Hello, World!");
325
- // A second line
326
- // A third line with &lt;html&gt; tags
327
- `); // Extra newline so line numbers visible if enabled.
328
-
329
- /*--- Tests for plugins ---*/
330
- // AutoCloseBrackets
331
- testAddingText("AutoCloseBrackets", textarea, function(textarea) {
332
- addText(textarea, `\nconsole.log("A test message`);
333
- move(textarea, 2);
334
- addText(textarea, `;\nconsole.log("Another test message");\n{[{[]}(([[`);
335
- backspace(textarea);
336
- backspace(textarea);
337
- backspace(textarea);
338
- addText(textarea, `)`);
339
- }, '\nconsole.log("A test message");\nconsole.log("Another test message");\n{[{[]}()]}', 77, 77);
340
-
341
- // Autocomplete
342
- addText(textarea, "popup");
343
-
344
- await waitAsync(50); // Wait for popup to be rendered
345
-
346
- testAssertion("Autocomplete", "Popup Shows", confirm("Does the autocomplete popup display correctly? (OK=Yes)"), "user-judged");
347
- backspace(textarea);
348
-
349
- await waitAsync(50); // Wait for popup disappearance to be rendered
350
-
351
- testAssertion("Autocomplete", "Popup Disappears", confirm("Has the popup disappeared? (OK=Yes)"), "user-judged");
352
- backspace(textarea);
353
- backspace(textarea);
354
- backspace(textarea);
355
- backspace(textarea);
356
-
357
- // Autodetect - these tests have been made so the programming language is very obvious
358
- // - the efficacy of autodetection is highlight.js' responsibility.
359
- if(isHLJS) {
360
- // Check detects XML - Replace all code with XML
361
- textarea.selectionStart = 0;
362
- textarea.selectionEnd = textarea.value.length;
363
- backspace(textarea);
364
- addText(textarea, 'console.log("Hello, World!");\nfunction sayHello(name) {\n console.log("Hello, " + name + "!");\n}\nsayHello("code-input");');
365
- await waitAsync(50); // Wait for highlighting so language attribute updates
366
- assertEqual("Autodetect", "Detects JavaScript", codeInputElement.getAttribute("language"), "javascript");
367
-
368
- // Check detects Python - Replace all code with Python
369
- textarea.selectionStart = 0;
370
- textarea.selectionEnd = textarea.value.length;
371
- backspace(textarea);
372
- addText(textarea, '#!/usr/bin/python\nprint("Hello, World!")\nfor i in range(5):\n print(i)');
373
- await waitAsync(50); // Wait for highlighting so language attribute updates
374
- assertEqual("Autodetect", "Detects Python", codeInputElement.getAttribute("language"), "python");
375
-
376
- // Check detects CSS - Replace all code with CSS
377
- textarea.selectionStart = 0;
378
- textarea.selectionEnd = textarea.value.length;
379
- backspace(textarea);
380
- addText(textarea, "body, html {\n height: 100%;\n background-color: blue;\n color: red;\n}");
381
- await waitAsync(50); // Wait for highlighting so language attribute updates
382
- assertEqual("Autodetect", "Detects CSS", codeInputElement.getAttribute("language"), "css");
383
- }
384
-
385
- // FindAndReplace
386
- // Replace all code
387
- textarea.selectionStart = 0;
388
- textarea.selectionEnd = textarea.value.length;
389
- backspace(textarea);
390
- addText(textarea, "// hello /\\S/g\nhe('llo', /\\s/g);\nhello");
391
- textarea.selectionStart = textarea.selectionEnd = 0; // So focuses on first match
392
-
393
- await waitAsync(50); // Wait for highlighting so text updates
394
-
395
- // Open dialog and get interactive elements
396
- textarea.dispatchEvent(new KeyboardEvent("keydown", { "cancelable": true, "key": "f", "ctrlKey": true }));
397
- let inputBoxes = codeInputElement.querySelectorAll(".code-input_find-and-replace_dialog input");
398
- let findInput = inputBoxes[0];
399
- let regExpCheckbox = inputBoxes[1];
400
- let caseSensitiveCheckbox = inputBoxes[2];
401
- let replaceInput = inputBoxes[3];
402
-
403
- let buttons = codeInputElement.querySelectorAll(".code-input_find-and-replace_dialog button");
404
- let nextMatchButton = buttons[0];
405
- let previousMatchButton = buttons[1];
406
- let replaceButton = buttons[2];
407
- let replaceAllButton = buttons[3];
408
-
409
- let replaceDropdown = codeInputElement.querySelector(".code-input_find-and-replace_dialog details summary");
410
-
411
- // Run find/replace tests
412
- findInput.value = "/\\s/g";
413
- caseSensitiveCheckbox.click(); // Now case-sensitive
414
- await waitAsync(150); // Wait for highlighting so matches update
415
- testAssertion("FindAndReplace", "Finds Case-Sensitive Matches Correctly", confirm("Is there a match on only the lowercase '/\\s/g'?"), "user-judged");
416
-
417
- findInput.value = "he[^l]*llo";
418
- regExpCheckbox.click(); // Now regex
419
- caseSensitiveCheckbox.click(); // Now not case-sensitive
420
- await waitAsync(150); // Wait for highlighting so matches update
421
- // Focuses on next match after /\s/g, therefore third he...llo
422
- testAssertion("FindAndReplace", "Finds RegExp Matches Correctly", confirm("Are there matches on all 'he...llo's?"), "user-judged");
423
-
424
- replaceDropdown.click();
425
- previousMatchButton.click();
426
- replaceInput.value = "do('hello";
427
- replaceButton.click();
428
- await waitAsync(50); // Wait for buttons to work
429
- assertEqual("FindAndReplace", "Replaces Once Correctly", textarea.value, "// hello /\\S/g\ndo('hello', /\\s/g);\nhello");
430
- nextMatchButton.click(); // Back to first match
431
-
432
- // Exit find input box
433
- codeInputElement.querySelector(".code-input_find-and-replace_dialog").dispatchEvent(new KeyboardEvent("keydown", { "key": "Escape" }));
434
- codeInputElement.querySelector(".code-input_find-and-replace_dialog").dispatchEvent(new KeyboardEvent("keyup", { "key": "Escape" }));
435
-
436
- // Check first hello now selected
437
- assertEqual("FindAndReplace", "Selection Start on Focused Match when Dialog Exited", textarea.selectionStart, 3);
438
- assertEqual("FindAndReplace", "Selection End on Focused Match when Dialog Exited", textarea.selectionEnd, 8);
439
-
440
- // Open replace dialog; conduct a find and replace
441
- textarea.dispatchEvent(new KeyboardEvent("keydown", { "cancelable": true, "key": "h", "ctrlKey": true }));
442
- findInput.value = "";
443
- findInput.focus();
444
- allowInputEvents(findInput);
445
- addText(findInput, "hello");
446
- await waitAsync(200); // Wait for highlighting so matches update
447
-
448
- replaceInput.value = "hi";
449
- replaceAllButton.click();
450
- assertEqual("FindAndReplace", "Replaces All Correctly", textarea.value, "// hi /\\S/g\ndo('hi', /\\s/g);\nhi");
451
-
452
- // Exit find input box
453
- codeInputElement.querySelector(".code-input_find-and-replace_dialog").dispatchEvent(new KeyboardEvent("keydown", { "key": "Escape" }));
454
- codeInputElement.querySelector(".code-input_find-and-replace_dialog").dispatchEvent(new KeyboardEvent("keyup", { "key": "Escape" }));
455
-
456
- // GoToLine
457
- // Replace all code
458
- textarea.selectionStart = 0;
459
- textarea.selectionEnd = textarea.value.length;
460
- backspace(textarea);
461
- addText(textarea, "// 7 times table\nlet i = 1;\nwhile(i <= 12) { console.log(`7 x ${i} = ${7*i}`) }\n// That's my code.\n// This is another comment\n// Another\n// Line");
462
-
463
- textarea.dispatchEvent(new KeyboardEvent("keydown", { "cancelable": true, "key": "g", "ctrlKey": true }));
464
- let lineInput = codeInputElement.querySelector(".code-input_go-to-line_dialog input");
465
- lineInput.value = "1";
466
- lineInput.dispatchEvent(new KeyboardEvent("keydown", { "key": "Enter" }));
467
- lineInput.dispatchEvent(new KeyboardEvent("keyup", { "key": "Enter" }));
468
- assertEqual("GoToLine", "Line Only", textarea.selectionStart, 0);
469
-
470
- textarea.dispatchEvent(new KeyboardEvent("keydown", { "cancelable": true, "key": "g", "ctrlKey": true }));
471
- lineInput.value = "3:18";
472
- lineInput.dispatchEvent(new KeyboardEvent("keydown", { "key": "Enter" }));
473
- lineInput.dispatchEvent(new KeyboardEvent("keyup", { "key": "Enter" }));
474
- assertEqual("GoToLine", "Line and Column", textarea.selectionStart, 45);
475
-
476
- textarea.dispatchEvent(new KeyboardEvent("keydown", { "cancelable": true, "key": "g", "ctrlKey": true }));
477
- lineInput.value = "10";
478
- lineInput.dispatchEvent(new KeyboardEvent("keydown", { "key": "Enter" }));
479
- lineInput.dispatchEvent(new KeyboardEvent("keyup", { "key": "Enter" }));
480
- assertEqual("GoToLine", "Rejects Out-of-range Line", lineInput.classList.contains("code-input_go-to-line_error"), true);
481
-
482
- textarea.dispatchEvent(new KeyboardEvent("keydown", { "cancelable": true, "key": "g", "ctrlKey": true }));
483
- lineInput.value = "2:12";
484
- lineInput.dispatchEvent(new KeyboardEvent("keydown", { "key": "Enter" }));
485
- lineInput.dispatchEvent(new KeyboardEvent("keyup", { "key": "Enter" }));
486
- assertEqual("GoToLine", "Rejects Out-of-range Column", lineInput.classList.contains("code-input_go-to-line_error"), true);
487
-
488
- textarea.dispatchEvent(new KeyboardEvent("keydown", { "cancelable": true, "key": "g", "ctrlKey": true }));
489
- lineInput.value = "sausages";
490
- lineInput.dispatchEvent(new KeyboardEvent("keydown", { "key": "Enter" }));
491
- lineInput.dispatchEvent(new KeyboardEvent("keyup", { "key": "Enter" }));
492
- assertEqual("GoToLine", "Rejects Invalid Input", lineInput.classList.contains("code-input_go-to-line_error"), true);
493
- assertEqual("GoToLine", "Stays open when Rejects Input", lineInput.parentElement.classList.contains("code-input_go-to-line_hidden-dialog"), false);
494
-
495
- lineInput.dispatchEvent(new KeyboardEvent("keydown", { "key": "Escape" }));
496
- lineInput.dispatchEvent(new KeyboardEvent("keyup", { "key": "Escape" }));
497
- assertEqual("GoToLine", "Exits when Esc pressed", lineInput.parentElement.classList.contains("code-input_go-to-line_hidden-dialog"), true);
498
-
499
- // Indent
500
- textarea.selectionStart = textarea.selectionEnd = textarea.value.length;
501
- addText(textarea, "\nfor(let i = 0; i < 100; i++) {\n for(let j = i; j < 100; j++) {\n // Here's some code\n console.log(i,j);\n }\n}\n{\n // This is indented\n}");
502
- textarea.selectionStart = 0;
503
- textarea.selectionEnd = textarea.value.length;
504
- textarea.dispatchEvent(new KeyboardEvent("keydown", { "key": "Tab", "shiftKey": false }));
505
- textarea.dispatchEvent(new KeyboardEvent("keyup", { "key": "Tab", "shiftKey": false }));
506
- assertEqual("Indent", "Indents Lines", textarea.value, " // 7 times table\n let i = 1;\n while(i <= 12) { console.log(`7 x ${i} = ${7*i}`) }\n // That's my code.\n // This is another comment\n // Another\n // Line\n for(let i = 0; i < 100; i++) {\n for(let j = i; j < 100; j++) {\n // Here's some code\n console.log(i,j);\n }\n }\n {\n // This is indented\n }");
507
- textarea.dispatchEvent(new KeyboardEvent("keydown", { "key": "Tab", "shiftKey": true }));
508
- textarea.dispatchEvent(new KeyboardEvent("keyup", { "key": "Tab", "shiftKey": true }));
509
- assertEqual("Indent", "Unindents Lines", textarea.value, "// 7 times table\nlet i = 1;\nwhile(i <= 12) { console.log(`7 x ${i} = ${7*i}`) }\n// That's my code.\n// This is another comment\n// Another\n// Line\nfor(let i = 0; i < 100; i++) {\n for(let j = i; j < 100; j++) {\n // Here's some code\n console.log(i,j);\n }\n}\n{\n // This is indented\n}");
510
- textarea.dispatchEvent(new KeyboardEvent("keydown", { "key": "Tab", "shiftKey": true }));
511
- textarea.dispatchEvent(new KeyboardEvent("keyup", { "key": "Tab", "shiftKey": true }));
512
- assertEqual("Indent", "Unindents Lines where some are already fully unindented", textarea.value, "// 7 times table\nlet i = 1;\nwhile(i <= 12) { console.log(`7 x ${i} = ${7*i}`) }\n// That's my code.\n// This is another comment\n// Another\n// Line\nfor(let i = 0; i < 100; i++) {\nfor(let j = i; j < 100; j++) {\n // Here's some code\n console.log(i,j);\n}\n}\n{\n// This is indented\n}");
513
-
514
- textarea.selectionStart = 255;
515
- textarea.selectionEnd = 274;
516
- textarea.dispatchEvent(new KeyboardEvent("keydown", { "key": "Tab", "shiftKey": false }));
517
- textarea.dispatchEvent(new KeyboardEvent("keyup", { "key": "Tab", "shiftKey": false }));
518
- assertEqual("Indent", "Indents Lines by Selection", textarea.value, "// 7 times table\nlet i = 1;\nwhile(i <= 12) { console.log(`7 x ${i} = ${7*i}`) }\n// That's my code.\n// This is another comment\n// Another\n// Line\nfor(let i = 0; i < 100; i++) {\nfor(let j = i; j < 100; j++) {\n // Here's some code\n console.log(i,j);\n}\n}\n{\n // This is indented\n}");
519
-
520
- textarea.selectionStart = 265;
521
- textarea.selectionEnd = 265;
522
- textarea.dispatchEvent(new KeyboardEvent("keydown", { "key": "Tab", "shiftKey": true }));
523
- textarea.dispatchEvent(new KeyboardEvent("keyup", { "key": "Tab", "shiftKey": true }));
524
- assertEqual("Indent", "Unindents Lines by Selection", textarea.value, "// 7 times table\nlet i = 1;\nwhile(i <= 12) { console.log(`7 x ${i} = ${7*i}`) }\n// That's my code.\n// This is another comment\n// Another\n// Line\nfor(let i = 0; i < 100; i++) {\nfor(let j = i; j < 100; j++) {\n // Here's some code\n console.log(i,j);\n}\n}\n{\n// This is indented\n}");
525
-
526
- // Indent+AutoCloseBrackets
527
- // Clear all code
528
- textarea.selectionStart = 0;
529
- textarea.selectionEnd = textarea.value.length;
530
- backspace(textarea);
531
-
532
- testAddingText("Indent-AutoCloseBrackets", textarea, function(textarea) {
533
- addText(textarea, `function printTriples(max) {\nfor(let i = 0; i < max-2; i++) {\nfor(let j = 0; j < max-1; j++) {\nfor(let k = 0; k < max; k++) {\nconsole.log(i,j,k);\n}\n//Hmmm...\n}//Test auto-unindent\n{`, true);
534
- move(textarea, 1); // Move after created closing bracket
535
- backspace(textarea); // Remove created closing bracket
536
- }, 'function printTriples(max) {\n for(let i = 0; i < max-2; i++) {\n for(let j = 0; j < max-1; j++) {\n for(let k = 0; k < max; k++) {\n console.log(i,j,k);\n }\n //Hmmm...\n }//Test auto-unindent\n {\n }\n }\n }\n}', 221, 221);
537
-
538
- // SelectTokenCallbacks
539
- if(isHLJS) {
540
- addText(textarea, "\nlet x = 1;\nlet y = 2;\nconsole.log(`${x} + ${y} = ${x+y}`);");
541
- move(textarea, -4); // Ends at |: "${x+y|}`);"
542
- textarea.selectionStart -= 35; // Starts at |: "let y = |2;"
543
- await waitAsync(50); // Wait for highlighting so text updates
544
- assertEqual("SelectTokenCallbacks", "Number of Selected Tokens", codeInputElement.querySelectorAll(".in-selection").length, 13);
545
- assertEqual("SelectTokenCallbacks", "Number of Selected .hljs-string Tokens", codeInputElement.querySelectorAll(".hljs-string.in-selection").length, 0); // Since parentTokensAreSelected set to false
546
- assertEqual("SelectTokenCallbacks", "Number of Selected .hljs-subst Tokens", codeInputElement.querySelectorAll(".hljs-subst.in-selection").length, 2);
547
- } else {
548
- // Combined with compatiblity-added match-braces plugin
549
- addText(textarea, "\n[(),((),'Hi')]");
550
- await waitAsync(50); // Wait for highlighting so text updates
551
- // Move back 2 characters so just after 'Hi'
552
- move(textarea, -2);
553
- await waitAsync(50); // Wait for highlighting so text updates
554
- assertEqual("SelectTokenCallbacks", "Number of Selected Braces 1", codeInputElement.getElementsByClassName("brace-hover").length, 2);
555
- // Move forward 1 character so between )]
556
- move(textarea, 1);
557
- await waitAsync(50); // Wait for highlighting so text updates
558
- assertEqual("SelectTokenCallbacks", "Number of Selected Braces 2", codeInputElement.getElementsByClassName("brace-hover").length, 4);
559
- }
560
-
561
- // SpecialChars
562
- // Clear all code
563
- textarea.selectionStart = 0;
564
- textarea.selectionEnd = textarea.value.length;
565
- backspace(textarea);
566
-
567
- addText(textarea, '"Some special characters: \u0096,\u0001\u0003,\u0002..."');
568
- textarea.selectionStart = textarea.value.length-4;
569
- textarea.selectionEnd = textarea.value.length;
570
-
571
- await waitAsync(50); // Wait for special characters to be rendered
572
-
573
- testAssertion("SpecialChars", "Displays Correctly", confirm("Do the special characters read (0096),(0001)(0003),(0002) and align with the ellipsis? (OK=Yes)"), "user-judged");
574
-
575
- // Large amounts of code
576
- // Clear all code
577
- textarea.selectionStart = 0;
578
- textarea.selectionEnd = textarea.value.length;
579
- backspace(textarea);
580
- fetch(new Request("https://cdn.jsdelivr.net/gh/webcoder49/code-input@2.1/code-input.js"))
581
- .then((response) => response.text())
582
- .then((code) => {
583
- textarea.value = "// code-input v2.1: A large code file (not the latest version!)\n// Editing this here should give little latency.\n\n"+code;
584
-
585
- textarea.selectionStart = 112;
586
- textarea.selectionEnd = 112;
587
- addText(textarea, "\n", true);
588
-
589
- document.getElementById("collapse-results").setAttribute("open", true);
590
- });
591
-
592
- /* Make it clear if any tests have failed */
593
- if(testsFailed) {
594
- document.querySelector("h2").style.backgroundColor = "red";
595
- document.querySelector("h2").textContent = "Some Tests have Failed.";
596
- } else {
597
- document.querySelector("h2").style.backgroundColor = "lightgreen";
598
- document.querySelector("h2").textContent = "All Tests have Passed.";
599
- }
600
- }