@webcoder49/code-input 1.5.0 → 1.5.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/.github/workflows/minify.yml +21 -21
- package/.github/workflows/npm-publish.yml +21 -0
- package/LICENSE +21 -21
- package/README.md +112 -115
- package/code-input.css +100 -100
- package/code-input.js +759 -422
- package/code-input.min.js +1 -1
- package/package.json +1 -1
- package/plugins/README.md +68 -68
- package/plugins/autocomplete.css +14 -14
- package/plugins/autocomplete.js +79 -79
- package/plugins/autodetect.js +28 -28
- package/plugins/debounce-update.js +40 -40
- package/plugins/indent.js +153 -153
- package/plugins/indent.min.js +1 -1
- package/plugins/prism-line-numbers.css +19 -19
- package/plugins/special-chars.css +97 -97
- package/plugins/special-chars.js +218 -218
- package/plugins/special-chars.min.css +4 -4
- package/plugins/test.js +37 -37
package/code-input.js
CHANGED
|
@@ -1,422 +1,759 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
1
|
+
/**
|
|
2
|
+
* **code-input** is a library which lets you create custom HTML `<code-input>`
|
|
3
|
+
* elements that act like `<textarea>` elements but support syntax-highlighted
|
|
4
|
+
* code, implemented using any typical syntax highlighting library. [MIT-Licensed]
|
|
5
|
+
*
|
|
6
|
+
* **<https://github.com/WebCoder49/code-input>**
|
|
7
|
+
*/
|
|
8
|
+
var codeInput = {
|
|
9
|
+
/**
|
|
10
|
+
* A list of attributes that will trigger the
|
|
11
|
+
* `codeInput.CodeInput.attributeChangedCallback`
|
|
12
|
+
* when modified in a code-input element. This
|
|
13
|
+
* does not include events, which are handled in
|
|
14
|
+
* `codeInput.CodeInput.addEventListener` and
|
|
15
|
+
* `codeInput.CodeInput.removeEventListener`.
|
|
16
|
+
*/
|
|
17
|
+
observedAttributes: [
|
|
18
|
+
"value",
|
|
19
|
+
"placeholder",
|
|
20
|
+
"lang",
|
|
21
|
+
"template"
|
|
22
|
+
],
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* A list of attributes that will be moved to
|
|
26
|
+
* the textarea after they are applied on the
|
|
27
|
+
* code-input element.
|
|
28
|
+
*/
|
|
29
|
+
textareaSyncAttributes: [
|
|
30
|
+
"value",
|
|
31
|
+
"name",
|
|
32
|
+
// Form validation - https://developer.mozilla.org/en-US/docs/Learn/Forms/Form_validation#using_built-in_form_validation
|
|
33
|
+
"required",
|
|
34
|
+
"minlength", "maxlength",
|
|
35
|
+
"min", "max",
|
|
36
|
+
"type",
|
|
37
|
+
"pattern"
|
|
38
|
+
],
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* A list of events whose listeners will be moved to
|
|
42
|
+
* the textarea after they are added to the
|
|
43
|
+
* code-input element.
|
|
44
|
+
*/
|
|
45
|
+
textareaSyncEvents: [
|
|
46
|
+
"change",
|
|
47
|
+
"selectionchange",
|
|
48
|
+
"invalid",
|
|
49
|
+
"input"
|
|
50
|
+
],
|
|
51
|
+
|
|
52
|
+
/* ------------------------------------
|
|
53
|
+
* ------------Templates---------------
|
|
54
|
+
* ------------------------------------ */
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* The templates currently available for any code-input elements
|
|
58
|
+
* to use. Registered using `codeInput.registerTemplate`.
|
|
59
|
+
* Key - Template Name
|
|
60
|
+
* Value - A Template Object
|
|
61
|
+
* @type {Object}
|
|
62
|
+
*/
|
|
63
|
+
usedTemplates: {
|
|
64
|
+
},
|
|
65
|
+
/**
|
|
66
|
+
* The name of the default template that a code-input element that
|
|
67
|
+
* does not specify the template attribute uses.
|
|
68
|
+
* @type {string}
|
|
69
|
+
*/
|
|
70
|
+
defaultTemplate: undefined,
|
|
71
|
+
/**
|
|
72
|
+
* A queue of elements waiting for a template to be registered,
|
|
73
|
+
* allowing elements to be created in HTML with a template before
|
|
74
|
+
* the template is registered in JS, for ease of use.
|
|
75
|
+
* Key - Template Name
|
|
76
|
+
* Value - An array of code-input elements
|
|
77
|
+
* @type {Object}
|
|
78
|
+
*/
|
|
79
|
+
templateNotYetRegisteredQueue: {},
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Register a template so code-input elements with a template attribute that equals the templateName will use the template.
|
|
83
|
+
* See `codeInput.templates` for constructors to create templates.
|
|
84
|
+
* @param {string} templateName - the name to register the template under
|
|
85
|
+
* @param {Object} template - a Template object instance - see `codeInput.templates`
|
|
86
|
+
*/
|
|
87
|
+
registerTemplate: function (templateName, template) {
|
|
88
|
+
if(!(typeof templateName == "string" || templateName instanceof String)) throw TypeError(`Template for "${templateName}" must be a string.`);
|
|
89
|
+
if(!(typeof template.highlight == "function" || template.highlight instanceof Function)) throw TypeError(`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.`);
|
|
90
|
+
if(!(typeof template.includeCodeInputInHighlightFunc == "boolean" || template.includeCodeInputInHighlightFunc instanceof Boolean)) throw TypeError(`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.`);
|
|
91
|
+
if(!(typeof template.preElementStyled == "boolean" || template.preElementStyled instanceof Boolean)) throw TypeError(`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.`);
|
|
92
|
+
if(!(typeof template.isCode == "boolean" || template.isCode instanceof Boolean)) throw TypeError(`Template for "${templateName}" invalid, because the isCode value provided is not a true or false; it is "${template.isCode}". Please make sure you use one of the constructors in codeInput.templates, and that you provide the correct arguments.`);
|
|
93
|
+
if(!Array.isArray(template.plugins)) throw TypeError(`Template for "${templateName}" invalid, because the plugin array provided is not an array; it is "${template.plugins}". Please make sure you use one of the constructors in codeInput.templates, and that you provide the correct arguments.`);
|
|
94
|
+
template.plugins.forEach((plugin, i) => {
|
|
95
|
+
if(!(plugin instanceof codeInput.Plugin)) {
|
|
96
|
+
throw TypeError(`Template for "${templateName}" invalid, because the plugin provided at index ${i} is not valid; it is "${template.plugins[i]}". Please make sure you use one of the constructors in codeInput.templates, and that you provide the correct arguments.`);
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
codeInput.usedTemplates[templateName] = template;
|
|
101
|
+
// Add waiting code-input elements wanting this template from queue
|
|
102
|
+
if (templateName in codeInput.templateNotYetRegisteredQueue) {
|
|
103
|
+
for (let i in codeInput.templateNotYetRegisteredQueue[templateName]) {
|
|
104
|
+
elem = codeInput.templateNotYetRegisteredQueue[templateName][i];
|
|
105
|
+
elem.template = template;
|
|
106
|
+
elem.setup();
|
|
107
|
+
}
|
|
108
|
+
console.log(`code-input: template: Added existing elements with template ${templateName}`);
|
|
109
|
+
}
|
|
110
|
+
if (codeInput.defaultTemplate == undefined) {
|
|
111
|
+
codeInput.defaultTemplate = templateName;
|
|
112
|
+
// Add elements with default template from queue
|
|
113
|
+
if (undefined in codeInput.templateNotYetRegisteredQueue) {
|
|
114
|
+
for (let i in codeInput.templateNotYetRegisteredQueue[undefined]) {
|
|
115
|
+
elem = codeInput.templateNotYetRegisteredQueue[undefined][i];
|
|
116
|
+
elem.template = template;
|
|
117
|
+
elem.setup();
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
console.log(`code-input: template: Set template ${templateName} as default`);
|
|
121
|
+
}
|
|
122
|
+
console.log(`code-input: template: Created template ${templateName}`);
|
|
123
|
+
},
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Constructors for creating templates.
|
|
127
|
+
* Each code-input element has a template attribute that
|
|
128
|
+
* tells it which template to use.
|
|
129
|
+
* Each template contains functions and preferences that
|
|
130
|
+
* run the syntax-highlighting and let code-input control
|
|
131
|
+
* the highlighting.
|
|
132
|
+
* For adding small pieces of functionality, please see `codeInput.plugins`.
|
|
133
|
+
*/
|
|
134
|
+
templates: {
|
|
135
|
+
/**
|
|
136
|
+
* Constructor to create a custom template instance. Pass this into `codeInput.registerTemplate` to use it.
|
|
137
|
+
* I would strongly recommend using the built-in simpler template `codeInput.templates.prism` or `codeInput.templates.hljs`.
|
|
138
|
+
* @param {Function} highlight - a callback to highlight the code, that takes an HTML `<code>` element inside a `<pre>` element as a parameter
|
|
139
|
+
* @param {boolean} preElementStyled - is the <pre> element CSS-styled as well as the `<code>` element? If true, `<pre>` element's scrolling is synchronised; if false, <code> element's scrolling is synchronised.
|
|
140
|
+
* @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]'.
|
|
141
|
+
* @param {boolean} includeCodeInputInHighlightFunc - Setting this to true passes the `<code-input>` element as a second argument to the highlight function.
|
|
142
|
+
* @param {codeInput.Plugin[]} plugins - An array of plugin objects to add extra features - see `codeInput.plugins`
|
|
143
|
+
* @returns template object
|
|
144
|
+
*/
|
|
145
|
+
custom(highlight = function () { }, preElementStyled = true, isCode = true, includeCodeInputInHighlightFunc = false, plugins = []) {
|
|
146
|
+
return {
|
|
147
|
+
highlight: highlight,
|
|
148
|
+
includeCodeInputInHighlightFunc: includeCodeInputInHighlightFunc,
|
|
149
|
+
preElementStyled: preElementStyled,
|
|
150
|
+
isCode: isCode,
|
|
151
|
+
plugins: plugins,
|
|
152
|
+
};
|
|
153
|
+
},
|
|
154
|
+
/**
|
|
155
|
+
* Constructor to create a template that uses Prism.js syntax highlighting (https://prismjs.com/)
|
|
156
|
+
* @param {Object} prism Import Prism.js, then after that import pass the `Prism` object as this parameter.
|
|
157
|
+
* @param {codeInput.Plugin[]} plugins - An array of plugin objects to add extra features - see `codeInput.plugins`
|
|
158
|
+
* @returns template object
|
|
159
|
+
*/
|
|
160
|
+
prism(prism, plugins = []) { // Dependency: Prism.js (https://prismjs.com/)
|
|
161
|
+
return {
|
|
162
|
+
includeCodeInputInHighlightFunc: false,
|
|
163
|
+
highlight: prism.highlightElement,
|
|
164
|
+
preElementStyled: true,
|
|
165
|
+
isCode: true,
|
|
166
|
+
plugins: plugins,
|
|
167
|
+
};
|
|
168
|
+
},
|
|
169
|
+
/**
|
|
170
|
+
* Constructor to create a template that uses highlight.js syntax highlighting (https://highlightjs.org/)
|
|
171
|
+
* @param {Object} hljs Import highlight.js, then after that import pass the `hljs` object as this parameter.
|
|
172
|
+
* @param {codeInput.Plugin[]} plugins - An array of plugin objects to add extra features - see `codeInput.plugins`
|
|
173
|
+
* @returns template object
|
|
174
|
+
*/
|
|
175
|
+
hljs(hljs, plugins = []) { // Dependency: Highlight.js (https://highlightjs.org/)
|
|
176
|
+
return {
|
|
177
|
+
includeCodeInputInHighlightFunc: false,
|
|
178
|
+
highlight: hljs.highlightElement,
|
|
179
|
+
preElementStyled: false,
|
|
180
|
+
isCode: true,
|
|
181
|
+
plugins: plugins,
|
|
182
|
+
};
|
|
183
|
+
},
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Constructor to create a proof-of-concept template that gives a message if too many characters are typed.
|
|
187
|
+
* @param {codeInput.Plugin[]} plugins - An array of plugin objects to add extra features - see `codeInput.plugins`
|
|
188
|
+
* @returns template object
|
|
189
|
+
*/
|
|
190
|
+
characterLimit(plugins) {
|
|
191
|
+
return {
|
|
192
|
+
highlight: function (resultElement, codeInput, plugins = []) {
|
|
193
|
+
|
|
194
|
+
let characterLimit = Number(codeInput.getAttribute("data-character-limit"));
|
|
195
|
+
|
|
196
|
+
let normalCharacters = codeInput.escapeHtml(codeInput.value.slice(0, characterLimit));
|
|
197
|
+
let overflowCharacters = codeInput.escapeHtml(codeInput.value.slice(characterLimit));
|
|
198
|
+
|
|
199
|
+
resultElement.innerHTML = `${normalCharacters}<mark class="overflow">${overflowCharacters}</mark>`;
|
|
200
|
+
if (overflowCharacters.length > 0) {
|
|
201
|
+
resultElement.innerHTML += ` <mark class="overflow-msg">${codeInput.getAttribute("data-overflow-msg") || "(Character limit reached)"}</mark>`;
|
|
202
|
+
}
|
|
203
|
+
},
|
|
204
|
+
includeCodeInputInHighlightFunc: true,
|
|
205
|
+
preElementStyled: true,
|
|
206
|
+
isCode: false,
|
|
207
|
+
plugins: plugins,
|
|
208
|
+
}
|
|
209
|
+
},
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Constructor to create a proof-of-concept template that shows text in a repeating series of colors.
|
|
213
|
+
* @param {string[]} rainbowColors - An array of CSS colors, in the order each color will be shown
|
|
214
|
+
* @param {string} delimiter - The character used to split up parts of text where each part is a different colour (e.g. "" = characters, " " = words)
|
|
215
|
+
* @param {codeInput.Plugin[]} plugins - An array of plugin objects to add extra features - see `codeInput.plugins`
|
|
216
|
+
* @returns template object
|
|
217
|
+
*/
|
|
218
|
+
rainbowText(rainbowColors = ["red", "orangered", "orange", "goldenrod", "gold", "green", "darkgreen", "navy", "blue", "magenta"], delimiter = "", plugins = []) {
|
|
219
|
+
return {
|
|
220
|
+
highlight: function (resultElement, codeInput) {
|
|
221
|
+
let htmlResult = [];
|
|
222
|
+
let sections = codeInput.value.split(codeInput.template.delimiter);
|
|
223
|
+
for (let i = 0; i < sections.length; i++) {
|
|
224
|
+
htmlResult.push(`<span style="color: ${codeInput.template.rainbowColors[i % codeInput.template.rainbowColors.length]}">${codeInput.escapeHtml(sections[i])}</span>`);
|
|
225
|
+
}
|
|
226
|
+
resultElement.innerHTML = htmlResult.join(codeInput.template.delimiter);
|
|
227
|
+
},
|
|
228
|
+
includeCodeInputInHighlightFunc: true,
|
|
229
|
+
preElementStyled: true,
|
|
230
|
+
isCode: false,
|
|
231
|
+
rainbowColors: rainbowColors,
|
|
232
|
+
delimiter: delimiter,
|
|
233
|
+
plugins: plugins,
|
|
234
|
+
}
|
|
235
|
+
},
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* @deprecated Please use `codeInput.characterLimit(plugins)`
|
|
239
|
+
*/
|
|
240
|
+
character_limit() {
|
|
241
|
+
return this.characterLimit([]);
|
|
242
|
+
},
|
|
243
|
+
/**
|
|
244
|
+
* @deprecated Please use `codeInput.rainbowText`
|
|
245
|
+
*/
|
|
246
|
+
rainbow_text(rainbowColors = ["red", "orangered", "orange", "goldenrod", "gold", "green", "darkgreen", "navy", "blue", "magenta"], delimiter = "", plugins = []) {
|
|
247
|
+
return this.rainbowText(rainbowColors, delimiter, plugins);
|
|
248
|
+
}
|
|
249
|
+
},
|
|
250
|
+
|
|
251
|
+
/* ------------------------------------
|
|
252
|
+
* ------------Plugins-----------------
|
|
253
|
+
* ------------------------------------ */
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Where plugins are stored, after they are imported. The plugin
|
|
257
|
+
* file assigns them a space in this object.
|
|
258
|
+
* For adding completely new syntax-highlighting algorithms, please see `codeInput.templates`.
|
|
259
|
+
* Key - plugin name
|
|
260
|
+
* Value - plugin object
|
|
261
|
+
* @type {Object}
|
|
262
|
+
*/
|
|
263
|
+
plugins: {
|
|
264
|
+
},
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Plugins are imported from the plugins folder. They will then
|
|
268
|
+
* provide custom extra functionality to code-input elements.
|
|
269
|
+
*/
|
|
270
|
+
Plugin: class {
|
|
271
|
+
constructor() {
|
|
272
|
+
console.log("code-input: plugin: Created plugin");
|
|
273
|
+
|
|
274
|
+
codeInput.observedAttributes = codeInput.observedAttributes.concat(self.observedAttributes);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Runs before code is highlighted.
|
|
279
|
+
* @param {codeInput.CodeInput} codeInput - The codeInput element
|
|
280
|
+
*/
|
|
281
|
+
beforeHighlight(codeInput) { }
|
|
282
|
+
/**
|
|
283
|
+
* Runs after code is highlighted.
|
|
284
|
+
* @param {codeInput.CodeInput} codeInput - The codeInput element
|
|
285
|
+
*/
|
|
286
|
+
afterHighlight(codeInput) { }
|
|
287
|
+
/**
|
|
288
|
+
* Runs before elements are added into a code-input element.
|
|
289
|
+
* @param {codeInput.CodeInput} codeInput - The codeInput element
|
|
290
|
+
*/
|
|
291
|
+
beforeElementsAdded(codeInput) { }
|
|
292
|
+
/**
|
|
293
|
+
* Runs after elements are added into a code-input element (useful for adding events to the textarea).
|
|
294
|
+
* @param {codeInput.CodeInput} codeInput - The codeInput element
|
|
295
|
+
*/
|
|
296
|
+
afterElementsAdded(codeInput) { }
|
|
297
|
+
/**
|
|
298
|
+
* Runs when an attribute of a code-input element is changed (you must add the attribute name to `codeInput.Plugin.observedAttributes` first).
|
|
299
|
+
* @param {codeInput.CodeInput} codeInput - The codeInput element
|
|
300
|
+
* @param {string} name - The name of the attribute
|
|
301
|
+
* @param {string} oldValue - The value of the attribute before it was changed
|
|
302
|
+
* @param {string} newValue - The value of the attribute after it is changed
|
|
303
|
+
*/
|
|
304
|
+
attributeChanged(codeInput, name, oldValue, newValue) { }
|
|
305
|
+
/**
|
|
306
|
+
* The HTML attributes to watch for this plugin, and report any
|
|
307
|
+
* modifications to the `codeInput.Plugin.attributeChanged` method.
|
|
308
|
+
*/
|
|
309
|
+
observedAttributes = []
|
|
310
|
+
},
|
|
311
|
+
|
|
312
|
+
/* ------------------------------------
|
|
313
|
+
* -------------Main-------------------
|
|
314
|
+
* ------------------------------------ */
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* A code-input element.
|
|
318
|
+
*/
|
|
319
|
+
CodeInput: class extends HTMLElement {
|
|
320
|
+
constructor() {
|
|
321
|
+
super(); // Element
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* When events are transferred to the textarea element, callbacks
|
|
326
|
+
* are bound to set the this variable to the code-inpute element
|
|
327
|
+
* rather than the textarea. This allows the callback to be converted
|
|
328
|
+
* to a bound one:
|
|
329
|
+
* Key - Callback not bound
|
|
330
|
+
* Value - Callback that is bound, with this equalling the code-input element in the callback
|
|
331
|
+
*/
|
|
332
|
+
boundEventCallbacks = {};
|
|
333
|
+
|
|
334
|
+
/** Trigger this event in all plugins with a optional list of arguments
|
|
335
|
+
* @param {string} eventName - the name of the event to trigger
|
|
336
|
+
* @param {Array} args - the arguments to pass into the event callback in the template after the code-input element. Normally left empty
|
|
337
|
+
*/
|
|
338
|
+
pluginEvt(eventName, args) {
|
|
339
|
+
for (let i in this.template.plugins) {
|
|
340
|
+
let plugin = this.template.plugins[i];
|
|
341
|
+
if (eventName in plugin) {
|
|
342
|
+
if (args === undefined) {
|
|
343
|
+
plugin[eventName](this);
|
|
344
|
+
} else {
|
|
345
|
+
plugin[eventName](this, ...args);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/* ------------------------------------
|
|
352
|
+
* ----------Main Functionality--------
|
|
353
|
+
* ------------------------------------
|
|
354
|
+
* The main function of a code-input element is to take
|
|
355
|
+
* code written in its textarea element, copy this code into
|
|
356
|
+
* the result (pre code) element, then use the template object
|
|
357
|
+
* to syntax-highlight it. */
|
|
358
|
+
|
|
359
|
+
/** Update the text value to the result element, after the textarea contents have changed.
|
|
360
|
+
* @param {string} value - The text value of the code-input element
|
|
361
|
+
*/
|
|
362
|
+
update(value) {
|
|
363
|
+
// Prevent this from running multiple times on the same input when "value" attribute is changed,
|
|
364
|
+
// by not running when value is already equal to the input of this (implying update has already
|
|
365
|
+
// been run). Thank you to peterprvy for this.
|
|
366
|
+
if (this.ignoreValueUpdate) return;
|
|
367
|
+
|
|
368
|
+
this.ignoreValueUpdate = true;
|
|
369
|
+
this.value = value;
|
|
370
|
+
this.ignoreValueUpdate = false;
|
|
371
|
+
if (this.querySelector("textarea").value != value) this.querySelector("textarea").value = value;
|
|
372
|
+
|
|
373
|
+
|
|
374
|
+
let resultElement = this.querySelector("pre code");
|
|
375
|
+
|
|
376
|
+
// Handle final newlines
|
|
377
|
+
if (value[value.length - 1] == "\n") {
|
|
378
|
+
value += " ";
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// Update code
|
|
382
|
+
resultElement.innerHTML = this.escapeHtml(value);
|
|
383
|
+
this.pluginEvt("beforeHighlight");
|
|
384
|
+
|
|
385
|
+
// Syntax Highlight
|
|
386
|
+
if (this.template.includeCodeInputInHighlightFunc) this.template.highlight(resultElement, this);
|
|
387
|
+
else this.template.highlight(resultElement);
|
|
388
|
+
|
|
389
|
+
this.pluginEvt("afterHighlight");
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* Synchronise the scrolling of the textarea to the result element.
|
|
394
|
+
*/
|
|
395
|
+
syncScroll() {
|
|
396
|
+
let inputElement = this.querySelector("textarea");
|
|
397
|
+
let resultElement = this.template.preElementStyled ? this.querySelector("pre") : this.querySelector("pre code");
|
|
398
|
+
|
|
399
|
+
resultElement.scrollTop = inputElement.scrollTop;
|
|
400
|
+
resultElement.scrollLeft = inputElement.scrollLeft;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
/**
|
|
404
|
+
* HTML-escape an arbitrary string.
|
|
405
|
+
* @param {string} text - The original, unescaped text
|
|
406
|
+
* @returns {string} - The new, HTML-escaped text
|
|
407
|
+
*/
|
|
408
|
+
escapeHtml(text) {
|
|
409
|
+
return text.replace(new RegExp("&", "g"), "&").replace(new RegExp("<", "g"), "<"); /* Global RegExp */
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
/**
|
|
413
|
+
* Get the template object this code-input element is using.
|
|
414
|
+
* @returns {Object} - Template object
|
|
415
|
+
*/
|
|
416
|
+
getTemplate() {
|
|
417
|
+
let templateName;
|
|
418
|
+
if (this.getAttribute("template") == undefined) {
|
|
419
|
+
// Default
|
|
420
|
+
templateName = codeInput.defaultTemplate;
|
|
421
|
+
} else {
|
|
422
|
+
templateName = this.getAttribute("template");
|
|
423
|
+
}
|
|
424
|
+
if (templateName in codeInput.usedTemplates) {
|
|
425
|
+
return codeInput.usedTemplates[templateName];
|
|
426
|
+
} else {
|
|
427
|
+
// Doesn't exist - add to queue
|
|
428
|
+
if (!(templateName in codeInput.templateNotYetRegisteredQueue)) {
|
|
429
|
+
codeInput.templateNotYetRegisteredQueue[templateName] = [];
|
|
430
|
+
}
|
|
431
|
+
codeInput.templateNotYetRegisteredQueue[templateName].push(this);
|
|
432
|
+
return undefined;
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* Set up and initialise the textarea.
|
|
438
|
+
* This will be called once the template has been added.
|
|
439
|
+
*/
|
|
440
|
+
setup() {
|
|
441
|
+
this.classList.add("code-input_registered"); // Remove register message
|
|
442
|
+
if (this.template.preElementStyled) this.classList.add("code-input_pre-element-styled");
|
|
443
|
+
|
|
444
|
+
this.pluginEvt("beforeElementsAdded");
|
|
445
|
+
|
|
446
|
+
// First-time attribute sync
|
|
447
|
+
let lang = this.getAttribute("lang");
|
|
448
|
+
let placeholder = this.getAttribute("placeholder") || this.getAttribute("lang") || "";
|
|
449
|
+
let value = this.value || this.innerHTML || "";
|
|
450
|
+
|
|
451
|
+
this.innerHTML = ""; // Clear Content
|
|
452
|
+
|
|
453
|
+
// Create textarea
|
|
454
|
+
let textarea = document.createElement("textarea");
|
|
455
|
+
textarea.placeholder = placeholder;
|
|
456
|
+
textarea.value = value;
|
|
457
|
+
textarea.setAttribute("spellcheck", "false");
|
|
458
|
+
|
|
459
|
+
// Synchronise attributes to textarea
|
|
460
|
+
codeInput.textareaSyncAttributes.forEach((attribute) => {
|
|
461
|
+
if (this.hasAttribute(attribute)) {
|
|
462
|
+
textarea.setAttribute(attribute, this.getAttribute(attribute));
|
|
463
|
+
}
|
|
464
|
+
});
|
|
465
|
+
|
|
466
|
+
textarea.addEventListener('input', (evt) => { textarea.parentElement.update(textarea.value); textarea.parentElement.sync_scroll(); });
|
|
467
|
+
textarea.addEventListener('scroll', (evt) => textarea.parentElement.sync_scroll());
|
|
468
|
+
|
|
469
|
+
this.append(textarea);
|
|
470
|
+
|
|
471
|
+
// Create result element
|
|
472
|
+
let code = document.createElement("code");
|
|
473
|
+
let pre = document.createElement("pre");
|
|
474
|
+
pre.setAttribute("aria-hidden", "true"); // Hide for screen readers
|
|
475
|
+
pre.append(code);
|
|
476
|
+
this.append(pre);
|
|
477
|
+
|
|
478
|
+
if (this.template.isCode) {
|
|
479
|
+
if (lang != undefined && lang != "") {
|
|
480
|
+
code.classList.add("language-" + lang);
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
this.pluginEvt("afterElementsAdded");
|
|
485
|
+
|
|
486
|
+
this.update(value);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
/**
|
|
490
|
+
* @deprecated Please use `codeInput.CodeInput.syncScroll`
|
|
491
|
+
*/
|
|
492
|
+
sync_scroll() {
|
|
493
|
+
this.syncScroll();
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
/**
|
|
497
|
+
* @deprecated Please use `codeInput.CodeInput.escapeHtml`
|
|
498
|
+
*/
|
|
499
|
+
escape_html(text) {
|
|
500
|
+
return this.escapeHtml(text);
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
/**
|
|
504
|
+
* @deprecated Please use `codeInput.CodeInput.escapeHtml`
|
|
505
|
+
*/
|
|
506
|
+
get_template() {
|
|
507
|
+
return this.getTemplate();
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
|
|
511
|
+
/* ------------------------------------
|
|
512
|
+
* -----------Callbacks----------------
|
|
513
|
+
* ------------------------------------
|
|
514
|
+
* Implement the `HTMLElement` callbacks
|
|
515
|
+
* to trigger the main functionality properly. */
|
|
516
|
+
|
|
517
|
+
/**
|
|
518
|
+
* When the code-input element has been added to the document,
|
|
519
|
+
* find its template and set up the element.
|
|
520
|
+
*/
|
|
521
|
+
connectedCallback() {
|
|
522
|
+
this.template = this.getTemplate();
|
|
523
|
+
if (this.template != undefined) this.setup();
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
/**
|
|
527
|
+
* Get the HTML attributes that need to be monitored and reported
|
|
528
|
+
* to `codeInput.CodeInput.attributeChangedCallback` when modified.
|
|
529
|
+
*/
|
|
530
|
+
static get observedAttributes() {
|
|
531
|
+
return codeInput.observedAttributes.concat(codeInput.textareaSyncAttributes);
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
/**
|
|
535
|
+
* Triggered when an HTML attribute in `codeInput.CodeInput.observedAttributes`
|
|
536
|
+
* has been modified.
|
|
537
|
+
* @param {string} name - The name of the attribute
|
|
538
|
+
* @param {string} oldValue - The value of the attribute before it was changed
|
|
539
|
+
* @param {string} newValue - The value of the attribute after it is changed
|
|
540
|
+
*/
|
|
541
|
+
attributeChangedCallback(name, oldValue, newValue) {
|
|
542
|
+
if (this.isConnected) {
|
|
543
|
+
this.pluginEvt("attributeChanged", [name, oldValue, newValue]);
|
|
544
|
+
switch (name) {
|
|
545
|
+
|
|
546
|
+
case "value":
|
|
547
|
+
this.update(newValue);
|
|
548
|
+
break;
|
|
549
|
+
case "placeholder":
|
|
550
|
+
this.querySelector("textarea").placeholder = newValue;
|
|
551
|
+
break;
|
|
552
|
+
case "template":
|
|
553
|
+
this.template = codeInput.usedTemplates[newValue || codeInput.defaultTemplate];
|
|
554
|
+
if (this.template.preElementStyled) this.classList.add("code-input_pre-element-styled");
|
|
555
|
+
else this.classList.remove("code-input_pre-element-styled");
|
|
556
|
+
// Syntax Highlight
|
|
557
|
+
this.update(this.value);
|
|
558
|
+
|
|
559
|
+
break;
|
|
560
|
+
|
|
561
|
+
case "lang":
|
|
562
|
+
|
|
563
|
+
let code = this.querySelector("pre code");
|
|
564
|
+
let mainTextarea = this.querySelector("textarea");
|
|
565
|
+
|
|
566
|
+
// Check not already updated
|
|
567
|
+
if (newValue != null) {
|
|
568
|
+
newValue = newValue.toLowerCase();
|
|
569
|
+
|
|
570
|
+
if (code.classList.contains(`language-${newValue}`)) break; // Already updated
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
|
|
574
|
+
// Case insensitive
|
|
575
|
+
oldValue = oldValue.toLowerCase();
|
|
576
|
+
|
|
577
|
+
// Remove old language class and add new
|
|
578
|
+
console.log("code-input: Language: REMOVE", "language-" + oldValue);
|
|
579
|
+
code.classList.remove("language-" + oldValue); // From CODE
|
|
580
|
+
code.parentElement.classList.remove("language-" + oldValue); // From PRE
|
|
581
|
+
code.classList.remove("language-none"); // Prism
|
|
582
|
+
code.parentElement.classList.remove("language-none"); // Prism
|
|
583
|
+
|
|
584
|
+
if (newValue != undefined && newValue != "") {
|
|
585
|
+
code.classList.add("language-" + newValue);
|
|
586
|
+
console.log("code-input: Language:ADD", "language-" + newValue);
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
if (mainTextarea.placeholder == oldValue) mainTextarea.placeholder = newValue;
|
|
590
|
+
|
|
591
|
+
this.update(this.value);
|
|
592
|
+
|
|
593
|
+
break;
|
|
594
|
+
default:
|
|
595
|
+
if (codeInput.textareaSyncAttributes.includes(name)) {
|
|
596
|
+
this.querySelector("textarea").setAttribute(name, newValue);
|
|
597
|
+
}
|
|
598
|
+
break;
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
/* ------------------------------------
|
|
605
|
+
* -----------Overrides----------------
|
|
606
|
+
* ------------------------------------
|
|
607
|
+
* Override/Implement ordinary HTML textarea functionality so that the <code-input>
|
|
608
|
+
* element acts just like a <textarea>. */
|
|
609
|
+
|
|
610
|
+
/**
|
|
611
|
+
* @override
|
|
612
|
+
*/
|
|
613
|
+
addEventListener(type, listener, options = undefined) {
|
|
614
|
+
let boundCallback = listener.bind(this);
|
|
615
|
+
this.boundEventCallbacks[listener] = boundCallback;
|
|
616
|
+
|
|
617
|
+
if (codeInput.textareaSyncEvents.includes(type)) {
|
|
618
|
+
if (options === undefined) {
|
|
619
|
+
this.querySelector("textarea").addEventListener(type, boundCallback);
|
|
620
|
+
} else {
|
|
621
|
+
this.querySelector("textarea").addEventListener(type, boundCallback, options);
|
|
622
|
+
}
|
|
623
|
+
} else {
|
|
624
|
+
if (options === undefined) {
|
|
625
|
+
super.addEventListener(type, boundCallback);
|
|
626
|
+
} else {
|
|
627
|
+
super.addEventListener(type, boundCallback, options);
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
/**
|
|
633
|
+
* @override
|
|
634
|
+
*/
|
|
635
|
+
removeEventListener(type, listener, options = null) {
|
|
636
|
+
let boundCallback = this.boundEventCallbacks[listener];
|
|
637
|
+
if (type == "change") {
|
|
638
|
+
if (options === null) {
|
|
639
|
+
this.querySelector("textarea").removeEventListener("change", boundCallback);
|
|
640
|
+
} else {
|
|
641
|
+
this.querySelector("textarea").removeEventListener("change", boundCallback, options);
|
|
642
|
+
}
|
|
643
|
+
} else if (type == "selectionchange") {
|
|
644
|
+
if (options === null) {
|
|
645
|
+
this.querySelector("textarea").removeEventListener("selectionchange", boundCallback);
|
|
646
|
+
} else {
|
|
647
|
+
this.querySelector("textarea").removeEventListener("selectionchange", boundCallback, options);
|
|
648
|
+
}
|
|
649
|
+
} else {
|
|
650
|
+
super.removeEventListener(type, listener, options);
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
/**
|
|
655
|
+
* Get the text contents of the code-input element.
|
|
656
|
+
*/
|
|
657
|
+
get value() {
|
|
658
|
+
return this.getAttribute("value");
|
|
659
|
+
}
|
|
660
|
+
/**
|
|
661
|
+
* Set the text contents of the code-input element.
|
|
662
|
+
* @param {string} val - New text contents
|
|
663
|
+
*/
|
|
664
|
+
set value(val) {
|
|
665
|
+
return this.setAttribute("value", val);
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
/**
|
|
669
|
+
* Get the placeholder of the code-input element that appears
|
|
670
|
+
* when no code has been entered.
|
|
671
|
+
*/
|
|
672
|
+
get placeholder() {
|
|
673
|
+
return this.getAttribute("placeholder");
|
|
674
|
+
}
|
|
675
|
+
/**
|
|
676
|
+
* Set the placeholder of the code-input element that appears
|
|
677
|
+
* when no code has been entered.
|
|
678
|
+
* @param {string} val - New placeholder
|
|
679
|
+
*/
|
|
680
|
+
set placeholder(val) {
|
|
681
|
+
return this.setAttribute("placeholder", val);
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
/**
|
|
685
|
+
* Returns a ValidityState object that represents the validity states of an element.
|
|
686
|
+
*
|
|
687
|
+
* See `HTMLTextAreaElement.validity`
|
|
688
|
+
*/
|
|
689
|
+
get validity() {
|
|
690
|
+
return this.querySelector("textarea").validity;
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
/**
|
|
694
|
+
* Returns the error message that would be displayed if the user submits the form, or an empty string if no error message.
|
|
695
|
+
* It also triggers the standard error message, such as "this is a required field". The result is that the user sees validation
|
|
696
|
+
* messages without actually submitting.
|
|
697
|
+
*
|
|
698
|
+
* See `HTMLTextAreaElement.validationMessage`
|
|
699
|
+
*/
|
|
700
|
+
get validationMessage() {
|
|
701
|
+
return this.querySelector("textarea").validationMessage;
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
/**
|
|
705
|
+
* Sets a custom error message that is displayed when a form is submitted.
|
|
706
|
+
*
|
|
707
|
+
* See `HTMLTextAreaElement.setCustomValidity`
|
|
708
|
+
* @param error Sets a custom error message that is displayed when a form is submitted.
|
|
709
|
+
*/
|
|
710
|
+
setCustomValidity(error) {
|
|
711
|
+
return this.querySelector("textarea").setCustomValidity(error);
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
/**
|
|
715
|
+
* Returns whether a form will validate when it is submitted,
|
|
716
|
+
* without having to submit it.
|
|
717
|
+
*
|
|
718
|
+
* See `HTMLTextAreaElement.checkValidity`
|
|
719
|
+
*/
|
|
720
|
+
checkValidity() {
|
|
721
|
+
return this.querySelector("textarea").checkValidity();
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
/**
|
|
725
|
+
* See `HTMLTextAreaElement.reportValidity`
|
|
726
|
+
*/
|
|
727
|
+
reportValidity() {
|
|
728
|
+
return this.querySelector("textarea").reportValidity();
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
|
|
732
|
+
/**
|
|
733
|
+
* @override
|
|
734
|
+
*/
|
|
735
|
+
setAttribute(qualifiedName, value) {
|
|
736
|
+
super.setAttribute(qualifiedName, value); // code-input
|
|
737
|
+
this.querySelector("textarea").setAttribute(qualifiedName, value); // textarea
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
/**
|
|
741
|
+
* @override
|
|
742
|
+
*/
|
|
743
|
+
getAttribute(qualifiedName) {
|
|
744
|
+
if (this.querySelector("textarea") == null) {
|
|
745
|
+
return super.getAttribute(qualifiedName);
|
|
746
|
+
}
|
|
747
|
+
return this.querySelector("textarea").getAttribute(qualifiedName); // textarea
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
/**
|
|
751
|
+
* Allows plugins to store data in the scope of a single element.
|
|
752
|
+
* Key - name of the plugin
|
|
753
|
+
* Value - object of data to be stored; different plugins may use this differently.
|
|
754
|
+
*/
|
|
755
|
+
pluginData = {};
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
customElements.define("code-input", codeInput.CodeInput);
|