@webcoder49/code-input 2.1.0 → 2.2.1
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/CONTRIBUTING.md +11 -1
- package/README.md +17 -8
- package/code-input.css +47 -22
- package/code-input.d.ts +65 -4
- package/code-input.js +127 -176
- package/code-input.min.css +1 -1
- package/code-input.min.js +1 -1
- package/package.json +1 -1
- package/plugins/README.md +21 -6
- package/plugins/auto-close-brackets.js +61 -0
- package/plugins/auto-close-brackets.min.js +1 -0
- package/plugins/autocomplete.js +18 -11
- package/plugins/autocomplete.min.js +1 -1
- package/plugins/autodetect.js +4 -4
- package/plugins/autodetect.min.js +1 -1
- package/plugins/find-and-replace.css +145 -0
- package/plugins/find-and-replace.js +652 -0
- package/plugins/find-and-replace.min.css +1 -0
- package/plugins/find-and-replace.min.js +1 -0
- package/plugins/go-to-line.css +77 -0
- package/plugins/go-to-line.js +157 -0
- package/plugins/go-to-line.min.css +1 -0
- package/plugins/go-to-line.min.js +1 -0
- package/plugins/indent.js +71 -11
- package/plugins/indent.min.js +1 -1
- package/plugins/special-chars.css +0 -4
- package/plugins/special-chars.js +60 -58
- package/plugins/special-chars.min.css +1 -1
- package/plugins/special-chars.min.js +1 -1
- package/plugins/test.js +1 -2
- package/plugins/test.min.js +1 -1
- package/tests/hljs.html +54 -0
- package/tests/prism.html +55 -0
- package/tests/tester.js +529 -0
- package/tests/tester.min.js +18 -0
- package/plugins/debounce-update.js +0 -40
- package/plugins/debounce-update.min.js +0 -1
package/code-input.js
CHANGED
|
@@ -19,6 +19,7 @@ var codeInput = {
|
|
|
19
19
|
observedAttributes: [
|
|
20
20
|
"value",
|
|
21
21
|
"placeholder",
|
|
22
|
+
"language",
|
|
22
23
|
"lang",
|
|
23
24
|
"template"
|
|
24
25
|
],
|
|
@@ -29,7 +30,6 @@ var codeInput = {
|
|
|
29
30
|
* code-input element.
|
|
30
31
|
*/
|
|
31
32
|
textareaSyncAttributes: [
|
|
32
|
-
"aria-*",
|
|
33
33
|
"value",
|
|
34
34
|
// Form validation - https://developer.mozilla.org/en-US/docs/Learn/Forms/Form_validation#using_built-in_form_validation
|
|
35
35
|
"min", "max",
|
|
@@ -103,7 +103,7 @@ var codeInput = {
|
|
|
103
103
|
* @param {Object} template - a Template object instance - see `codeInput.templates`
|
|
104
104
|
*/
|
|
105
105
|
registerTemplate: function (templateName, template) {
|
|
106
|
-
if(!(typeof templateName == "string" || templateName instanceof String)) throw TypeError(`code-input:
|
|
106
|
+
if(!(typeof templateName == "string" || templateName instanceof String)) throw TypeError(`code-input: Name of template "${templateName}" must be a string.`);
|
|
107
107
|
if(!(typeof template.highlight == "function" || template.highlight instanceof Function)) throw TypeError(`code-input: Template for "${templateName}" invalid, because the highlight function provided is not a function; it is "${template.highlight}". Please make sure you use one of the constructors in codeInput.templates, and that you provide the correct arguments.`);
|
|
108
108
|
if(!(typeof template.includeCodeInputInHighlightFunc == "boolean" || template.includeCodeInputInHighlightFunc instanceof Boolean)) throw TypeError(`code-input: Template for "${templateName}" invalid, because the includeCodeInputInHighlightFunc value provided is not a true or false; it is "${template.includeCodeInputInHighlightFunc}". Please make sure you use one of the constructors in codeInput.templates, and that you provide the correct arguments.`);
|
|
109
109
|
if(!(typeof template.preElementStyled == "boolean" || template.preElementStyled instanceof Boolean)) throw TypeError(`code-input: Template for "${templateName}" invalid, because the preElementStyled value provided is not a true or false; it is "${template.preElementStyled}". Please make sure you use one of the constructors in codeInput.templates, and that you provide the correct arguments.`);
|
|
@@ -124,7 +124,7 @@ var codeInput = {
|
|
|
124
124
|
elem = codeInput.templateNotYetRegisteredQueue[templateName][i];
|
|
125
125
|
elem.template = template;
|
|
126
126
|
codeInput.runOnceWindowLoaded((function(elem) { elem.connectedCallback(); }).bind(null, elem), elem);
|
|
127
|
-
// Bind sets elem
|
|
127
|
+
// Bind sets elem as first parameter of function
|
|
128
128
|
// So innerHTML can be read
|
|
129
129
|
}
|
|
130
130
|
console.log(`code-input: template: Added existing elements with template ${templateName}`);
|
|
@@ -138,7 +138,7 @@ var codeInput = {
|
|
|
138
138
|
elem = codeInput.templateNotYetRegisteredQueue[undefined][i];
|
|
139
139
|
elem.template = template;
|
|
140
140
|
codeInput.runOnceWindowLoaded((function(elem) { elem.connectedCallback(); }).bind(null, elem), elem);
|
|
141
|
-
// Bind sets elem
|
|
141
|
+
// Bind sets elem as first parameter of function
|
|
142
142
|
// So innerHTML can be read
|
|
143
143
|
}
|
|
144
144
|
}
|
|
@@ -163,7 +163,7 @@ var codeInput = {
|
|
|
163
163
|
* @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
164
|
* @param {boolean} includeCodeInputInHighlightFunc - Setting this to true passes the `<code-input>` element as a second argument to the highlight function.
|
|
165
165
|
* @param {codeInput.Plugin[]} plugins - An array of plugin objects to add extra features - see `codeInput.Plugin`
|
|
166
|
-
* @returns template object
|
|
166
|
+
* @returns {codeInput.Template} template object
|
|
167
167
|
*/
|
|
168
168
|
constructor(highlight = function () { }, preElementStyled = true, isCode = true, includeCodeInputInHighlightFunc = false, plugins = []) {
|
|
169
169
|
this.highlight = highlight;
|
|
@@ -179,7 +179,7 @@ var codeInput = {
|
|
|
179
179
|
* `<code-input>` element parameter if `this.includeCodeInputInHighlightFunc` is
|
|
180
180
|
* `true`.
|
|
181
181
|
*/
|
|
182
|
-
highlight = function() {};
|
|
182
|
+
highlight = function(codeElement) {};
|
|
183
183
|
|
|
184
184
|
/**
|
|
185
185
|
* Is the <pre> element CSS-styled as well as the `<code>` element?
|
|
@@ -226,37 +226,38 @@ var codeInput = {
|
|
|
226
226
|
* Constructor to create a template that uses Prism.js syntax highlighting (https://prismjs.com/)
|
|
227
227
|
* @param {Object} prism Import Prism.js, then after that import pass the `Prism` object as this parameter.
|
|
228
228
|
* @param {codeInput.Plugin[]} plugins - An array of plugin objects to add extra features - see `codeInput.plugins`
|
|
229
|
-
* @returns template object
|
|
229
|
+
* @returns {codeInput.Template} template object
|
|
230
230
|
*/
|
|
231
231
|
prism(prism, plugins = []) { // Dependency: Prism.js (https://prismjs.com/)
|
|
232
|
-
return
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
plugins
|
|
238
|
-
|
|
232
|
+
return new codeInput.Template(
|
|
233
|
+
prism.highlightElement, // highlight
|
|
234
|
+
true, // preElementStyled
|
|
235
|
+
true, // isCode
|
|
236
|
+
false, // includeCodeInputInHighlightFunc
|
|
237
|
+
plugins
|
|
238
|
+
);
|
|
239
239
|
},
|
|
240
240
|
/**
|
|
241
241
|
* Constructor to create a template that uses highlight.js syntax highlighting (https://highlightjs.org/)
|
|
242
242
|
* @param {Object} hljs Import highlight.js, then after that import pass the `hljs` object as this parameter.
|
|
243
243
|
* @param {codeInput.Plugin[]} plugins - An array of plugin objects to add extra features - see `codeInput.plugins`
|
|
244
|
-
* @returns template object
|
|
244
|
+
* @returns {codeInput.Template} template object
|
|
245
245
|
*/
|
|
246
246
|
hljs(hljs, plugins = []) { // Dependency: Highlight.js (https://highlightjs.org/)
|
|
247
|
-
return
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
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
|
+
);
|
|
254
257
|
},
|
|
255
258
|
|
|
256
259
|
/**
|
|
257
|
-
*
|
|
258
|
-
* @param {codeInput.Plugin[]} plugins - An array of plugin objects to add extra features - see `codeInput.plugins`
|
|
259
|
-
* @returns template object
|
|
260
|
+
* @deprecated Make your own version of this template if you need it - we think it isn't widely used so will remove it from the next version of code-input.
|
|
260
261
|
*/
|
|
261
262
|
characterLimit(plugins) {
|
|
262
263
|
return {
|
|
@@ -280,11 +281,7 @@ var codeInput = {
|
|
|
280
281
|
},
|
|
281
282
|
|
|
282
283
|
/**
|
|
283
|
-
*
|
|
284
|
-
* @param {string[]} rainbowColors - An array of CSS colors, in the order each color will be shown
|
|
285
|
-
* @param {string} delimiter - The character used to split up parts of text where each part is a different colour (e.g. "" = characters, " " = words)
|
|
286
|
-
* @param {codeInput.Plugin[]} plugins - An array of plugin objects to add extra features - see `codeInput.plugins`
|
|
287
|
-
* @returns template object
|
|
284
|
+
* @deprecated Make your own version of this template if you need it - we think it isn't widely used so will remove it from the next version of code-input.
|
|
288
285
|
*/
|
|
289
286
|
rainbowText(rainbowColors = ["red", "orangered", "orange", "goldenrod", "gold", "green", "darkgreen", "navy", "blue", "magenta"], delimiter = "", plugins = []) {
|
|
290
287
|
return {
|
|
@@ -299,20 +296,22 @@ var codeInput = {
|
|
|
299
296
|
includeCodeInputInHighlightFunc: true,
|
|
300
297
|
preElementStyled: true,
|
|
301
298
|
isCode: false,
|
|
299
|
+
|
|
302
300
|
rainbowColors: rainbowColors,
|
|
303
301
|
delimiter: delimiter,
|
|
302
|
+
|
|
304
303
|
plugins: plugins,
|
|
305
304
|
}
|
|
306
305
|
},
|
|
307
306
|
|
|
308
307
|
/**
|
|
309
|
-
* @deprecated
|
|
308
|
+
* @deprecated Make your own version of this template if you need it - we think it isn't widely used so will remove it from the next version of code-input.
|
|
310
309
|
*/
|
|
311
310
|
character_limit() {
|
|
312
311
|
return this.characterLimit([]);
|
|
313
312
|
},
|
|
314
313
|
/**
|
|
315
|
-
* @deprecated
|
|
314
|
+
* @deprecated Make your own version of this template if you need it - we think it isn't widely used so will remove it from the next version of code-input.
|
|
316
315
|
*/
|
|
317
316
|
rainbow_text(rainbowColors = ["red", "orangered", "orange", "goldenrod", "gold", "green", "darkgreen", "navy", "blue", "magenta"], delimiter = "", plugins = []) {
|
|
318
317
|
return this.rainbowText(rainbowColors, delimiter, plugins);
|
|
@@ -374,14 +373,7 @@ var codeInput = {
|
|
|
374
373
|
console.log("code-input: plugin: Created plugin");
|
|
375
374
|
|
|
376
375
|
observedAttributes.forEach((attribute) => {
|
|
377
|
-
|
|
378
|
-
let regexFromWildcard = codeInput.wildcard2regex(attribute);
|
|
379
|
-
if(regexFromWildcard == null) {
|
|
380
|
-
// Not a wildcard
|
|
381
|
-
codeInput.observedAttributes.push(attribute);
|
|
382
|
-
} else {
|
|
383
|
-
codeInput.observedAttributes.regexp.push(regexFromWildcard);
|
|
384
|
-
}
|
|
376
|
+
codeInput.observedAttributes.push(attribute);
|
|
385
377
|
});
|
|
386
378
|
}
|
|
387
379
|
|
|
@@ -426,10 +418,6 @@ var codeInput = {
|
|
|
426
418
|
constructor() {
|
|
427
419
|
super(); // Element
|
|
428
420
|
}
|
|
429
|
-
/**
|
|
430
|
-
* Store value internally
|
|
431
|
-
*/
|
|
432
|
-
_value = '';
|
|
433
421
|
|
|
434
422
|
/**
|
|
435
423
|
* Exposed child textarea element for user to input code in
|
|
@@ -439,13 +427,19 @@ var codeInput = {
|
|
|
439
427
|
* Exposed child pre element where syntax-highlighted code is outputted.
|
|
440
428
|
* Contains this.codeElement as its only child.
|
|
441
429
|
*/
|
|
442
|
-
preElement = null
|
|
430
|
+
preElement = null
|
|
443
431
|
/**
|
|
444
432
|
* Exposed child pre element's child code element where syntax-highlighted code is outputted.
|
|
445
433
|
* Has this.preElement as its parent.
|
|
446
434
|
*/
|
|
447
435
|
codeElement = null;
|
|
448
436
|
|
|
437
|
+
/**
|
|
438
|
+
* Exposed non-scrolling element designed to contain dialog boxes etc. that shouldn't scroll
|
|
439
|
+
* with the code-input element.
|
|
440
|
+
*/
|
|
441
|
+
dialogContainerElement = null;
|
|
442
|
+
|
|
449
443
|
/**
|
|
450
444
|
* Form-Associated Custom Element Callbacks
|
|
451
445
|
* https://html.spec.whatwg.org/multipage/custom-elements.html#custom-elements-face-example
|
|
@@ -487,31 +481,48 @@ var codeInput = {
|
|
|
487
481
|
* the result (pre code) element, then use the template object
|
|
488
482
|
* to syntax-highlight it. */
|
|
489
483
|
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
484
|
+
needsHighlight = false; // Just inputted
|
|
485
|
+
|
|
486
|
+
/**
|
|
487
|
+
* Highlight the code as soon as possible
|
|
488
|
+
*/
|
|
489
|
+
scheduleHighlight() {
|
|
490
|
+
this.needsHighlight = true;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
/**
|
|
494
|
+
* Call an animation frame
|
|
493
495
|
*/
|
|
494
|
-
|
|
495
|
-
//
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
this.
|
|
502
|
-
|
|
496
|
+
animateFrame() {
|
|
497
|
+
// Synchronise the size of the pre/code and textarea elements
|
|
498
|
+
if(this.template.preElementStyled) {
|
|
499
|
+
this.style.backgroundColor = getComputedStyle(this.preElement).backgroundColor;
|
|
500
|
+
this.textareaElement.style.height = getComputedStyle(this.preElement).height;
|
|
501
|
+
this.textareaElement.style.width = getComputedStyle(this.preElement).width;
|
|
502
|
+
} else {
|
|
503
|
+
this.style.backgroundColor = getComputedStyle(this.codeElement).backgroundColor;
|
|
504
|
+
this.textareaElement.style.height = getComputedStyle(this.codeElement).height;
|
|
505
|
+
this.textareaElement.style.width = getComputedStyle(this.codeElement).width;
|
|
503
506
|
}
|
|
504
507
|
|
|
505
|
-
|
|
506
|
-
this.
|
|
507
|
-
|
|
508
|
-
|
|
508
|
+
// Synchronise the contents of the pre/code and textarea elements
|
|
509
|
+
if(this.needsHighlight) {
|
|
510
|
+
this.update();
|
|
511
|
+
this.needsHighlight = false;
|
|
512
|
+
}
|
|
509
513
|
|
|
514
|
+
window.requestAnimationFrame(this.animateFrame.bind(this));
|
|
515
|
+
}
|
|
510
516
|
|
|
517
|
+
/**
|
|
518
|
+
* Update the text value to the result element, after the textarea contents have changed.
|
|
519
|
+
*/
|
|
520
|
+
update() {
|
|
511
521
|
let resultElement = this.codeElement;
|
|
522
|
+
let value = this.value;
|
|
512
523
|
|
|
513
524
|
// Handle final newlines
|
|
514
|
-
if (value[value.length - 1] == "\n") {
|
|
525
|
+
if (value[value.length - 1] == "\n" || value.length == 0) {
|
|
515
526
|
value += " ";
|
|
516
527
|
}
|
|
517
528
|
|
|
@@ -526,17 +537,6 @@ var codeInput = {
|
|
|
526
537
|
this.pluginEvt("afterHighlight");
|
|
527
538
|
}
|
|
528
539
|
|
|
529
|
-
/**
|
|
530
|
-
* Synchronise the scrolling of the textarea to the result element.
|
|
531
|
-
*/
|
|
532
|
-
syncScroll() {
|
|
533
|
-
let inputElement = this.textareaElement;
|
|
534
|
-
let resultElement = this.template.preElementStyled ? this.preElement : this.codeElement;
|
|
535
|
-
|
|
536
|
-
resultElement.scrollTop = inputElement.scrollTop;
|
|
537
|
-
resultElement.scrollLeft = inputElement.scrollLeft;
|
|
538
|
-
}
|
|
539
|
-
|
|
540
540
|
/**
|
|
541
541
|
* HTML-escape an arbitrary string.
|
|
542
542
|
* @param {string} text - The original, unescaped text
|
|
@@ -592,7 +592,7 @@ var codeInput = {
|
|
|
592
592
|
this.pluginEvt("beforeElementsAdded");
|
|
593
593
|
|
|
594
594
|
// First-time attribute sync
|
|
595
|
-
let lang = this.getAttribute("lang");
|
|
595
|
+
let lang = this.getAttribute("language") || this.getAttribute("lang");
|
|
596
596
|
let placeholder = this.getAttribute("placeholder") || this.getAttribute("lang") || "";
|
|
597
597
|
let value = this.unescapeHtml(this.innerHTML) || this.getAttribute("value") || "";
|
|
598
598
|
// Value attribute deprecated, but included for compatibility
|
|
@@ -611,22 +611,14 @@ var codeInput = {
|
|
|
611
611
|
this.innerHTML = ""; // Clear Content
|
|
612
612
|
|
|
613
613
|
// Synchronise attributes to textarea
|
|
614
|
-
|
|
615
|
-
|
|
614
|
+
for(let i = 0; i < this.attributes.length; i++) {
|
|
615
|
+
let attribute = this.attributes[i].name;
|
|
616
|
+
if (codeInput.textareaSyncAttributes.includes(attribute) || attribute.substring(0, 5) == "aria-") {
|
|
616
617
|
textarea.setAttribute(attribute, this.getAttribute(attribute));
|
|
617
618
|
}
|
|
618
|
-
}
|
|
619
|
-
codeInput.textareaSyncAttributes.regexp.forEach((reg) =>
|
|
620
|
-
{
|
|
621
|
-
for(const attr of this.attributes) {
|
|
622
|
-
if (attr.nodeName.match(reg)) {
|
|
623
|
-
textarea.setAttribute(attr.nodeName, attr.nodeValue);
|
|
624
|
-
}
|
|
625
|
-
}
|
|
626
|
-
});
|
|
619
|
+
}
|
|
627
620
|
|
|
628
|
-
textarea.addEventListener('input', (evt) => {
|
|
629
|
-
textarea.addEventListener('scroll', (evt) => textarea.parentElement.sync_scroll());
|
|
621
|
+
textarea.addEventListener('input', (evt) => { this.value = this.textareaElement.value; });
|
|
630
622
|
|
|
631
623
|
// Save element internally
|
|
632
624
|
this.textareaElement = textarea;
|
|
@@ -645,22 +637,22 @@ var codeInput = {
|
|
|
645
637
|
|
|
646
638
|
if (this.template.isCode) {
|
|
647
639
|
if (lang != undefined && lang != "") {
|
|
648
|
-
code.classList.add("language-" + lang);
|
|
640
|
+
code.classList.add("language-" + lang.toLowerCase());
|
|
649
641
|
}
|
|
650
642
|
}
|
|
651
643
|
|
|
652
|
-
|
|
644
|
+
// dialogContainerElement used to store non-scrolling dialog boxes, etc.
|
|
645
|
+
let dialogContainerElement = document.createElement("div");
|
|
646
|
+
dialogContainerElement.classList.add("code-input_dialog-container");
|
|
647
|
+
this.append(dialogContainerElement);
|
|
648
|
+
this.dialogContainerElement = dialogContainerElement;
|
|
653
649
|
|
|
654
|
-
this.
|
|
650
|
+
this.pluginEvt("afterElementsAdded");
|
|
655
651
|
|
|
656
652
|
this.dispatchEvent(new CustomEvent("code-input_load"));
|
|
657
|
-
}
|
|
658
653
|
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
*/
|
|
662
|
-
sync_scroll() {
|
|
663
|
-
this.syncScroll();
|
|
654
|
+
this.value = value;
|
|
655
|
+
this.animateFrame();
|
|
664
656
|
}
|
|
665
657
|
|
|
666
658
|
/**
|
|
@@ -671,7 +663,7 @@ var codeInput = {
|
|
|
671
663
|
}
|
|
672
664
|
|
|
673
665
|
/**
|
|
674
|
-
* @deprecated Please use `codeInput.CodeInput.
|
|
666
|
+
* @deprecated Please use `codeInput.CodeInput.getTemplate`
|
|
675
667
|
*/
|
|
676
668
|
get_template() {
|
|
677
669
|
return this.getTemplate();
|
|
@@ -715,13 +707,8 @@ var codeInput = {
|
|
|
715
707
|
return this.attributeChangedCallback(mutation.attributeName, mutation.oldValue, super.getAttribute(mutation.attributeName));
|
|
716
708
|
}
|
|
717
709
|
}
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
for(let i = 0; i < codeInput.observedAttributes.regexp.length; i++) {
|
|
721
|
-
const reg = codeInput.observedAttributes.regexp[i];
|
|
722
|
-
if (mutation.attributeName.match(reg)) {
|
|
723
|
-
return this.attributeChangedCallback(mutation.attributeName, mutation.oldValue, super.getAttribute(mutation.attributeName));
|
|
724
|
-
}
|
|
710
|
+
if (mutation.attributeName.substring(0, 5) == "aria-") {
|
|
711
|
+
return this.attributeChangedCallback(mutation.attributeName, mutation.oldValue, super.getAttribute(mutation.attributeName));
|
|
725
712
|
}
|
|
726
713
|
}
|
|
727
714
|
}
|
|
@@ -745,20 +732,17 @@ var codeInput = {
|
|
|
745
732
|
case "value":
|
|
746
733
|
this.value = newValue;
|
|
747
734
|
break;
|
|
748
|
-
case "placeholder":
|
|
749
|
-
this.textareaElement.placeholder = newValue;
|
|
750
|
-
break;
|
|
751
735
|
case "template":
|
|
752
736
|
this.template = codeInput.usedTemplates[newValue || codeInput.defaultTemplate];
|
|
753
737
|
if (this.template.preElementStyled) this.classList.add("code-input_pre-element-styled");
|
|
754
738
|
else this.classList.remove("code-input_pre-element-styled");
|
|
755
739
|
// Syntax Highlight
|
|
756
|
-
this.
|
|
740
|
+
this.needsHighlight = true;
|
|
757
741
|
|
|
758
742
|
break;
|
|
759
743
|
|
|
760
744
|
case "lang":
|
|
761
|
-
|
|
745
|
+
case "language":
|
|
762
746
|
let code = this.codeElement;
|
|
763
747
|
let mainTextarea = this.textareaElement;
|
|
764
748
|
|
|
@@ -785,11 +769,11 @@ var codeInput = {
|
|
|
785
769
|
|
|
786
770
|
if (mainTextarea.placeholder == oldValue) mainTextarea.placeholder = newValue;
|
|
787
771
|
|
|
788
|
-
this.
|
|
772
|
+
this.needsHighlight = true;
|
|
789
773
|
|
|
790
774
|
break;
|
|
791
775
|
default:
|
|
792
|
-
if (codeInput.textareaSyncAttributes.includes(name)) {
|
|
776
|
+
if (codeInput.textareaSyncAttributes.includes(name) || name.substring(0, 5) == "aria-") {
|
|
793
777
|
if(newValue == null || newValue == undefined) {
|
|
794
778
|
this.textareaElement.removeAttribute(name);
|
|
795
779
|
} else {
|
|
@@ -822,10 +806,12 @@ var codeInput = {
|
|
|
822
806
|
* @override
|
|
823
807
|
*/
|
|
824
808
|
addEventListener(type, listener, options = undefined) {
|
|
809
|
+
// Save a copy of the callback where `this` refers to the code-input element
|
|
825
810
|
let boundCallback = listener.bind(this);
|
|
826
811
|
this.boundEventCallbacks[listener] = boundCallback;
|
|
827
812
|
|
|
828
813
|
if (codeInput.textareaSyncEvents.includes(type)) {
|
|
814
|
+
// Synchronise with textarea
|
|
829
815
|
if (options === undefined) {
|
|
830
816
|
if(this.textareaElement == null) {
|
|
831
817
|
this.addEventListener("code-input_load", () => { this.textareaElement.addEventListener(type, boundCallback); });
|
|
@@ -840,6 +826,7 @@ var codeInput = {
|
|
|
840
826
|
}
|
|
841
827
|
}
|
|
842
828
|
} else {
|
|
829
|
+
// Synchronise with code-input element
|
|
843
830
|
if (options === undefined) {
|
|
844
831
|
super.addEventListener(type, boundCallback);
|
|
845
832
|
} else {
|
|
@@ -851,22 +838,32 @@ var codeInput = {
|
|
|
851
838
|
/**
|
|
852
839
|
* @override
|
|
853
840
|
*/
|
|
854
|
-
removeEventListener(type, listener, options =
|
|
841
|
+
removeEventListener(type, listener, options = undefined) {
|
|
842
|
+
// Save a copy of the callback where `this` refers to the code-input element
|
|
855
843
|
let boundCallback = this.boundEventCallbacks[listener];
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
844
|
+
|
|
845
|
+
if (codeInput.textareaSyncEvents.includes(type)) {
|
|
846
|
+
// Synchronise with textarea
|
|
847
|
+
if (options === undefined) {
|
|
848
|
+
if(this.textareaElement == null) {
|
|
849
|
+
this.addEventListener("code-input_load", () => { this.textareaElement.removeEventListener(type, boundCallback); });
|
|
850
|
+
} else {
|
|
851
|
+
this.textareaElement.removeEventListener(type, boundCallback);
|
|
852
|
+
}
|
|
859
853
|
} else {
|
|
860
|
-
this.textareaElement
|
|
854
|
+
if(this.textareaElement == null) {
|
|
855
|
+
this.addEventListener("code-input_load", () => { this.textareaElement.removeEventListener(type, boundCallback, options); });
|
|
856
|
+
} else {
|
|
857
|
+
this.textareaElement.removeEventListener(type, boundCallback, options);
|
|
858
|
+
}
|
|
861
859
|
}
|
|
862
|
-
} else
|
|
863
|
-
|
|
864
|
-
|
|
860
|
+
} else {
|
|
861
|
+
// Synchronise with code-input element
|
|
862
|
+
if (options === undefined) {
|
|
863
|
+
super.removeEventListener(type, boundCallback);
|
|
865
864
|
} else {
|
|
866
|
-
|
|
865
|
+
super.removeEventListener(type, boundCallback, options);
|
|
867
866
|
}
|
|
868
|
-
} else {
|
|
869
|
-
super.removeEventListener(type, listener, options);
|
|
870
867
|
}
|
|
871
868
|
}
|
|
872
869
|
|
|
@@ -874,7 +871,8 @@ var codeInput = {
|
|
|
874
871
|
* Get the text contents of the code-input element.
|
|
875
872
|
*/
|
|
876
873
|
get value() {
|
|
877
|
-
|
|
874
|
+
// Get from editable textarea element
|
|
875
|
+
return this.textareaElement.value;
|
|
878
876
|
}
|
|
879
877
|
/**
|
|
880
878
|
* Set the text contents of the code-input element.
|
|
@@ -884,8 +882,10 @@ var codeInput = {
|
|
|
884
882
|
if (val === null || val === undefined) {
|
|
885
883
|
val = "";
|
|
886
884
|
}
|
|
887
|
-
|
|
888
|
-
this.
|
|
885
|
+
// Save in editable textarea element
|
|
886
|
+
this.textareaElement.value = val;
|
|
887
|
+
// Trigger highlight
|
|
888
|
+
this.needsHighlight = true;
|
|
889
889
|
return val;
|
|
890
890
|
}
|
|
891
891
|
|
|
@@ -963,34 +963,10 @@ var codeInput = {
|
|
|
963
963
|
* Update value on form reset
|
|
964
964
|
*/
|
|
965
965
|
formResetCallback() {
|
|
966
|
-
this.
|
|
967
|
-
};
|
|
968
|
-
},
|
|
969
|
-
|
|
970
|
-
arrayWildcards2regex(list) {
|
|
971
|
-
for(let i = 0; i < list.length; i++) {
|
|
972
|
-
const name = list[i];
|
|
973
|
-
if (name.indexOf("*") < 0)
|
|
974
|
-
continue;
|
|
975
|
-
|
|
976
|
-
list.regexp.push(new RegExp("^" +
|
|
977
|
-
name.replace(/[/\-\\^$+?.()|[\]{}]/g, '\\$&')
|
|
978
|
-
.replace("*", ".*")
|
|
979
|
-
+ "$", "i"));
|
|
980
|
-
list.splice(i--, 1);
|
|
966
|
+
this.value = this.initialValue;
|
|
981
967
|
};
|
|
982
968
|
},
|
|
983
969
|
|
|
984
|
-
wildcard2regex(wildcard) {
|
|
985
|
-
if (wildcard.indexOf("*") < 0)
|
|
986
|
-
return null;
|
|
987
|
-
|
|
988
|
-
return new RegExp("^" +
|
|
989
|
-
wildcard.replace(/[/\-\\^$+?.()|[\]{}]/g, '\\$&')
|
|
990
|
-
.replace("*", ".*")
|
|
991
|
-
+ "$", "i");
|
|
992
|
-
},
|
|
993
|
-
|
|
994
970
|
/**
|
|
995
971
|
* To ensure the DOM is ready, run this callback after the window
|
|
996
972
|
* has loaded (or now if it has already loaded)
|
|
@@ -1008,29 +984,4 @@ window.addEventListener("load", function() {
|
|
|
1008
984
|
codeInput.windowLoaded = true;
|
|
1009
985
|
});
|
|
1010
986
|
|
|
1011
|
-
|
|
1012
|
-
/**
|
|
1013
|
-
* convert wildcards into regex
|
|
1014
|
-
*/
|
|
1015
|
-
|
|
1016
|
-
{
|
|
1017
|
-
Object.defineProperty(codeInput.textareaSyncAttributes, 'regexp', {
|
|
1018
|
-
value: [],
|
|
1019
|
-
writable: false,
|
|
1020
|
-
enumerable: false,
|
|
1021
|
-
configurable: false
|
|
1022
|
-
});
|
|
1023
|
-
codeInput.observedAttributes = codeInput.observedAttributes.concat(codeInput.textareaSyncAttributes);
|
|
1024
|
-
|
|
1025
|
-
Object.defineProperty(codeInput.observedAttributes, 'regexp', {
|
|
1026
|
-
value: [],
|
|
1027
|
-
writable: false,
|
|
1028
|
-
enumerable: false,
|
|
1029
|
-
configurable: false
|
|
1030
|
-
});
|
|
1031
|
-
|
|
1032
|
-
codeInput.arrayWildcards2regex(codeInput.textareaSyncAttributes);
|
|
1033
|
-
codeInput.arrayWildcards2regex(codeInput.observedAttributes);
|
|
1034
|
-
}
|
|
1035
|
-
|
|
1036
|
-
customElements.define("code-input", codeInput.CodeInput);
|
|
987
|
+
customElements.define("code-input", codeInput.CodeInput);
|
package/code-input.min.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
code-input{position:relative;top:0;left:0;
|
|
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){margin:0!important;margin-bottom:calc(-1 * var(--padding,16px))!important;padding:var(--padding,16px)!important;border:0}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);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}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:not(.code-input_loaded) pre,code-input:not(.code-input_loaded) textarea{opacity:0}code-input:not(.code-input_loaded)::before{color:#ccc}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:not(.code-input_registered)::before{content:"Use codeInput.registerTemplate to set up.";display:block;color:grey}code-input .code-input_dialog-container{z-index:2;position:sticky;grid-row:1;grid-column:1;top:0;left:0;width:100%;height:0;text-align:left}
|
package/code-input.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var codeInput={observedAttributes:["value","placeholder","lang","template"],textareaSyncAttributes:["aria-*","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"],usedTemplates:{},defaultTemplate:void 0,templateNotYetRegisteredQueue:{},registerTemplate:function(a,b){if(!("string"==typeof a||a instanceof String))throw TypeError(`code-input: Template for "${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])elem=codeInput.templateNotYetRegisteredQueue[a][c],elem.template=b,codeInput.runOnceWindowLoaded(function(a){a.connectedCallback()}.bind(null,elem),elem);console.log(`code-input: template: Added existing elements with template ${a}`)}if(null==codeInput.defaultTemplate){if(codeInput.defaultTemplate=a,void 0 in codeInput.templateNotYetRegisteredQueue)for(let a in codeInput.templateNotYetRegisteredQueue[void 0])elem=codeInput.templateNotYetRegisteredQueue[void 0][a],elem.template=b,codeInput.runOnceWindowLoaded(function(a){a.connectedCallback()}.bind(null,elem),elem);console.log(`code-input: template: Set template ${a} as default`)}console.log(`code-input: template: Created template ${a}`)},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{includeCodeInputInHighlightFunc:!1,highlight:a.highlightElement,preElementStyled:!0,isCode:!0,plugins:b}},hljs(a,b=[]){return{includeCodeInputInHighlightFunc:!1,highlight:a.highlightElement,preElementStyled:!1,isCode:!0,plugins: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){console.log("code-input: plugin: Created plugin"),a.forEach(a=>{let b=codeInput.wildcard2regex(a);null==b?codeInput.observedAttributes.push(a):codeInput.observedAttributes.regexp.push(b)})}beforeHighlight(){}afterHighlight(){}beforeElementsAdded(){}afterElementsAdded(){}attributeChanged(){}},CodeInput:class extends HTMLElement{constructor(){super()}_value="";textareaElement=null;preElement=null;codeElement=null;static formAssociated=!0;boundEventCallbacks={};pluginEvt(a,b){for(let c in this.template.plugins){let d=this.template.plugins[c];a in d&&(b===void 0?d[a](this):d[a](this,...b))}}update(a){if(!this.ignoreValueUpdate){if(null==this.textareaElement)return void this.addEventListener("code-input_load",()=>{this.update(a)});this.ignoreValueUpdate=!0,this.value=a,this.ignoreValueUpdate=!1,this.textareaElement.value!=a&&(this.textareaElement.value=a);let b=this.codeElement;"\n"==a[a.length-1]&&(a+=" "),b.innerHTML=this.escapeHtml(a),this.pluginEvt("beforeHighlight"),this.template.includeCodeInputInHighlightFunc?this.template.highlight(b,this):this.template.highlight(b),this.pluginEvt("afterHighlight")}}syncScroll(){let a=this.textareaElement,b=this.template.preElementStyled?this.preElement:this.codeElement;b.scrollTop=a.scrollTop,b.scrollLeft=a.scrollLeft}escapeHtml(a){return a.replace(/&/g,"&").replace(/</g,"<")}unescapeHtml(a){return a.replace(/&/g,"&").replace(/</g,"<").replace(/>/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.template.preElementStyled&&this.classList.add("code-input_pre-element-styled"),this.pluginEvt("beforeElementsAdded");let a=this.getAttribute("lang"),b=this.getAttribute("placeholder")||this.getAttribute("lang")||"",c=this.unescapeHtml(this.innerHTML)||this.getAttribute("value")||"";this.initialValue=c;let d=document.createElement("textarea");d.placeholder=b,""!=c&&(d.value=c),d.innerHTML=this.innerHTML,d.setAttribute("spellcheck","false"),this.innerHTML="",codeInput.textareaSyncAttributes.forEach(a=>{this.hasAttribute(a)&&d.setAttribute(a,this.getAttribute(a))}),codeInput.textareaSyncAttributes.regexp.forEach(a=>{for(const b of this.attributes)b.nodeName.match(a)&&d.setAttribute(b.nodeName,b.nodeValue)}),d.addEventListener("input",()=>{d.parentElement.update(d.value),d.parentElement.sync_scroll()}),d.addEventListener("scroll",()=>d.parentElement.sync_scroll()),this.textareaElement=d,this.append(d);let e=document.createElement("code"),f=document.createElement("pre");f.setAttribute("aria-hidden","true"),this.preElement=f,this.codeElement=e,f.append(e),this.append(f),this.template.isCode&&a!=null&&""!=a&&e.classList.add("language-"+a),this.pluginEvt("afterElementsAdded"),this.update(c),this.dispatchEvent(new CustomEvent("code-input_load"))}sync_scroll(){this.syncScroll()}escape_html(a){return this.escapeHtml(a)}get_template(){return this.getTemplate()}connectedCallback(){this.template=this.getTemplate(),this.template!=null&&(this.classList.add("code-input_registered"),codeInput.runOnceWindowLoaded(()=>{this.setup(),this.classList.add("code-input_loaded")},this)),this.mutationObserver=new MutationObserver(this.mutationObserverCallback.bind(this)),this.mutationObserver.observe(this,{attributes:!0,attributeOldValue:!0})}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.observedAttributes.regexp.length;a++){const c=codeInput.observedAttributes.regexp[a];if(b.attributeName.match(c))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"placeholder":this.textareaElement.placeholder=c;break;case"template":this.template=codeInput.usedTemplates[c||codeInput.defaultTemplate],this.template.preElementStyled?this.classList.add("code-input_pre-element-styled"):this.classList.remove("code-input_pre-element-styled"),this.update(this.value);break;case"lang":let d=this.codeElement,e=this.textareaElement;if(null!=c&&(c=c.toLowerCase(),d.classList.contains(`language-${c}`)))break;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.update(this.value);break;default:codeInput.textareaSyncAttributes.includes(a)?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=b.bind(this);this.boundEventCallbacks[b]=d,codeInput.textareaSyncEvents.includes(a)?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=null){let d=this.boundEventCallbacks[b];"change"==a?null===c?this.textareaElement.removeEventListener("change",d):this.textareaElement.removeEventListener("change",d,c):"selectionchange"==a?null===c?this.textareaElement.removeEventListener("selectionchange",d):this.textareaElement.removeEventListener("selectionchange",d,c):super.removeEventListener(a,b,c)}get value(){return this._value}set value(a){return(null===a||void 0===a)&&(a=""),this._value=a,this.update(a),a}get placeholder(){return this.getAttribute("placeholder")}set placeholder(a){return this.setAttribute("placeholder",a)}get validity(){return this.textareaElement.validity}get validationMessage(){return this.textareaElement.validationMessage}setCustomValidity(a){return this.textareaElement.setCustomValidity(a)}checkValidity(){return this.textareaElement.checkValidity()}reportValidity(){return this.textareaElement.reportValidity()}pluginData={};formResetCallback(){this.update(this.initialValue)}},arrayWildcards2regex(a){for(let b=0;b<a.length;b++){const c=a[b];0>c.indexOf("*")||(a.regexp.push(new RegExp("^"+c.replace(/[/\-\\^$+?.()|[\]{}]/g,"\\$&").replace("*",".*")+"$","i")),a.splice(b--,1))}},wildcard2regex(a){return 0>a.indexOf("*")?null:new RegExp("^"+a.replace(/[/\-\\^$+?.()|[\]{}]/g,"\\$&").replace("*",".*")+"$","i")},runOnceWindowLoaded(a){codeInput.windowLoaded?a():window.addEventListener("load",a)},windowLoaded:!1};window.addEventListener("load",function(){codeInput.windowLoaded=!0}),Object.defineProperty(codeInput.textareaSyncAttributes,"regexp",{value:[],writable:!1,enumerable:!1,configurable:!1}),codeInput.observedAttributes=codeInput.observedAttributes.concat(codeInput.textareaSyncAttributes),Object.defineProperty(codeInput.observedAttributes,"regexp",{value:[],writable:!1,enumerable:!1,configurable:!1}),codeInput.arrayWildcards2regex(codeInput.textareaSyncAttributes),codeInput.arrayWildcards2regex(codeInput.observedAttributes),customElements.define("code-input",codeInput.CodeInput);
|
|
1
|
+
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"],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])elem=codeInput.templateNotYetRegisteredQueue[a][c],elem.template=b,codeInput.runOnceWindowLoaded(function(a){a.connectedCallback()}.bind(null,elem),elem);console.log(`code-input: template: Added existing elements with template ${a}`)}if(null==codeInput.defaultTemplate){if(codeInput.defaultTemplate=a,void 0 in codeInput.templateNotYetRegisteredQueue)for(let a in codeInput.templateNotYetRegisteredQueue[void 0])elem=codeInput.templateNotYetRegisteredQueue[void 0][a],elem.template=b,codeInput.runOnceWindowLoaded(function(a){a.connectedCallback()}.bind(null,elem),elem);console.log(`code-input: template: Set template ${a} as default`)}console.log(`code-input: template: Created template ${a}`)},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.Template(a.highlightElement,!0,!0,!1,b)},hljs(a,b=[]){return new codeInput.Template(function(b){b.removeAttribute("data-highlighted"),a.highlightElement(b)},!1,!0,!1,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){console.log("code-input: plugin: Created plugin"),a.forEach(a=>{codeInput.observedAttributes.push(a)})}beforeHighlight(){}afterHighlight(){}beforeElementsAdded(){}afterElementsAdded(){}attributeChanged(){}},CodeInput:class extends HTMLElement{constructor(){super()}textareaElement=null;preElement=null;codeElement=null;dialogContainerElement=null;static formAssociated=!0;boundEventCallbacks={};pluginEvt(a,b){for(let c in this.template.plugins){let d=this.template.plugins[c];a in d&&(b===void 0?d[a](this):d[a](this,...b))}}needsHighlight=!1;scheduleHighlight(){this.needsHighlight=!0}animateFrame(){this.template.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),this.needsHighlight&&(this.update(),this.needsHighlight=!1),window.requestAnimationFrame(this.animateFrame.bind(this))}update(){let a=this.codeElement,b=this.value;("\n"==b[b.length-1]||0==b.length)&&(b+=" "),a.innerHTML=this.escapeHtml(b),this.pluginEvt("beforeHighlight"),this.template.includeCodeInputInHighlightFunc?this.template.highlight(a,this):this.template.highlight(a),this.pluginEvt("afterHighlight")}escapeHtml(a){return a.replace(/&/g,"&").replace(/</g,"<")}unescapeHtml(a){return a.replace(/&/g,"&").replace(/</g,"<").replace(/>/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.template.preElementStyled&&this.classList.add("code-input_pre-element-styled"),this.pluginEvt("beforeElementsAdded");let a=this.getAttribute("language")||this.getAttribute("lang"),b=this.getAttribute("placeholder")||this.getAttribute("lang")||"",c=this.unescapeHtml(this.innerHTML)||this.getAttribute("value")||"";this.initialValue=c;let d=document.createElement("textarea");d.placeholder=b,""!=c&&(d.value=c),d.innerHTML=this.innerHTML,d.setAttribute("spellcheck","false"),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))&&d.setAttribute(a,this.getAttribute(a));d.addEventListener("input",()=>{this.value=this.textareaElement.value}),this.textareaElement=d,this.append(d);let e=document.createElement("code"),f=document.createElement("pre");f.setAttribute("aria-hidden","true"),this.preElement=f,this.codeElement=e,f.append(e),this.append(f),this.template.isCode&&a!=null&&""!=a&&e.classList.add("language-"+a.toLowerCase());let g=document.createElement("div");g.classList.add("code-input_dialog-container"),this.append(g),this.dialogContainerElement=g,this.pluginEvt("afterElementsAdded"),this.dispatchEvent(new CustomEvent("code-input_load")),this.value=c,this.animateFrame()}escape_html(a){return this.escapeHtml(a)}get_template(){return this.getTemplate()}connectedCallback(){this.template=this.getTemplate(),this.template!=null&&(this.classList.add("code-input_registered"),codeInput.runOnceWindowLoaded(()=>{this.setup(),this.classList.add("code-input_loaded")},this)),this.mutationObserver=new MutationObserver(this.mutationObserverCallback.bind(this)),this.mutationObserver.observe(this,{attributes:!0,attributeOldValue:!0})}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));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.template=codeInput.usedTemplates[c||codeInput.defaultTemplate],this.template.preElementStyled?this.classList.add("code-input_pre-element-styled"):this.classList.remove("code-input_pre-element-styled"),this.needsHighlight=!0;break;case"lang":case"language":let d=this.codeElement,e=this.textareaElement;if(null!=c&&(c=c.toLowerCase(),d.classList.contains(`language-${c}`)))break;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.needsHighlight=!0;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=b.bind(this);this.boundEventCallbacks[b]=d,codeInput.textareaSyncEvents.includes(a)?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)}get value(){return this.textareaElement.value}set value(a){return(null===a||void 0===a)&&(a=""),this.textareaElement.value=a,this.needsHighlight=!0,a}get placeholder(){return this.getAttribute("placeholder")}set placeholder(a){return this.setAttribute("placeholder",a)}get validity(){return this.textareaElement.validity}get validationMessage(){return this.textareaElement.validationMessage}setCustomValidity(a){return this.textareaElement.setCustomValidity(a)}checkValidity(){return this.textareaElement.checkValidity()}reportValidity(){return this.textareaElement.reportValidity()}pluginData={};formResetCallback(){this.value=this.initialValue}},runOnceWindowLoaded(a){codeInput.windowLoaded?a():window.addEventListener("load",a)},windowLoaded:!1};window.addEventListener("load",function(){codeInput.windowLoaded=!0}),customElements.define("code-input",codeInput.CodeInput);
|