@@ -14,41 +14,158 @@ interface Params {
1414 Headers : Object ;
1515 Limit : number ;
1616 Method : string ;
17- ParamName : string ;
17+ QueryArg : string ;
1818 Url : string ;
1919
20+ // Keyboard mapping event
21+ KeyboardMappings : { [ name : string ] : MappingEvent ; } ;
22+
2023 // Workable elements
2124 DOMResults : Element ;
2225 Request : XMLHttpRequest ;
2326 Input : Element ;
2427
2528 // Workflow methods
26- _Blur : any ;
27- _EmptyMessage : any ;
28- _Focus : any ;
29- _Limit : any ;
30- _Method : any ;
31- _OnKeyUp : any ;
32- _Open : any ;
33- _ParamName : any ;
34- _Position : any ;
35- _Post : any ;
36- _Pre : any ;
37- _Select : any ;
38- _Url : any ;
29+ _Blur : any ;
30+ _EmptyMessage : any ;
31+ _Focus : any ;
32+ _Limit : any ;
33+ _Method : any ;
34+ _Open : any ;
35+ _QueryArg : any ;
36+ _Position : any ;
37+ _Post : any ;
38+ _Pre : any ;
39+ _Select : any ;
40+ _Url : any ;
41+ }
42+
43+ interface MappingCondition {
44+ Not : boolean ;
45+ }
46+
47+ interface MappingConditionIs extends MappingCondition {
48+ Is : number ;
49+ }
50+
51+ interface MappingConditionRange extends MappingCondition {
52+ From : number ;
53+ To : number ;
54+ }
55+
56+ enum ConditionOperator { AND , OR } ;
57+
58+ interface MappingEvent {
59+ Conditions : MappingCondition [ ] ;
60+ Callback : any ;
61+ Operator : ConditionOperator ;
3962}
4063
4164// Core
4265class AutoComplete {
66+ static merge : any = function ( ) : any {
67+ var merge : any = { } ,
68+ tmp : any ;
69+
70+ for ( var i = 0 ; i < arguments . length ; i ++ ) {
71+ for ( tmp in arguments [ i ] ) {
72+ merge [ tmp ] = arguments [ i ] [ tmp ] ;
73+ }
74+ }
75+
76+ return merge ;
77+ } ;
4378 static defaults : Params = {
4479 EmptyMessage : "No result here" ,
4580 Headers : {
4681 "Content-type" : "application/x-www-form-urlencoded"
4782 } ,
4883 Limit : 0 ,
4984 Method : "GET" ,
50- ParamName : "q" ,
85+ QueryArg : "q" ,
5186 Url : null ,
87+
88+ KeyboardMappings : {
89+ "Enter" : {
90+ Conditions : [ {
91+ Is : 13 ,
92+ Not : false
93+ } ] ,
94+ Callback : function ( event : KeyboardEvent ) {
95+ if ( this . DOMResults . getAttribute ( "class" ) . indexOf ( "open" ) != - 1 ) {
96+ var liActive = this . DOMResults . querySelector ( "li.active" ) ;
97+
98+ if ( liActive !== null ) {
99+ this . _Select ( liActive ) ;
100+ this . DOMResults . setAttribute ( "class" , "autocomplete" ) ;
101+ }
102+ }
103+ } ,
104+ Operator : ConditionOperator . AND
105+ } ,
106+ "KeyUpAndDown" : {
107+ Conditions : [ {
108+ Is : 38 ,
109+ Not : false
110+ } ,
111+ {
112+ Is : 40 ,
113+ Not : false
114+ } ] ,
115+ Callback : function ( event : KeyboardEvent ) {
116+ var first = this . DOMResults . querySelector ( "li:first-child:not(.locked)" ) ,
117+ active = this . DOMResults . querySelector ( "li.active" ) ;
118+
119+ if ( active ) {
120+ var currentIndex = Array . prototype . indexOf . call ( active . parentNode . children , active ) ,
121+ position = currentIndex + ( event . keyCode - 39 ) ,
122+ lisCount = this . DOMResults . getElementsByTagName ( "li" ) . length ;
123+
124+ if ( position < 0 ) {
125+ position = lisCount - 1 ;
126+ } else if ( position >= lisCount ) {
127+ position = 0 ;
128+ }
129+
130+ active . setAttribute ( "class" , "" ) ;
131+ active . parentElement . childNodes . item ( position ) . setAttribute ( "class" , "active" ) ;
132+ } else if ( first ) {
133+ first . setAttribute ( "class" , "active" ) ;
134+ }
135+ } ,
136+ Not : false ,
137+ Operator : ConditionOperator . OR
138+ } ,
139+ "AlphaNum" : {
140+ Conditions : [ {
141+ Is : 13 ,
142+ Not : true
143+ } , {
144+ From : 35 ,
145+ To : 40 ,
146+ Not : true
147+ } ] ,
148+ Callback : function ( event : KeyboardEvent ) {
149+ var oldValue = this . Input . getAttribute ( "data-autocomplete-old-value" ) ,
150+ currentValue = this . _Pre ( ) ;
151+
152+ if ( currentValue !== "" ) {
153+ if ( ! oldValue || currentValue != oldValue ) {
154+ this . DOMResults . setAttribute ( "class" , "autocomplete open" ) ;
155+ }
156+
157+ AutoComplete . prototype . ajax ( this , function ( ) {
158+ if ( this . Request . readyState == 4 && this . Request . status == 200 ) {
159+ if ( ! this . _Post ( this . Request . response ) ) {
160+ this . _Open ( ) ;
161+ }
162+ }
163+ } . bind ( this ) ) ;
164+ }
165+ } ,
166+ Operator : ConditionOperator . AND
167+ }
168+ } ,
52169
53170 DOMResults : document . createElement ( "div" ) ,
54171 Request : null ,
@@ -83,14 +200,14 @@ class AutoComplete {
83200
84201 return this . Method ;
85202 } ,
86- _ParamName : function ( ) : string {
87- console . log ( "ParamName " , this ) ;
203+ _QueryArg : function ( ) : string {
204+ console . log ( "QueryArg " , this ) ;
88205
89206 if ( this . Input . hasAttribute ( "data-autocomplete-param-name" ) ) {
90207 return this . Input . getAttribute ( "data-autocomplete-param-name" ) ;
91208 }
92209
93- return this . ParamName ;
210+ return this . QueryArg ;
94211 } ,
95212 _Url : function ( ) : string {
96213 console . log ( "Url" , this ) ;
@@ -122,63 +239,12 @@ class AutoComplete {
122239 this . DOMResults . setAttribute ( "class" , "autocomplete open" ) ;
123240 }
124241 } ,
125- _OnKeyUp : function ( event : KeyboardEvent ) : void {
126- console . log ( "OnKeyUp" , this , "KeyboardEvent" , event ) ;
127-
128- var first = this . DOMResults . querySelector ( "li:first-child:not(.locked)" ) ,
129- input = event . target ,
130- inputValue = this . Pre ( ) ,
131- dataAutocompleteOldValue = this . Input . getAttribute ( "data-autocomplete-old-value" ) ,
132- keyCode = event . keyCode ,
133- currentIndex ,
134- position ,
135- lisCount ,
136- liActive ;
137-
138- if ( keyCode == 13 && this . DOMResults . getAttribute ( "class" ) . indexOf ( "open" ) != - 1 ) {
139- liActive = this . DOMResults . querySelector ( "li.active" ) ;
140- if ( liActive !== null ) {
141- this . Select ( liActive ) ;
142- this . DOMResults . setAttribute ( "class" , "autocomplete" ) ;
143- }
144- }
145-
146- if ( keyCode == 38 || keyCode == 40 ) {
147- liActive = this . DOMResults . querySelector ( "li.active" ) ;
148-
149- if ( liActive ) {
150- currentIndex = Array . prototype . indexOf . call ( liActive . parentNode . children , liActive ) ;
151- position = currentIndex + ( keyCode - 39 ) ;
152- lisCount = this . DOMResults . getElementsByTagName ( "li" ) . length ;
153-
154- liActive . setAttribute ( "class" , "" ) ;
155-
156- if ( position < 0 ) {
157- position = lisCount - 1 ;
158- } else if ( position >= lisCount ) {
159- position = 0 ;
160- }
161-
162- liActive . parentElement . childNodes . item ( position ) . setAttribute ( "class" , "active" ) ;
163- } else if ( first ) {
164- first . setAttribute ( "class" , "active" ) ;
165- }
166- } else if ( keyCode != 13 && ( keyCode < 35 || keyCode > 40 ) ) {
167- if ( inputValue && this . _Url ( ) ) {
168- if ( ! dataAutocompleteOldValue || inputValue != dataAutocompleteOldValue ) {
169- this . DOMResults . setAttribute ( "class" , "autocomplete open" ) ;
170- }
171-
172- AutoComplete . prototype . ajax ( this ) ;
173- }
174- }
175- } ,
176242 _Open : function ( ) : void {
177243 console . log ( "Open" , this ) ;
178244 var params = this ;
179245 Array . prototype . forEach . call ( this . DOMResults . getElementsByTagName ( "li" ) , function ( li ) {
180246 li . onclick = function ( event ) {
181- params . Select ( event . target ) ;
247+ params . _Select ( event . target ) ;
182248 } ;
183249 } ) ;
184250 } ,
@@ -187,7 +253,7 @@ class AutoComplete {
187253 this . DOMResults . setAttribute ( "class" , "autocomplete" ) ;
188254 this . DOMResults . setAttribute ( "style" , "top:" + ( this . Input . offsetTop + this . Input . offsetHeight ) + "px;left:" + this . Input . offsetLeft + "px;width:" + this . Input . clientWidth + "px;" ) ;
189255 } ,
190- _Post : function ( response ) : void {
256+ _Post : function ( response : string ) : void {
191257 console . log ( "Post" , this ) ;
192258 try {
193259 response = JSON . parse ( response ) ;
@@ -255,12 +321,14 @@ class AutoComplete {
255321 } ,
256322 _Select : function ( item ) : void {
257323 console . log ( "Select" , this ) ;
258- this . Input . setAttribute ( "data-autocomplete-old-value" , this . Input . value = item . getAttribute ( "data-autocomplete-value" , item . innerHTML ) ) ;
324+
325+ this . Input . value = item . getAttribute ( "data-autocomplete-value" , item . innerHTML ) ;
326+ this . Input . setAttribute ( "data-autocomplete-old-value" , this . Input . value ) ;
259327 } ,
260328 } ;
261329
262330 // Constructor
263- constructor ( params : Object = { } , selector : any = "[data-autocomplete]" ) : void {
331+ constructor ( params : Object = { } , selector : any = "[data-autocomplete]" ) {
264332 if ( Array . isArray ( selector ) ) {
265333 selector . forEach ( function ( s : string ) {
266334 new AutoComplete ( params , s ) ;
@@ -280,7 +348,7 @@ class AutoComplete {
280348
281349 console . log ( "Selector" , selector ) ;
282350
283- AutoComplete . prototype . create ( MergeObject ( AutoComplete . defaults , params , {
351+ AutoComplete . prototype . create ( AutoComplete . merge ( AutoComplete . defaults , params , {
284352 Input : selector ,
285353 } ) ) ;
286354 }
@@ -296,7 +364,7 @@ class AutoComplete {
296364
297365 params . Input . addEventListener ( "focus" , params . _Focus . bind ( params ) ) ;
298366
299- params . Input . addEventListener ( "keyup" , params . _OnKeyUp . bind ( params ) ) ;
367+ params . Input . addEventListener ( "keyup" , AutoComplete . prototype . event . bind ( null , params ) ) ;
300368
301369 params . Input . addEventListener ( "blur" , params . _Blur . bind ( params ) ) ;
302370 params . Input . addEventListener ( "position" , params . _Position . bind ( params ) ) ;
@@ -306,7 +374,47 @@ class AutoComplete {
306374 }
307375 }
308376
309- ajax ( params : Params ) : void {
377+ event ( params : Params , event : KeyboardEvent ) : void {
378+ console . log ( "Event" , params , "KeyboardEvent" , event ) ;
379+
380+ for ( name in params . KeyboardMappings ) {
381+ var mapping : MappingEvent = AutoComplete . merge ( {
382+ Operator : ConditionOperator . AND
383+ } , params . KeyboardMappings [ name ] ) ,
384+ match : boolean = ConditionOperator . AND == mapping . Operator ;
385+
386+ mapping . Conditions . forEach ( function ( condition : MappingCondition ) {
387+ if ( ( match == true && mapping . Operator == ConditionOperator . AND ) || ( match == false && ConditionOperator . OR ) ) {
388+ condition = AutoComplete . merge ( {
389+ Not : false
390+ } , condition ) ;
391+
392+ // For MappingConditionIs object
393+ if ( condition . hasOwnProperty ( "Is" ) ) {
394+ if ( condition . Is == event . keyCode ) {
395+ match = ! condition . Not ;
396+ } else {
397+ match = condition . Not ;
398+ }
399+ }
400+ // For MappingConditionRange object
401+ else if ( condition . hasOwnProperty ( "From" ) && condition . hasOwnProperty ( "To" ) ) {
402+ if ( event . keyCode >= condition . From && event . keyCode <= condition . To ) {
403+ match = ! condition . Not ;
404+ } else {
405+ match = condition . Not ;
406+ }
407+ }
408+ }
409+ } ) ;
410+
411+ if ( match == true ) {
412+ mapping . Callback . bind ( params , event ) ( ) ;
413+ }
414+ } ;
415+ }
416+
417+ ajax ( params : Params , callback : any ) : void {
310418 console . log ( "AJAX" , params ) ;
311419 if ( params . Request ) {
312420 params . Request . abort ( ) ;
@@ -315,7 +423,7 @@ class AutoComplete {
315423 var propertyHeaders = Object . getOwnPropertyNames ( params . Headers ) ,
316424 method = params . _Method ( ) ,
317425 url = params . _Url ( ) ,
318- queryParams = params . ParamName + "=" + params . _Pre ( ) ;
426+ queryParams = params . QueryArg + "=" + params . _Pre ( ) ;
319427
320428 if ( method . match ( / ^ G E T $ / i) ) {
321429 url += "?" + queryParams ;
@@ -328,13 +436,7 @@ class AutoComplete {
328436 params . Request . setRequestHeader ( propertyHeaders [ i ] , params . Headers [ propertyHeaders [ i ] ] ) ;
329437 }
330438
331- params . Request . onreadystatechange = function ( ) {
332- if ( params . Request . readyState == 4 && params . Request . status == 200 ) {
333- if ( ! params . _Post ( params . Request . response ) ) {
334- params . _Open ( ) ;
335- }
336- }
337- } ;
439+ params . Request . onreadystatechange = callback ;
338440
339441 params . Request . send ( queryParams ) ;
340442 }
@@ -345,22 +447,10 @@ class AutoComplete {
345447 params . Input . removeEventListener ( "position" , params . _Position ) ;
346448 params . Input . removeEventListener ( "focus" , params . _Focus ) ;
347449 params . Input . removeEventListener ( "blur" , params . _Blur ) ;
348- params . Input . removeEventListener ( "keyup" , params . _OnKeyUp ) ;
450+ // params.Input.removeEventListener("keyup", AutoComplete.prototype.event );
349451 params . DOMResults . parentNode . removeChild ( params . DOMResults ) ;
350452
351453 // delete(params);
352454 }
353455}
354456
355- function MergeObject ( ) : any {
356- var merge : any = { } ,
357- tmp : any ;
358-
359- for ( var i = 0 ; i < arguments . length ; i ++ ) {
360- for ( tmp in arguments [ i ] ) {
361- merge [ tmp ] = arguments [ i ] [ tmp ] ;
362- }
363- }
364-
365- return merge ;
366- }
0 commit comments