33// Based on a CSS-Tricks Post
44
55var 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+ last_events : { } , // Last events applied; removed when changed so can be added to textarea, etc.
17+ /* Templates */
618 usedTemplates : {
719 } ,
820 defaultTemplate : undefined ,
921 templateQueue : { } , // lists of elements for each unrecognised template
22+
23+ /* Plugins */
1024 plugins : { // Import a plugin from the plugins folder and it will be saved here.
1125 } ,
1226 Plugin : class {
27+ constructor ( ) {
28+ console . log ( "code-input: plugin: Created plugin!" ) ;
29+
30+ // Add attributes
31+ codeInput . observedAttributes = codeInput . observedAttributes . concat ( self . observedAttributes ) ;
32+ }
33+
1334 /* Runs before code is highlighted; Params: codeInput element) */
1435 beforeHighlight ( codeInput ) { }
1536 /* Runs after code is highlighted; Params: codeInput element) */
@@ -22,6 +43,8 @@ var codeInput = {
2243 attributeChanged ( codeInput , name , oldValue , newValue ) { }
2344 observedAttributes = [ ]
2445 } ,
46+
47+ /* Main */
2548 CodeInput : class extends HTMLElement { // Create code input element
2649 constructor ( ) {
2750 super ( ) ; // Element
@@ -146,6 +169,18 @@ var codeInput = {
146169
147170 this . plugin_evt ( "afterElementsAdded" ) ;
148171
172+ // Events
173+ textarea = this . querySelector ( "textarea" ) ;
174+ // Add event listeners, bound so `this` can be referenced
175+ if ( this . onchange ) {
176+ textarea . addEventListener ( "change" , this . onchange . bind ( this ) ) ;
177+ this . onchange = undefined ; // Prevent duplicate
178+ }
179+ if ( this . onselectionchange ) {
180+ textarea . addEventListener ( "selectionchange" , this . onselectionchange . bind ( this ) ) ;
181+ this . onselectionchange = undefined ; // Prevent duplicate
182+ }
183+
149184 /* Add code from value attribute - useful for loading from backend */
150185 this . update ( value , this ) ;
151186 }
@@ -156,14 +191,8 @@ var codeInput = {
156191 this . template = this . get_template ( ) ;
157192 if ( this . template != undefined ) this . setup ( ) ;
158193 }
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 ;
194+ static get observedAttributes ( ) {
195+ return codeInput . observedAttributes ;
167196 }
168197
169198 attributeChangedCallback ( name , oldValue , newValue ) {
@@ -188,33 +217,66 @@ var codeInput = {
188217 else this . classList . remove ( "code-input_pre-element-styled" ) ;
189218 // Syntax Highlight
190219 this . update ( this . value ) ;
220+
221+ break ;
191222
192223 case "lang" :
193224 let code = this . querySelector ( "pre code" ) ;
194- let textarea = this . querySelector ( "textarea" ) ;
225+ let main_textarea = this . querySelector ( "textarea" ) ;
195226
196227 // Case insensitive
197228 oldValue = oldValue . toLowerCase ( ) ;
198229 newValue = newValue . toLowerCase ( ) ;
199230
200231 // Remove old language class and add new
201- console . log ( "REMOVE" , "language-" + oldValue ) ;
232+ console . log ( "code-input: Language: REMOVE" , "language-" + oldValue ) ;
202233 code . classList . remove ( "language-" + oldValue ) ; // From CODE
203234 code . parentElement . classList . remove ( "language-" + oldValue ) ; // From PRE
204235 code . classList . remove ( "language-none" ) ; // Prism
205236 code . parentElement . classList . remove ( "language-none" ) ; // Prism
206237
207238 if ( newValue != undefined && newValue != "" ) {
208239 code . classList . add ( "language-" + newValue ) ;
209- console . log ( "ADD" , "language-" + newValue ) ;
240+ console . log ( "code-input: Language: ADD" , "language-" + newValue ) ;
210241 }
211242
212- if ( textarea . placeholder == oldValue ) textarea . placeholder = newValue ;
243+ if ( main_textarea . placeholder == oldValue ) main_textarea . placeholder = newValue ;
213244
214245 this . update ( this . value ) ;
215-
216- default :
217- this . plugin_evt ( "attributeChanged" , [ name , oldValue , newValue ] ) ; // Plugin event
246+
247+ break ;
248+
249+ // Events
250+ case "onchange" :
251+ {
252+ // Doesn't exist
253+ let textarea = this . querySelector ( "textarea" )
254+ if ( oldValue ) {
255+ textarea . removeEventListener ( "change" , this . last_events [ "change" ] ) ;
256+ }
257+ if ( newValue ) {
258+ this . last_events [ "change" ] = newValue . bind ( this ) ;
259+ textarea . addEventListener ( "change" , this . last_events [ "change" ] ) ;
260+ this . onchange = undefined ; // Prevent duplicate
261+ }
262+ }
263+ break ;
264+ case "onselectionchange" :
265+ {
266+ // Doesn't exist
267+ let textarea = this . querySelector ( "textarea" )
268+ if ( oldValue ) {
269+ textarea . removeEventListener ( "selectionchange" , this . last_events [ "selectionchange" ] ) ;
270+ }
271+ if ( newValue ) {
272+ this . last_events [ "selectionchange" ] = newValue . bind ( this ) ;
273+ textarea . addEventListener ( "selectionchange" , this . last_events [ "selectionchange" ] ) ;
274+ this . onselectionchange = undefined ; // Prevent duplicate
275+ }
276+ }
277+ break ;
278+
279+ this . plugin_evt ( "attributeChanged" , [ name , oldValue , newValue ] ) ; // Plugin event
218280 }
219281 }
220282
@@ -235,6 +297,7 @@ var codeInput = {
235297 return this . setAttribute ( "placeholder" , val ) ;
236298 }
237299 } ,
300+
238301 registerTemplate : function ( template_name , template ) {
239302 // Set default class
240303 codeInput . usedTemplates [ template_name ] = template ;
@@ -245,6 +308,7 @@ var codeInput = {
245308 elem . template = template ;
246309 elem . setup ( ) ;
247310 }
311+ console . log ( `code-input: template: Added existing elements with template ${ template_name } ` ) ;
248312 }
249313 if ( codeInput . defaultTemplate == undefined ) {
250314 codeInput . defaultTemplate = template_name ;
@@ -256,7 +320,9 @@ var codeInput = {
256320 elem . setup ( ) ;
257321 }
258322 }
323+ console . log ( `code-input: template: Set template ${ template_name } as default` ) ;
259324 }
325+ console . log ( `code-input: template: Created template ${ template_name } ` ) ;
260326 } ,
261327 templates : {
262328 custom ( highlight = function ( ) { } , preElementStyled = true , isCode = true , includeCodeInputInHighlightFunc = false , plugins = [ ] ) {
0 commit comments