Index: trunk/extensions/UploadWizard/UploadWizardHooks.php |
— | — | @@ -20,10 +20,11 @@ |
21 | 21 | 'jquery.ui.dialog', |
22 | 22 | 'jquery.ui.datepicker', |
23 | 23 | 'jquery.ui.progressbar', |
| 24 | + 'jquery.suggestions', |
24 | 25 | 'jquery.ui.widget', |
25 | 26 | 'mediawiki.language', |
26 | 27 | 'mediawiki.util', |
27 | | - 'ext.uploadwizard.mediawiki.language.parser' |
| 28 | + 'ext.uploadwizard.mediawiki.language.parser', |
28 | 29 | ), |
29 | 30 | 'scripts' => array( |
30 | 31 | |
— | — | @@ -35,7 +36,6 @@ |
36 | 37 | 'resources/jquery/jquery.autocomplete.js', |
37 | 38 | 'resources/jquery/jquery.spinner.js', |
38 | 39 | 'resources/jquery/jquery.autoEllipsis.js', |
39 | | - 'resources/jquery/jquery.suggestions.js', |
40 | 40 | 'resources/jquery/jquery.removeCtrl.js', |
41 | 41 | 'resources/jquery/jquery.pubsub.js', |
42 | 42 | |
— | — | @@ -87,7 +87,6 @@ |
88 | 88 | ), |
89 | 89 | 'styles' => array( |
90 | 90 | 'resources/jquery/jquery.tipsy.css', |
91 | | - 'resources/jquery/jquery.suggestions.css', |
92 | 91 | 'resources/uploadWizard.css', |
93 | 92 | 'resources/jquery/jquery.arrowSteps.css', |
94 | 93 | 'resources/jquery/jquery.mwCoolCats.css', |
Index: trunk/extensions/UploadWizard/resources/jquery/jquery.suggestions.css |
— | — | @@ -1,68 +0,0 @@ |
2 | | -/* suggestions plugin */ |
3 | | - |
4 | | -.suggestions { |
5 | | - overflow: hidden; |
6 | | - position: absolute; |
7 | | - top: 0px; |
8 | | - left: 0px; |
9 | | - width: 0px; |
10 | | - border: none; |
11 | | - z-index: 99; |
12 | | - padding: 0; |
13 | | - margin: -1px 0 0 0; |
14 | | -} |
15 | | -.suggestions-special { |
16 | | - position: relative; |
17 | | - background-color: Window; |
18 | | - font-size: 0.8em; |
19 | | - cursor: pointer; |
20 | | - border: solid 1px #aaaaaa; |
21 | | - padding: 0; |
22 | | - margin: 0; |
23 | | - margin-top: -2px; |
24 | | - display: none; |
25 | | - padding: 0.25em 0.25em; |
26 | | - line-height: 1.25em; |
27 | | -} |
28 | | -.suggestions-results { |
29 | | - background-color: white; |
30 | | - background-color: Window; |
31 | | - font-size: 0.8em; |
32 | | - cursor: pointer; |
33 | | - border: solid 1px #aaaaaa; |
34 | | - padding: 0; |
35 | | - margin: 0; |
36 | | -} |
37 | | -.suggestions-result { |
38 | | - color: black; |
39 | | - color: WindowText; |
40 | | - margin: 0; |
41 | | - line-height: 1.5em; |
42 | | - padding: 0.01em 0.25em; |
43 | | -} |
44 | | -.suggestions-result-current { |
45 | | - background-color: #4C59A6; |
46 | | - background-color: Highlight; |
47 | | - color: white; |
48 | | - color: HighlightText; |
49 | | -} |
50 | | -.suggestions-special .special-label { |
51 | | - font-size: 0.8em; |
52 | | - color: gray; |
53 | | -} |
54 | | -.suggestions-special .special-query { |
55 | | - color: black; |
56 | | - font-style: italic; |
57 | | -} |
58 | | -.suggestions-special .special-hover { |
59 | | - background-color: silver; |
60 | | -} |
61 | | -.suggestions-result-current .special-label, |
62 | | -.suggestions-result-current .special-query { |
63 | | - color: white; |
64 | | - color: HighlightText; |
65 | | -} |
66 | | -.autoellipsis-matched, |
67 | | -.highlight { |
68 | | - font-weight: bold; |
69 | | -} |
\ No newline at end of file |
Index: trunk/extensions/UploadWizard/resources/jquery/jquery.suggestions.js |
— | — | @@ -1,521 +0,0 @@ |
2 | | -/** |
3 | | - * This plugin provides a generic way to add suggestions to a text box. |
4 | | - * |
5 | | - * Usage: |
6 | | - * |
7 | | - * Set options: |
8 | | - * $('#textbox').suggestions( { option1: value1, option2: value2 } ); |
9 | | - * $('#textbox').suggestions( option, value ); |
10 | | - * Get option: |
11 | | - * value = $('#textbox').suggestions( option ); |
12 | | - * Initialize: |
13 | | - * $('#textbox').suggestions(); |
14 | | - * |
15 | | - * Options: |
16 | | - * |
17 | | - * fetch(query): Callback that should fetch suggestions and set the suggestions property. Executed in the context of the |
18 | | - * textbox |
19 | | - * Type: Function |
20 | | - * cancel: Callback function to call when any pending asynchronous suggestions fetches should be canceled. |
21 | | - * Executed in the context of the textbox |
22 | | - * Type: Function |
23 | | - * special: Set of callbacks for rendering and selecting |
24 | | - * Type: Object of Functions 'render' and 'select' |
25 | | - * result: Set of callbacks for rendering and selecting |
26 | | - * Type: Object of Functions 'render' and 'select' |
27 | | - * $region: jQuery selection of element to place the suggestions below and match width of |
28 | | - * Type: jQuery Object, Default: $(this) |
29 | | - * suggestions: Suggestions to display |
30 | | - * Type: Array of strings |
31 | | - * maxRows: Maximum number of suggestions to display at one time |
32 | | - * Type: Number, Range: 1 - 100, Default: 7 |
33 | | - * delay: Number of ms to wait for the user to stop typing |
34 | | - * Type: Number, Range: 0 - 1200, Default: 120 |
35 | | - * submitOnClick: Whether to submit the form containing the textbox when a suggestion is clicked |
36 | | - * Type: Boolean, Default: false |
37 | | - * maxExpandFactor: Maximum suggestions box width relative to the textbox width. If set to e.g. 2, the suggestions box |
38 | | - * will never be grown beyond 2 times the width of the textbox. |
39 | | - * Type: Number, Range: 1 - infinity, Default: 3 |
40 | | - * positionFromLeft: Whether to position the suggestion box with the left attribute or the right |
41 | | - * Type: Boolean, Default: true |
42 | | - * highlightInput: Whether to hightlight matched portions of the input or not |
43 | | - * Type: Boolean, Default: false |
44 | | - */ |
45 | | -( function( $ ) { |
46 | | - |
47 | | -$.suggestions = { |
48 | | - /** |
49 | | - * Cancel any delayed updateSuggestions() call and inform the user so |
50 | | - * they can cancel their result fetching if they use AJAX or something |
51 | | - */ |
52 | | - cancel: function( context ) { |
53 | | - if ( context.data.timerID != null ) { |
54 | | - clearTimeout( context.data.timerID ); |
55 | | - } |
56 | | - if ( typeof context.config.cancel == 'function' ) { |
57 | | - context.config.cancel.call( context.data.$textbox ); |
58 | | - } |
59 | | - }, |
60 | | - /** |
61 | | - * Restore the text the user originally typed in the textbox, before it was overwritten by highlight(). This |
62 | | - * restores the value the currently displayed suggestions are based on, rather than the value just before |
63 | | - * highlight() overwrote it; the former is arguably slightly more sensible. |
64 | | - */ |
65 | | - restore: function( context ) { |
66 | | - context.data.$textbox.val( context.data.prevText ); |
67 | | - }, |
68 | | - /** |
69 | | - * Ask the user-specified callback for new suggestions. Any previous delayed call to this function still pending |
70 | | - * will be canceled. If the value in the textbox hasn't changed since the last time suggestions were fetched, this |
71 | | - * function does nothing. |
72 | | - * @param {Boolean} delayed Whether or not to delay this by the currently configured amount of time |
73 | | - */ |
74 | | - update: function( context, delayed ) { |
75 | | - // Only fetch if the value in the textbox changed |
76 | | - function maybeFetch() { |
77 | | - if ( context.data.$textbox.val() !== context.data.prevText ) { |
78 | | - context.data.prevText = context.data.$textbox.val(); |
79 | | - if ( typeof context.config.fetch == 'function' ) { |
80 | | - context.config.fetch.call( context.data.$textbox, context.data.$textbox.val() ); |
81 | | - } |
82 | | - } |
83 | | - } |
84 | | - // Cancel previous call |
85 | | - if ( context.data.timerID != null ) { |
86 | | - clearTimeout( context.data.timerID ); |
87 | | - } |
88 | | - if ( delayed ) { |
89 | | - // Start a new asynchronous call |
90 | | - context.data.timerID = setTimeout( maybeFetch, context.config.delay ); |
91 | | - } else { |
92 | | - maybeFetch(); |
93 | | - } |
94 | | - $.suggestions.special( context ); |
95 | | - }, |
96 | | - special: function( context ) { |
97 | | - // Allow custom rendering - but otherwise don't do any rendering |
98 | | - if ( typeof context.config.special.render == 'function' ) { |
99 | | - // Wait for the browser to update the value |
100 | | - setTimeout( function() { |
101 | | - // Render special |
102 | | - $special = context.data.$container.find( '.suggestions-special' ); |
103 | | - context.config.special.render.call( $special, context.data.$textbox.val() ); |
104 | | - }, 1 ); |
105 | | - } |
106 | | - }, |
107 | | - /** |
108 | | - * Sets the value of a property, and updates the widget accordingly |
109 | | - * @param {String} property Name of property |
110 | | - * @param {Mixed} value Value to set property with |
111 | | - */ |
112 | | - configure: function( context, property, value ) { |
113 | | - // Validate creation using fallback values |
114 | | - switch( property ) { |
115 | | - case 'fetch': |
116 | | - case 'cancel': |
117 | | - case 'special': |
118 | | - case 'result': |
119 | | - case '$region': |
120 | | - context.config[property] = value; |
121 | | - break; |
122 | | - case 'suggestions': |
123 | | - context.config[property] = value; |
124 | | - // Update suggestions |
125 | | - if ( typeof context.data !== 'undefined' ) { |
126 | | - if ( context.data.$textbox.val().length == 0 ) { |
127 | | - // Hide the div when no suggestion exist |
128 | | - context.data.$container.hide(); |
129 | | - } else { |
130 | | - // Rebuild the suggestions list |
131 | | - context.data.$container.show(); |
132 | | - // Update the size and position of the list |
133 | | - var newCSS = { |
134 | | - 'top': context.config.$region.offset().top + context.config.$region.outerHeight(), |
135 | | - 'bottom': 'auto', |
136 | | - 'width': context.config.$region.outerWidth(), |
137 | | - 'height': 'auto' |
138 | | - }; |
139 | | - if ( context.config.positionFromLeft ) { |
140 | | - newCSS['left'] = context.config.$region.offset().left; |
141 | | - newCSS['right'] = 'auto'; |
142 | | - } else { |
143 | | - newCSS['left'] = 'auto'; |
144 | | - newCSS['right'] = $( 'body' ).width() - ( context.config.$region.offset().left + context.config.$region.outerWidth() ); |
145 | | - } |
146 | | - context.data.$container.css( newCSS ); |
147 | | - var $results = context.data.$container.children( '.suggestions-results' ); |
148 | | - $results.empty(); |
149 | | - var expWidth = -1; |
150 | | - var $autoEllipseMe = $( [] ); |
151 | | - var matchedText = null; |
152 | | - for ( var i = 0; i < context.config.suggestions.length; i++ ) { |
153 | | - var text = context.config.suggestions[i]; |
154 | | - var $result = $( '<div />' ) |
155 | | - .addClass( 'suggestions-result' ) |
156 | | - .attr( 'rel', i ) |
157 | | - .data( 'text', context.config.suggestions[i] ) |
158 | | - .mousemove( function( e ) { |
159 | | - context.data.selectedWithMouse = true; |
160 | | - $.suggestions.highlight( |
161 | | - context, $(this).closest( '.suggestions-results div' ), false |
162 | | - ); |
163 | | - } ) |
164 | | - .appendTo( $results ); |
165 | | - // Allow custom rendering |
166 | | - if ( typeof context.config.result.render == 'function' ) { |
167 | | - context.config.result.render.call( $result, context.config.suggestions[i] ); |
168 | | - } else { |
169 | | - // Add <span> with text |
170 | | - if( context.config.highlightInput ) { |
171 | | - matchedText = context.data.prevText; |
172 | | - } |
173 | | - $result.append( $( '<span />' ) |
174 | | - .css( 'whiteSpace', 'nowrap' ) |
175 | | - .text( text ) |
176 | | - ); |
177 | | - |
178 | | - // Widen results box if needed |
179 | | - // New width is only calculated here, applied later |
180 | | - var $span = $result.children( 'span' ); |
181 | | - if ( $span.outerWidth() > $result.width() && $span.outerWidth() > expWidth ) { |
182 | | - // factor in any padding, margin, or border space on the parent |
183 | | - expWidth = $span.outerWidth() + ( context.data.$container.width() - $span.parent().width()); |
184 | | - } |
185 | | - $autoEllipseMe = $autoEllipseMe.add( $result ); |
186 | | - } |
187 | | - } |
188 | | - // Apply new width for results box, if any |
189 | | - if ( expWidth > context.data.$container.width() ) { |
190 | | - var maxWidth = context.config.maxExpandFactor*context.data.$textbox.width(); |
191 | | - context.data.$container.width( Math.min( expWidth, maxWidth ) ); |
192 | | - } |
193 | | - // autoEllipse the results. Has to be done after changing the width |
194 | | - $autoEllipseMe.autoEllipsis( { hasSpan: true, tooltip: true, matchText: matchedText } ); |
195 | | - } |
196 | | - } |
197 | | - break; |
198 | | - case 'maxRows': |
199 | | - context.config[property] = Math.max( 1, Math.min( 100, value ) ); |
200 | | - break; |
201 | | - case 'delay': |
202 | | - context.config[property] = Math.max( 0, Math.min( 1200, value ) ); |
203 | | - break; |
204 | | - case 'maxExpandFactor': |
205 | | - context.config[property] = Math.max( 1, value ); |
206 | | - break; |
207 | | - case 'submitOnClick': |
208 | | - case 'positionFromLeft': |
209 | | - case 'highlightInput': |
210 | | - context.config[property] = value ? true : false; |
211 | | - break; |
212 | | - } |
213 | | - }, |
214 | | - /** |
215 | | - * Highlight a result in the results table |
216 | | - * @param result <tr> to highlight: jQuery object, or 'prev' or 'next' |
217 | | - * @param updateTextbox If true, put the suggestion in the textbox |
218 | | - */ |
219 | | - highlight: function( context, result, updateTextbox ) { |
220 | | - var selected = context.data.$container.find( '.suggestions-result-current' ); |
221 | | - if ( !result.get || selected.get( 0 ) != result.get( 0 ) ) { |
222 | | - if ( result == 'prev' ) { |
223 | | - if( selected.is( '.suggestions-special' ) ) { |
224 | | - result = context.data.$container.find( '.suggestions-result:last' ) |
225 | | - } else { |
226 | | - result = selected.prev(); |
227 | | - if ( selected.length == 0 ) { |
228 | | - // we are at the begginning, so lets jump to the last item |
229 | | - if ( context.data.$container.find( '.suggestions-special' ).html() != "" ) { |
230 | | - result = context.data.$container.find( '.suggestions-special' ); |
231 | | - } else { |
232 | | - result = context.data.$container.find( '.suggestions-results div:last' ); |
233 | | - } |
234 | | - } |
235 | | - } |
236 | | - } else if ( result == 'next' ) { |
237 | | - if ( selected.length == 0 ) { |
238 | | - // No item selected, go to the first one |
239 | | - result = context.data.$container.find( '.suggestions-results div:first' ); |
240 | | - if ( result.length == 0 && context.data.$container.find( '.suggestions-special' ).html() != "" ) { |
241 | | - // No suggestion exists, go to the special one directly |
242 | | - result = context.data.$container.find( '.suggestions-special' ); |
243 | | - } |
244 | | - } else { |
245 | | - result = selected.next(); |
246 | | - if ( selected.is( '.suggestions-special' ) ) { |
247 | | - result = $( [] ); |
248 | | - } else if ( |
249 | | - result.length == 0 && |
250 | | - context.data.$container.find( '.suggestions-special' ).html() != "" |
251 | | - ) { |
252 | | - // We were at the last item, jump to the specials! |
253 | | - result = context.data.$container.find( '.suggestions-special' ); |
254 | | - } |
255 | | - } |
256 | | - } |
257 | | - selected.removeClass( 'suggestions-result-current' ); |
258 | | - result.addClass( 'suggestions-result-current' ); |
259 | | - } |
260 | | - if ( updateTextbox ) { |
261 | | - if ( result.length == 0 || result.is( '.suggestions-special' ) ) { |
262 | | - $.suggestions.restore( context ); |
263 | | - } else { |
264 | | - context.data.$textbox.val( result.data( 'text' ) ); |
265 | | - // .val() doesn't call any event handlers, so |
266 | | - // let the world know what happened |
267 | | - context.data.$textbox.change(); |
268 | | - } |
269 | | - context.data.$textbox.trigger( 'change' ); |
270 | | - } |
271 | | - }, |
272 | | - /** |
273 | | - * Respond to keypress event |
274 | | - * @param {Integer} key Code of key pressed |
275 | | - */ |
276 | | - keypress: function( e, context, key ) { |
277 | | - var wasVisible = context.data.$container.is( ':visible' ); |
278 | | - var preventDefault = false; |
279 | | - switch ( key ) { |
280 | | - // Arrow down |
281 | | - case 40: |
282 | | - if ( wasVisible ) { |
283 | | - $.suggestions.highlight( context, 'next', true ); |
284 | | - context.data.selectedWithMouse = false; |
285 | | - } else { |
286 | | - $.suggestions.update( context, false ); |
287 | | - } |
288 | | - preventDefault = true; |
289 | | - break; |
290 | | - // Arrow up |
291 | | - case 38: |
292 | | - if ( wasVisible ) { |
293 | | - $.suggestions.highlight( context, 'prev', true ); |
294 | | - context.data.selectedWithMouse = false; |
295 | | - } |
296 | | - preventDefault = wasVisible; |
297 | | - break; |
298 | | - // Escape |
299 | | - case 27: |
300 | | - context.data.$container.hide(); |
301 | | - $.suggestions.restore( context ); |
302 | | - $.suggestions.cancel( context ); |
303 | | - context.data.$textbox.trigger( 'change' ); |
304 | | - preventDefault = wasVisible; |
305 | | - break; |
306 | | - // Enter |
307 | | - case 13: |
308 | | - context.data.$container.hide(); |
309 | | - preventDefault = wasVisible; |
310 | | - selected = context.data.$container.find( '.suggestions-result-current' ); |
311 | | - if ( selected.size() == 0 || context.data.selectedWithMouse ) { |
312 | | - // if nothing is selected OR if something was selected with the mouse, |
313 | | - // cancel any current requests and submit the form |
314 | | - $.suggestions.cancel( context ); |
315 | | - context.config.$region.closest( 'form' ).submit(); |
316 | | - } else if ( selected.is( '.suggestions-special' ) ) { |
317 | | - if ( typeof context.config.special.select == 'function' ) { |
318 | | - context.config.special.select.call( selected, context.data.$textbox ); |
319 | | - } |
320 | | - } else { |
321 | | - if ( typeof context.config.result.select == 'function' ) { |
322 | | - $.suggestions.highlight( context, selected, true ); |
323 | | - context.config.result.select.call( selected, context.data.$textbox ); |
324 | | - } else { |
325 | | - $.suggestions.highlight( context, selected, true ); |
326 | | - } |
327 | | - } |
328 | | - break; |
329 | | - default: |
330 | | - $.suggestions.update( context, true ); |
331 | | - break; |
332 | | - } |
333 | | - if ( preventDefault ) { |
334 | | - e.preventDefault(); |
335 | | - e.stopImmediatePropagation(); |
336 | | - } |
337 | | - } |
338 | | -}; |
339 | | -$.fn.suggestions = function() { |
340 | | - |
341 | | - // Multi-context fields |
342 | | - var returnValue = null; |
343 | | - var args = arguments; |
344 | | - |
345 | | - $(this).each( function() { |
346 | | - |
347 | | - /* Construction / Loading */ |
348 | | - |
349 | | - var context = $(this).data( 'suggestions-context' ); |
350 | | - if ( typeof context == 'undefined' || context == null ) { |
351 | | - context = { |
352 | | - config: { |
353 | | - 'fetch' : function() {}, |
354 | | - 'cancel': function() {}, |
355 | | - 'special': {}, |
356 | | - 'result': {}, |
357 | | - '$region': $(this), |
358 | | - 'suggestions': [], |
359 | | - 'maxRows': 7, |
360 | | - 'delay': 120, |
361 | | - 'submitOnClick': false, |
362 | | - 'maxExpandFactor': 3, |
363 | | - 'positionFromLeft': true, |
364 | | - 'highlightInput': false |
365 | | - } |
366 | | - }; |
367 | | - } |
368 | | - |
369 | | - /* API */ |
370 | | - |
371 | | - // Handle various calling styles |
372 | | - if ( args.length > 0 ) { |
373 | | - if ( typeof args[0] == 'object' ) { |
374 | | - // Apply set of properties |
375 | | - for ( var key in args[0] ) { |
376 | | - $.suggestions.configure( context, key, args[0][key] ); |
377 | | - } |
378 | | - } else if ( typeof args[0] == 'string' ) { |
379 | | - if ( args.length > 1 ) { |
380 | | - // Set property values |
381 | | - $.suggestions.configure( context, args[0], args[1] ); |
382 | | - } else if ( returnValue == null ) { |
383 | | - // Get property values, but don't give access to internal data - returns only the first |
384 | | - returnValue = ( args[0] in context.config ? undefined : context.config[args[0]] ); |
385 | | - } |
386 | | - } |
387 | | - } |
388 | | - |
389 | | - /* Initialization */ |
390 | | - |
391 | | - if ( typeof context.data == 'undefined' ) { |
392 | | - context.data = { |
393 | | - // ID of running timer |
394 | | - 'timerID': null, |
395 | | - // Text in textbox when suggestions were last fetched |
396 | | - 'prevText': null, |
397 | | - // Number of results visible without scrolling |
398 | | - 'visibleResults': 0, |
399 | | - // Suggestion the last mousedown event occured on |
400 | | - 'mouseDownOn': $( [] ), |
401 | | - '$textbox': $(this), |
402 | | - 'selectedWithMouse': false |
403 | | - }; |
404 | | - // Setup the css for positioning the results box |
405 | | - var newCSS = { |
406 | | - 'top': Math.round( context.data.$textbox.offset().top + context.data.$textbox.outerHeight() ), |
407 | | - 'width': context.data.$textbox.outerWidth(), |
408 | | - 'display': 'none' |
409 | | - }; |
410 | | - if ( context.config.positionFromLeft ) { |
411 | | - newCSS['left'] = context.config.$region.offset().left; |
412 | | - newCSS['right'] = 'auto'; |
413 | | - } else { |
414 | | - newCSS['left'] = 'auto'; |
415 | | - newCSS['right'] = $( 'body' ).width() - ( context.config.$region.offset().left + context.config.$region.outerWidth() ); |
416 | | - } |
417 | | - |
418 | | - context.data.$container = $( '<div />' ) |
419 | | - .css( newCSS ) |
420 | | - .addClass( 'suggestions' ) |
421 | | - .append( |
422 | | - $( '<div />' ).addClass( 'suggestions-results' ) |
423 | | - // Can't use click() because the container div is hidden when the textbox loses focus. Instead, |
424 | | - // listen for a mousedown followed by a mouseup on the same div |
425 | | - .mousedown( function( e ) { |
426 | | - context.data.mouseDownOn = $( e.target ).closest( '.suggestions-results div' ); |
427 | | - } ) |
428 | | - .mouseup( function( e ) { |
429 | | - var $result = $( e.target ).closest( '.suggestions-results div' ); |
430 | | - var $other = context.data.mouseDownOn; |
431 | | - context.data.mouseDownOn = $( [] ); |
432 | | - if ( $result.get( 0 ) != $other.get( 0 ) ) { |
433 | | - return; |
434 | | - } |
435 | | - $.suggestions.highlight( context, $result, true ); |
436 | | - context.data.$container.hide(); |
437 | | - if ( typeof context.config.result.select == 'function' ) { |
438 | | - context.config.result.select.call( $result, context.data.$textbox ); |
439 | | - } |
440 | | - context.data.$textbox.focus(); |
441 | | - } ) |
442 | | - ) |
443 | | - .append( |
444 | | - $( '<div />' ).addClass( 'suggestions-special' ) |
445 | | - // Can't use click() because the container div is hidden when the textbox loses focus. Instead, |
446 | | - // listen for a mousedown followed by a mouseup on the same div |
447 | | - .mousedown( function( e ) { |
448 | | - context.data.mouseDownOn = $( e.target ).closest( '.suggestions-special' ); |
449 | | - } ) |
450 | | - .mouseup( function( e ) { |
451 | | - var $special = $( e.target ).closest( '.suggestions-special' ); |
452 | | - var $other = context.data.mouseDownOn; |
453 | | - context.data.mouseDownOn = $( [] ); |
454 | | - if ( $special.get( 0 ) != $other.get( 0 ) ) { |
455 | | - return; |
456 | | - } |
457 | | - context.data.$container.hide(); |
458 | | - if ( typeof context.config.special.select == 'function' ) { |
459 | | - context.config.special.select.call( $special, context.data.$textbox ); |
460 | | - } |
461 | | - context.data.$textbox.focus(); |
462 | | - } ) |
463 | | - .mousemove( function( e ) { |
464 | | - context.data.selectedWithMouse = true; |
465 | | - $.suggestions.highlight( |
466 | | - context, $( e.target ).closest( '.suggestions-special' ), false |
467 | | - ); |
468 | | - } ) |
469 | | - ) |
470 | | - .appendTo( $( 'body' ) ); |
471 | | - $(this) |
472 | | - // Stop browser autocomplete from interfering |
473 | | - .attr( 'autocomplete', 'off') |
474 | | - .keydown( function( e ) { |
475 | | - // Store key pressed to handle later |
476 | | - context.data.keypressed = ( e.keyCode == undefined ) ? e.which : e.keyCode; |
477 | | - context.data.keypressedCount = 0; |
478 | | - |
479 | | - switch ( context.data.keypressed ) { |
480 | | - // This preventDefault logic is duplicated from |
481 | | - // $.suggestions.keypress(), which sucks |
482 | | - case 40: |
483 | | - e.preventDefault(); |
484 | | - e.stopImmediatePropagation(); |
485 | | - break; |
486 | | - case 38: |
487 | | - case 27: |
488 | | - case 13: |
489 | | - if ( context.data.$container.is( ':visible' ) ) { |
490 | | - e.preventDefault(); |
491 | | - e.stopImmediatePropagation(); |
492 | | - } |
493 | | - } |
494 | | - } ) |
495 | | - .keypress( function( e ) { |
496 | | - context.data.keypressedCount++; |
497 | | - $.suggestions.keypress( e, context, context.data.keypressed ); |
498 | | - } ) |
499 | | - .keyup( function( e ) { |
500 | | - // Some browsers won't throw keypress() for arrow keys. If we got a keydown and a keyup without a |
501 | | - // keypress in between, solve it |
502 | | - if ( context.data.keypressedCount == 0 ) { |
503 | | - $.suggestions.keypress( e, context, context.data.keypressed ); |
504 | | - } |
505 | | - } ) |
506 | | - .blur( function() { |
507 | | - // When losing focus because of a mousedown |
508 | | - // on a suggestion, don't hide the suggestions |
509 | | - if ( context.data.mouseDownOn.length > 0 ) { |
510 | | - return; |
511 | | - } |
512 | | - context.data.$container.hide(); |
513 | | - $.suggestions.cancel( context ); |
514 | | - } ); |
515 | | - } |
516 | | - // Store the context for next time |
517 | | - $(this).data( 'suggestions-context', context ); |
518 | | - } ); |
519 | | - return returnValue !== null ? returnValue : $(this); |
520 | | -}; |
521 | | - |
522 | | -} )( jQuery ); |