@webcoder49/code-input 2.6.4 → 2.6.5

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.
package/code-input.css CHANGED
@@ -26,6 +26,10 @@ code-input {
26
26
  /* Normal inline styles */
27
27
  margin: 8px;
28
28
  --padding: 16px;
29
+ --padding-left: var(--padding, 16px);
30
+ --padding-right: var(--padding, 16px);
31
+ --padding-top: var(--padding, 16px);
32
+ --padding-bottom: var(--padding, 16px);
29
33
  height: 250px;
30
34
  font-size: inherit;
31
35
  font-family: monospace;
@@ -40,19 +44,20 @@ code-input {
40
44
  grid-template-rows: 100%;
41
45
  }
42
46
 
43
-
44
- code-input:not(.code-input_loaded) {
45
- padding: var(--padding, 16px)!important;
47
+ code-input * {
48
+ box-sizing: content-box; /* Make height, width work consistently no matter the box-sizing of ancestors; dialogs can be styled as wanted so are excluded. */
46
49
  }
47
50
 
48
51
  code-input textarea, code-input:not(.code-input_pre-element-styled) pre code, code-input.code-input_pre-element-styled pre {
49
52
  /* Both elements need the same text and space styling so they are directly on top of each other */
50
53
  margin: 0px!important;
51
- padding: var(--padding, 16px)!important;
54
+ padding-left: var(--padding-left, 16px)!important;
55
+ padding-right: var(--padding-right, 16px)!important;
56
+ padding-top: var(--padding-top, 16px)!important;
57
+ padding-bottom: var(--padding-bottom, 16px)!important;
52
58
  border: 0;
53
- min-width: calc(100% - var(--padding, 16px) * 2);
54
- min-height: calc(100% - var(--padding, 16px) * 2);
55
- box-sizing: content-box; /* Make height, width work consistently no matter the box-sizing of ancestors; dialogs can be styled as wanted so are excluded. */
59
+ min-width: calc(100% - var(--padding-left, 16px) - var(--padding-right, 16px));
60
+ min-height: calc(100% - var(--padding-top, 16px) - var(--padding-bottom, 16px));
56
61
  overflow: hidden;
57
62
  resize: none;
58
63
  grid-row: 1;
@@ -138,42 +143,6 @@ code-input:has(textarea:focus):not(.code-input_mouse-focused) {
138
143
  outline: 2px solid currentColor;
139
144
  }
140
145
 
141
- /* Before registering give a hint about how to register. */
142
- code-input:not(.code-input_registered) {
143
- overflow: hidden;
144
- display: block;
145
- box-sizing: border-box; /* Include padding in width/height */
146
- }
147
-
148
- code-input:not(.code-input_registered)::after {
149
- /* Display message to register */
150
- content: "No highlighting. JavaScript support is disabled or insufficient, or codeInput.registerTemplate has not been called.";
151
- display: block;
152
- position: absolute;
153
- bottom: 0;
154
- left: var(--padding, 16px);
155
- width: calc(100% - 2 * var(--padding, 16px));
156
- overflow-x: auto;
157
-
158
- border-top: 1px solid currentColor;
159
- outline-top: 0;
160
- background-color: inherit;
161
- color: inherit;
162
-
163
- margin: 0;
164
- padding: 0;
165
- height: 2em;
166
- }
167
-
168
- code-input:not(.code-input_registered) textarea {
169
- /* Don't overlap with message */
170
- min-height: calc(100% - var(--padding, 16px) * 2 - 2em);
171
- }
172
-
173
- code-input:not(.code-input_loaded) pre, code-input:not(.code-input_loaded) textarea:not([data-code-input-fallback]) {
174
- opacity: 0;
175
- }
176
-
177
146
  /* Contains dialog boxes that might appear as the result of a plugin.
178
147
  Sticks to the top of the code-input element */
179
148
 
@@ -195,9 +164,6 @@ code-input .code-input_dialog-container {
195
164
  /* Dialog boxes' text is based on text-direction */
196
165
  text-align: inherit;
197
166
  }
198
- code-input.code-input_pre-element-styled .code-input_dialog-container {
199
- width: calc(100% + 2 * var(--padding, 16px));
200
- }
201
167
 
202
168
  [dir=rtl] code-input .code-input_dialog-container, code-input[dir=rtl] .code-input_dialog-container {
203
169
  left: unset;
@@ -217,14 +183,16 @@ code-input .code-input_dialog-container .code-input_keyboard-navigation-instruct
217
183
  background-color: black;
218
184
  color: white;
219
185
  padding: 2px;
186
+ padding-left: var(--padding-left, 16px);
187
+ padding-right: var(--padding-right, 16px);
220
188
  margin: 0;
221
189
  text-wrap: balance;
222
- overflow: hidden;
223
- text-overflow: ellipsis;
190
+ overflow-x: hidden;
191
+ overflow-y: auto;
224
192
 
225
193
  width: 100%;
226
194
  box-sizing: border-box;
227
- max-height: 3em;
195
+ height: 3em;
228
196
  }
229
197
 
230
198
  code-input:not(:has(textarea:not([data-code-input-fallback]):focus)) .code-input_dialog-container .code-input_keyboard-navigation-instructions,
@@ -238,17 +206,58 @@ code-input .code-input_dialog-container .code-input_keyboard-navigation-instruct
238
206
  code-input:not(:has(.code-input_keyboard-navigation-instructions:empty)):has(textarea:not([data-code-input-fallback]):focus):not(.code-input_mouse-focused) textarea,
239
207
  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,
240
208
  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 {
241
- padding-top: calc(var(--padding, 16px) + 3em)!important;
209
+ padding-top: calc(var(--padding-top, 16px) + 3em)!important;
210
+ min-height: calc(100% - var(--padding-top, 16px) - 3em - var(--padding-bottom, 16px));
211
+ }
212
+
213
+ /* Pre-loaded appearance */
214
+
215
+ code-input:not(.code-input_loaded) {
216
+ padding-left: var(--padding-left, 16px)!important;
217
+ padding-right: var(--padding-right, 16px)!important;
218
+ padding: var(--padding-top, 16px)!important;
219
+ padding: var(--padding-bottom, 16px)!important;
220
+ overflow: hidden;
221
+ display: block;
222
+ box-sizing: border-box; /* Include padding in width/height */
223
+ }
224
+
225
+ code-input:not(.code-input_loaded)::after {
226
+ /* Display message to register */
227
+ content: "No highlighting. JavaScript support is disabled or insufficient, or codeInput.registerTemplate has not been called.";
228
+ display: block;
229
+ position: absolute;
230
+ bottom: 0;
231
+ left: var(--padding-left, 16px);
232
+ width: calc(100% - var(--padding-left, 1.6px) - var(--padding-right, 1.6px));
233
+ overflow-x: auto;
234
+
235
+ border-top: 1px solid currentColor;
236
+ outline-top: 0;
237
+ background-color: inherit;
238
+ color: inherit;
239
+
240
+ margin: 0;
241
+ padding: 0;
242
+ height: 2em;
242
243
  }
243
- 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):not(.code-input_pre-element-styled) pre code, 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 {
244
- min-height: calc(100% - var(--padding, 16px) * 2 - 3em);
244
+
245
+
246
+ code-input:not(.code-input_loaded) pre, code-input:not(.code-input_loaded) textarea:not([data-code-input-fallback]) {
247
+ opacity: 0;
245
248
  }
246
249
 
247
250
  /* No JavaScript fallback - styles to override all previous */
248
251
 
252
+ code-input:has(textarea[data-code-input-fallback]) {
253
+ padding: 0!important; /* Padding now in the textarea */
254
+ box-sizing: content-box;
255
+ }
249
256
  code-input textarea[data-code-input-fallback] {
250
257
  overflow: auto;
251
258
  background-color: inherit;
252
259
  color: inherit;
253
- height: max-content;
260
+
261
+ /* Don't overlap with message */
262
+ min-height: calc(100% - var(--padding-top, 16px) - 2em - var(--padding-bottom, 16px));
254
263
  }
package/code-input.js CHANGED
@@ -620,9 +620,26 @@ var codeInput = {
620
620
  this.classList.add("code-input_registered"); // Remove register message
621
621
  if (this.templateObject.preElementStyled) this.classList.add("code-input_pre-element-styled");
622
622
 
623
- this.pluginEvt("beforeElementsAdded");
624
-
625
623
  const fallbackTextarea = this.querySelector("textarea[data-code-input-fallback]");
624
+ let fallbackFocused = false;
625
+ let fallbackSelectionStart = undefined;
626
+ let fallbackSelectionEnd = undefined;
627
+ let fallbackSelectionDirection = undefined;
628
+ let fallbackScrollLeft = undefined;
629
+ let fallbackScrollTop = undefined;
630
+ if(fallbackTextarea) {
631
+ // Move some attributes to new textarea so typing during
632
+ // slow load not interrupted
633
+ if(fallbackTextarea === document.activeElement) { // Thanks to https://stackoverflow.com/a/36430896
634
+ fallbackFocused = true;
635
+ }
636
+ fallbackSelectionStart = fallbackTextarea.selectionStart;
637
+ fallbackSelectionEnd = fallbackTextarea.selectionEnd;
638
+ fallbackSelectionDirection = fallbackTextarea.selectionDirection;
639
+ fallbackScrollLeft = fallbackTextarea.scrollLeft;
640
+ fallbackScrollTop = fallbackTextarea.scrollTop;
641
+ }
642
+
626
643
  let value;
627
644
  if(fallbackTextarea) {
628
645
  // Fallback textarea exists
@@ -638,11 +655,15 @@ var codeInput = {
638
655
  }
639
656
  // Sync value
640
657
  value = fallbackTextarea.value;
658
+ // Backwards compatibility with plugins
659
+ this.innerHTML = this.escapeHtml(value);
641
660
  } else {
642
661
  value = this.unescapeHtml(this.innerHTML);
643
662
  }
644
663
  value = value || this.getAttribute("value") || "";
645
664
 
665
+ this.pluginEvt("beforeElementsAdded");
666
+
646
667
  // First-time attribute sync
647
668
  const lang = this.getAttribute("language") || this.getAttribute("lang");
648
669
  const placeholder = this.getAttribute("placeholder") || lang || "";
@@ -671,9 +692,23 @@ var codeInput = {
671
692
  // Accessibility - detect when mouse focus to remove focus outline + keyboard navigation guidance that could irritate users.
672
693
  this.addEventListener("mousedown", () => {
673
694
  this.classList.add("code-input_mouse-focused");
695
+ // Wait for CSS to update padding
696
+ window.setTimeout(() => {
697
+ this.syncSize();
698
+ }, 0);
674
699
  });
675
700
  textarea.addEventListener("blur", () => {
676
701
  this.classList.remove("code-input_mouse-focused");
702
+ // Wait for CSS to update padding
703
+ window.setTimeout(() => {
704
+ this.syncSize();
705
+ }, 0);
706
+ });
707
+ textarea.addEventListener("focus", () => {
708
+ // Wait for CSS to update padding
709
+ window.setTimeout(() => {
710
+ this.syncSize();
711
+ }, 0);
677
712
  });
678
713
 
679
714
  this.innerHTML = ""; // Clear Content
@@ -726,13 +761,25 @@ var codeInput = {
726
761
  this.dispatchEvent(new CustomEvent("code-input_load"));
727
762
 
728
763
  this.value = value;
764
+
765
+ // Update with fallback textarea's state so can keep editing
766
+ // if loaded slowly
767
+ if(fallbackSelectionStart !== undefined) {
768
+ console.log("sel", fallbackSelectionStart, fallbackSelectionEnd, fallbackSelectionDirection, "scr", fallbackScrollTop, fallbackScrollLeft, "foc", fallbackFocused);
769
+ textarea.setSelectionRange(fallbackSelectionStart, fallbackSelectionEnd, fallbackSelectionDirection);
770
+ textarea.scrollTo(fallbackScrollTop, fallbackScrollLeft);
771
+ }
772
+ if(fallbackFocused) {
773
+ textarea.focus();
774
+ }
775
+
729
776
  this.animateFrame();
730
777
 
731
778
  const resizeObserver = new ResizeObserver((elements) => {
732
779
  // The only element that could be resized is this code-input element.
733
780
  this.syncSize();
734
781
  });
735
- resizeObserver.observe(this);
782
+ resizeObserver.observe(this.textareaElement);
736
783
 
737
784
  this.classList.add("code-input_loaded");
738
785
  }
@@ -1128,14 +1175,40 @@ var codeInput = {
1128
1175
  get wrap() { return this.getAttribute("wrap") || ""; }
1129
1176
  set wrap(val) { this.setAttribute("wrap", val); }
1130
1177
 
1178
+ /**
1179
+ * Get the JavaScript method from the internal textarea
1180
+ * element, throwing an error when no textarea is present.
1181
+ * The method is bound to the textarea as `this`.
1182
+ *
1183
+ * For internal use - treat the code-input element as a
1184
+ * textarea for the standard functions (e.g. document.
1185
+ * querySelector("code-input").focus()).
1186
+ */
1187
+ getTextareaMethod(name) {
1188
+ if(this.textareaElement) {
1189
+ return this.textareaElement[name].bind(this.textareaElement);
1190
+ } else {
1191
+ // Unregistered
1192
+ const fallbackTextarea = this.querySelector("textarea[data-code-input-fallback]");
1193
+ if(fallbackTextarea) {
1194
+ return fallbackTextarea[name].bind(fallbackTextarea);
1195
+ } else {
1196
+ throw new Error("Cannot call "+name+" on an unregistered code-input element without a data-code-input-fallback textarea.");
1197
+ }
1198
+ }
1199
+ }
1131
1200
 
1132
- blur(options={}) { return this.textareaElement.blur(options); }
1133
- checkValidity() { return this.textareaElement.checkValidity(); }
1134
- focus(options={}) { return this.textareaElement.focus(options); }
1135
- reportValidity() { return this.textareaElement.reportValidity(); }
1136
- setCustomValidity(error) { this.textareaElement.setCustomValidity(error); }
1137
- setRangeText(replacement, selectionStart=this.selectionStart, selectionEnd=this.selectionEnd, selectMode="preserve") { this.getTextareaProperty("setRangeText")(replacement, selectionStart, selectionEnd, selectMode); }
1138
- setSelectionRange(selectionStart, selectionEnd, selectionDirection="none") { this.getTextareaProperty("setSelectionRange")(selectionStart, selectionEnd, selectionDirection); }
1201
+ blur(options={}) { this.getTextareaMethod("blur")(options); }
1202
+ checkValidity() { return this.getTextareaMethod("checkValidity")(); }
1203
+ focus(options={}) { this.getTextareaMethod("focus")(options); }
1204
+ reportValidity() { return this.getTextareaMethod("reportValidity")(); }
1205
+ setCustomValidity(error) { this.getTextareaMethod("setCustomValidity")(error); }
1206
+ setRangeText(replacement, selectionStart=this.selectionStart, selectionEnd=this.selectionEnd, selectMode="preserve") {
1207
+ this.getTextareaMethod("setRangeText")(replacement, selectionStart, selectionEnd, selectMode);
1208
+ // Reflect that value updated
1209
+ if(this.textareaElement) this.scheduleHighlight();
1210
+ }
1211
+ setSelectionRange(selectionStart, selectionEnd, selectionDirection="none") { this.getTextareaMethod("setSelectionRange")(selectionStart, selectionEnd, selectionDirection); }
1139
1212
 
1140
1213
  /**
1141
1214
  * Allows plugins to store data in the scope of a single element.
@@ -1 +1 @@
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;text-align:start;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}
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;--padding-left:var(--padding, 16px);--padding-right:var(--padding, 16px);--padding-top:var(--padding, 16px);--padding-bottom:var(--padding, 16px);height:250px;font-size:inherit;font-family:monospace;text-align:start;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 *{box-sizing:content-box}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-left:var(--padding-left,16px)!important;padding-right:var(--padding-right,16px)!important;padding-top:var(--padding-top,16px)!important;padding-bottom:var(--padding-bottom,16px)!important;border:0;min-width:calc(100% - var(--padding-left,16px) - var(--padding-right,16px));min-height:calc(100% - var(--padding-top,16px) - var(--padding-bottom,16px));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 .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}[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;padding-left:var(--padding-left,16px);padding-right:var(--padding-right,16px);margin:0;text-wrap:balance;overflow-x:hidden;overflow-y:auto;width:100%;box-sizing:border-box;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-top,16px) + 3em)!important;min-height:calc(100% - var(--padding-top,16px) - 3em - var(--padding-bottom,16px))}code-input:not(.code-input_loaded){padding-left:var(--padding-left,16px)!important;padding-right:var(--padding-right,16px)!important;padding:var(--padding-top,16px)!important;padding:var(--padding-bottom,16px)!important;overflow:hidden;display:block;box-sizing:border-box}code-input:not(.code-input_loaded)::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-left,16px);width:calc(100% - var(--padding-left,1.6px) - var(--padding-right,1.6px));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_loaded) pre,code-input:not(.code-input_loaded) textarea:not([data-code-input-fallback]){opacity:0}code-input:has(textarea[data-code-input-fallback]){padding:0!important;box-sizing:content-box}code-input textarea[data-code-input-fallback]{overflow:auto;background-color:inherit;color:inherit;min-height:calc(100% - var(--padding-top,16px) - 2em - var(--padding-bottom,16px))}
package/code-input.min.js CHANGED
@@ -9,4 +9,4 @@
9
9
  * @license MIT
10
10
  *
11
11
  * **<https://code-input-js.org>**
12
- */"use strict";var codeInput={observedAttributes:["value","placeholder","language","lang","template"],textareaSyncAttributes:["value","min","max","type","pattern","autocomplete","autocorrect","autofocus","cols","dirname","disabled","form","maxlength","minlength","name","placeholder","readonly","required","rows","spellcheck","wrap"],textareaSyncEvents:["change","selectionchange","invalid","input","focus","blur","focusin","focusout"],usedTemplates:{},defaultTemplate:void 0,templateNotYetRegisteredQueue:{},registerTemplate:function(a,b){if(!("string"==typeof a||a instanceof String))throw TypeError(`code-input: Name of template "${a}" must be a string.`);if(!("function"==typeof b.highlight||b.highlight instanceof Function))throw TypeError(`code-input: Template for "${a}" invalid, because the highlight function provided is not a function; it is "${b.highlight}". Please make sure you use one of the constructors in codeInput.templates, and that you provide the correct arguments.`);if(!("boolean"==typeof b.includeCodeInputInHighlightFunc||b.includeCodeInputInHighlightFunc instanceof Boolean))throw TypeError(`code-input: Template for "${a}" invalid, because the includeCodeInputInHighlightFunc value provided is not a true or false; it is "${b.includeCodeInputInHighlightFunc}". Please make sure you use one of the constructors in codeInput.templates, and that you provide the correct arguments.`);if(!("boolean"==typeof b.preElementStyled||b.preElementStyled instanceof Boolean))throw TypeError(`code-input: Template for "${a}" invalid, because the preElementStyled value provided is not a true or false; it is "${b.preElementStyled}". Please make sure you use one of the constructors in codeInput.templates, and that you provide the correct arguments.`);if(!("boolean"==typeof b.isCode||b.isCode instanceof Boolean))throw TypeError(`code-input: Template for "${a}" invalid, because the isCode value provided is not a true or false; it is "${b.isCode}". Please make sure you use one of the constructors in codeInput.templates, and that you provide the correct arguments.`);if(!Array.isArray(b.plugins))throw TypeError(`code-input: Template for "${a}" invalid, because the plugin array provided is not an array; it is "${b.plugins}". Please make sure you use one of the constructors in codeInput.templates, and that you provide the correct arguments.`);if(b.plugins.forEach((c,d)=>{if(!(c instanceof codeInput.Plugin))throw TypeError(`code-input: Template for "${a}" invalid, because the plugin provided at index ${d} is not valid; it is "${b.plugins[d]}". Please make sure you use one of the constructors in codeInput.templates, and that you provide the correct arguments.`)}),codeInput.usedTemplates[a]=b,a in codeInput.templateNotYetRegisteredQueue)for(let c in codeInput.templateNotYetRegisteredQueue[a]){const d=codeInput.templateNotYetRegisteredQueue[a][c];d.templateObject=b,d.setup()}if(null==codeInput.defaultTemplate&&(codeInput.defaultTemplate=a,void 0 in codeInput.templateNotYetRegisteredQueue))for(let a in codeInput.templateNotYetRegisteredQueue[void 0]){const c=codeInput.templateNotYetRegisteredQueue[void 0][a];c.templateObject=b,c.setup()}},Template:class{constructor(a=function(){},b=!0,c=!0,d=!1,e=[]){this.highlight=a,this.preElementStyled=b,this.isCode=c,this.includeCodeInputInHighlightFunc=d,this.plugins=e}highlight=function(){};preElementStyled=!0;isCode=!0;includeCodeInputInHighlightFunc=!1;plugins=[]},templates:{prism(a,b=[]){return new codeInput.templates.Prism(a,b)},hljs(a,b=[]){return new codeInput.templates.Hljs(a,b)},characterLimit(a){return{highlight:function(a,b,c=[]){let d=+b.getAttribute("data-character-limit"),e=b.escapeHtml(b.value.slice(0,d)),f=b.escapeHtml(b.value.slice(d));a.innerHTML=`${e}<mark class="overflow">${f}</mark>`,0<f.length&&(a.innerHTML+=` <mark class="overflow-msg">${b.getAttribute("data-overflow-msg")||"(Character limit reached)"}</mark>`)},includeCodeInputInHighlightFunc:!0,preElementStyled:!0,isCode:!1,plugins:a}},rainbowText(a=["red","orangered","orange","goldenrod","gold","green","darkgreen","navy","blue","magenta"],b="",c=[]){return{highlight:function(a,b){let c=[],d=b.value.split(b.template.delimiter);for(let e=0;e<d.length;e++)c.push(`<span style="color: ${b.template.rainbowColors[e%b.template.rainbowColors.length]}">${b.escapeHtml(d[e])}</span>`);a.innerHTML=c.join(b.template.delimiter)},includeCodeInputInHighlightFunc:!0,preElementStyled:!0,isCode:!1,rainbowColors:a,delimiter:b,plugins:c}},character_limit(){return this.characterLimit([])},rainbow_text(a=["red","orangered","orange","goldenrod","gold","green","darkgreen","navy","blue","magenta"],b="",c=[]){return this.rainbowText(a,b,c)},custom(a=function(){},b=!0,c=!0,d=!1,e=[]){return{highlight:a,includeCodeInputInHighlightFunc:d,preElementStyled:b,isCode:c,plugins:e}}},plugins:new Proxy({},{get(a,b){if(a[b]==null)throw ReferenceError(`code-input: Plugin '${b}' is not defined. Please ensure you import the necessary files from the plugins folder in the WebCoder49/code-input repository, in the <head> of your HTML, before the plugin is instatiated.`);return a[b]}}),Plugin:class{constructor(a){a.forEach(a=>{codeInput.observedAttributes.push(a)})}addTranslations(a,b){for(const c in b)a[c]=b[c]}beforeHighlight(){}afterHighlight(){}beforeElementsAdded(){}afterElementsAdded(){}attributeChanged(){}},CodeInput:class extends HTMLElement{constructor(){super()}templateObject=null;textareaElement=null;preElement=null;codeElement=null;dialogContainerElement=null;static formAssociated=!0;boundEventCallbacks={};pluginEvt(a,b){for(let c in this.templateObject.plugins){let d=this.templateObject.plugins[c];a in d&&(b===void 0?d[a](this):d[a](this,...b))}}needsHighlight=!1;originalAriaDescription;scheduleHighlight(){this.needsHighlight=!0}animateFrame(){this.needsHighlight&&(this.update(),this.needsHighlight=!1),window.requestAnimationFrame(this.animateFrame.bind(this))}update(){let a=this.codeElement,b=this.value;b+="\n",a.innerHTML=this.escapeHtml(b),this.pluginEvt("beforeHighlight"),this.templateObject.includeCodeInputInHighlightFunc?this.templateObject.highlight(a,this):this.templateObject.highlight(a),this.syncSize(),this.pluginEvt("afterHighlight")}syncSize(){this.templateObject.preElementStyled?(this.style.backgroundColor=getComputedStyle(this.preElement).backgroundColor,this.textareaElement.style.height=getComputedStyle(this.preElement).height,this.textareaElement.style.width=getComputedStyle(this.preElement).width):(this.style.backgroundColor=getComputedStyle(this.codeElement).backgroundColor,this.textareaElement.style.height=getComputedStyle(this.codeElement).height,this.textareaElement.style.width=getComputedStyle(this.codeElement).width)}setKeyboardNavInstructions(a,b){this.dialogContainerElement.querySelector(".code-input_keyboard-navigation-instructions").innerText=a,b?this.textareaElement.setAttribute("aria-description",this.originalAriaDescription+". "+a):this.textareaElement.setAttribute("aria-description",a)}escapeHtml(a){return a.replace(/&/g,"&amp;").replace(/</g,"&lt;")}unescapeHtml(a){return a.replace(/&amp;/g,"&").replace(/&lt;/g,"<").replace(/&gt;/g,">")}getTemplate(){let a;return a=null==this.getAttribute("template")?codeInput.defaultTemplate:this.getAttribute("template"),a in codeInput.usedTemplates?codeInput.usedTemplates[a]:(a in codeInput.templateNotYetRegisteredQueue||(codeInput.templateNotYetRegisteredQueue[a]=[]),void codeInput.templateNotYetRegisteredQueue[a].push(this))}setup(){if(null!=this.textareaElement)return;this.classList.add("code-input_registered"),this.mutationObserver=new MutationObserver(this.mutationObserverCallback.bind(this)),this.mutationObserver.observe(this,{attributes:!0,attributeOldValue:!0}),this.classList.add("code-input_registered"),this.templateObject.preElementStyled&&this.classList.add("code-input_pre-element-styled"),this.pluginEvt("beforeElementsAdded");const a=this.querySelector("textarea[data-code-input-fallback]");let b;if(a){let c=a.getAttributeNames();for(let b=0;b<c.length;b++){const d=c[b];"data-code-input-fallback"!=d&&(this.hasAttribute(d)||this.setAttribute(d,a.getAttribute(d)))}b=a.value}else b=this.unescapeHtml(this.innerHTML);b=b||this.getAttribute("value")||"";const c=this.getAttribute("language")||this.getAttribute("lang"),d=this.getAttribute("placeholder")||c||"";this.initialValue=b;const e=document.createElement("textarea");e.placeholder=d,""!=b&&(e.value=b),e.innerHTML=this.innerHTML,this.hasAttribute("spellcheck")||e.setAttribute("spellcheck","false"),e.setAttribute("tabindex",this.getAttribute("tabindex")||0),this.setAttribute("tabindex",-1),this.originalAriaDescription=this.getAttribute("aria-description")||"Code input field",this.addEventListener("mousedown",()=>{this.classList.add("code-input_mouse-focused")}),e.addEventListener("blur",()=>{this.classList.remove("code-input_mouse-focused")}),this.innerHTML="";for(let a,b=0;b<this.attributes.length;b++)a=this.attributes[b].name,(codeInput.textareaSyncAttributes.includes(a)||"aria-"==a.substring(0,5))&&e.setAttribute(a,this.getAttribute(a));e.addEventListener("input",()=>{this.value=this.textareaElement.value}),this.textareaElement=e,this.append(e);let f=document.createElement("code"),g=document.createElement("pre");g.setAttribute("aria-hidden","true"),g.setAttribute("tabindex","-1"),g.setAttribute("inert",!0),this.preElement=g,this.codeElement=f,g.append(f),this.append(g),this.templateObject.isCode&&c!=null&&""!=c&&f.classList.add("language-"+c.toLowerCase());let h=document.createElement("div");h.classList.add("code-input_dialog-container"),this.append(h),this.dialogContainerElement=h;let i=document.createElement("div");i.classList.add("code-input_keyboard-navigation-instructions"),h.append(i),this.pluginEvt("afterElementsAdded"),this.dispatchEvent(new CustomEvent("code-input_load")),this.value=b,this.animateFrame();const j=new ResizeObserver(()=>{this.syncSize()});j.observe(this),this.classList.add("code-input_loaded")}escape_html(a){return this.escapeHtml(a)}get_template(){return this.getTemplate()}get template(){return this.templateObject}set template(a){}connectedCallback(){this.templateObject=this.getTemplate(),this.templateObject!=null&&(this.classList.add("code-input_registered"),window.addEventListener("DOMContentLoaded",this.setup.bind(this)))}mutationObserverCallback(a){for(const b of a)if("attributes"===b.type){for(let a=0;a<codeInput.observedAttributes.length;a++)if(b.attributeName==codeInput.observedAttributes[a])return this.attributeChangedCallback(b.attributeName,b.oldValue,super.getAttribute(b.attributeName));for(let a=0;a<codeInput.textareaSyncAttributes.length;a++)if(b.attributeName==codeInput.textareaSyncAttributes[a])return this.attributeChangedCallback(b.attributeName,b.oldValue,super.getAttribute(b.attributeName));if("aria-"==b.attributeName.substring(0,5))return this.attributeChangedCallback(b.attributeName,b.oldValue,super.getAttribute(b.attributeName))}}disconnectedCallback(){this.mutationObserver.disconnect()}attributeChangedCallback(a,b,c){if(this.isConnected)switch(this.pluginEvt("attributeChanged",[a,b,c]),a){case"value":this.value=c;break;case"template":this.templateObject=codeInput.usedTemplates[c||codeInput.defaultTemplate],this.templateObject.preElementStyled?this.classList.add("code-input_pre-element-styled"):this.classList.remove("code-input_pre-element-styled"),this.scheduleHighlight();break;case"lang":case"language":let d=this.codeElement,e=this.textareaElement;if(null!=c&&(c=c.toLowerCase(),d.classList.contains(`language-${c}`)))break;null!==b&&(b=b.toLowerCase(),d.classList.remove("language-"+b),d.parentElement.classList.remove("language-"+b)),d.classList.remove("language-none"),d.parentElement.classList.remove("language-none"),null!=c&&""!=c&&d.classList.add("language-"+c),e.placeholder==b&&(e.placeholder=c),this.scheduleHighlight();break;default:codeInput.textareaSyncAttributes.includes(a)||"aria-"==a.substring(0,5)?null==c||null==c?this.textareaElement.removeAttribute(a):this.textareaElement.setAttribute(a,c):codeInput.textareaSyncAttributes.regexp.forEach(b=>{a.match(b)&&(null==c?this.textareaElement.removeAttribute(a):this.textareaElement.setAttribute(a,c))})}}addEventListener(a,b,c=void 0){let d=function(a){"function"==typeof b?b(a):b&&b.handleEvent&&b.handleEvent(a)}.bind(this);this.boundEventCallbacks[b]=d,codeInput.textareaSyncEvents.includes(a)?(this.boundEventCallbacks[b]=d,c===void 0?null==this.textareaElement?this.addEventListener("code-input_load",()=>{this.textareaElement.addEventListener(a,d)}):this.textareaElement.addEventListener(a,d):null==this.textareaElement?this.addEventListener("code-input_load",()=>{this.textareaElement.addEventListener(a,d,c)}):this.textareaElement.addEventListener(a,d,c)):c===void 0?super.addEventListener(a,d):super.addEventListener(a,d,c)}removeEventListener(a,b,c=void 0){let d=this.boundEventCallbacks[b];codeInput.textareaSyncEvents.includes(a)?c===void 0?null==this.textareaElement?this.addEventListener("code-input_load",()=>{this.textareaElement.removeEventListener(a,d)}):this.textareaElement.removeEventListener(a,d):null==this.textareaElement?this.addEventListener("code-input_load",()=>{this.textareaElement.removeEventListener(a,d,c)}):this.textareaElement.removeEventListener(a,d,c):c===void 0?super.removeEventListener(a,d):super.removeEventListener(a,d,c)}getTextareaProperty(a,b=void 0){if(this.textareaElement)return this.textareaElement[a];else{const c=this.querySelector("textarea[data-code-input-fallback]");if(c)return c[a];if(void 0===b)throw new Error("Cannot get "+a+" of an unregistered code-input element without a data-code-input-fallback textarea.");return b}}setTextareaProperty(a,b,c=!0){if(this.textareaElement)this.textareaElement[a]=b;else{const d=this.querySelector("textarea[data-code-input-fallback]");if(d)d[a]=b;else{if(!c)return(!1);throw new Error("Cannot set "+a+" of an unregistered code-input element without a data-code-input-fallback textarea.")}}return(!0)}get autocomplete(){return this.getAttribute("autocomplete")}set autocomplete(a){return this.setAttribute("autocomplete",a)}get cols(){return this.getTextareaProperty("cols",+this.getAttribute("cols"))}set cols(a){this.setAttribute("cols",a)}get defaultValue(){return this.initialValue}set defaultValue(a){this.initialValue=a}get textContent(){return this.initialValue}set textContent(a){this.initialValue=a}get dirName(){return this.getAttribute("dirName")||""}set dirName(a){this.setAttribute("dirname",a)}get disabled(){return this.hasAttribute("disabled")}set disabled(a){a?this.setAttribute("disabled",!0):this.removeAttribute("disabled")}get form(){return this.getTextareaProperty("form")}get labels(){return this.getTextareaProperty("labels")}get maxLength(){const a=+this.getAttribute("maxlength");return isNaN(a)?-1:a}set maxLength(a){-1==a?this.removeAttribute("maxlength"):this.setAttribute("maxlength",a)}get minLength(){const a=+this.getAttribute("minlength");return isNaN(a)?-1:a}set minLength(a){-1==a?this.removeAttribute("minlength"):this.setAttribute("minlength",a)}get name(){return this.getAttribute("name")||""}set name(a){this.setAttribute("name",a)}get placeholder(){return this.getAttribute("placeholder")||""}set placeholder(a){this.setAttribute("placeholder",a)}get readOnly(){return this.hasAttribute("readonly")}set readOnly(a){a?this.setAttribute("readonly",!0):this.removeAttribute("readonly")}get required(){return this.hasAttribute("readonly")}set required(a){a?this.setAttribute("readonly",!0):this.removeAttribute("readonly")}get rows(){return this.getTextareaProperty("rows",+this.getAttribute("rows"))}set rows(a){this.setAttribute("rows",a)}get selectionDirection(){return this.getTextareaProperty("selectionDirection")}set selectionDirection(a){this.setTextareaProperty("selectionDirection",a)}get selectionEnd(){return this.getTextareaProperty("selectionEnd")}set selectionEnd(a){this.setTextareaProperty("selectionEnd",a)}get selectionStart(){return this.getTextareaProperty("selectionStart")}set selectionStart(a){this.setTextareaProperty("selectionStart",a)}get textLength(){return this.value.length}get type(){return"textarea"}get validationMessage(){return this.getTextareaProperty("validationMessage")}get validity(){return this.getTextareaProperty("validationMessage")}get value(){return this.getTextareaProperty("value",this.getAttribute("value")||this.innerHTML)}set value(a){a=a||"",this.setTextareaProperty("value",a,!1)?this.textareaElement&&this.scheduleHighlight():this.innerHTML=a}get willValidate(){return this.getTextareaProperty("willValidate",this.disabled||this.readOnly)}get wrap(){return this.getAttribute("wrap")||""}set wrap(a){this.setAttribute("wrap",a)}blur(a={}){return this.textareaElement.blur(a)}checkValidity(){return this.textareaElement.checkValidity()}focus(a={}){return this.textareaElement.focus(a)}reportValidity(){return this.textareaElement.reportValidity()}setCustomValidity(a){this.textareaElement.setCustomValidity(a)}setRangeText(a,b=this.selectionStart,c=this.selectionEnd,d="preserve"){this.getTextareaProperty("setRangeText")(a,b,c,d)}setSelectionRange(a,b,c="none"){this.getTextareaProperty("setSelectionRange")(a,b,c)}pluginData={};formResetCallback(){this.value=this.initialValue}}};{class a extends codeInput.Template{constructor(a,b=[],c=!0){super(a.highlightElement,c,!0,!1,b)}}codeInput.templates.Prism=a;class b extends codeInput.Template{constructor(a,b=[],c=!1){super(function(b){b.removeAttribute("data-highlighted"),a.highlightElement(b)},c,!0,!1,b)}}codeInput.templates.Hljs=b}customElements.define("code-input",codeInput.CodeInput);
12
+ */"use strict";var codeInput={observedAttributes:["value","placeholder","language","lang","template"],textareaSyncAttributes:["value","min","max","type","pattern","autocomplete","autocorrect","autofocus","cols","dirname","disabled","form","maxlength","minlength","name","placeholder","readonly","required","rows","spellcheck","wrap"],textareaSyncEvents:["change","selectionchange","invalid","input","focus","blur","focusin","focusout"],usedTemplates:{},defaultTemplate:void 0,templateNotYetRegisteredQueue:{},registerTemplate:function(a,b){if(!("string"==typeof a||a instanceof String))throw TypeError(`code-input: Name of template "${a}" must be a string.`);if(!("function"==typeof b.highlight||b.highlight instanceof Function))throw TypeError(`code-input: Template for "${a}" invalid, because the highlight function provided is not a function; it is "${b.highlight}". Please make sure you use one of the constructors in codeInput.templates, and that you provide the correct arguments.`);if(!("boolean"==typeof b.includeCodeInputInHighlightFunc||b.includeCodeInputInHighlightFunc instanceof Boolean))throw TypeError(`code-input: Template for "${a}" invalid, because the includeCodeInputInHighlightFunc value provided is not a true or false; it is "${b.includeCodeInputInHighlightFunc}". Please make sure you use one of the constructors in codeInput.templates, and that you provide the correct arguments.`);if(!("boolean"==typeof b.preElementStyled||b.preElementStyled instanceof Boolean))throw TypeError(`code-input: Template for "${a}" invalid, because the preElementStyled value provided is not a true or false; it is "${b.preElementStyled}". Please make sure you use one of the constructors in codeInput.templates, and that you provide the correct arguments.`);if(!("boolean"==typeof b.isCode||b.isCode instanceof Boolean))throw TypeError(`code-input: Template for "${a}" invalid, because the isCode value provided is not a true or false; it is "${b.isCode}". Please make sure you use one of the constructors in codeInput.templates, and that you provide the correct arguments.`);if(!Array.isArray(b.plugins))throw TypeError(`code-input: Template for "${a}" invalid, because the plugin array provided is not an array; it is "${b.plugins}". Please make sure you use one of the constructors in codeInput.templates, and that you provide the correct arguments.`);if(b.plugins.forEach((c,d)=>{if(!(c instanceof codeInput.Plugin))throw TypeError(`code-input: Template for "${a}" invalid, because the plugin provided at index ${d} is not valid; it is "${b.plugins[d]}". Please make sure you use one of the constructors in codeInput.templates, and that you provide the correct arguments.`)}),codeInput.usedTemplates[a]=b,a in codeInput.templateNotYetRegisteredQueue)for(let c in codeInput.templateNotYetRegisteredQueue[a]){const d=codeInput.templateNotYetRegisteredQueue[a][c];d.templateObject=b,d.setup()}if(null==codeInput.defaultTemplate&&(codeInput.defaultTemplate=a,void 0 in codeInput.templateNotYetRegisteredQueue))for(let a in codeInput.templateNotYetRegisteredQueue[void 0]){const c=codeInput.templateNotYetRegisteredQueue[void 0][a];c.templateObject=b,c.setup()}},Template:class{constructor(a=function(){},b=!0,c=!0,d=!1,e=[]){this.highlight=a,this.preElementStyled=b,this.isCode=c,this.includeCodeInputInHighlightFunc=d,this.plugins=e}highlight=function(){};preElementStyled=!0;isCode=!0;includeCodeInputInHighlightFunc=!1;plugins=[]},templates:{prism(a,b=[]){return new codeInput.templates.Prism(a,b)},hljs(a,b=[]){return new codeInput.templates.Hljs(a,b)},characterLimit(a){return{highlight:function(a,b,c=[]){let d=+b.getAttribute("data-character-limit"),e=b.escapeHtml(b.value.slice(0,d)),f=b.escapeHtml(b.value.slice(d));a.innerHTML=`${e}<mark class="overflow">${f}</mark>`,0<f.length&&(a.innerHTML+=` <mark class="overflow-msg">${b.getAttribute("data-overflow-msg")||"(Character limit reached)"}</mark>`)},includeCodeInputInHighlightFunc:!0,preElementStyled:!0,isCode:!1,plugins:a}},rainbowText(a=["red","orangered","orange","goldenrod","gold","green","darkgreen","navy","blue","magenta"],b="",c=[]){return{highlight:function(a,b){let c=[],d=b.value.split(b.template.delimiter);for(let e=0;e<d.length;e++)c.push(`<span style="color: ${b.template.rainbowColors[e%b.template.rainbowColors.length]}">${b.escapeHtml(d[e])}</span>`);a.innerHTML=c.join(b.template.delimiter)},includeCodeInputInHighlightFunc:!0,preElementStyled:!0,isCode:!1,rainbowColors:a,delimiter:b,plugins:c}},character_limit(){return this.characterLimit([])},rainbow_text(a=["red","orangered","orange","goldenrod","gold","green","darkgreen","navy","blue","magenta"],b="",c=[]){return this.rainbowText(a,b,c)},custom(a=function(){},b=!0,c=!0,d=!1,e=[]){return{highlight:a,includeCodeInputInHighlightFunc:d,preElementStyled:b,isCode:c,plugins:e}}},plugins:new Proxy({},{get(a,b){if(a[b]==null)throw ReferenceError(`code-input: Plugin '${b}' is not defined. Please ensure you import the necessary files from the plugins folder in the WebCoder49/code-input repository, in the <head> of your HTML, before the plugin is instatiated.`);return a[b]}}),Plugin:class{constructor(a){a.forEach(a=>{codeInput.observedAttributes.push(a)})}addTranslations(a,b){for(const c in b)a[c]=b[c]}beforeHighlight(){}afterHighlight(){}beforeElementsAdded(){}afterElementsAdded(){}attributeChanged(){}},CodeInput:class extends HTMLElement{constructor(){super()}templateObject=null;textareaElement=null;preElement=null;codeElement=null;dialogContainerElement=null;static formAssociated=!0;boundEventCallbacks={};pluginEvt(a,b){for(let c in this.templateObject.plugins){let d=this.templateObject.plugins[c];a in d&&(b===void 0?d[a](this):d[a](this,...b))}}needsHighlight=!1;originalAriaDescription;scheduleHighlight(){this.needsHighlight=!0}animateFrame(){this.needsHighlight&&(this.update(),this.needsHighlight=!1),window.requestAnimationFrame(this.animateFrame.bind(this))}update(){let a=this.codeElement,b=this.value;b+="\n",a.innerHTML=this.escapeHtml(b),this.pluginEvt("beforeHighlight"),this.templateObject.includeCodeInputInHighlightFunc?this.templateObject.highlight(a,this):this.templateObject.highlight(a),this.syncSize(),this.pluginEvt("afterHighlight")}syncSize(){this.templateObject.preElementStyled?(this.style.backgroundColor=getComputedStyle(this.preElement).backgroundColor,this.textareaElement.style.height=getComputedStyle(this.preElement).height,this.textareaElement.style.width=getComputedStyle(this.preElement).width):(this.style.backgroundColor=getComputedStyle(this.codeElement).backgroundColor,this.textareaElement.style.height=getComputedStyle(this.codeElement).height,this.textareaElement.style.width=getComputedStyle(this.codeElement).width)}setKeyboardNavInstructions(a,b){this.dialogContainerElement.querySelector(".code-input_keyboard-navigation-instructions").innerText=a,b?this.textareaElement.setAttribute("aria-description",this.originalAriaDescription+". "+a):this.textareaElement.setAttribute("aria-description",a)}escapeHtml(a){return a.replace(/&/g,"&amp;").replace(/</g,"&lt;")}unescapeHtml(a){return a.replace(/&amp;/g,"&").replace(/&lt;/g,"<").replace(/&gt;/g,">")}getTemplate(){let a;return a=null==this.getAttribute("template")?codeInput.defaultTemplate:this.getAttribute("template"),a in codeInput.usedTemplates?codeInput.usedTemplates[a]:(a in codeInput.templateNotYetRegisteredQueue||(codeInput.templateNotYetRegisteredQueue[a]=[]),void codeInput.templateNotYetRegisteredQueue[a].push(this))}setup(){if(null!=this.textareaElement)return;this.classList.add("code-input_registered"),this.mutationObserver=new MutationObserver(this.mutationObserverCallback.bind(this)),this.mutationObserver.observe(this,{attributes:!0,attributeOldValue:!0}),this.classList.add("code-input_registered"),this.templateObject.preElementStyled&&this.classList.add("code-input_pre-element-styled");const a=this.querySelector("textarea[data-code-input-fallback]");let b,c,d,e,f,g=!1;a&&(a===document.activeElement&&(g=!0),b=a.selectionStart,c=a.selectionEnd,d=a.selectionDirection,e=a.scrollLeft,f=a.scrollTop);let h;if(a){let b=a.getAttributeNames();for(let c=0;c<b.length;c++){const d=b[c];"data-code-input-fallback"!=d&&(this.hasAttribute(d)||this.setAttribute(d,a.getAttribute(d)))}h=a.value,this.innerHTML=this.escapeHtml(h)}else h=this.unescapeHtml(this.innerHTML);h=h||this.getAttribute("value")||"",this.pluginEvt("beforeElementsAdded");const i=this.getAttribute("language")||this.getAttribute("lang"),j=this.getAttribute("placeholder")||i||"";this.initialValue=h;const k=document.createElement("textarea");k.placeholder=j,""!=h&&(k.value=h),k.innerHTML=this.innerHTML,this.hasAttribute("spellcheck")||k.setAttribute("spellcheck","false"),k.setAttribute("tabindex",this.getAttribute("tabindex")||0),this.setAttribute("tabindex",-1),this.originalAriaDescription=this.getAttribute("aria-description")||"Code input field",this.addEventListener("mousedown",()=>{this.classList.add("code-input_mouse-focused"),window.setTimeout(()=>{this.syncSize()},0)}),k.addEventListener("blur",()=>{this.classList.remove("code-input_mouse-focused"),window.setTimeout(()=>{this.syncSize()},0)}),k.addEventListener("focus",()=>{window.setTimeout(()=>{this.syncSize()},0)}),this.innerHTML="";for(let a,b=0;b<this.attributes.length;b++)a=this.attributes[b].name,(codeInput.textareaSyncAttributes.includes(a)||"aria-"==a.substring(0,5))&&k.setAttribute(a,this.getAttribute(a));k.addEventListener("input",()=>{this.value=this.textareaElement.value}),this.textareaElement=k,this.append(k);let l=document.createElement("code"),m=document.createElement("pre");m.setAttribute("aria-hidden","true"),m.setAttribute("tabindex","-1"),m.setAttribute("inert",!0),this.preElement=m,this.codeElement=l,m.append(l),this.append(m),this.templateObject.isCode&&i!=null&&""!=i&&l.classList.add("language-"+i.toLowerCase());let n=document.createElement("div");n.classList.add("code-input_dialog-container"),this.append(n),this.dialogContainerElement=n;let o=document.createElement("div");o.classList.add("code-input_keyboard-navigation-instructions"),n.append(o),this.pluginEvt("afterElementsAdded"),this.dispatchEvent(new CustomEvent("code-input_load")),this.value=h,b!==void 0&&(console.log("sel",b,c,d,"scr",f,e,"foc",g),k.setSelectionRange(b,c,d),k.scrollTo(f,e)),g&&k.focus(),this.animateFrame();const p=new ResizeObserver(()=>{this.syncSize()});p.observe(this.textareaElement),this.classList.add("code-input_loaded")}escape_html(a){return this.escapeHtml(a)}get_template(){return this.getTemplate()}get template(){return this.templateObject}set template(a){}connectedCallback(){this.templateObject=this.getTemplate(),this.templateObject!=null&&(this.classList.add("code-input_registered"),window.addEventListener("DOMContentLoaded",this.setup.bind(this)))}mutationObserverCallback(a){for(const b of a)if("attributes"===b.type){for(let a=0;a<codeInput.observedAttributes.length;a++)if(b.attributeName==codeInput.observedAttributes[a])return this.attributeChangedCallback(b.attributeName,b.oldValue,super.getAttribute(b.attributeName));for(let a=0;a<codeInput.textareaSyncAttributes.length;a++)if(b.attributeName==codeInput.textareaSyncAttributes[a])return this.attributeChangedCallback(b.attributeName,b.oldValue,super.getAttribute(b.attributeName));if("aria-"==b.attributeName.substring(0,5))return this.attributeChangedCallback(b.attributeName,b.oldValue,super.getAttribute(b.attributeName))}}disconnectedCallback(){this.mutationObserver.disconnect()}attributeChangedCallback(a,b,c){if(this.isConnected)switch(this.pluginEvt("attributeChanged",[a,b,c]),a){case"value":this.value=c;break;case"template":this.templateObject=codeInput.usedTemplates[c||codeInput.defaultTemplate],this.templateObject.preElementStyled?this.classList.add("code-input_pre-element-styled"):this.classList.remove("code-input_pre-element-styled"),this.scheduleHighlight();break;case"lang":case"language":let d=this.codeElement,e=this.textareaElement;if(null!=c&&(c=c.toLowerCase(),d.classList.contains(`language-${c}`)))break;null!==b&&(b=b.toLowerCase(),d.classList.remove("language-"+b),d.parentElement.classList.remove("language-"+b)),d.classList.remove("language-none"),d.parentElement.classList.remove("language-none"),null!=c&&""!=c&&d.classList.add("language-"+c),e.placeholder==b&&(e.placeholder=c),this.scheduleHighlight();break;default:codeInput.textareaSyncAttributes.includes(a)||"aria-"==a.substring(0,5)?null==c||null==c?this.textareaElement.removeAttribute(a):this.textareaElement.setAttribute(a,c):codeInput.textareaSyncAttributes.regexp.forEach(b=>{a.match(b)&&(null==c?this.textareaElement.removeAttribute(a):this.textareaElement.setAttribute(a,c))})}}addEventListener(a,b,c=void 0){let d=function(a){"function"==typeof b?b(a):b&&b.handleEvent&&b.handleEvent(a)}.bind(this);this.boundEventCallbacks[b]=d,codeInput.textareaSyncEvents.includes(a)?(this.boundEventCallbacks[b]=d,c===void 0?null==this.textareaElement?this.addEventListener("code-input_load",()=>{this.textareaElement.addEventListener(a,d)}):this.textareaElement.addEventListener(a,d):null==this.textareaElement?this.addEventListener("code-input_load",()=>{this.textareaElement.addEventListener(a,d,c)}):this.textareaElement.addEventListener(a,d,c)):c===void 0?super.addEventListener(a,d):super.addEventListener(a,d,c)}removeEventListener(a,b,c=void 0){let d=this.boundEventCallbacks[b];codeInput.textareaSyncEvents.includes(a)?c===void 0?null==this.textareaElement?this.addEventListener("code-input_load",()=>{this.textareaElement.removeEventListener(a,d)}):this.textareaElement.removeEventListener(a,d):null==this.textareaElement?this.addEventListener("code-input_load",()=>{this.textareaElement.removeEventListener(a,d,c)}):this.textareaElement.removeEventListener(a,d,c):c===void 0?super.removeEventListener(a,d):super.removeEventListener(a,d,c)}getTextareaProperty(a,b=void 0){if(this.textareaElement)return this.textareaElement[a];else{const c=this.querySelector("textarea[data-code-input-fallback]");if(c)return c[a];if(void 0===b)throw new Error("Cannot get "+a+" of an unregistered code-input element without a data-code-input-fallback textarea.");return b}}setTextareaProperty(a,b,c=!0){if(this.textareaElement)this.textareaElement[a]=b;else{const d=this.querySelector("textarea[data-code-input-fallback]");if(d)d[a]=b;else{if(!c)return(!1);throw new Error("Cannot set "+a+" of an unregistered code-input element without a data-code-input-fallback textarea.")}}return(!0)}get autocomplete(){return this.getAttribute("autocomplete")}set autocomplete(a){return this.setAttribute("autocomplete",a)}get cols(){return this.getTextareaProperty("cols",+this.getAttribute("cols"))}set cols(a){this.setAttribute("cols",a)}get defaultValue(){return this.initialValue}set defaultValue(a){this.initialValue=a}get textContent(){return this.initialValue}set textContent(a){this.initialValue=a}get dirName(){return this.getAttribute("dirName")||""}set dirName(a){this.setAttribute("dirname",a)}get disabled(){return this.hasAttribute("disabled")}set disabled(a){a?this.setAttribute("disabled",!0):this.removeAttribute("disabled")}get form(){return this.getTextareaProperty("form")}get labels(){return this.getTextareaProperty("labels")}get maxLength(){const a=+this.getAttribute("maxlength");return isNaN(a)?-1:a}set maxLength(a){-1==a?this.removeAttribute("maxlength"):this.setAttribute("maxlength",a)}get minLength(){const a=+this.getAttribute("minlength");return isNaN(a)?-1:a}set minLength(a){-1==a?this.removeAttribute("minlength"):this.setAttribute("minlength",a)}get name(){return this.getAttribute("name")||""}set name(a){this.setAttribute("name",a)}get placeholder(){return this.getAttribute("placeholder")||""}set placeholder(a){this.setAttribute("placeholder",a)}get readOnly(){return this.hasAttribute("readonly")}set readOnly(a){a?this.setAttribute("readonly",!0):this.removeAttribute("readonly")}get required(){return this.hasAttribute("readonly")}set required(a){a?this.setAttribute("readonly",!0):this.removeAttribute("readonly")}get rows(){return this.getTextareaProperty("rows",+this.getAttribute("rows"))}set rows(a){this.setAttribute("rows",a)}get selectionDirection(){return this.getTextareaProperty("selectionDirection")}set selectionDirection(a){this.setTextareaProperty("selectionDirection",a)}get selectionEnd(){return this.getTextareaProperty("selectionEnd")}set selectionEnd(a){this.setTextareaProperty("selectionEnd",a)}get selectionStart(){return this.getTextareaProperty("selectionStart")}set selectionStart(a){this.setTextareaProperty("selectionStart",a)}get textLength(){return this.value.length}get type(){return"textarea"}get validationMessage(){return this.getTextareaProperty("validationMessage")}get validity(){return this.getTextareaProperty("validationMessage")}get value(){return this.getTextareaProperty("value",this.getAttribute("value")||this.innerHTML)}set value(a){a=a||"",this.setTextareaProperty("value",a,!1)?this.textareaElement&&this.scheduleHighlight():this.innerHTML=a}get willValidate(){return this.getTextareaProperty("willValidate",this.disabled||this.readOnly)}get wrap(){return this.getAttribute("wrap")||""}set wrap(a){this.setAttribute("wrap",a)}getTextareaMethod(a){if(this.textareaElement)return this.textareaElement[a].bind(this.textareaElement);else{const b=this.querySelector("textarea[data-code-input-fallback]");if(b)return b[a].bind(b);throw new Error("Cannot call "+a+" on an unregistered code-input element without a data-code-input-fallback textarea.")}}blur(a={}){this.getTextareaMethod("blur")(a)}checkValidity(){return this.getTextareaMethod("checkValidity")()}focus(a={}){this.getTextareaMethod("focus")(a)}reportValidity(){return this.getTextareaMethod("reportValidity")()}setCustomValidity(a){this.getTextareaMethod("setCustomValidity")(a)}setRangeText(a,b=this.selectionStart,c=this.selectionEnd,d="preserve"){this.getTextareaMethod("setRangeText")(a,b,c,d),this.textareaElement&&this.scheduleHighlight()}setSelectionRange(a,b,c="none"){this.getTextareaMethod("setSelectionRange")(a,b,c)}pluginData={};formResetCallback(){this.value=this.initialValue}}};{class a extends codeInput.Template{constructor(a,b=[],c=!0){super(a.highlightElement,c,!0,!1,b)}}codeInput.templates.Prism=a;class b extends codeInput.Template{constructor(a,b=[],c=!1){super(function(b){b.removeAttribute("data-highlighted"),a.highlightElement(b)},c,!0,!1,b)}}codeInput.templates.Hljs=b}customElements.define("code-input",codeInput.CodeInput);
package/docs/_index.md CHANGED
@@ -10,7 +10,7 @@ Aiming to be [more <mark>flexible</mark>, <mark>lightweight</mark>,
10
10
  [HTML forms](interface/forms), the [`<textarea>` JavaScript interface](interface/js), more languages and
11
11
  more use cases.
12
12
 
13
- *code-input.js is free, libre, open source software under the MIT (AKA Expat) license.* **Download it [from the Git repository](https://github.com/WebCoder49/code-input/tree/v2.6.4), [in a ZIP archive](/release/code-input-js-v2.6.4.zip), [in a TAR.GZ archive](/release/code-input-js-v2.6.4.tar.gz), or from `@webcoder49/code-input` on the NPM registry ([Yarn](https://yarnpkg.com/package?name=@webcoder49/code-input), [NPM](https://npmjs.com/package/@webcoder49/code-input), etc.).**
13
+ *code-input.js is free, libre, open source software under the MIT (AKA Expat) license.* **Download it [from the Git repository](https://github.com/WebCoder49/code-input/tree/v2.6.5), [in a ZIP archive](/release/code-input-js-v2.6.5.zip), [in a TAR.GZ archive](/release/code-input-js-v2.6.5.tar.gz), or from `@webcoder49/code-input` on the NPM registry ([Yarn](https://yarnpkg.com/package?name=@webcoder49/code-input), [NPM](https://npmjs.com/package/@webcoder49/code-input), etc.).**
14
14
 
15
15
  ## Get Started with a Demo
16
16
 
@@ -7,6 +7,6 @@ title = 'Styling `code-input` elements with CSS'
7
7
  > Contributors: 2025 Oliver Geer
8
8
 
9
9
  `code-input` elements can be styled like `textarea` elements in most cases; however, there are some exceptions:
10
- * The CSS variable `--padding` should be used rather than the property `padding` (e.g. `<code-input style="--padding: 10px;">...`)
10
+ * The CSS variable `--padding` should be used rather than the property `padding` (e.g. `<code-input style="--padding: 10px;">...`), or `--padding-left`, `--padding-right`, `--padding-top` and `--padding-bottom` instead of the CSS properties of the same names. For technical reasons, the value must have a unit (i.e. `0px`, not `0`).
11
11
  * Background colours set on `code-input` elements will not work with highlighters that set background colours themselves - use `(code-input's selector) pre[class*="language-"]` for Prism.js or `.hljs` for highlight.js to target the highlighted element with higher specificity than the highlighter's theme. You may also set the `background-color` of the code-input element for its appearance when its template is unregistered / there is no JavaScript.
12
12
  * For now, elements on top of `code-input` elements should have a CSS `z-index` at least 3 greater than the `code-input` element.
@@ -60,7 +60,7 @@ Note the `.mjs` extensions on code-input.js import paths. They are needed, and a
60
60
  The import paths above assume a package manager and `package.json` export paths are being used.
61
61
 
62
62
  In some setups, this will not work. You have two options (replace `node_modules/@webcoder49/code-input` with the relative path to the library, if it is different):
63
- * use relative paths instead: replace `"@webcoder49/code-input/path/to/file.mjs"` with `"node_modules/@webcoder49/code-input/esm/path/to/file.mjs"` (note the `esm` directory). Also replace `"@webcoder49/code-input/path/to/file.mjs"` with `"node_modules/@highlightjs/cdn-assets/es/path/to/file.mjs"` (note the `es` directory) *If you're not using an import map yet, I recommend this option because import maps are not supported on as many browsers.*
63
+ * use relative paths instead: assuming you are importing from your project's root directory and have installed the libraries with a typical JS package manager, replace `"@webcoder49/code-input/path/to/file.mjs"` with `"./node_modules/@webcoder49/code-input/esm/path/to/file.mjs"` (note the `esm` directory). Also replace `"@webcoder49/code-input/path/to/file.mjs"` with `"./node_modules/@highlightjs/cdn-assets/es/path/to/file.mjs"` (note the `es` directory) *If you're not using an import map yet, I recommend this option because import maps are not supported on as many browsers.*
64
64
  * If you're using an [import map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules#importing_modules_using_import_maps), add the following to it:
65
65
  ```json
66
66
  {
@@ -518,9 +518,26 @@ var codeInput = {
518
518
  this.classList.add("code-input_registered"); // Remove register message
519
519
  if (this.templateObject.preElementStyled) this.classList.add("code-input_pre-element-styled");
520
520
 
521
- this.pluginEvt("beforeElementsAdded");
522
-
523
521
  const fallbackTextarea = this.querySelector("textarea[data-code-input-fallback]");
522
+ let fallbackFocused = false;
523
+ let fallbackSelectionStart = undefined;
524
+ let fallbackSelectionEnd = undefined;
525
+ let fallbackSelectionDirection = undefined;
526
+ let fallbackScrollLeft = undefined;
527
+ let fallbackScrollTop = undefined;
528
+ if(fallbackTextarea) {
529
+ // Move some attributes to new textarea so typing during
530
+ // slow load not interrupted
531
+ if(fallbackTextarea === document.activeElement) { // Thanks to https://stackoverflow.com/a/36430896
532
+ fallbackFocused = true;
533
+ }
534
+ fallbackSelectionStart = fallbackTextarea.selectionStart;
535
+ fallbackSelectionEnd = fallbackTextarea.selectionEnd;
536
+ fallbackSelectionDirection = fallbackTextarea.selectionDirection;
537
+ fallbackScrollLeft = fallbackTextarea.scrollLeft;
538
+ fallbackScrollTop = fallbackTextarea.scrollTop;
539
+ }
540
+
524
541
  let value;
525
542
  if(fallbackTextarea) {
526
543
  // Fallback textarea exists
@@ -536,11 +553,15 @@ var codeInput = {
536
553
  }
537
554
  // Sync value
538
555
  value = fallbackTextarea.value;
556
+ // Backwards compatibility with plugins
557
+ this.innerHTML = this.escapeHtml(value);
539
558
  } else {
540
559
  value = this.unescapeHtml(this.innerHTML);
541
560
  }
542
561
  value = value || this.getAttribute("value") || "";
543
562
 
563
+ this.pluginEvt("beforeElementsAdded");
564
+
544
565
  // First-time attribute sync
545
566
  const lang = this.getAttribute("language") || this.getAttribute("lang");
546
567
  const placeholder = this.getAttribute("placeholder") || lang || "";
@@ -569,9 +590,23 @@ var codeInput = {
569
590
  // Accessibility - detect when mouse focus to remove focus outline + keyboard navigation guidance that could irritate users.
570
591
  this.addEventListener("mousedown", () => {
571
592
  this.classList.add("code-input_mouse-focused");
593
+ // Wait for CSS to update padding
594
+ window.setTimeout(() => {
595
+ this.syncSize();
596
+ }, 0);
572
597
  });
573
598
  textarea.addEventListener("blur", () => {
574
599
  this.classList.remove("code-input_mouse-focused");
600
+ // Wait for CSS to update padding
601
+ window.setTimeout(() => {
602
+ this.syncSize();
603
+ }, 0);
604
+ });
605
+ textarea.addEventListener("focus", () => {
606
+ // Wait for CSS to update padding
607
+ window.setTimeout(() => {
608
+ this.syncSize();
609
+ }, 0);
575
610
  });
576
611
 
577
612
  this.innerHTML = ""; // Clear Content
@@ -624,13 +659,25 @@ var codeInput = {
624
659
  this.dispatchEvent(new CustomEvent("code-input_load"));
625
660
 
626
661
  this.value = value;
662
+
663
+ // Update with fallback textarea's state so can keep editing
664
+ // if loaded slowly
665
+ if(fallbackSelectionStart !== undefined) {
666
+ console.log("sel", fallbackSelectionStart, fallbackSelectionEnd, fallbackSelectionDirection, "scr", fallbackScrollTop, fallbackScrollLeft, "foc", fallbackFocused);
667
+ textarea.setSelectionRange(fallbackSelectionStart, fallbackSelectionEnd, fallbackSelectionDirection);
668
+ textarea.scrollTo(fallbackScrollTop, fallbackScrollLeft);
669
+ }
670
+ if(fallbackFocused) {
671
+ textarea.focus();
672
+ }
673
+
627
674
  this.animateFrame();
628
675
 
629
676
  const resizeObserver = new ResizeObserver((elements) => {
630
677
  // The only element that could be resized is this code-input element.
631
678
  this.syncSize();
632
679
  });
633
- resizeObserver.observe(this);
680
+ resizeObserver.observe(this.textareaElement);
634
681
 
635
682
  this.classList.add("code-input_loaded");
636
683
  }
@@ -1026,14 +1073,40 @@ var codeInput = {
1026
1073
  get wrap() { return this.getAttribute("wrap") || ""; }
1027
1074
  set wrap(val) { this.setAttribute("wrap", val); }
1028
1075
 
1076
+ /**
1077
+ * Get the JavaScript method from the internal textarea
1078
+ * element, throwing an error when no textarea is present.
1079
+ * The method is bound to the textarea as `this`.
1080
+ *
1081
+ * For internal use - treat the code-input element as a
1082
+ * textarea for the standard functions (e.g. document.
1083
+ * querySelector("code-input").focus()).
1084
+ */
1085
+ getTextareaMethod(name) {
1086
+ if(this.textareaElement) {
1087
+ return this.textareaElement[name].bind(this.textareaElement);
1088
+ } else {
1089
+ // Unregistered
1090
+ const fallbackTextarea = this.querySelector("textarea[data-code-input-fallback]");
1091
+ if(fallbackTextarea) {
1092
+ return fallbackTextarea[name].bind(fallbackTextarea);
1093
+ } else {
1094
+ throw new Error("Cannot call "+name+" on an unregistered code-input element without a data-code-input-fallback textarea.");
1095
+ }
1096
+ }
1097
+ }
1029
1098
 
1030
- blur(options={}) { return this.textareaElement.blur(options); }
1031
- checkValidity() { return this.textareaElement.checkValidity(); }
1032
- focus(options={}) { return this.textareaElement.focus(options); }
1033
- reportValidity() { return this.textareaElement.reportValidity(); }
1034
- setCustomValidity(error) { this.textareaElement.setCustomValidity(error); }
1035
- setRangeText(replacement, selectionStart=this.selectionStart, selectionEnd=this.selectionEnd, selectMode="preserve") { this.getTextareaProperty("setRangeText")(replacement, selectionStart, selectionEnd, selectMode); }
1036
- setSelectionRange(selectionStart, selectionEnd, selectionDirection="none") { this.getTextareaProperty("setSelectionRange")(selectionStart, selectionEnd, selectionDirection); }
1099
+ blur(options={}) { this.getTextareaMethod("blur")(options); }
1100
+ checkValidity() { return this.getTextareaMethod("checkValidity")(); }
1101
+ focus(options={}) { this.getTextareaMethod("focus")(options); }
1102
+ reportValidity() { return this.getTextareaMethod("reportValidity")(); }
1103
+ setCustomValidity(error) { this.getTextareaMethod("setCustomValidity")(error); }
1104
+ setRangeText(replacement, selectionStart=this.selectionStart, selectionEnd=this.selectionEnd, selectMode="preserve") {
1105
+ this.getTextareaMethod("setRangeText")(replacement, selectionStart, selectionEnd, selectMode);
1106
+ // Reflect that value updated
1107
+ if(this.textareaElement) this.scheduleHighlight();
1108
+ }
1109
+ setSelectionRange(selectionStart, selectionEnd, selectionDirection="none") { this.getTextareaMethod("setSelectionRange")(selectionStart, selectionEnd, selectionDirection); }
1037
1110
 
1038
1111
  /**
1039
1112
  * Allows plugins to store data in the scope of a single element.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webcoder49/code-input",
3
- "version": "2.6.4",
3
+ "version": "2.6.5",
4
4
  "description": "An editable &lt;textarea&gt; that supports *any* syntax highlighting algorithm, for code or something else. Also, added plugins.",
5
5
  "browser": "code-input.js",
6
6
  "exports": {
@@ -7,13 +7,18 @@
7
7
  /* Update padding to match line-numbers plugin */
8
8
  code-input.line-numbers textarea, code-input.line-numbers.code-input_pre-element-styled pre, code-input.line-numbers:not(.code-input_pre-element-styled) pre code,
9
9
  .line-numbers code-input textarea, .line-numbers code-input.code-input_pre-element-styled pre, .line-numbers code-input:not(.code-input_pre-element-styled) pre code {
10
- padding-left: max(3.8em, var(--padding, 16px))!important;
10
+ padding-left: max(3.8em, var(--padding-left, 16px))!important;
11
11
  }
12
12
 
13
13
  /* Ensure pre code/textarea just wide enough to give 100% width with line numbers */
14
14
  code-input.line-numbers, .line-numbers code-input {
15
- grid-template-columns: calc(100% - max(0em, calc(3.8em - var(--padding, 16px))));
15
+ grid-template-columns: calc(100% - max(0em, calc(3.8em - var(--padding-left, 16px))));
16
16
  }
17
+ /* Despite the above, keep dialog container full width */
18
+ code-input.line-numbers .code-input_dialog-container, .line-numbers code-input .code-input_dialog-container {
19
+ width: calc(100% + max(0em, calc(3.8em - var(--padding-left, 16px))));
20
+ }
21
+
17
22
 
18
23
  /* Override Prism styles so there's no display:inline, relatively-positioned code element which breaks offsetTop, used in FindAndReplace, in Firefox. */
19
24
  code-input pre[class*=language-].line-numbers>code {
@@ -21,10 +26,10 @@ code-input pre[class*=language-].line-numbers>code {
21
26
  }
22
27
  /* Line numbers now positioned relative to the pre element not the code element. */
23
28
  code-input .line-numbers .line-numbers-rows {
24
- left: 0;
25
- top: var(--padding);
29
+ left: max(0em, calc(var(--padding-left, 16px) - 3.8em));
30
+ top: var(--padding-top);
26
31
  }
27
32
  /* Things with padding when instructions are present */
28
33
  code-input:not(:has(.code-input_keyboard-navigation-instructions:empty)):has(textarea:not([data-code-input-fallback]):focus):not(.code-input_mouse-focused) .line-numbers .line-numbers-rows {
29
- top: calc(var(--padding) + 3em);
34
+ top: calc(var(--padding-top) + 3em);
30
35
  }
@@ -1 +1 @@
1
- .line-numbers code-input textarea,.line-numbers code-input.code-input_pre-element-styled pre,.line-numbers code-input:not(.code-input_pre-element-styled) pre code,code-input.line-numbers textarea,code-input.line-numbers.code-input_pre-element-styled pre,code-input.line-numbers:not(.code-input_pre-element-styled) pre code{padding-left:max(3.8em,var(--padding,16px))!important}.line-numbers code-input,code-input.line-numbers{grid-template-columns:calc(100% - max(0em,calc(3.8em - var(--padding,16px))))}code-input pre[class*=language-].line-numbers>code{position:static}code-input .line-numbers .line-numbers-rows{left:0;top:var(--padding)}code-input:not(:has(.code-input_keyboard-navigation-instructions:empty)):has(textarea:not([data-code-input-fallback]):focus):not(.code-input_mouse-focused) .line-numbers .line-numbers-rows{top:calc(var(--padding) + 3em)}
1
+ .line-numbers code-input textarea,.line-numbers code-input.code-input_pre-element-styled pre,.line-numbers code-input:not(.code-input_pre-element-styled) pre code,code-input.line-numbers textarea,code-input.line-numbers.code-input_pre-element-styled pre,code-input.line-numbers:not(.code-input_pre-element-styled) pre code{padding-left:max(3.8em,var(--padding-left,16px))!important}.line-numbers code-input,code-input.line-numbers{grid-template-columns:calc(100% - max(0em,calc(3.8em - var(--padding-left,16px))))}.line-numbers code-input .code-input_dialog-container,code-input.line-numbers .code-input_dialog-container{width:calc(100% + max(0em,calc(3.8em - var(--padding-left,16px))))}code-input pre[class*=language-].line-numbers>code{position:static}code-input .line-numbers .line-numbers-rows{left:max(0,calc(var(--padding-left,16px) - 3.8em));top:var(--padding-top)}code-input:not(:has(.code-input_keyboard-navigation-instructions:empty)):has(textarea:not([data-code-input-fallback]):focus):not(.code-input_mouse-focused) .line-numbers .line-numbers-rows{top:calc(var(--padding-top) + 3em)}