[SPIP] +2.1.12
[velocampus/web/www.git] / www / plugins / auto / jquery_ui / javascript / jquery-ui-1.8.16 / ui / jquery.ui.autocomplete.js
diff --git a/www/plugins/auto/jquery_ui/javascript/jquery-ui-1.8.16/ui/jquery.ui.autocomplete.js b/www/plugins/auto/jquery_ui/javascript/jquery-ui-1.8.16/ui/jquery.ui.autocomplete.js
new file mode 100644 (file)
index 0000000..edf7976
--- /dev/null
@@ -0,0 +1,612 @@
+/*
+ * jQuery UI Autocomplete 1.8.16
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Autocomplete
+ *
+ * Depends:
+ *     jquery.ui.core.js
+ *     jquery.ui.widget.js
+ *     jquery.ui.position.js
+ */
+(function( $, undefined ) {
+
+// used to prevent race conditions with remote data sources
+var requestIndex = 0;
+
+$.widget( "ui.autocomplete", {
+       options: {
+               appendTo: "body",
+               autoFocus: false,
+               delay: 300,
+               minLength: 1,
+               position: {
+                       my: "left top",
+                       at: "left bottom",
+                       collision: "none"
+               },
+               source: null
+       },
+
+       pending: 0,
+
+       _create: function() {
+               var self = this,
+                       doc = this.element[ 0 ].ownerDocument,
+                       suppressKeyPress;
+
+               this.element
+                       .addClass( "ui-autocomplete-input" )
+                       .attr( "autocomplete", "off" )
+                       // TODO verify these actually work as intended
+                       .attr({
+                               role: "textbox",
+                               "aria-autocomplete": "list",
+                               "aria-haspopup": "true"
+                       })
+                       .bind( "keydown.autocomplete", function( event ) {
+                               if ( self.options.disabled || self.element.propAttr( "readOnly" ) ) {
+                                       return;
+                               }
+
+                               suppressKeyPress = false;
+                               var keyCode = $.ui.keyCode;
+                               switch( event.keyCode ) {
+                               case keyCode.PAGE_UP:
+                                       self._move( "previousPage", event );
+                                       break;
+                               case keyCode.PAGE_DOWN:
+                                       self._move( "nextPage", event );
+                                       break;
+                               case keyCode.UP:
+                                       self._move( "previous", event );
+                                       // prevent moving cursor to beginning of text field in some browsers
+                                       event.preventDefault();
+                                       break;
+                               case keyCode.DOWN:
+                                       self._move( "next", event );
+                                       // prevent moving cursor to end of text field in some browsers
+                                       event.preventDefault();
+                                       break;
+                               case keyCode.ENTER:
+                               case keyCode.NUMPAD_ENTER:
+                                       // when menu is open and has focus
+                                       if ( self.menu.active ) {
+                                               // #6055 - Opera still allows the keypress to occur
+                                               // which causes forms to submit
+                                               suppressKeyPress = true;
+                                               event.preventDefault();
+                                       }
+                                       //passthrough - ENTER and TAB both select the current element
+                               case keyCode.TAB:
+                                       if ( !self.menu.active ) {
+                                               return;
+                                       }
+                                       self.menu.select( event );
+                                       break;
+                               case keyCode.ESCAPE:
+                                       self.element.val( self.term );
+                                       self.close( event );
+                                       break;
+                               default:
+                                       // keypress is triggered before the input value is changed
+                                       clearTimeout( self.searching );
+                                       self.searching = setTimeout(function() {
+                                               // only search if the value has changed
+                                               if ( self.term != self.element.val() ) {
+                                                       self.selectedItem = null;
+                                                       self.search( null, event );
+                                               }
+                                       }, self.options.delay );
+                                       break;
+                               }
+                       })
+                       .bind( "keypress.autocomplete", function( event ) {
+                               if ( suppressKeyPress ) {
+                                       suppressKeyPress = false;
+                                       event.preventDefault();
+                               }
+                       })
+                       .bind( "focus.autocomplete", function() {
+                               if ( self.options.disabled ) {
+                                       return;
+                               }
+
+                               self.selectedItem = null;
+                               self.previous = self.element.val();
+                       })
+                       .bind( "blur.autocomplete", function( event ) {
+                               if ( self.options.disabled ) {
+                                       return;
+                               }
+
+                               clearTimeout( self.searching );
+                               // clicks on the menu (or a button to trigger a search) will cause a blur event
+                               self.closing = setTimeout(function() {
+                                       self.close( event );
+                                       self._change( event );
+                               }, 150 );
+                       });
+               this._initSource();
+               this.response = function() {
+                       return self._response.apply( self, arguments );
+               };
+               this.menu = $( "<ul></ul>" )
+                       .addClass( "ui-autocomplete" )
+                       .appendTo( $( this.options.appendTo || "body", doc )[0] )
+                       // prevent the close-on-blur in case of a "slow" click on the menu (long mousedown)
+                       .mousedown(function( event ) {
+                               // clicking on the scrollbar causes focus to shift to the body
+                               // but we can't detect a mouseup or a click immediately afterward
+                               // so we have to track the next mousedown and close the menu if
+                               // the user clicks somewhere outside of the autocomplete
+                               var menuElement = self.menu.element[ 0 ];
+                               if ( !$( event.target ).closest( ".ui-menu-item" ).length ) {
+                                       setTimeout(function() {
+                                               $( document ).one( 'mousedown', function( event ) {
+                                                       if ( event.target !== self.element[ 0 ] &&
+                                                               event.target !== menuElement &&
+                                                               !$.ui.contains( menuElement, event.target ) ) {
+                                                               self.close();
+                                                       }
+                                               });
+                                       }, 1 );
+                               }
+
+                               // use another timeout to make sure the blur-event-handler on the input was already triggered
+                               setTimeout(function() {
+                                       clearTimeout( self.closing );
+                               }, 13);
+                       })
+                       .menu({
+                               focus: function( event, ui ) {
+                                       var item = ui.item.data( "item.autocomplete" );
+                                       if ( false !== self._trigger( "focus", event, { item: item } ) ) {
+                                               // use value to match what will end up in the input, if it was a key event
+                                               if ( /^key/.test(event.originalEvent.type) ) {
+                                                       self.element.val( item.value );
+                                               }
+                                       }
+                               },
+                               selected: function( event, ui ) {
+                                       var item = ui.item.data( "item.autocomplete" ),
+                                               previous = self.previous;
+
+                                       // only trigger when focus was lost (click on menu)
+                                       if ( self.element[0] !== doc.activeElement ) {
+                                               self.element.focus();
+                                               self.previous = previous;
+                                               // #6109 - IE triggers two focus events and the second
+                                               // is asynchronous, so we need to reset the previous
+                                               // term synchronously and asynchronously :-(
+                                               setTimeout(function() {
+                                                       self.previous = previous;
+                                                       self.selectedItem = item;
+                                               }, 1);
+                                       }
+
+                                       if ( false !== self._trigger( "select", event, { item: item } ) ) {
+                                               self.element.val( item.value );
+                                       }
+                                       // reset the term after the select event
+                                       // this allows custom select handling to work properly
+                                       self.term = self.element.val();
+
+                                       self.close( event );
+                                       self.selectedItem = item;
+                               },
+                               blur: function( event, ui ) {
+                                       // don't set the value of the text field if it's already correct
+                                       // this prevents moving the cursor unnecessarily
+                                       if ( self.menu.element.is(":visible") &&
+                                               ( self.element.val() !== self.term ) ) {
+                                               self.element.val( self.term );
+                                       }
+                               }
+                       })
+                       .zIndex( this.element.zIndex() + 1 )
+                       // workaround for jQuery bug #5781 http://dev.jquery.com/ticket/5781
+                       .css({ top: 0, left: 0 })
+                       .hide()
+                       .data( "menu" );
+               if ( $.fn.bgiframe ) {
+                        this.menu.element.bgiframe();
+               }
+       },
+
+       destroy: function() {
+               this.element
+                       .removeClass( "ui-autocomplete-input" )
+                       .removeAttr( "autocomplete" )
+                       .removeAttr( "role" )
+                       .removeAttr( "aria-autocomplete" )
+                       .removeAttr( "aria-haspopup" );
+               this.menu.element.remove();
+               $.Widget.prototype.destroy.call( this );
+       },
+
+       _setOption: function( key, value ) {
+               $.Widget.prototype._setOption.apply( this, arguments );
+               if ( key === "source" ) {
+                       this._initSource();
+               }
+               if ( key === "appendTo" ) {
+                       this.menu.element.appendTo( $( value || "body", this.element[0].ownerDocument )[0] )
+               }
+               if ( key === "disabled" && value && this.xhr ) {
+                       this.xhr.abort();
+               }
+       },
+
+       _initSource: function() {
+               var self = this,
+                       array,
+                       url;
+               if ( $.isArray(this.options.source) ) {
+                       array = this.options.source;
+                       this.source = function( request, response ) {
+                               response( $.ui.autocomplete.filter(array, request.term) );
+                       };
+               } else if ( typeof this.options.source === "string" ) {
+                       url = this.options.source;
+                       this.source = function( request, response ) {
+                               if ( self.xhr ) {
+                                       self.xhr.abort();
+                               }
+                               self.xhr = $.ajax({
+                                       url: url,
+                                       data: request,
+                                       dataType: "json",
+                                       autocompleteRequest: ++requestIndex,
+                                       success: function( data, status ) {
+                                               if ( this.autocompleteRequest === requestIndex ) {
+                                                       response( data );
+                                               }
+                                       },
+                                       error: function() {
+                                               if ( this.autocompleteRequest === requestIndex ) {
+                                                       response( [] );
+                                               }
+                                       }
+                               });
+                       };
+               } else {
+                       this.source = this.options.source;
+               }
+       },
+
+       search: function( value, event ) {
+               value = value != null ? value : this.element.val();
+
+               // always save the actual value, not the one passed as an argument
+               this.term = this.element.val();
+
+               if ( value.length < this.options.minLength ) {
+                       return this.close( event );
+               }
+
+               clearTimeout( this.closing );
+               if ( this._trigger( "search", event ) === false ) {
+                       return;
+               }
+
+               return this._search( value );
+       },
+
+       _search: function( value ) {
+               this.pending++;
+               this.element.addClass( "ui-autocomplete-loading" );
+
+               this.source( { term: value }, this.response );
+       },
+
+       _response: function( content ) {
+               if ( !this.options.disabled && content && content.length ) {
+                       content = this._normalize( content );
+                       this._suggest( content );
+                       this._trigger( "open" );
+               } else {
+                       this.close();
+               }
+               this.pending--;
+               if ( !this.pending ) {
+                       this.element.removeClass( "ui-autocomplete-loading" );
+               }
+       },
+
+       close: function( event ) {
+               clearTimeout( this.closing );
+               if ( this.menu.element.is(":visible") ) {
+                       this.menu.element.hide();
+                       this.menu.deactivate();
+                       this._trigger( "close", event );
+               }
+       },
+       
+       _change: function( event ) {
+               if ( this.previous !== this.element.val() ) {
+                       this._trigger( "change", event, { item: this.selectedItem } );
+               }
+       },
+
+       _normalize: function( items ) {
+               // assume all items have the right format when the first item is complete
+               if ( items.length && items[0].label && items[0].value ) {
+                       return items;
+               }
+               return $.map( items, function(item) {
+                       if ( typeof item === "string" ) {
+                               return {
+                                       label: item,
+                                       value: item
+                               };
+                       }
+                       return $.extend({
+                               label: item.label || item.value,
+                               value: item.value || item.label
+                       }, item );
+               });
+       },
+
+       _suggest: function( items ) {
+               var ul = this.menu.element
+                       .empty()
+                       .zIndex( this.element.zIndex() + 1 );
+               this._renderMenu( ul, items );
+               // TODO refresh should check if the active item is still in the dom, removing the need for a manual deactivate
+               this.menu.deactivate();
+               this.menu.refresh();
+
+               // size and position menu
+               ul.show();
+               this._resizeMenu();
+               ul.position( $.extend({
+                       of: this.element
+               }, this.options.position ));
+
+               if ( this.options.autoFocus ) {
+                       this.menu.next( new $.Event("mouseover") );
+               }
+       },
+
+       _resizeMenu: function() {
+               var ul = this.menu.element;
+               ul.outerWidth( Math.max(
+                       ul.width( "" ).outerWidth(),
+                       this.element.outerWidth()
+               ) );
+       },
+
+       _renderMenu: function( ul, items ) {
+               var self = this;
+               $.each( items, function( index, item ) {
+                       self._renderItem( ul, item );
+               });
+       },
+
+       _renderItem: function( ul, item) {
+               return $( "<li></li>" )
+                       .data( "item.autocomplete", item )
+                       .append( $( "<a></a>" ).text( item.label ) )
+                       .appendTo( ul );
+       },
+
+       _move: function( direction, event ) {
+               if ( !this.menu.element.is(":visible") ) {
+                       this.search( null, event );
+                       return;
+               }
+               if ( this.menu.first() && /^previous/.test(direction) ||
+                               this.menu.last() && /^next/.test(direction) ) {
+                       this.element.val( this.term );
+                       this.menu.deactivate();
+                       return;
+               }
+               this.menu[ direction ]( event );
+       },
+
+       widget: function() {
+               return this.menu.element;
+       }
+});
+
+$.extend( $.ui.autocomplete, {
+       escapeRegex: function( value ) {
+               return value.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
+       },
+       filter: function(array, term) {
+               var matcher = new RegExp( $.ui.autocomplete.escapeRegex(term), "i" );
+               return $.grep( array, function(value) {
+                       return matcher.test( value.label || value.value || value );
+               });
+       }
+});
+
+}( jQuery ));
+
+/*
+ * jQuery UI Menu (not officially released)
+ * 
+ * This widget isn't yet finished and the API is subject to change. We plan to finish
+ * it for the next release. You're welcome to give it a try anyway and give us feedback,
+ * as long as you're okay with migrating your code later on. We can help with that, too.
+ *
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Menu
+ *
+ * Depends:
+ *     jquery.ui.core.js
+ *  jquery.ui.widget.js
+ */
+(function($) {
+
+$.widget("ui.menu", {
+       _create: function() {
+               var self = this;
+               this.element
+                       .addClass("ui-menu ui-widget ui-widget-content ui-corner-all")
+                       .attr({
+                               role: "listbox",
+                               "aria-activedescendant": "ui-active-menuitem"
+                       })
+                       .click(function( event ) {
+                               if ( !$( event.target ).closest( ".ui-menu-item a" ).length ) {
+                                       return;
+                               }
+                               // temporary
+                               event.preventDefault();
+                               self.select( event );
+                       });
+               this.refresh();
+       },
+       
+       refresh: function() {
+               var self = this;
+
+               // don't refresh list items that are already adapted
+               var items = this.element.children("li:not(.ui-menu-item):has(a)")
+                       .addClass("ui-menu-item")
+                       .attr("role", "menuitem");
+               
+               items.children("a")
+                       .addClass("ui-corner-all")
+                       .attr("tabindex", -1)
+                       // mouseenter doesn't work with event delegation
+                       .mouseenter(function( event ) {
+                               self.activate( event, $(this).parent() );
+                       })
+                       .mouseleave(function() {
+                               self.deactivate();
+                       });
+       },
+
+       activate: function( event, item ) {
+               this.deactivate();
+               if (this.hasScroll()) {
+                       var offset = item.offset().top - this.element.offset().top,
+                               scroll = this.element.scrollTop(),
+                               elementHeight = this.element.height();
+                       if (offset < 0) {
+                               this.element.scrollTop( scroll + offset);
+                       } else if (offset >= elementHeight) {
+                               this.element.scrollTop( scroll + offset - elementHeight + item.height());
+                       }
+               }
+               this.active = item.eq(0)
+                       .children("a")
+                               .addClass("ui-state-hover")
+                               .attr("id", "ui-active-menuitem")
+                       .end();
+               this._trigger("focus", event, { item: item });
+       },
+
+       deactivate: function() {
+               if (!this.active) { return; }
+
+               this.active.children("a")
+                       .removeClass("ui-state-hover")
+                       .removeAttr("id");
+               this._trigger("blur");
+               this.active = null;
+       },
+
+       next: function(event) {
+               this.move("next", ".ui-menu-item:first", event);
+       },
+
+       previous: function(event) {
+               this.move("prev", ".ui-menu-item:last", event);
+       },
+
+       first: function() {
+               return this.active && !this.active.prevAll(".ui-menu-item").length;
+       },
+
+       last: function() {
+               return this.active && !this.active.nextAll(".ui-menu-item").length;
+       },
+
+       move: function(direction, edge, event) {
+               if (!this.active) {
+                       this.activate(event, this.element.children(edge));
+                       return;
+               }
+               var next = this.active[direction + "All"](".ui-menu-item").eq(0);
+               if (next.length) {
+                       this.activate(event, next);
+               } else {
+                       this.activate(event, this.element.children(edge));
+               }
+       },
+
+       // TODO merge with previousPage
+       nextPage: function(event) {
+               if (this.hasScroll()) {
+                       // TODO merge with no-scroll-else
+                       if (!this.active || this.last()) {
+                               this.activate(event, this.element.children(".ui-menu-item:first"));
+                               return;
+                       }
+                       var base = this.active.offset().top,
+                               height = this.element.height(),
+                               result = this.element.children(".ui-menu-item").filter(function() {
+                                       var close = $(this).offset().top - base - height + $(this).height();
+                                       // TODO improve approximation
+                                       return close < 10 && close > -10;
+                               });
+
+                       // TODO try to catch this earlier when scrollTop indicates the last page anyway
+                       if (!result.length) {
+                               result = this.element.children(".ui-menu-item:last");
+                       }
+                       this.activate(event, result);
+               } else {
+                       this.activate(event, this.element.children(".ui-menu-item")
+                               .filter(!this.active || this.last() ? ":first" : ":last"));
+               }
+       },
+
+       // TODO merge with nextPage
+       previousPage: function(event) {
+               if (this.hasScroll()) {
+                       // TODO merge with no-scroll-else
+                       if (!this.active || this.first()) {
+                               this.activate(event, this.element.children(".ui-menu-item:last"));
+                               return;
+                       }
+
+                       var base = this.active.offset().top,
+                               height = this.element.height();
+                               result = this.element.children(".ui-menu-item").filter(function() {
+                                       var close = $(this).offset().top - base + height - $(this).height();
+                                       // TODO improve approximation
+                                       return close < 10 && close > -10;
+                               });
+
+                       // TODO try to catch this earlier when scrollTop indicates the last page anyway
+                       if (!result.length) {
+                               result = this.element.children(".ui-menu-item:first");
+                       }
+                       this.activate(event, result);
+               } else {
+                       this.activate(event, this.element.children(".ui-menu-item")
+                               .filter(!this.active || this.first() ? ":last" : ":first"));
+               }
+       },
+
+       hasScroll: function() {
+               return this.element.height() < this.element[ $.fn.prop ? "prop" : "attr" ]("scrollHeight");
+       },
+
+       select: function( event ) {
+               this._trigger("selected", event, { item: this.active });
+       }
+});
+
+}(jQuery));