11
22
33( function ( UI ) {
4-
4+
55 /** section: scripty2 ui
66 * class S2.UI.Autocompleter < S2.UI.Base
77 *
88 **/
99 UI . Autocompleter = Class . create ( UI . Base , {
1010 NAME : "S2.UI.Autocompleter" ,
11-
11+
1212 /**
1313 * new S2.UI.Autocompleter(element, options)
1414 *
1717 initialize : function ( element , options ) {
1818 this . element = $ ( element ) ;
1919 var opt = this . setOptions ( options ) ;
20-
20+
2121 UI . addClassNames ( this . element , 'ui-widget ui-autocompleter' ) ;
22-
22+
2323 this . input = this . element . down ( 'input[type="text"]' ) ;
24-
24+
2525 if ( ! this . input ) {
2626 this . input = new Element ( 'input' , { type : 'text' } ) ;
2727 this . element . insert ( this . input ) ;
2828 }
29-
29+
3030 this . input . insert ( { before : this . button } ) ;
3131 this . input . setAttribute ( 'autocomplete' , 'off' ) ;
32-
32+
3333 this . name = opt . parameterName || this . input . readAttribute ( 'name' ) ;
34-
34+
3535 if ( opt . choices ) {
3636 this . choices = opt . choices . clone ( ) ;
3737 }
38-
38+
3939 this . menu = new UI . Menu ( ) ;
4040 this . element . insert ( this . menu . element ) ;
4141
4747 top : ( iLayout . get ( 'top' ) + iLayout . get ( 'margin-box-height' ) ) + 'px'
4848 } ) ;
4949 } ) . bind ( this ) . defer ( ) ;
50-
50+
5151 this . observers = {
5252 blur : this . _blur . bind ( this ) ,
5353 keyup : this . _keyup . bind ( this ) ,
5454 keydown : this . _keydown . bind ( this ) ,
5555 selected : this . _selected . bind ( this )
5656 } ;
57-
57+
5858 this . addObservers ( ) ;
5959 } ,
60-
60+
6161 addObservers : function ( ) {
6262 this . input . observe ( 'blur' , this . observers . blur ) ;
6363 this . input . observe ( 'keyup' , this . observers . keyup ) ;
6666 this . menu . observe ( 'ui:menu:selected' ,
6767 this . observers . selected ) ;
6868 } ,
69-
69+
7070 _schedule : function ( ) {
7171 this . _unschedule ( ) ;
7272 this . _timeout = this . _change . bind ( this ) . delay ( this . options . frequency ) ;
7373 } ,
74-
74+
7575 _unschedule : function ( ) {
7676 if ( this . _timeout ) window . clearTimeout ( this . _timeout ) ;
7777 } ,
7878
7979 _keyup : function ( event ) {
8080 var value = this . input . getValue ( ) ;
81-
81+
8282 if ( value ) {
8383 if ( value . blank ( ) || value . length < this . options . minCharacters ) {
8484 // Empty values mean the menu should be hidden and all timers
9595 this . menu . close ( ) ;
9696 this . _unschedule ( ) ;
9797 }
98-
98+
9999 this . _value = value ;
100100 } ,
101-
101+
102102 _keydown : function ( event ) {
103103 if ( UI . modifierUsed ( event ) ) return ;
104104 if ( ! this . menu . isOpen ( ) ) return ;
105-
105+
106106 var keyCode = event . keyCode || event . charCode ;
107-
107+
108108 switch ( event . keyCode ) {
109109 case Event . KEY_UP :
110110 this . menu . moveHighlight ( - 1 ) ;
128128 break ;
129129 }
130130 } ,
131-
131+
132132 // TODO: Implement tokenizing.
133133 _getInput : function ( ) {
134134 return this . input . getValue ( ) ;
135135 } ,
136-
136+
137137 // TODO: Implement tokenizing.
138138 _setInput : function ( value ) {
139139 this . input . setValue ( value ) ;
140140 } ,
141-
141+
142142 _change : function ( ) {
143143 this . findChoices ( ) ;
144144 } ,
145-
145+
146146 /**
147147 * S2.UI.Autocompleter#findChoices() -> undefined
148148 *
149149 * Triggers an update of the choices presented to the user. If results
150150 * come from the server, this is an asynchronous operation.
151151 **/
152152 findChoices : function ( ) {
153- var value = this . _getInput ( ) ;
154- var choices = this . choices || [ ] ;
153+ var value = this . _getInput ( ) ,
154+ choices = this . choices || [ ] ,
155+ choiceValue ,
156+ choiceAttribute = this . options . choiceAttribute ;
157+
155158 var results = choices . inject ( [ ] , function ( memo , choice ) {
156- if ( choice . toLowerCase ( ) . include ( value . toLowerCase ( ) ) ) {
159+ choiceValue = Object . isUndefined ( choiceAttribute ) ? choice : choice [ choiceAttribute ]
160+ if ( choiceValue . toLowerCase ( ) . include ( value . toLowerCase ( ) ) ) {
157161 memo . push ( choice ) ;
158162 }
159163 return memo ;
160164 } ) ;
161-
165+
162166 this . setChoices ( results ) ;
163167 } ,
164-
168+
165169 setChoices : function ( results ) {
166170 this . results = results ;
167171 this . _updateMenu ( results ) ;
168172 } ,
169-
173+
170174 _updateMenu : function ( results ) {
171175 var opt = this . options ;
172-
176+
173177 this . menu . clear ( ) ;
174-
178+
175179 // Build a case-insensitive regexp for highlighting the substring match.
176180 var needle = new RegExp ( RegExp . escape ( this . _value ) , 'i' ) ;
177181 for ( var i = 0 , result , li , text ; result = results [ i ] ; i ++ ) {
182+ value = Object . isUndefined ( opt . choiceAttribute ) ? result : result [ opt . choiceAttribute ]
183+
178184 text = opt . highlightSubstring ?
179- result . replace ( needle , "<b>$&</b>" ) :
180- result ;
181-
182- li = new Element ( 'li' ) . update ( text ) ;
185+ value . replace ( needle , "<b>$&</b>" ) :
186+ value ;
187+
188+ li = new Element ( 'li' ) . update ( Object . isUndefined ( opt . listTemplate ) ? text : opt . listTemplate . evaluate ( { text : text , object : result } ) ) ;
183189 li . store ( 'ui.autocompleter.value' , result ) ;
184190 this . menu . addChoice ( li ) ;
185191 }
186-
192+
187193 if ( results . length === 0 ) {
188194 this . menu . close ( ) ;
189195 } else {
190196 this . menu . open ( ) ;
191197 }
192198 } ,
193-
199+
194200 _moveMenuChoice : function ( delta ) {
195201 var choices = this . list . down ( 'li' ) ;
196202 this . _selectedIndex = ( this . _selectedIndex + delta ) . constrain (
197203 - 1 , this . results . length - 1 ) ;
198-
204+
199205 this . _highlightMenuChoice ( ) ;
200206 } ,
201-
207+
202208 _highlightMenuChoice : function ( element ) {
203209 var choices = this . list . select ( 'li' ) , index ;
204-
210+
205211 if ( Object . isElement ( element ) ) {
206212 index = choices . indexOf ( element ) ;
207213 } else if ( Object . isNumber ( element ) ) {
213219 UI . removeClassNames ( choices , 'ui-state-active' ) ;
214220 if ( index === - 1 || index === null ) return ;
215221 choices [ index ] . addClassName ( 'ui-state-active' ) ;
216-
222+
217223 this . _selectedIndex = index ;
218224 } ,
219-
225+
220226 _selected : function ( event ) {
221227 var memo = event . memo , li = memo . element ;
222-
228+
223229 if ( li ) {
224230 var value = li . retrieve ( 'ui.autocompleter.value' ) ;
225231 var result = this . element . fire ( 'ui:autocompleter:selected' , {
226232 instance : this ,
227233 value : value
228234 } ) ;
229235 if ( result . stopped ) return ;
230- this . _setInput ( value ) ;
236+ this . _setInput ( Object . isUndefined ( this . options . choiceAttribute ) ? value : value [ this . options . choiceAttribute ] ) ;
231237 }
232238 this . menu . close ( ) ;
233239 } ,
234-
240+
235241 _blur : function ( event ) {
236242 this . _unschedule ( ) ;
237243 this . menu . close ( ) ;
238244 }
239245 } ) ;
240-
246+
241247 Object . extend ( UI . Autocompleter , {
242248 DEFAULT_OPTIONS : {
243249 tokens : [ ] ,
244250 frequency : 0.4 ,
245251 minCharacters : 1 ,
246-
252+
247253 highlightSubstring : true ,
248-
254+
249255 onShow : Prototype . K ,
250256 onHide : Prototype . K
251257 }
252258 } ) ;
253-
259+
254260} ) ( S2 . UI ) ;
0 commit comments