3
3
// Based on a CSS-Tricks Post
4
4
5
5
var codeInput = {
6
+ observedAttributes : [
7
+ "value" ,
8
+ "placeholder" ,
9
+ "lang" ,
10
+ "template" ,
11
+ "onchange" ,
12
+ "onselectionchange"
13
+ ] ,
14
+ // Attributes to monitor - needs to be global and static
15
+
16
+ /* Templates */
6
17
usedTemplates : {
7
18
} ,
8
19
defaultTemplate : undefined ,
9
20
templateQueue : { } , // lists of elements for each unrecognised template
21
+
22
+ /* Plugins */
10
23
plugins : { // Import a plugin from the plugins folder and it will be saved here.
11
24
} ,
12
25
Plugin : class {
26
+ constructor ( ) {
27
+ console . log ( "code-input: plugin: Created plugin!" ) ;
28
+
29
+ // Add attributes
30
+ codeInput . observedAttributes = codeInput . observedAttributes . concat ( self . observedAttributes ) ;
31
+ }
32
+
13
33
/* Runs before code is highlighted; Params: codeInput element) */
14
34
beforeHighlight ( codeInput ) { }
15
35
/* Runs after code is highlighted; Params: codeInput element) */
@@ -22,11 +42,14 @@ var codeInput = {
22
42
attributeChanged ( codeInput , name , oldValue , newValue ) { }
23
43
observedAttributes = [ ]
24
44
} ,
45
+
46
+ /* Main */
25
47
CodeInput : class extends HTMLElement { // Create code input element
26
48
constructor ( ) {
27
49
super ( ) ; // Element
28
50
}
29
51
52
+ last_events = { } ; // Last events applied; removed when changed so can be added to textarea, etc.
30
53
31
54
/* Run this event in all plugins with a optional list of arguments */
32
55
plugin_evt ( id , args ) {
@@ -146,6 +169,12 @@ var codeInput = {
146
169
147
170
this . plugin_evt ( "afterElementsAdded" ) ;
148
171
172
+ // Events
173
+ textarea = this . querySelector ( "textarea" ) ;
174
+ // Add event listeners, bound so `this` can be referenced
175
+ this . transfer_event ( "change" , this . querySelector ( "textarea" ) , null , this . onchange ) ;
176
+ this . transfer_event ( "selectionchange" , this . querySelector ( "textarea" ) , null , this . onselectionchange ) ;
177
+
149
178
/* Add code from value attribute - useful for loading from backend */
150
179
this . update ( value , this ) ;
151
180
}
@@ -156,20 +185,16 @@ var codeInput = {
156
185
this . template = this . get_template ( ) ;
157
186
if ( this . template != undefined ) this . setup ( ) ;
158
187
}
159
- get observedAttributes ( ) {
160
- let attrs = [ "value" , "placeholder" , "lang" , "template" ] ; // Attributes to monitor
161
-
162
- /* Add from plugins */
163
- for ( let plugin in this . template . plugins ) {
164
- attrs = attrs . concat ( plugin . observedAttributes ) ;
165
- }
166
- return attrs ;
188
+ static get observedAttributes ( ) {
189
+ return codeInput . observedAttributes ;
167
190
}
168
191
169
192
attributeChangedCallback ( name , oldValue , newValue ) {
170
193
if ( this . isConnected ) {
171
194
// This will sometimes be called before the element has been created, so trying to update an attribute causes an error.
172
195
// Thanks to Kevin Loughead for pointing this out.
196
+
197
+ this . plugin_evt ( "attributeChanged" , [ name , oldValue , newValue ] ) ; // Plugin event
173
198
switch ( name ) {
174
199
175
200
case "value" :
@@ -188,38 +213,60 @@ var codeInput = {
188
213
else this . classList . remove ( "code-input_pre-element-styled" ) ;
189
214
// Syntax Highlight
190
215
this . update ( this . value ) ;
216
+
217
+ break ;
191
218
192
219
case "lang" :
193
220
let code = this . querySelector ( "pre code" ) ;
194
- let textarea = this . querySelector ( "textarea" ) ;
221
+ let main_textarea = this . querySelector ( "textarea" ) ;
195
222
196
223
// Case insensitive
197
224
oldValue = oldValue . toLowerCase ( ) ;
198
225
newValue = newValue . toLowerCase ( ) ;
199
226
200
227
// Remove old language class and add new
201
- console . log ( "REMOVE" , "language-" + oldValue ) ;
228
+ console . log ( "code-input: Language: REMOVE" , "language-" + oldValue ) ;
202
229
code . classList . remove ( "language-" + oldValue ) ; // From CODE
203
230
code . parentElement . classList . remove ( "language-" + oldValue ) ; // From PRE
204
231
code . classList . remove ( "language-none" ) ; // Prism
205
232
code . parentElement . classList . remove ( "language-none" ) ; // Prism
206
233
207
234
if ( newValue != undefined && newValue != "" ) {
208
235
code . classList . add ( "language-" + newValue ) ;
209
- console . log ( "ADD" , "language-" + newValue ) ;
236
+ console . log ( "code-input: Language: ADD" , "language-" + newValue ) ;
210
237
}
211
238
212
- if ( textarea . placeholder == oldValue ) textarea . placeholder = newValue ;
239
+ if ( main_textarea . placeholder == oldValue ) main_textarea . placeholder = newValue ;
213
240
214
241
this . update ( this . value ) ;
215
-
216
- default :
217
- this . plugin_evt ( "attributeChanged" , [ name , oldValue , newValue ] ) ; // Plugin event
242
+
243
+ break ;
244
+
245
+ // Events
246
+ case "onchange" :
247
+ this . transfer_event ( "change" , this . querySelector ( "textarea" ) , oldValue , newValue ) ;
248
+ break ;
249
+ case "onselectionchange" :
250
+ this . transfer_event ( "selectionchange" , this . querySelector ( "textarea" ) , oldValue , newValue ) ;
251
+ break ;
218
252
}
219
253
}
220
254
221
255
}
222
256
257
+ /* Transfer an event by name from this to an inner element. */
258
+ transfer_event ( evt_name , transfer_to , oldValue , newValue ) {
259
+ // Doesn't exist
260
+ if ( oldValue ) {
261
+ transfer_to . removeEventListener ( evt_name , this . last_events [ evt_name ] ) ;
262
+ }
263
+ if ( newValue ) {
264
+ this . last_events [ evt_name ] = this . onchange . bind ( this ) ;
265
+ transfer_to . addEventListener ( evt_name , this . last_events [ evt_name ] ) ;
266
+ this [ `on${ evt_name } ` ] = undefined ; // Prevent duplicate
267
+ }
268
+ }
269
+
223
270
/* Value attribute */
224
271
get value ( ) {
225
272
return this . getAttribute ( "value" ) ;
@@ -235,6 +282,7 @@ var codeInput = {
235
282
return this . setAttribute ( "placeholder" , val ) ;
236
283
}
237
284
} ,
285
+
238
286
registerTemplate : function ( template_name , template ) {
239
287
// Set default class
240
288
codeInput . usedTemplates [ template_name ] = template ;
@@ -245,6 +293,7 @@ var codeInput = {
245
293
elem . template = template ;
246
294
elem . setup ( ) ;
247
295
}
296
+ console . log ( `code-input: template: Added existing elements with template ${ template_name } ` ) ;
248
297
}
249
298
if ( codeInput . defaultTemplate == undefined ) {
250
299
codeInput . defaultTemplate = template_name ;
@@ -256,7 +305,9 @@ var codeInput = {
256
305
elem . setup ( ) ;
257
306
}
258
307
}
308
+ console . log ( `code-input: template: Set template ${ template_name } as default` ) ;
259
309
}
310
+ console . log ( `code-input: template: Created template ${ template_name } ` ) ;
260
311
} ,
261
312
templates : {
262
313
custom ( highlight = function ( ) { } , preElementStyled = true , isCode = true , includeCodeInputInHighlightFunc = false , plugins = [ ] ) {
0 commit comments