Révision 503b3f7b
Ajouté par Assos Assos il y a environ 10 ans
drupal7/sites/all/modules/jquery_update/replace/ui/ui/jquery.ui.autocomplete.js | ||
---|---|---|
1 |
/* |
|
2 |
* jQuery UI Autocomplete 1.8.11 |
|
1 |
/*! |
|
2 |
* jQuery UI Autocomplete 1.10.2 |
|
3 |
* http://jqueryui.com |
|
3 | 4 |
* |
4 |
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
|
|
5 |
* Dual licensed under the MIT or GPL Version 2 licenses.
|
|
5 |
* Copyright 2013 jQuery Foundation and other contributors
|
|
6 |
* Released under the MIT license.
|
|
6 | 7 |
* http://jquery.org/license |
7 | 8 |
* |
8 |
* http://docs.jquery.com/UI/Autocomplete
|
|
9 |
* http://api.jqueryui.com/autocomplete/
|
|
9 | 10 |
* |
10 | 11 |
* Depends: |
11 | 12 |
* jquery.ui.core.js |
12 | 13 |
* jquery.ui.widget.js |
13 | 14 |
* jquery.ui.position.js |
15 |
* jquery.ui.menu.js |
|
14 | 16 |
*/ |
15 | 17 |
(function( $, undefined ) { |
16 | 18 |
|
... | ... | |
18 | 20 |
var requestIndex = 0; |
19 | 21 |
|
20 | 22 |
$.widget( "ui.autocomplete", { |
23 |
version: "1.10.2", |
|
24 |
defaultElement: "<input>", |
|
21 | 25 |
options: { |
22 |
appendTo: "body",
|
|
26 |
appendTo: null,
|
|
23 | 27 |
autoFocus: false, |
24 | 28 |
delay: 300, |
25 | 29 |
minLength: 1, |
... | ... | |
28 | 32 |
at: "left bottom", |
29 | 33 |
collision: "none" |
30 | 34 |
}, |
31 |
source: null |
|
35 |
source: null, |
|
36 |
|
|
37 |
// callbacks |
|
38 |
change: null, |
|
39 |
close: null, |
|
40 |
focus: null, |
|
41 |
open: null, |
|
42 |
response: null, |
|
43 |
search: null, |
|
44 |
select: null |
|
32 | 45 |
}, |
33 | 46 |
|
34 | 47 |
pending: 0, |
35 | 48 |
|
36 | 49 |
_create: function() { |
37 |
var self = this, |
|
38 |
doc = this.element[ 0 ].ownerDocument, |
|
39 |
suppressKeyPress; |
|
50 |
// Some browsers only repeat keydown events, not keypress events, |
|
51 |
// so we use the suppressKeyPress flag to determine if we've already |
|
52 |
// handled the keydown event. #7269 |
|
53 |
// Unfortunately the code for & in keypress is the same as the up arrow, |
|
54 |
// so we use the suppressKeyPressRepeat flag to avoid handling keypress |
|
55 |
// events when we know the keydown event was used to modify the |
|
56 |
// search term. #7799 |
|
57 |
var suppressKeyPress, suppressKeyPressRepeat, suppressInput, |
|
58 |
nodeName = this.element[0].nodeName.toLowerCase(), |
|
59 |
isTextarea = nodeName === "textarea", |
|
60 |
isInput = nodeName === "input"; |
|
61 |
|
|
62 |
this.isMultiLine = |
|
63 |
// Textareas are always multi-line |
|
64 |
isTextarea ? true : |
|
65 |
// Inputs are always single-line, even if inside a contentEditable element |
|
66 |
// IE also treats inputs as contentEditable |
|
67 |
isInput ? false : |
|
68 |
// All other element types are determined by whether or not they're contentEditable |
|
69 |
this.element.prop( "isContentEditable" ); |
|
70 |
|
|
71 |
this.valueMethod = this.element[ isTextarea || isInput ? "val" : "text" ]; |
|
72 |
this.isNewMenu = true; |
|
40 | 73 |
|
41 | 74 |
this.element |
42 | 75 |
.addClass( "ui-autocomplete-input" ) |
43 |
.attr( "autocomplete", "off" ) |
|
44 |
// TODO verify these actually work as intended |
|
45 |
.attr({
|
|
46 |
role: "textbox",
|
|
47 |
"aria-autocomplete": "list",
|
|
48 |
"aria-haspopup": "true"
|
|
49 |
})
|
|
50 |
.bind( "keydown.autocomplete", function( event ) {
|
|
51 |
if ( self.options.disabled || self.element.attr( "readonly" ) ) {
|
|
76 |
.attr( "autocomplete", "off" );
|
|
77 |
|
|
78 |
this._on( this.element, {
|
|
79 |
keydown: function( event ) {
|
|
80 |
/*jshint maxcomplexity:15*/
|
|
81 |
if ( this.element.prop( "readOnly" ) ) {
|
|
82 |
suppressKeyPress = true;
|
|
83 |
suppressInput = true;
|
|
84 |
suppressKeyPressRepeat = true;
|
|
52 | 85 |
return; |
53 | 86 |
} |
54 | 87 |
|
55 | 88 |
suppressKeyPress = false; |
89 |
suppressInput = false; |
|
90 |
suppressKeyPressRepeat = false; |
|
56 | 91 |
var keyCode = $.ui.keyCode; |
57 | 92 |
switch( event.keyCode ) { |
58 | 93 |
case keyCode.PAGE_UP: |
59 |
self._move( "previousPage", event ); |
|
94 |
suppressKeyPress = true; |
|
95 |
this._move( "previousPage", event ); |
|
60 | 96 |
break; |
61 | 97 |
case keyCode.PAGE_DOWN: |
62 |
self._move( "nextPage", event ); |
|
98 |
suppressKeyPress = true; |
|
99 |
this._move( "nextPage", event ); |
|
63 | 100 |
break; |
64 | 101 |
case keyCode.UP: |
65 |
self._move( "previous", event ); |
|
66 |
// prevent moving cursor to beginning of text field in some browsers |
|
67 |
event.preventDefault(); |
|
102 |
suppressKeyPress = true; |
|
103 |
this._keyEvent( "previous", event ); |
|
68 | 104 |
break; |
69 | 105 |
case keyCode.DOWN: |
70 |
self._move( "next", event ); |
|
71 |
// prevent moving cursor to end of text field in some browsers |
|
72 |
event.preventDefault(); |
|
106 |
suppressKeyPress = true; |
|
107 |
this._keyEvent( "next", event ); |
|
73 | 108 |
break; |
74 | 109 |
case keyCode.ENTER: |
75 | 110 |
case keyCode.NUMPAD_ENTER: |
76 | 111 |
// when menu is open and has focus |
77 |
if ( self.menu.active ) {
|
|
112 |
if ( this.menu.active ) {
|
|
78 | 113 |
// #6055 - Opera still allows the keypress to occur |
79 | 114 |
// which causes forms to submit |
80 | 115 |
suppressKeyPress = true; |
81 | 116 |
event.preventDefault(); |
117 |
this.menu.select( event ); |
|
82 | 118 |
} |
83 |
//passthrough - ENTER and TAB both select the current element
|
|
119 |
break;
|
|
84 | 120 |
case keyCode.TAB: |
85 |
if ( !self.menu.active ) {
|
|
86 |
return;
|
|
121 |
if ( this.menu.active ) {
|
|
122 |
this.menu.select( event );
|
|
87 | 123 |
} |
88 |
self.menu.select( event ); |
|
89 | 124 |
break; |
90 | 125 |
case keyCode.ESCAPE: |
91 |
self.element.val( self.term ); |
|
92 |
self.close( event ); |
|
126 |
if ( this.menu.element.is( ":visible" ) ) { |
|
127 |
this._value( this.term ); |
|
128 |
this.close( event ); |
|
129 |
// Different browsers have different default behavior for escape |
|
130 |
// Single press can mean undo or clear |
|
131 |
// Double press in IE means clear the whole form |
|
132 |
event.preventDefault(); |
|
133 |
} |
|
93 | 134 |
break; |
94 | 135 |
default: |
95 |
// keypress is triggered before the input value is changed |
|
96 |
clearTimeout( self.searching ); |
|
97 |
self.searching = setTimeout(function() { |
|
98 |
// only search if the value has changed |
|
99 |
if ( self.term != self.element.val() ) { |
|
100 |
self.selectedItem = null; |
|
101 |
self.search( null, event ); |
|
102 |
} |
|
103 |
}, self.options.delay ); |
|
136 |
suppressKeyPressRepeat = true; |
|
137 |
// search timeout should be triggered before the input value is changed |
|
138 |
this._searchTimeout( event ); |
|
104 | 139 |
break; |
105 | 140 |
} |
106 |
})
|
|
107 |
.bind( "keypress.autocomplete", function( event ) {
|
|
141 |
},
|
|
142 |
keypress: function( event ) {
|
|
108 | 143 |
if ( suppressKeyPress ) { |
109 | 144 |
suppressKeyPress = false; |
110 | 145 |
event.preventDefault(); |
146 |
return; |
|
111 | 147 |
} |
112 |
}) |
|
113 |
.bind( "focus.autocomplete", function() { |
|
114 |
if ( self.options.disabled ) { |
|
148 |
if ( suppressKeyPressRepeat ) { |
|
115 | 149 |
return; |
116 | 150 |
} |
117 | 151 |
|
118 |
self.selectedItem = null; |
|
119 |
self.previous = self.element.val(); |
|
120 |
}) |
|
121 |
.bind( "blur.autocomplete", function( event ) { |
|
122 |
if ( self.options.disabled ) { |
|
152 |
// replicate some key handlers to allow them to repeat in Firefox and Opera |
|
153 |
var keyCode = $.ui.keyCode; |
|
154 |
switch( event.keyCode ) { |
|
155 |
case keyCode.PAGE_UP: |
|
156 |
this._move( "previousPage", event ); |
|
157 |
break; |
|
158 |
case keyCode.PAGE_DOWN: |
|
159 |
this._move( "nextPage", event ); |
|
160 |
break; |
|
161 |
case keyCode.UP: |
|
162 |
this._keyEvent( "previous", event ); |
|
163 |
break; |
|
164 |
case keyCode.DOWN: |
|
165 |
this._keyEvent( "next", event ); |
|
166 |
break; |
|
167 |
} |
|
168 |
}, |
|
169 |
input: function( event ) { |
|
170 |
if ( suppressInput ) { |
|
171 |
suppressInput = false; |
|
172 |
event.preventDefault(); |
|
173 |
return; |
|
174 |
} |
|
175 |
this._searchTimeout( event ); |
|
176 |
}, |
|
177 |
focus: function() { |
|
178 |
this.selectedItem = null; |
|
179 |
this.previous = this._value(); |
|
180 |
}, |
|
181 |
blur: function( event ) { |
|
182 |
if ( this.cancelBlur ) { |
|
183 |
delete this.cancelBlur; |
|
123 | 184 |
return; |
124 | 185 |
} |
125 | 186 |
|
126 |
clearTimeout( self.searching ); |
|
127 |
// clicks on the menu (or a button to trigger a search) will cause a blur event |
|
128 |
self.closing = setTimeout(function() { |
|
129 |
self.close( event ); |
|
130 |
self._change( event ); |
|
131 |
}, 150 ); |
|
132 |
}); |
|
187 |
clearTimeout( this.searching ); |
|
188 |
this.close( event ); |
|
189 |
this._change( event ); |
|
190 |
} |
|
191 |
}); |
|
192 |
|
|
133 | 193 |
this._initSource(); |
134 |
this.response = function() { |
|
135 |
return self._response.apply( self, arguments ); |
|
136 |
}; |
|
137 |
this.menu = $( "<ul></ul>" ) |
|
138 |
.addClass( "ui-autocomplete" ) |
|
139 |
.appendTo( $( this.options.appendTo || "body", doc )[0] ) |
|
140 |
// prevent the close-on-blur in case of a "slow" click on the menu (long mousedown) |
|
141 |
.mousedown(function( event ) { |
|
194 |
this.menu = $( "<ul>" ) |
|
195 |
.addClass( "ui-autocomplete ui-front" ) |
|
196 |
.appendTo( this._appendTo() ) |
|
197 |
.menu({ |
|
198 |
// custom key handling for now |
|
199 |
input: $(), |
|
200 |
// disable ARIA support, the live region takes care of that |
|
201 |
role: null |
|
202 |
}) |
|
203 |
.hide() |
|
204 |
.data( "ui-menu" ); |
|
205 |
|
|
206 |
this._on( this.menu.element, { |
|
207 |
mousedown: function( event ) { |
|
208 |
// prevent moving focus out of the text field |
|
209 |
event.preventDefault(); |
|
210 |
|
|
211 |
// IE doesn't prevent moving focus even with event.preventDefault() |
|
212 |
// so we set a flag to know when we should ignore the blur event |
|
213 |
this.cancelBlur = true; |
|
214 |
this._delay(function() { |
|
215 |
delete this.cancelBlur; |
|
216 |
}); |
|
217 |
|
|
142 | 218 |
// clicking on the scrollbar causes focus to shift to the body |
143 | 219 |
// but we can't detect a mouseup or a click immediately afterward |
144 | 220 |
// so we have to track the next mousedown and close the menu if |
145 | 221 |
// the user clicks somewhere outside of the autocomplete |
146 |
var menuElement = self.menu.element[ 0 ];
|
|
222 |
var menuElement = this.menu.element[ 0 ];
|
|
147 | 223 |
if ( !$( event.target ).closest( ".ui-menu-item" ).length ) { |
148 |
setTimeout(function() { |
|
149 |
$( document ).one( 'mousedown', function( event ) { |
|
150 |
if ( event.target !== self.element[ 0 ] && |
|
151 |
event.target !== menuElement && |
|
152 |
!$.ui.contains( menuElement, event.target ) ) { |
|
153 |
self.close(); |
|
224 |
this._delay(function() { |
|
225 |
var that = this; |
|
226 |
this.document.one( "mousedown", function( event ) { |
|
227 |
if ( event.target !== that.element[ 0 ] && |
|
228 |
event.target !== menuElement && |
|
229 |
!$.contains( menuElement, event.target ) ) { |
|
230 |
that.close(); |
|
154 | 231 |
} |
155 | 232 |
}); |
156 |
}, 1 );
|
|
233 |
}); |
|
157 | 234 |
} |
235 |
}, |
|
236 |
menufocus: function( event, ui ) { |
|
237 |
// support: Firefox |
|
238 |
// Prevent accidental activation of menu items in Firefox (#7024 #9118) |
|
239 |
if ( this.isNewMenu ) { |
|
240 |
this.isNewMenu = false; |
|
241 |
if ( event.originalEvent && /^mouse/.test( event.originalEvent.type ) ) { |
|
242 |
this.menu.blur(); |
|
243 |
|
|
244 |
this.document.one( "mousemove", function() { |
|
245 |
$( event.target ).trigger( event.originalEvent ); |
|
246 |
}); |
|
158 | 247 |
|
159 |
// use another timeout to make sure the blur-event-handler on the input was already triggered |
|
160 |
setTimeout(function() { |
|
161 |
clearTimeout( self.closing ); |
|
162 |
}, 13); |
|
163 |
}) |
|
164 |
.menu({ |
|
165 |
focus: function( event, ui ) { |
|
166 |
var item = ui.item.data( "item.autocomplete" ); |
|
167 |
if ( false !== self._trigger( "focus", event, { item: item } ) ) { |
|
168 |
// use value to match what will end up in the input, if it was a key event |
|
169 |
if ( /^key/.test(event.originalEvent.type) ) { |
|
170 |
self.element.val( item.value ); |
|
171 |
} |
|
172 |
} |
|
173 |
}, |
|
174 |
selected: function( event, ui ) { |
|
175 |
var item = ui.item.data( "item.autocomplete" ), |
|
176 |
previous = self.previous; |
|
177 |
|
|
178 |
// only trigger when focus was lost (click on menu) |
|
179 |
if ( self.element[0] !== doc.activeElement ) { |
|
180 |
self.element.focus(); |
|
181 |
self.previous = previous; |
|
182 |
// #6109 - IE triggers two focus events and the second |
|
183 |
// is asynchronous, so we need to reset the previous |
|
184 |
// term synchronously and asynchronously :-( |
|
185 |
setTimeout(function() { |
|
186 |
self.previous = previous; |
|
187 |
self.selectedItem = item; |
|
188 |
}, 1); |
|
248 |
return; |
|
189 | 249 |
} |
250 |
} |
|
190 | 251 |
|
191 |
if ( false !== self._trigger( "select", event, { item: item } ) ) { |
|
192 |
self.element.val( item.value ); |
|
193 |
} |
|
194 |
// reset the term after the select event |
|
195 |
// this allows custom select handling to work properly |
|
196 |
self.term = self.element.val(); |
|
197 |
|
|
198 |
self.close( event ); |
|
199 |
self.selectedItem = item; |
|
200 |
}, |
|
201 |
blur: function( event, ui ) { |
|
202 |
// don't set the value of the text field if it's already correct |
|
203 |
// this prevents moving the cursor unnecessarily |
|
204 |
if ( self.menu.element.is(":visible") && |
|
205 |
( self.element.val() !== self.term ) ) { |
|
206 |
self.element.val( self.term ); |
|
252 |
var item = ui.item.data( "ui-autocomplete-item" ); |
|
253 |
if ( false !== this._trigger( "focus", event, { item: item } ) ) { |
|
254 |
// use value to match what will end up in the input, if it was a key event |
|
255 |
if ( event.originalEvent && /^key/.test( event.originalEvent.type ) ) { |
|
256 |
this._value( item.value ); |
|
207 | 257 |
} |
258 |
} else { |
|
259 |
// Normally the input is populated with the item's value as the |
|
260 |
// menu is navigated, causing screen readers to notice a change and |
|
261 |
// announce the item. Since the focus event was canceled, this doesn't |
|
262 |
// happen, so we update the live region so that screen readers can |
|
263 |
// still notice the change and announce it. |
|
264 |
this.liveRegion.text( item.value ); |
|
208 | 265 |
} |
266 |
}, |
|
267 |
menuselect: function( event, ui ) { |
|
268 |
var item = ui.item.data( "ui-autocomplete-item" ), |
|
269 |
previous = this.previous; |
|
270 |
|
|
271 |
// only trigger when focus was lost (click on menu) |
|
272 |
if ( this.element[0] !== this.document[0].activeElement ) { |
|
273 |
this.element.focus(); |
|
274 |
this.previous = previous; |
|
275 |
// #6109 - IE triggers two focus events and the second |
|
276 |
// is asynchronous, so we need to reset the previous |
|
277 |
// term synchronously and asynchronously :-( |
|
278 |
this._delay(function() { |
|
279 |
this.previous = previous; |
|
280 |
this.selectedItem = item; |
|
281 |
}); |
|
282 |
} |
|
283 |
|
|
284 |
if ( false !== this._trigger( "select", event, { item: item } ) ) { |
|
285 |
this._value( item.value ); |
|
286 |
} |
|
287 |
// reset the term after the select event |
|
288 |
// this allows custom select handling to work properly |
|
289 |
this.term = this._value(); |
|
290 |
|
|
291 |
this.close( event ); |
|
292 |
this.selectedItem = item; |
|
293 |
} |
|
294 |
}); |
|
295 |
|
|
296 |
this.liveRegion = $( "<span>", { |
|
297 |
role: "status", |
|
298 |
"aria-live": "polite" |
|
209 | 299 |
}) |
210 |
.zIndex( this.element.zIndex() + 1 ) |
|
211 |
// workaround for jQuery bug #5781 http://dev.jquery.com/ticket/5781 |
|
212 |
.css({ top: 0, left: 0 }) |
|
213 |
.hide() |
|
214 |
.data( "menu" ); |
|
215 |
if ( $.fn.bgiframe ) { |
|
216 |
this.menu.element.bgiframe(); |
|
217 |
} |
|
300 |
.addClass( "ui-helper-hidden-accessible" ) |
|
301 |
.insertAfter( this.element ); |
|
302 |
|
|
303 |
// turning off autocomplete prevents the browser from remembering the |
|
304 |
// value when navigating through history, so we re-enable autocomplete |
|
305 |
// if the page is unloaded before the widget is destroyed. #7790 |
|
306 |
this._on( this.window, { |
|
307 |
beforeunload: function() { |
|
308 |
this.element.removeAttr( "autocomplete" ); |
|
309 |
} |
|
310 |
}); |
|
218 | 311 |
}, |
219 | 312 |
|
220 |
destroy: function() { |
|
313 |
_destroy: function() { |
|
314 |
clearTimeout( this.searching ); |
|
221 | 315 |
this.element |
222 | 316 |
.removeClass( "ui-autocomplete-input" ) |
223 |
.removeAttr( "autocomplete" ) |
|
224 |
.removeAttr( "role" ) |
|
225 |
.removeAttr( "aria-autocomplete" ) |
|
226 |
.removeAttr( "aria-haspopup" ); |
|
317 |
.removeAttr( "autocomplete" ); |
|
227 | 318 |
this.menu.element.remove(); |
228 |
$.Widget.prototype.destroy.call( this );
|
|
319 |
this.liveRegion.remove();
|
|
229 | 320 |
}, |
230 | 321 |
|
231 | 322 |
_setOption: function( key, value ) { |
232 |
$.Widget.prototype._setOption.apply( this, arguments );
|
|
323 |
this._super( key, value );
|
|
233 | 324 |
if ( key === "source" ) { |
234 | 325 |
this._initSource(); |
235 | 326 |
} |
236 | 327 |
if ( key === "appendTo" ) { |
237 |
this.menu.element.appendTo( $( value || "body", this.element[0].ownerDocument )[0] )
|
|
328 |
this.menu.element.appendTo( this._appendTo() );
|
|
238 | 329 |
} |
239 | 330 |
if ( key === "disabled" && value && this.xhr ) { |
240 | 331 |
this.xhr.abort(); |
241 | 332 |
} |
242 | 333 |
}, |
243 | 334 |
|
335 |
_appendTo: function() { |
|
336 |
var element = this.options.appendTo; |
|
337 |
|
|
338 |
if ( element ) { |
|
339 |
element = element.jquery || element.nodeType ? |
|
340 |
$( element ) : |
|
341 |
this.document.find( element ).eq( 0 ); |
|
342 |
} |
|
343 |
|
|
344 |
if ( !element ) { |
|
345 |
element = this.element.closest( ".ui-front" ); |
|
346 |
} |
|
347 |
|
|
348 |
if ( !element.length ) { |
|
349 |
element = this.document[0].body; |
|
350 |
} |
|
351 |
|
|
352 |
return element; |
|
353 |
}, |
|
354 |
|
|
244 | 355 |
_initSource: function() { |
245 |
var self = this, |
|
246 |
array, |
|
247 |
url; |
|
356 |
var array, url, |
|
357 |
that = this; |
|
248 | 358 |
if ( $.isArray(this.options.source) ) { |
249 | 359 |
array = this.options.source; |
250 | 360 |
this.source = function( request, response ) { |
251 |
response( $.ui.autocomplete.filter(array, request.term) );
|
|
361 |
response( $.ui.autocomplete.filter( array, request.term ) );
|
|
252 | 362 |
}; |
253 | 363 |
} else if ( typeof this.options.source === "string" ) { |
254 | 364 |
url = this.options.source; |
255 | 365 |
this.source = function( request, response ) { |
256 |
if ( self.xhr ) {
|
|
257 |
self.xhr.abort();
|
|
366 |
if ( that.xhr ) {
|
|
367 |
that.xhr.abort();
|
|
258 | 368 |
} |
259 |
self.xhr = $.ajax({
|
|
369 |
that.xhr = $.ajax({
|
|
260 | 370 |
url: url, |
261 | 371 |
data: request, |
262 | 372 |
dataType: "json", |
263 |
autocompleteRequest: ++requestIndex, |
|
264 |
success: function( data, status ) { |
|
265 |
if ( this.autocompleteRequest === requestIndex ) { |
|
266 |
response( data ); |
|
267 |
} |
|
373 |
success: function( data ) { |
|
374 |
response( data ); |
|
268 | 375 |
}, |
269 | 376 |
error: function() { |
270 |
if ( this.autocompleteRequest === requestIndex ) { |
|
271 |
response( [] ); |
|
272 |
} |
|
377 |
response( [] ); |
|
273 | 378 |
} |
274 | 379 |
}); |
275 | 380 |
}; |
... | ... | |
278 | 383 |
} |
279 | 384 |
}, |
280 | 385 |
|
386 |
_searchTimeout: function( event ) { |
|
387 |
clearTimeout( this.searching ); |
|
388 |
this.searching = this._delay(function() { |
|
389 |
// only search if the value has changed |
|
390 |
if ( this.term !== this._value() ) { |
|
391 |
this.selectedItem = null; |
|
392 |
this.search( null, event ); |
|
393 |
} |
|
394 |
}, this.options.delay ); |
|
395 |
}, |
|
396 |
|
|
281 | 397 |
search: function( value, event ) { |
282 |
value = value != null ? value : this.element.val();
|
|
398 |
value = value != null ? value : this._value();
|
|
283 | 399 |
|
284 | 400 |
// always save the actual value, not the one passed as an argument |
285 |
this.term = this.element.val();
|
|
401 |
this.term = this._value();
|
|
286 | 402 |
|
287 | 403 |
if ( value.length < this.options.minLength ) { |
288 | 404 |
return this.close( event ); |
289 | 405 |
} |
290 | 406 |
|
291 |
clearTimeout( this.closing ); |
|
292 | 407 |
if ( this._trigger( "search", event ) === false ) { |
293 | 408 |
return; |
294 | 409 |
} |
... | ... | |
299 | 414 |
_search: function( value ) { |
300 | 415 |
this.pending++; |
301 | 416 |
this.element.addClass( "ui-autocomplete-loading" ); |
417 |
this.cancelSearch = false; |
|
418 |
|
|
419 |
this.source( { term: value }, this._response() ); |
|
420 |
}, |
|
421 |
|
|
422 |
_response: function() { |
|
423 |
var that = this, |
|
424 |
index = ++requestIndex; |
|
302 | 425 |
|
303 |
this.source( { term: value }, this.response ); |
|
426 |
return function( content ) { |
|
427 |
if ( index === requestIndex ) { |
|
428 |
that.__response( content ); |
|
429 |
} |
|
430 |
|
|
431 |
that.pending--; |
|
432 |
if ( !that.pending ) { |
|
433 |
that.element.removeClass( "ui-autocomplete-loading" ); |
|
434 |
} |
|
435 |
}; |
|
304 | 436 |
}, |
305 | 437 |
|
306 |
_response: function( content ) { |
|
307 |
if ( !this.options.disabled && content && content.length ) {
|
|
438 |
__response: function( content ) {
|
|
439 |
if ( content ) {
|
|
308 | 440 |
content = this._normalize( content ); |
441 |
} |
|
442 |
this._trigger( "response", null, { content: content } ); |
|
443 |
if ( !this.options.disabled && content && content.length && !this.cancelSearch ) { |
|
309 | 444 |
this._suggest( content ); |
310 | 445 |
this._trigger( "open" ); |
311 | 446 |
} else { |
312 |
this.close(); |
|
313 |
} |
|
314 |
this.pending--; |
|
315 |
if ( !this.pending ) { |
|
316 |
this.element.removeClass( "ui-autocomplete-loading" ); |
|
447 |
// use ._close() instead of .close() so we don't cancel future searches |
|
448 |
this._close(); |
|
317 | 449 |
} |
318 | 450 |
}, |
319 | 451 |
|
320 | 452 |
close: function( event ) { |
321 |
clearTimeout( this.closing ); |
|
322 |
if ( this.menu.element.is(":visible") ) { |
|
453 |
this.cancelSearch = true; |
|
454 |
this._close( event ); |
|
455 |
}, |
|
456 |
|
|
457 |
_close: function( event ) { |
|
458 |
if ( this.menu.element.is( ":visible" ) ) { |
|
323 | 459 |
this.menu.element.hide(); |
324 |
this.menu.deactivate(); |
|
460 |
this.menu.blur(); |
|
461 |
this.isNewMenu = true; |
|
325 | 462 |
this._trigger( "close", event ); |
326 | 463 |
} |
327 | 464 |
}, |
328 |
|
|
465 |
|
|
329 | 466 |
_change: function( event ) { |
330 |
if ( this.previous !== this.element.val() ) {
|
|
467 |
if ( this.previous !== this._value() ) {
|
|
331 | 468 |
this._trigger( "change", event, { item: this.selectedItem } ); |
332 | 469 |
} |
333 | 470 |
}, |
... | ... | |
337 | 474 |
if ( items.length && items[0].label && items[0].value ) { |
338 | 475 |
return items; |
339 | 476 |
} |
340 |
return $.map( items, function(item) {
|
|
477 |
return $.map( items, function( item ) {
|
|
341 | 478 |
if ( typeof item === "string" ) { |
342 | 479 |
return { |
343 | 480 |
label: item, |
... | ... | |
352 | 489 |
}, |
353 | 490 |
|
354 | 491 |
_suggest: function( items ) { |
355 |
var ul = this.menu.element |
|
356 |
.empty() |
|
357 |
.zIndex( this.element.zIndex() + 1 ); |
|
492 |
var ul = this.menu.element.empty(); |
|
358 | 493 |
this._renderMenu( ul, items ); |
359 |
// TODO refresh should check if the active item is still in the dom, removing the need for a manual deactivate |
|
360 |
this.menu.deactivate(); |
|
494 |
this.isNewMenu = true; |
|
361 | 495 |
this.menu.refresh(); |
362 | 496 |
|
363 | 497 |
// size and position menu |
... | ... | |
368 | 502 |
}, this.options.position )); |
369 | 503 |
|
370 | 504 |
if ( this.options.autoFocus ) { |
371 |
this.menu.next( new $.Event("mouseover") );
|
|
505 |
this.menu.next(); |
|
372 | 506 |
} |
373 | 507 |
}, |
374 | 508 |
|
375 | 509 |
_resizeMenu: function() { |
376 | 510 |
var ul = this.menu.element; |
377 | 511 |
ul.outerWidth( Math.max( |
378 |
ul.width( "" ).outerWidth(), |
|
512 |
// Firefox wraps long text (possibly a rounding bug) |
|
513 |
// so we add 1px to avoid the wrapping (#7513) |
|
514 |
ul.width( "" ).outerWidth() + 1, |
|
379 | 515 |
this.element.outerWidth() |
380 | 516 |
) ); |
381 | 517 |
}, |
382 | 518 |
|
383 | 519 |
_renderMenu: function( ul, items ) { |
384 |
var self = this;
|
|
520 |
var that = this;
|
|
385 | 521 |
$.each( items, function( index, item ) { |
386 |
self._renderItem( ul, item );
|
|
522 |
that._renderItemData( ul, item );
|
|
387 | 523 |
}); |
388 | 524 |
}, |
389 | 525 |
|
390 |
_renderItem: function( ul, item) { |
|
391 |
return $( "<li></li>" ) |
|
392 |
.data( "item.autocomplete", item ) |
|
393 |
.append( $( "<a></a>" ).text( item.label ) ) |
|
526 |
_renderItemData: function( ul, item ) { |
|
527 |
return this._renderItem( ul, item ).data( "ui-autocomplete-item", item ); |
|
528 |
}, |
|
529 |
|
|
530 |
_renderItem: function( ul, item ) { |
|
531 |
return $( "<li>" ) |
|
532 |
.append( $( "<a>" ).text( item.label ) ) |
|
394 | 533 |
.appendTo( ul ); |
395 | 534 |
}, |
396 | 535 |
|
397 | 536 |
_move: function( direction, event ) { |
398 |
if ( !this.menu.element.is(":visible") ) {
|
|
537 |
if ( !this.menu.element.is( ":visible" ) ) {
|
|
399 | 538 |
this.search( null, event ); |
400 | 539 |
return; |
401 | 540 |
} |
402 |
if ( this.menu.first() && /^previous/.test(direction) ||
|
|
403 |
this.menu.last() && /^next/.test(direction) ) {
|
|
404 |
this.element.val( this.term );
|
|
405 |
this.menu.deactivate();
|
|
541 |
if ( this.menu.isFirstItem() && /^previous/.test( direction ) ||
|
|
542 |
this.menu.isLastItem() && /^next/.test( direction ) ) {
|
|
543 |
this._value( this.term );
|
|
544 |
this.menu.blur();
|
|
406 | 545 |
return; |
407 | 546 |
} |
408 | 547 |
this.menu[ direction ]( event ); |
... | ... | |
410 | 549 |
|
411 | 550 |
widget: function() { |
412 | 551 |
return this.menu.element; |
552 |
}, |
|
553 |
|
|
554 |
_value: function() { |
|
555 |
return this.valueMethod.apply( this.element, arguments ); |
|
556 |
}, |
|
557 |
|
|
558 |
_keyEvent: function( keyEvent, event ) { |
|
559 |
if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) { |
|
560 |
this._move( keyEvent, event ); |
|
561 |
|
|
562 |
// prevents moving cursor to beginning/end of the text field in some browsers |
|
563 |
event.preventDefault(); |
|
564 |
} |
|
413 | 565 |
} |
414 | 566 |
}); |
415 | 567 |
|
416 | 568 |
$.extend( $.ui.autocomplete, { |
417 | 569 |
escapeRegex: function( value ) { |
418 |
return value.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
|
|
570 |
return value.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&");
|
|
419 | 571 |
}, |
420 | 572 |
filter: function(array, term) { |
421 | 573 |
var matcher = new RegExp( $.ui.autocomplete.escapeRegex(term), "i" ); |
... | ... | |
425 | 577 |
} |
426 | 578 |
}); |
427 | 579 |
|
428 |
}( jQuery )); |
|
429 |
|
|
430 |
/* |
|
431 |
* jQuery UI Menu (not officially released) |
|
432 |
* |
|
433 |
* This widget isn't yet finished and the API is subject to change. We plan to finish |
|
434 |
* it for the next release. You're welcome to give it a try anyway and give us feedback, |
|
435 |
* as long as you're okay with migrating your code later on. We can help with that, too. |
|
436 |
* |
|
437 |
* Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) |
|
438 |
* Dual licensed under the MIT or GPL Version 2 licenses. |
|
439 |
* http://jquery.org/license |
|
440 |
* |
|
441 |
* http://docs.jquery.com/UI/Menu |
|
442 |
* |
|
443 |
* Depends: |
|
444 |
* jquery.ui.core.js |
|
445 |
* jquery.ui.widget.js |
|
446 |
*/ |
|
447 |
(function($) { |
|
448 |
|
|
449 |
$.widget("ui.menu", { |
|
450 |
_create: function() { |
|
451 |
var self = this; |
|
452 |
this.element |
|
453 |
.addClass("ui-menu ui-widget ui-widget-content ui-corner-all") |
|
454 |
.attr({ |
|
455 |
role: "listbox", |
|
456 |
"aria-activedescendant": "ui-active-menuitem" |
|
457 |
}) |
|
458 |
.click(function( event ) { |
|
459 |
if ( !$( event.target ).closest( ".ui-menu-item a" ).length ) { |
|
460 |
return; |
|
461 |
} |
|
462 |
// temporary |
|
463 |
event.preventDefault(); |
|
464 |
self.select( event ); |
|
465 |
}); |
|
466 |
this.refresh(); |
|
467 |
}, |
|
468 |
|
|
469 |
refresh: function() { |
|
470 |
var self = this; |
|
471 |
|
|
472 |
// don't refresh list items that are already adapted |
|
473 |
var items = this.element.children("li:not(.ui-menu-item):has(a)") |
|
474 |
.addClass("ui-menu-item") |
|
475 |
.attr("role", "menuitem"); |
|
476 |
|
|
477 |
items.children("a") |
|
478 |
.addClass("ui-corner-all") |
|
479 |
.attr("tabindex", -1) |
|
480 |
// mouseenter doesn't work with event delegation |
|
481 |
.mouseenter(function( event ) { |
|
482 |
self.activate( event, $(this).parent() ); |
|
483 |
}) |
|
484 |
.mouseleave(function() { |
|
485 |
self.deactivate(); |
|
486 |
}); |
|
487 |
}, |
|
488 | 580 |
|
489 |
activate: function( event, item ) {
|
|
490 |
this.deactivate();
|
|
491 |
if (this.hasScroll()) {
|
|
492 |
var offset = item.offset().top - this.element.offset().top,
|
|
493 |
scroll = this.element.attr("scrollTop"),
|
|
494 |
elementHeight = this.element.height();
|
|
495 |
if (offset < 0) {
|
|
496 |
this.element.attr("scrollTop", scroll + offset);
|
|
497 |
} else if (offset >= elementHeight) {
|
|
498 |
this.element.attr("scrollTop", scroll + offset - elementHeight + item.height());
|
|
581 |
// live region extension, adding a `messages` option
|
|
582 |
// NOTE: This is an experimental API. We are still investigating
|
|
583 |
// a full solution for string manipulation and internationalization.
|
|
584 |
$.widget( "ui.autocomplete", $.ui.autocomplete, {
|
|
585 |
options: {
|
|
586 |
messages: {
|
|
587 |
noResults: "No search results.",
|
|
588 |
results: function( amount ) {
|
|
589 |
return amount + ( amount > 1 ? " results are" : " result is" ) +
|
|
590 |
" available, use up and down arrow keys to navigate.";
|
|
499 | 591 |
} |
500 | 592 |
} |
501 |
this.active = item.eq(0) |
|
502 |
.children("a") |
|
503 |
.addClass("ui-state-hover") |
|
504 |
.attr("id", "ui-active-menuitem") |
|
505 |
.end(); |
|
506 |
this._trigger("focus", event, { item: item }); |
|
507 |
}, |
|
508 |
|
|
509 |
deactivate: function() { |
|
510 |
if (!this.active) { return; } |
|
511 |
|
|
512 |
this.active.children("a") |
|
513 |
.removeClass("ui-state-hover") |
|
514 |
.removeAttr("id"); |
|
515 |
this._trigger("blur"); |
|
516 |
this.active = null; |
|
517 |
}, |
|
518 |
|
|
519 |
next: function(event) { |
|
520 |
this.move("next", ".ui-menu-item:first", event); |
|
521 |
}, |
|
522 |
|
|
523 |
previous: function(event) { |
|
524 |
this.move("prev", ".ui-menu-item:last", event); |
|
525 | 593 |
}, |
526 | 594 |
|
527 |
first: function() { |
|
528 |
return this.active && !this.active.prevAll(".ui-menu-item").length; |
|
529 |
}, |
|
530 |
|
|
531 |
last: function() { |
|
532 |
return this.active && !this.active.nextAll(".ui-menu-item").length; |
|
533 |
}, |
|
534 |
|
|
535 |
move: function(direction, edge, event) { |
|
536 |
if (!this.active) { |
|
537 |
this.activate(event, this.element.children(edge)); |
|
595 |
__response: function( content ) { |
|
596 |
var message; |
|
597 |
this._superApply( arguments ); |
|
598 |
if ( this.options.disabled || this.cancelSearch ) { |
|
538 | 599 |
return; |
539 | 600 |
} |
540 |
var next = this.active[direction + "All"](".ui-menu-item").eq(0); |
|
541 |
if (next.length) { |
|
542 |
this.activate(event, next); |
|
601 |
if ( content && content.length ) { |
|
602 |
message = this.options.messages.results( content.length ); |
|
543 | 603 |
} else { |
544 |
this.activate(event, this.element.children(edge));
|
|
604 |
message = this.options.messages.noResults;
|
|
545 | 605 |
} |
546 |
}, |
|
547 |
|
|
548 |
// TODO merge with previousPage |
|
549 |
nextPage: function(event) { |
|
550 |
if (this.hasScroll()) { |
|
551 |
// TODO merge with no-scroll-else |
|
552 |
if (!this.active || this.last()) { |
|
553 |
this.activate(event, this.element.children(".ui-menu-item:first")); |
|
554 |
return; |
|
555 |
} |
|
556 |
var base = this.active.offset().top, |
|
557 |
height = this.element.height(), |
|
558 |
result = this.element.children(".ui-menu-item").filter(function() { |
|
559 |
var close = $(this).offset().top - base - height + $(this).height(); |
|
560 |
// TODO improve approximation |
|
561 |
return close < 10 && close > -10; |
|
562 |
}); |
|
563 |
|
|
564 |
// TODO try to catch this earlier when scrollTop indicates the last page anyway |
|
565 |
if (!result.length) { |
|
566 |
result = this.element.children(".ui-menu-item:last"); |
|
567 |
} |
|
568 |
this.activate(event, result); |
|
569 |
} else { |
|
570 |
this.activate(event, this.element.children(".ui-menu-item") |
|
571 |
.filter(!this.active || this.last() ? ":first" : ":last")); |
|
572 |
} |
|
573 |
}, |
|
574 |
|
|
575 |
// TODO merge with nextPage |
|
576 |
previousPage: function(event) { |
|
577 |
if (this.hasScroll()) { |
|
578 |
// TODO merge with no-scroll-else |
|
579 |
if (!this.active || this.first()) { |
|
580 |
this.activate(event, this.element.children(".ui-menu-item:last")); |
|
581 |
return; |
|
582 |
} |
|
583 |
|
|
584 |
var base = this.active.offset().top, |
|
585 |
height = this.element.height(); |
|
586 |
result = this.element.children(".ui-menu-item").filter(function() { |
|
587 |
var close = $(this).offset().top - base + height - $(this).height(); |
|
588 |
// TODO improve approximation |
|
589 |
return close < 10 && close > -10; |
|
590 |
}); |
|
591 |
|
|
592 |
// TODO try to catch this earlier when scrollTop indicates the last page anyway |
|
593 |
if (!result.length) { |
|
594 |
result = this.element.children(".ui-menu-item:first"); |
|
595 |
} |
|
596 |
this.activate(event, result); |
|
597 |
} else { |
|
598 |
this.activate(event, this.element.children(".ui-menu-item") |
|
599 |
.filter(!this.active || this.first() ? ":last" : ":first")); |
|
600 |
} |
|
601 |
}, |
|
602 |
|
|
603 |
hasScroll: function() { |
|
604 |
return this.element.height() < this.element.attr("scrollHeight"); |
|
605 |
}, |
|
606 |
|
|
607 |
select: function( event ) { |
|
608 |
this._trigger("selected", event, { item: this.active }); |
|
606 |
this.liveRegion.text( message ); |
|
609 | 607 |
} |
610 | 608 |
}); |
611 | 609 |
|
612 |
}(jQuery)); |
|
610 |
}( jQuery )); |
Formats disponibles : Unified diff
Weekly update of contrib modules