@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
package/code-input.js CHANGED
@@ -1,10 +1,16 @@
1
1
  /**
2
2
  * **code-input** is a library which lets you create custom HTML `<code-input>`
3
3
  * elements that act like `<textarea>` elements but support syntax-highlighted
4
- * code, implemented using any typical syntax highlighting library. [MIT-Licensed]
5
- *
6
- * **<https://github.com/WebCoder49/code-input>**
4
+ * code, implemented using any typical syntax highlighting library.
5
+ *
6
+ * License of whole library for bundlers:
7
+ *
8
+ * Copyright 2021-2025 Oliver Geer and contributors
9
+ * @license MIT
10
+ *
11
+ * **<https://code-input-js.org>**
7
12
  */
13
+ "use strict";
8
14
 
9
15
 
10
16
  var codeInput = {
@@ -64,7 +70,11 @@ var codeInput = {
64
70
  "change",
65
71
  "selectionchange",
66
72
  "invalid",
67
- "input"
73
+ "input",
74
+ "focus",
75
+ "blur",
76
+ "focusin",
77
+ "focusout"
68
78
  ],
69
79
 
70
80
  /* ------------------------------------
@@ -121,13 +131,12 @@ var codeInput = {
121
131
  // Add waiting code-input elements wanting this template from queue
122
132
  if (templateName in codeInput.templateNotYetRegisteredQueue) {
123
133
  for (let i in codeInput.templateNotYetRegisteredQueue[templateName]) {
124
- elem = codeInput.templateNotYetRegisteredQueue[templateName][i];
125
- elem.template = template;
126
- codeInput.runOnceWindowLoaded((function(elem) { elem.connectedCallback(); }).bind(null, elem), elem);
134
+ const elem = codeInput.templateNotYetRegisteredQueue[templateName][i];
135
+ elem.templateObject = template;
136
+ elem.connectedCallback();
127
137
  // Bind sets elem as first parameter of function
128
138
  // So innerHTML can be read
129
139
  }
130
- console.log(`code-input: template: Added existing elements with template ${templateName}`);
131
140
  }
132
141
 
133
142
  if (codeInput.defaultTemplate == undefined) {
@@ -135,16 +144,14 @@ var codeInput = {
135
144
  // Add elements with default template from queue
136
145
  if (undefined in codeInput.templateNotYetRegisteredQueue) {
137
146
  for (let i in codeInput.templateNotYetRegisteredQueue[undefined]) {
138
- elem = codeInput.templateNotYetRegisteredQueue[undefined][i];
139
- elem.template = template;
140
- codeInput.runOnceWindowLoaded((function(elem) { elem.connectedCallback(); }).bind(null, elem), elem);
147
+ const elem = codeInput.templateNotYetRegisteredQueue[undefined][i];
148
+ elem.templateObject = template;
149
+ elem.connectedCallback();
141
150
  // Bind sets elem as first parameter of function
142
151
  // So innerHTML can be read
143
152
  }
144
153
  }
145
- console.log(`code-input: template: Set template ${templateName} as default`);
146
154
  }
147
- console.log(`code-input: template: Created template ${templateName}`);
148
155
  },
149
156
 
150
157
  /**
@@ -159,7 +166,7 @@ var codeInput = {
159
166
  * Constructor to create a custom template instance. Pass this into `codeInput.registerTemplate` to use it.
160
167
  * I would strongly recommend using the built-in simpler template `codeInput.templates.prism` or `codeInput.templates.hljs`.
161
168
  * @param {(codeElement: HTMLCodeElement, codeInput?: codeInput.CodeInput) => void} highlight - a callback to highlight the code, that takes an HTML `<code>` element inside a `<pre>` element as a parameter
162
- * @param {boolean} preElementStyled - is the `<pre>` element CSS-styled as well as the `<code>` element? If true, `<pre>` element's scrolling is synchronised; if false, `<code>` element's scrolling is synchronised.
169
+ * @param {boolean} preElementStyled - is the `<pre>` element CSS-styled (if so set to true), or the `<code>` element (false)?
163
170
  * @param {boolean} isCode - is this for writing code? If true, the code-input's lang HTML attribute can be used, and the `<code>` element will be given the class name 'language-[lang attribute's value]'.
164
171
  * @param {boolean} includeCodeInputInHighlightFunc - Setting this to true passes the `<code-input>` element as a second argument to the highlight function.
165
172
  * @param {codeInput.Plugin[]} plugins - An array of plugin objects to add extra features - see `codeInput.Plugin`
@@ -209,6 +216,7 @@ var codeInput = {
209
216
  plugins = [];
210
217
  },
211
218
 
219
+ // ESM-SUPPORT-START-TEMPLATES-BLOCK-1 Do not (re)move this - it's needed for ESM generation!
212
220
  /**
213
221
  * For creating a custom template from scratch, please
214
222
  * use `new codeInput.Template(...)`
@@ -222,38 +230,19 @@ var codeInput = {
222
230
  * For adding small pieces of functionality, please see `codeInput.plugins`.
223
231
  */
224
232
  templates: {
233
+ // (Source code for class templates after var codeInput = ... so they can extend the codeInput.Template class)
225
234
  /**
226
- * Constructor to create a template that uses Prism.js syntax highlighting (https://prismjs.com/)
227
- * @param {Object} prism Import Prism.js, then after that import pass the `Prism` object as this parameter.
228
- * @param {codeInput.Plugin[]} plugins - An array of plugin objects to add extra features - see `codeInput.plugins`
229
- * @returns {codeInput.Template} template object
235
+ * @deprecated Please use `new codeInput.templates.Prism(...)`
230
236
  */
231
237
  prism(prism, plugins = []) { // Dependency: Prism.js (https://prismjs.com/)
232
- return new codeInput.Template(
233
- prism.highlightElement, // highlight
234
- true, // preElementStyled
235
- true, // isCode
236
- false, // includeCodeInputInHighlightFunc
237
- plugins
238
- );
238
+ return new codeInput.templates.Prism(prism, plugins);
239
239
  },
240
+
240
241
  /**
241
- * Constructor to create a template that uses highlight.js syntax highlighting (https://highlightjs.org/)
242
- * @param {Object} hljs Import highlight.js, then after that import pass the `hljs` object as this parameter.
243
- * @param {codeInput.Plugin[]} plugins - An array of plugin objects to add extra features - see `codeInput.plugins`
244
- * @returns {codeInput.Template} template object
242
+ * @deprecated Please use `new codeInput.templates.Hljs(...)`
245
243
  */
246
244
  hljs(hljs, plugins = []) { // Dependency: Highlight.js (https://highlightjs.org/)
247
- return new codeInput.Template(
248
- function(codeElement) {
249
- codeElement.removeAttribute("data-highlighted");
250
- hljs.highlightElement(codeElement);
251
- }, // highlight
252
- false, // preElementStyled
253
- true, // isCode
254
- false, // includeCodeInputInHighlightFunc
255
- plugins
256
- );
245
+ return new codeInput.templates.Hljs(hljs, plugins);
257
246
  },
258
247
 
259
248
  /**
@@ -318,7 +307,7 @@ var codeInput = {
318
307
  },
319
308
 
320
309
  /**
321
- * @deprecated Please use `new codeInput.Template()`
310
+ * @deprecated Please use `new codeInput.Template(...)`
322
311
  */
323
312
  custom(highlight = function () { }, preElementStyled = true, isCode = true, includeCodeInputInHighlightFunc = false, plugins = []) {
324
313
  return {
@@ -330,6 +319,7 @@ var codeInput = {
330
319
  };
331
320
  },
332
321
  },
322
+ // ESM-SUPPORT-END-TEMPLATES-BLOCK-1 Do not (re)move this - it's needed for ESM generation!
333
323
 
334
324
  /* ------------------------------------
335
325
  * ------------Plugins-----------------
@@ -370,7 +360,6 @@ var codeInput = {
370
360
  * modifications to the `codeInput.Plugin.attributeChanged` method.
371
361
  */
372
362
  constructor(observedAttributes) {
373
- console.log("code-input: plugin: Created plugin");
374
363
 
375
364
  observedAttributes.forEach((attribute) => {
376
365
  codeInput.observedAttributes.push(attribute);
@@ -378,9 +367,9 @@ var codeInput = {
378
367
  }
379
368
 
380
369
  /**
381
- * Replace the keys in destination with any source
370
+ * Replace the values in destination with those from source where the keys match, in-place.
382
371
  * @param {Object} destination Where to place the translated strings, already filled with the keys pointing to English strings.
383
- * @param {Object} source The same keys, or some of them, mapped to translated strings.
372
+ * @param {Object} source The same keys, or some of them, mapped to translated strings. Keys not present here will retain the values they are maapped to in destination.
384
373
  */
385
374
  addTranslations(destination, source) {
386
375
  for(const key in source) {
@@ -423,13 +412,20 @@ var codeInput = {
423
412
  * ------------------------------------ */
424
413
 
425
414
  /**
426
- * A code-input element.
415
+ * A `<code-input>` element, an instance of an `HTMLElement`, and the result
416
+ * of `document.createElement("code-input")`. Attributes are only set when
417
+ * the element's template has been registered, and before this are null.
427
418
  */
428
419
  CodeInput: class extends HTMLElement {
429
420
  constructor() {
430
421
  super(); // Element
431
422
  }
432
423
 
424
+ /**
425
+ * When the code-input's template is registered, this contains its codeInput.Template object.
426
+ * Should be treated as read-only by external code.
427
+ */
428
+ templateObject = null;
433
429
  /**
434
430
  * Exposed child textarea element for user to input code in
435
431
  */
@@ -446,8 +442,8 @@ var codeInput = {
446
442
  codeElement = null;
447
443
 
448
444
  /**
449
- * Exposed non-scrolling element designed to contain dialog boxes etc. that shouldn't scroll
450
- * with the code-input element.
445
+ * Exposed non-scrolling element designed to contain dialog boxes etc. from plugins,
446
+ * that shouldn't scroll with the code-input element.
451
447
  */
452
448
  dialogContainerElement = null;
453
449
 
@@ -472,8 +468,8 @@ var codeInput = {
472
468
  * @param {Array} args - the arguments to pass into the event callback in the template after the code-input element. Normally left empty
473
469
  */
474
470
  pluginEvt(eventName, args) {
475
- for (let i in this.template.plugins) {
476
- let plugin = this.template.plugins[i];
471
+ for (let i in this.templateObject.plugins) {
472
+ let plugin = this.templateObject.plugins[i];
477
473
  if (eventName in plugin) {
478
474
  if (args === undefined) {
479
475
  plugin[eventName](this);
@@ -493,7 +489,6 @@ var codeInput = {
493
489
  * to syntax-highlight it. */
494
490
 
495
491
  needsHighlight = false; // Just inputted
496
- handleEventsFromTextarea = true; // Turn to false when unusual internal events are called on the textarea
497
492
  originalAriaDescription;
498
493
 
499
494
  /**
@@ -529,19 +524,11 @@ var codeInput = {
529
524
  this.pluginEvt("beforeHighlight");
530
525
 
531
526
  // Syntax Highlight
532
- if (this.template.includeCodeInputInHighlightFunc) this.template.highlight(resultElement, this);
533
- else this.template.highlight(resultElement);
527
+ if (this.templateObject.includeCodeInputInHighlightFunc) this.templateObject.highlight(resultElement, this);
528
+ else this.templateObject.highlight(resultElement);
534
529
 
535
530
  this.syncSize();
536
531
 
537
- // If editing here, scroll to the caret by focusing, though this shouldn't count as a focus event
538
- if(this.textareaElement === document.activeElement) {
539
- this.handleEventsFromTextarea = false;
540
- this.textareaElement.blur();
541
- this.textareaElement.focus();
542
- this.handleEventsFromTextarea = true;
543
- }
544
-
545
532
  this.pluginEvt("afterHighlight");
546
533
  }
547
534
 
@@ -550,7 +537,7 @@ var codeInput = {
550
537
  */
551
538
  syncSize() {
552
539
  // Synchronise the size of the pre/code and textarea elements
553
- if(this.template.preElementStyled) {
540
+ if(this.templateObject.preElementStyled) {
554
541
  this.style.backgroundColor = getComputedStyle(this.preElement).backgroundColor;
555
542
  this.textareaElement.style.height = getComputedStyle(this.preElement).height;
556
543
  this.textareaElement.style.width = getComputedStyle(this.preElement).width;
@@ -624,21 +611,45 @@ var codeInput = {
624
611
  setup() {
625
612
  if(this.textareaElement != null) return; // Already set up
626
613
 
614
+ this.mutationObserver = new MutationObserver(this.mutationObserverCallback.bind(this));
615
+ this.mutationObserver.observe(this, {
616
+ attributes: true,
617
+ attributeOldValue: true
618
+ });
619
+
627
620
  this.classList.add("code-input_registered"); // Remove register message
628
- if (this.template.preElementStyled) this.classList.add("code-input_pre-element-styled");
621
+ if (this.templateObject.preElementStyled) this.classList.add("code-input_pre-element-styled");
629
622
 
630
623
  this.pluginEvt("beforeElementsAdded");
631
624
 
625
+ const fallbackTextarea = this.querySelector("textarea[data-code-input-fallback]");
626
+ let value;
627
+ if(fallbackTextarea) {
628
+ // Fallback textarea exists
629
+ // Sync attributes; existing code-input attributes take priority
630
+ let textareaAttributeNames = fallbackTextarea.getAttributeNames();
631
+ for(let i = 0; i < textareaAttributeNames.length; i++) {
632
+ const attr = textareaAttributeNames[i];
633
+ if(!this.hasAttribute(attr)) {
634
+ this.setAttribute(attr, fallbackTextarea.getAttribute(attr));
635
+ }
636
+ }
637
+ // Sync value
638
+ value = fallbackTextarea.value;
639
+ } else {
640
+ value = this.unescapeHtml(this.innerHTML);
641
+ }
642
+ value = value || this.getAttribute("value") || "";
643
+
632
644
  // First-time attribute sync
633
- let lang = this.getAttribute("language") || this.getAttribute("lang");
634
- let placeholder = this.getAttribute("placeholder") || this.getAttribute("language") || this.getAttribute("lang") || "";
635
- let value = this.unescapeHtml(this.innerHTML) || this.getAttribute("value") || "";
636
- // Value attribute deprecated, but included for compatibility
645
+ const lang = this.getAttribute("language") || this.getAttribute("lang");
646
+ const placeholder = this.getAttribute("placeholder") || lang || "";
647
+
637
648
 
638
649
  this.initialValue = value; // For form reset
639
650
 
640
651
  // Create textarea
641
- let textarea = document.createElement("textarea");
652
+ const textarea = document.createElement("textarea");
642
653
  textarea.placeholder = placeholder;
643
654
  if(value != "") {
644
655
  textarea.value = value;
@@ -657,9 +668,7 @@ var codeInput = {
657
668
  this.classList.add("code-input_mouse-focused");
658
669
  });
659
670
  textarea.addEventListener("blur", () => {
660
- if(this.handleEventsFromTextarea) {
661
- this.classList.remove("code-input_mouse-focused");
662
- }
671
+ this.classList.remove("code-input_mouse-focused");
663
672
  });
664
673
 
665
674
  this.innerHTML = ""; // Clear Content
@@ -691,7 +700,7 @@ var codeInput = {
691
700
  pre.append(code);
692
701
  this.append(pre);
693
702
 
694
- if (this.template.isCode) {
703
+ if (this.templateObject.isCode) {
695
704
  if (lang != undefined && lang != "") {
696
705
  code.classList.add("language-" + lang.toLowerCase());
697
706
  }
@@ -722,19 +731,34 @@ var codeInput = {
722
731
  }
723
732
 
724
733
  /**
725
- * @deprecated Please use `codeInput.CodeInput.escapeHtml`
734
+ * @deprecated This shouldn't have been accessed as part of the library's public interface (to enable more flexibility in backwards-compatible versions), but is still here just in case it was.
726
735
  */
727
736
  escape_html(text) {
728
737
  return this.escapeHtml(text);
729
738
  }
730
739
 
731
740
  /**
732
- * @deprecated Please use `codeInput.CodeInput.getTemplate`
741
+ * @deprecated This shouldn't have been accessed as part of the library's public interface (to enable more flexibility in backwards-compatible versions), but is still here just in case it was.
733
742
  */
734
743
  get_template() {
735
744
  return this.getTemplate();
736
745
  }
737
746
 
747
+ /**
748
+ * @deprecated Present for backwards compatibility; use CodeInput.templateObject.
749
+ */
750
+ get template() {
751
+ return this.templateObject;
752
+ }
753
+
754
+ /**
755
+ * @deprecated The Vue framework may try to set the template
756
+ * property to the value of the template attribute, a string.
757
+ * This should not happen. Intentional use of this should
758
+ * also not happen since templates are changed by changing
759
+ * the template attribute to the name of one registered.
760
+ */
761
+ set template(value) { }
738
762
 
739
763
  /* ------------------------------------
740
764
  * -----------Callbacks----------------
@@ -747,19 +771,14 @@ var codeInput = {
747
771
  * find its template and set up the element.
748
772
  */
749
773
  connectedCallback() {
750
- this.template = this.getTemplate();
751
- if (this.template != undefined) {
774
+ // Stored in templateObject because some frameworks will override
775
+ // template property with the string value of the attribute
776
+ this.templateObject = this.getTemplate();
777
+ if (this.templateObject != undefined) {
752
778
  this.classList.add("code-input_registered");
753
- codeInput.runOnceWindowLoaded(() => {
754
- this.setup();
755
- this.classList.add("code-input_loaded");
756
- }, this);
757
- }
758
- this.mutationObserver = new MutationObserver(this.mutationObserverCallback.bind(this));
759
- this.mutationObserver.observe(this, {
760
- attributes: true,
761
- attributeOldValue: true
762
- });
779
+ this.setup();
780
+ this.classList.add("code-input_loaded");
781
+ }
763
782
  }
764
783
 
765
784
  mutationObserverCallback(mutationList, observer) {
@@ -799,8 +818,8 @@ var codeInput = {
799
818
  this.value = newValue;
800
819
  break;
801
820
  case "template":
802
- this.template = codeInput.usedTemplates[newValue || codeInput.defaultTemplate];
803
- if (this.template.preElementStyled) this.classList.add("code-input_pre-element-styled");
821
+ this.templateObject = codeInput.usedTemplates[newValue || codeInput.defaultTemplate];
822
+ if (this.templateObject.preElementStyled) this.classList.add("code-input_pre-element-styled");
804
823
  else this.classList.remove("code-input_pre-element-styled");
805
824
  // Syntax Highlight
806
825
  this.scheduleHighlight();
@@ -885,22 +904,20 @@ var codeInput = {
885
904
  this.boundEventCallbacks[listener] = boundCallback;
886
905
 
887
906
  if (codeInput.textareaSyncEvents.includes(type)) {
888
- // Synchronise with textarea, only when handleEventsFromTextarea is true
889
- // This callback is modified to only run when the handleEventsFromTextarea is set.
890
- let conditionalBoundCallback = function(evt) { if(this.handleEventsFromTextarea) boundCallback(evt); }.bind(this);
891
- this.boundEventCallbacks[listener] = conditionalBoundCallback;
907
+ // Synchronise with textarea
908
+ this.boundEventCallbacks[listener] = boundCallback;
892
909
 
893
910
  if (options === undefined) {
894
911
  if(this.textareaElement == null) {
895
912
  this.addEventListener("code-input_load", () => { this.textareaElement.addEventListener(type, boundCallback); });
896
913
  } else {
897
- this.textareaElement.addEventListener(type, conditionalBoundCallback);
914
+ this.textareaElement.addEventListener(type, boundCallback);
898
915
  }
899
916
  } else {
900
917
  if(this.textareaElement == null) {
901
918
  this.addEventListener("code-input_load", () => { this.textareaElement.addEventListener(type, boundCallback, options); });
902
919
  } else {
903
- this.textareaElement.addEventListener(type, conditionalBoundCallback, options);
920
+ this.textareaElement.addEventListener(type, boundCallback, options);
904
921
  }
905
922
  }
906
923
  } else {
@@ -949,8 +966,18 @@ var codeInput = {
949
966
  * Get the text contents of the code-input element.
950
967
  */
951
968
  get value() {
952
- // Get from editable textarea element
953
- return this.textareaElement.value;
969
+ if(this.textareaElement) {
970
+ // Get from editable textarea element
971
+ return this.textareaElement.value;
972
+ } else {
973
+ // Unregistered
974
+ const fallbackTextarea = this.querySelector("textarea[data-code-input-fallback]");
975
+ if(fallbackTextarea) {
976
+ return fallbackTextarea.value;
977
+ } else {
978
+ return this.innerHTML;
979
+ }
980
+ }
954
981
  }
955
982
  /**
956
983
  * Set the text contents of the code-input element.
@@ -960,11 +987,28 @@ var codeInput = {
960
987
  if (val === null || val === undefined) {
961
988
  val = "";
962
989
  }
963
- // Save in editable textarea element
964
- this.textareaElement.value = val;
965
- // Trigger highlight
966
- this.scheduleHighlight();
967
- return val;
990
+ if(this.textareaElement) {
991
+ // Save in editable textarea element
992
+ this.textareaElement.value = val;
993
+ // Trigger highlight
994
+ this.scheduleHighlight();
995
+ } else {
996
+ // Unregistered
997
+ const fallbackTextarea = this.querySelector("textarea[data-code-input-fallback]");
998
+ if(fallbackTextarea) {
999
+ fallbackTextarea.value = val;
1000
+ } else {
1001
+ this.innerHTML = val;
1002
+ }
1003
+ }
1004
+ }
1005
+
1006
+ // Synchronise blur and focus
1007
+ focus(options={}) {
1008
+ return this.textareaElement.focus(options);
1009
+ }
1010
+ blur(options={}) {
1011
+ return this.textareaElement.blur(options);
968
1012
  }
969
1013
 
970
1014
  /**
@@ -1032,7 +1076,7 @@ var codeInput = {
1032
1076
 
1033
1077
  /**
1034
1078
  * Allows plugins to store data in the scope of a single element.
1035
- * Key - name of the plugin
1079
+ * Key - name of the plugin, in camelCase
1036
1080
  * Value - object of data to be stored; different plugins may use this differently.
1037
1081
  */
1038
1082
  pluginData = {};
@@ -1043,19 +1087,66 @@ var codeInput = {
1043
1087
  formResetCallback() {
1044
1088
  this.value = this.initialValue;
1045
1089
  };
1046
- },
1090
+ }
1091
+ }
1047
1092
 
1048
- /**
1049
- * To ensure the DOM is ready, run this callback after the window
1050
- * has loaded (or now if it has already loaded)
1093
+ // ESM-SUPPORT-START-TEMPLATES-BLOCK-2 Do not (re)move this - it's needed for ESM generation!
1094
+ {
1095
+ // Templates are defined here after the codeInput variable is set, because they reference it by extending codeInput.Template.
1096
+
1097
+ // ESM-SUPPORT-START-TEMPLATE-prism Do not (re)move this - it's needed for ESM generation!
1098
+ /**
1099
+ * A template that uses Prism.js syntax highlighting (https://prismjs.com/).
1100
+ */
1101
+ class Prism extends codeInput.Template { // Dependency: Prism.js (https://prismjs.com/)
1102
+ /**
1103
+ * Constructor to create a template that uses Prism.js syntax highlighting (https://prismjs.com/)
1104
+ * @param {Object} prism Import Prism.js, then after that import pass the `Prism` object as this parameter.
1105
+ * @param {codeInput.Plugin[]} plugins - An array of plugin objects to add extra features - see `codeInput.plugins`
1106
+ * @param {boolean} preElementStyled - Defaults to true, which should be right for most themes. If the styling is broken, change to false. (See `codeInput.Template` constructor's definition.)
1107
+ * @returns {codeInput.Template} template object
1108
+ */
1109
+ constructor(prism, plugins = [], preElementStyled = true) {
1110
+ super(
1111
+ prism.highlightElement, // highlight
1112
+ preElementStyled, // preElementStyled
1113
+ true, // isCode
1114
+ false, // includeCodeInputInHighlightFunc
1115
+ plugins
1116
+ );
1117
+ }
1118
+ };
1119
+ // ESM-SUPPORT-END-TEMPLATE-prism Do not (re)move this - it's needed for ESM generation!
1120
+ codeInput.templates.Prism = Prism;
1121
+
1122
+ // ESM-SUPPORT-START-TEMPLATE-hljs Do not (re)move this - it's needed for ESM generation!
1123
+ /**
1124
+ * A template that uses highlight.js syntax highlighting (https://highlightjs.org/).
1051
1125
  */
1052
- runOnceWindowLoaded(callback, codeInputElem) {
1053
- if(document.readyState == "complete") {
1054
- callback(); // Fully loaded
1055
- } else {
1056
- window.addEventListener("load", callback);
1126
+ class Hljs extends codeInput.Template { // Dependency: Highlight.js (https://highlightjs.org/)
1127
+ /**
1128
+ * Constructor to create a template that uses highlight.js syntax highlighting (https://highlightjs.org/)
1129
+ * @param {Object} hljs Import highlight.js, then after that import pass the `hljs` object as this parameter.
1130
+ * @param {codeInput.Plugin[]} plugins - An array of plugin objects to add extra features - see `codeInput.plugins`
1131
+ * @param {boolean} preElementStyled - Defaults to false, which should be right for most themes. If the styling is broken, change to true. (See `codeInput.Template` constructor's definition.)
1132
+ * @returns {codeInput.Template} template object
1133
+ */
1134
+ constructor(hljs, plugins = [], preElementStyled = false) {
1135
+ super(
1136
+ function(codeElement) {
1137
+ codeElement.removeAttribute("data-highlighted");
1138
+ hljs.highlightElement(codeElement);
1139
+ }, // highlight
1140
+ preElementStyled, // preElementStyled
1141
+ true, // isCode
1142
+ false, // includeCodeInputInHighlightFunc
1143
+ plugins
1144
+ );
1057
1145
  }
1058
- }
1146
+ };
1147
+ // ESM-SUPPORT-END-TEMPLATE-hljs Do not (re)move this - it's needed for ESM generation!
1148
+ codeInput.templates.Hljs = Hljs;
1059
1149
  }
1150
+ // ESM-SUPPORT-END-TEMPLATES-BLOCK-2 Do not (re)move this - it's needed for ESM generation!
1060
1151
 
1061
1152
  customElements.define("code-input", codeInput.CodeInput);
@@ -1 +1 @@
1
- code-input{display:block;overflow-y:auto;overflow-x:auto;position:relative;top:0;left:0;margin:8px;--padding:16px;height:250px;font-size:inherit;font-family:monospace;line-height:1.5;tab-size:2;caret-color:#a9a9a9;white-space:pre;padding:0!important;display:grid;grid-template-columns:100%;grid-template-rows:100%}code-input:not(.code-input_loaded){padding:var(--padding,16px)!important}code-input textarea,code-input.code-input_pre-element-styled pre,code-input:not(.code-input_pre-element-styled) pre code{margin:0!important;padding:var(--padding,16px)!important;border:0;min-width:calc(100% - var(--padding) * 2);min-height:calc(100% - var(--padding) * 2);overflow:hidden;resize:none;grid-row:1;grid-column:1;display:block}code-input.code-input_pre-element-styled pre,code-input:not(.code-input_pre-element-styled) pre code{height:max-content;width:max-content}code-input.code-input_pre-element-styled pre code,code-input:not(.code-input_pre-element-styled) pre{margin:0!important;padding:0!important;width:100%;height:100%}code-input pre,code-input pre *,code-input textarea{font-size:inherit!important;font-family:inherit!important;line-height:inherit!important;tab-size:inherit!important;text-align:inherit!important}code-input textarea[dir=auto]+pre{unicode-bidi:plaintext}code-input textarea[dir=ltr]+pre{direction:ltr}code-input textarea[dir=rtl]+pre{direction:rtl}code-input pre,code-input textarea{grid-column:1;grid-row:1}code-input textarea{z-index:1}code-input pre{z-index:0}code-input textarea{color:transparent;background:0 0;caret-color:inherit!important}code-input textarea::placeholder{color:#d3d3d3}code-input pre,code-input textarea{white-space:inherit;word-spacing:normal;word-break:normal;word-wrap:normal}code-input textarea{resize:none;outline:0!important}code-input:has(textarea:focus):not(.code-input_mouse-focused){outline:2px solid #000}code-input:not(.code-input_registered){overflow:hidden;display:block;box-sizing:border-box}code-input:not(.code-input_registered)::after{content:"Use codeInput.registerTemplate to set up.";display:block;position:absolute;bottom:var(--padding);left:var(--padding);width:calc(100% - 2 * var(--padding));border-top:1px solid grey;outline:var(--padding) solid #fff;background-color:#fff}code-input:not(.code-input_loaded) pre,code-input:not(.code-input_loaded) textarea{opacity:0}code-input .code-input_dialog-container{z-index:2;position:sticky;grid-row:1;grid-column:1;top:0;left:0;margin:0;padding:0;width:100%;height:0;text-align:inherit}[dir=rtl] code-input .code-input_dialog-container,code-input[dir=rtl] .code-input_dialog-container{left:unset;right:0}code-input .code-input_dialog-container .code-input_keyboard-navigation-instructions{top:0;left:0;display:block;position:absolute;background-color:#000;color:#fff;padding:2px;padding-left:10px;margin:0;text-wrap:balance;overflow:hidden;text-overflow:ellipsis;width:calc(100% - 12px);max-height:3em}code-input:has(pre[dir=rtl]) .code-input_dialog-container .code-input_keyboard-navigation-instructions{left:unset;right:0}code-input .code-input_dialog-container .code-input_keyboard-navigation-instructions:empty,code-input.code-input_mouse-focused .code-input_dialog-container .code-input_keyboard-navigation-instructions,code-input:not(:has(textarea:focus)) .code-input_dialog-container .code-input_keyboard-navigation-instructions{display:none}code-input:not(:has(.code-input_keyboard-navigation-instructions:empty)):has(textarea:focus):not(.code-input_mouse-focused) textarea,code-input:not(:has(.code-input_keyboard-navigation-instructions:empty)):has(textarea:focus):not(.code-input_mouse-focused).code-input_pre-element-styled pre,code-input:not(:has(.code-input_keyboard-navigation-instructions:empty)):has(textarea:focus):not(.code-input_mouse-focused):not(.code-input_pre-element-styled) pre code{padding-top:calc(var(--padding) + 3em)!important}
1
+ code-input{display:block;overflow-y:auto;overflow-x:auto;position:relative;top:0;left:0;color:#000;background-color:#fff;margin:8px;--padding:16px;height:250px;font-size:inherit;font-family:monospace;line-height:1.5;tab-size:2;caret-color:#a9a9a9;white-space:pre;padding:0!important;display:grid;grid-template-columns:100%;grid-template-rows:100%}code-input:not(.code-input_loaded){padding:var(--padding,16px)!important}code-input textarea,code-input.code-input_pre-element-styled pre,code-input:not(.code-input_pre-element-styled) pre code{margin:0!important;padding:var(--padding,16px)!important;border:0;min-width:calc(100% - var(--padding,16px) * 2);min-height:calc(100% - var(--padding,16px) * 2);box-sizing:content-box;overflow:hidden;resize:none;grid-row:1;grid-column:1;display:block}code-input.code-input_pre-element-styled pre,code-input:not(.code-input_pre-element-styled) pre code{height:max-content;width:max-content}code-input.code-input_pre-element-styled pre code,code-input:not(.code-input_pre-element-styled) pre{margin:0!important;padding:0!important;border:0!important}code-input pre,code-input pre *,code-input textarea{font-size:inherit!important;font-family:inherit!important;line-height:inherit!important;tab-size:inherit!important;text-align:inherit!important}code-input textarea[dir=auto]+pre{unicode-bidi:plaintext}code-input textarea[dir=ltr]+pre{direction:ltr}code-input textarea[dir=rtl]+pre{direction:rtl}code-input pre,code-input textarea{grid-column:1;grid-row:1}code-input textarea:not([data-code-input-fallback]){z-index:1}code-input pre{z-index:0}code-input textarea:not([data-code-input-fallback]){color:transparent;background:0 0;caret-color:inherit!important}code-input textarea::placeholder{color:#d3d3d3}code-input pre,code-input textarea{white-space:inherit;word-spacing:normal;word-break:normal;word-wrap:normal}code-input textarea{resize:none;outline:0!important}code-input:has(textarea:focus):not(.code-input_mouse-focused){outline:2px solid currentColor}code-input:not(.code-input_registered){overflow:hidden;display:block;box-sizing:border-box}code-input:not(.code-input_registered)::after{content:"No highlighting. JavaScript support is disabled or insufficient, or codeInput.registerTemplate has not been called.";display:block;position:absolute;bottom:0;left:var(--padding,16px);width:calc(100% - 2 * var(--padding,16px));overflow-x:auto;border-top:1px solid currentColor;outline-top:0;background-color:inherit;color:inherit;margin:0;padding:0;height:2em}code-input:not(.code-input_registered) textarea{min-height:calc(100% - var(--padding,16px) * 2 - 2em)}code-input:not(.code-input_loaded) pre,code-input:not(.code-input_loaded) textarea:not([data-code-input-fallback]){opacity:0}code-input .code-input_dialog-container{z-index:2;position:sticky;grid-row:1;grid-column:1;top:0;left:0;margin:0;padding:0;height:0;width:100%;text-align:inherit}code-input.code-input_pre-element-styled .code-input_dialog-container{width:calc(100% + 2 * var(--padding,16px))}[dir=rtl] code-input .code-input_dialog-container,code-input[dir=rtl] .code-input_dialog-container{left:unset;right:0}code-input .code-input_dialog-container .code-input_keyboard-navigation-instructions{top:0;left:0;display:block;position:absolute;top:0;left:0;background-color:#000;color:#fff;padding:2px;margin:0;text-wrap:balance;overflow:hidden;text-overflow:ellipsis;width:100%;box-sizing:border-box;max-height:3em}code-input .code-input_dialog-container .code-input_keyboard-navigation-instructions:empty,code-input.code-input_mouse-focused .code-input_dialog-container .code-input_keyboard-navigation-instructions,code-input:not(:has(textarea:not([data-code-input-fallback]):focus)) .code-input_dialog-container .code-input_keyboard-navigation-instructions{display:none}code-input:not(:has(.code-input_keyboard-navigation-instructions:empty)):has(textarea:not([data-code-input-fallback]):focus):not(.code-input_mouse-focused) textarea,code-input:not(:has(.code-input_keyboard-navigation-instructions:empty)):has(textarea:not([data-code-input-fallback]):focus):not(.code-input_mouse-focused).code-input_pre-element-styled pre,code-input:not(:has(.code-input_keyboard-navigation-instructions:empty)):has(textarea:not([data-code-input-fallback]):focus):not(.code-input_mouse-focused):not(.code-input_pre-element-styled) pre code{padding-top:calc(var(--padding,16px) + 3em)!important}code-input:not(:has(.code-input_keyboard-navigation-instructions:empty)):has(textarea:not([data-code-input-fallback]):focus):not(.code-input_mouse-focused) textarea,code-input:not(:has(.code-input_keyboard-navigation-instructions:empty)):has(textarea:not([data-code-input-fallback]):focus):not(.code-input_mouse-focused).code-input_pre-element-styled pre,code-input:not(:has(.code-input_keyboard-navigation-instructions:empty)):has(textarea:not([data-code-input-fallback]):focus):not(.code-input_mouse-focused):not(.code-input_pre-element-styled) pre code{min-height:calc(100% - var(--padding,16px) * 2 - 3em)}code-input textarea[data-code-input-fallback]{overflow:auto;background-color:inherit;color:inherit;height:max-content}