
/*
 * jQuery UI Autocomplete @VERSION
 *
 * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 *
 * http://docs.jquery.com/UI/Autocomplete
 *
 * Depends:
 *	jquery.ui.core.js
 *	jquery.ui.widget.js
 *  jquery.ui.position.js
 */
(function( $ ) {

$.widget( "ui.autocomplete", {
	options: {
		minLength: 1,
		delay: 300
	},
	_create: function() {
		var self = this;

		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( "keyup.autocomplete", function( event ) {
				var keyCode = $.ui.keyCode;
				switch( event.keyCode ) {
				case keyCode.PAGE_UP:
					self._move( "previousPage", event );
					self._refreshScrollBar( $(this) );

					break;
				case keyCode.PAGE_DOWN:
					self._move( "nextPage", event );
					self._refreshScrollBar( $(this) );

					break;
				case keyCode.UP:
					self._move( "previous", event );
					self._refreshScrollBar( $(this) );

					// prevent moving cursor to beginning of text field in some browsers
					event.preventDefault();
					break;
				case keyCode.DOWN:
					self._move( "next", event );
					self._refreshScrollBar( $(this) );

					// prevent moving cursor to end of text field in some browsers
					event.preventDefault();
					break;
				case keyCode.ENTER:
					if ( self.menu.active ) {
						event.preventDefault();
					}
				case keyCode.TAB:
					if ( !self.menu.active ) {
						return;
					}
					self.menu.select();
					break;
				case keyCode.ESCAPE:
					self.element.val( self.term );
					self.close( event );
					break;
				case 16:
				case 17:
				case 18:
					// ignore metakeys (shift, ctrl, alt)
					break;
				default:
					self.element.removeAttr('focusMenu');
					// keypress is triggered before the input value is changed
					clearTimeout( self.searching );
					self.searching = setTimeout(function() {
						self.search( null, event );
					}, self.options.delay );
					break;
				}
			})
			.bind( "focus.autocomplete", function() {
				self.previous = self.element.val();
			})
			.bind( "blur.autocomplete", function( event ) {
				clearTimeout( self.searching );
				self.closing = setTimeout(function() {
					self.close( event );
				}, 150 );

			});

		this._initSource();
		this.response = function() {
			return self._response.apply( self, arguments );
		};
		this.menu = $( "<ul></ul>" )
			.addClass( "ui-autocomplete" )
			.appendTo( this.element.parent() )
			.menu({
				focus: function( event, ui ) {
					var item = ui.item.data( "item.autocomplete" );
					if ( item!=undefined && false !== self._trigger( "focus", null, { item: item } ) ) {
						// use value to match what will end up in the input
						self.element.attr('focusMenu','true');
						self.element.focus();
						_beta.fix.db=self.element.val();
						self.element.val( item.value );
					}
				},
				selected: function( event, ui ) {
					var item = ui.item.data( "item.autocomplete" );
					if ( false !== self._trigger( "select", event, { item: item } ) ) {
						self.element.val( item.value );
					}
					_beta.fix.db=self.element.val();

					self.close( event );
					self.element.removeAttr('focusMenu');
					self.previous = self.element.val();
					// only trigger when focus was lost (click on menu)
					if ( self.element[0] != document.activeElement ) {
						self.element.focus();
					}
				}
			})
			.zIndex( this.element.zIndex() + 1 )
			// workaround for jQuery bug #5781 http://dev.jquery.com/ticket/5781
			.css({ top: 0, left: 0 })
			.hide()
			.data( "menu" );

		self.menu.element.bind('mousewheel', function(event, delta) {
			self._refreshScrollBar( $(this) , delta ,true);
			return false;
		});

		if ( $.fn.bgIframe ) {
			 this.menu.element.bgIframe();
		}
	},

	destroy: function() {
		this.element
			.removeClass( "ui-autocomplete-input ui-widget ui-widget-content" )
			.removeAttr( "autocomplete" )
			.removeAttr( "role" )
			.removeAttr( "aria-autocomplete" )
			.removeAttr( "aria-haspopup" );
		this.menu.element.remove();
		$.Widget.prototype.destroy.call( this );
	},

	_setOption: function( key ) {
		$.Widget.prototype._setOption.apply( this, arguments );
		if ( key == "source" ) {
			this._initSource();
		}
	},

	_initSource: function() {
		if ( $.isArray(this.options.source) ) {
			var array = this.options.source;
			this.source = function( request, response ) {
				// escape regex characters
				var matcher = new RegExp( $.ui.autocomplete.escapeRegex(request.term), "i" );
				response( $.grep( array, function(value) {
    				return matcher.test( value.label || value.value || value );
				}) );
			};
		} else if ( typeof this.options.source == "string" ) {
			var url = this.options.source;
			this.source = function( request, response ) {
				$.getJSON( url, request, response );
			};
		} else {
			this.source = this.options.source;
		}
	},

	search: function( value, event ) {
		value = value != null ? value : this.element.val();
		if ( value.length < this.options.minLength ) {
			return this.close( event );
		}

		clearTimeout( this.closing );
		if ( this._trigger("search") === false ) {
			return;
		}

		return this._search( value );
	},

	_search: function( value ) {
		this.term = this.element
			.addClass( "ui-autocomplete-loading" )
			// always save the actual value, not the one passed as an argument
			.val();

		this.source( { term: value }, this.response );
	},

	_response: function( content ) {
		if ( content.length ) {
			content = this._normalize( content );
			this._trigger( "open" );
			this._suggest( content );
		} else {
			this.close();
		}
		this.element.removeClass( "ui-autocomplete-loading" );
	},

	close: function( event ) {
		this.element.removeAttr('focusMenu');

		clearTimeout( this.closing );
		if ( this.menu.element.is(":visible") ) {
			this._trigger( "close", event );
			this.menu.element.hide();
			this.menu.deactivate();
		}
		if ( this.previous != this.element.val() ) {
			this._trigger( "change", event );
		}
	},

	_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 self = this,
		ul = this.menu.element.empty();
		this._renderScrollBar( ul );
		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();
		this.menu.element.show().position({
			my: "left top",
			at: "left bottom",
			of: this.element,
			collision: "none"
		});
		this._refreshScrollBar( ul );
		if ( ul.width() <= this.element.width() ) {
			ul.width( this.element.width() );
		}
	},
	_refreshScrollBar: function ( ul ,delta , onlyrefresh) {
		if(ul.attr('scrollHeight')<=ul.attr('clientHeight')) {
			ul.find('li#top,li#bottom').hide();
		} else {
			ul.find('li#top,li#bottom').show();
		}
		var topv=ul.attr('scrollTop')+(delta!=undefined?(-30*delta):0);

		if(topv<0) topv=0;
 		else if(topv+ul.attr('clientHeight')>ul.attr('scrollHeight')) topv=ul.attr('scrollHeight')-ul.attr('clientHeight');

		if(onlyrefresh!=undefined && onlyrefresh==true) ul.attr("scrollTop", topv);

		ul.find('li#top').css('top',topv);
		ul.find('li#bottom').css('top',topv + ul.attr('clientHeight')).css('marginTop',-22);
		return false;
	},
	_renderScrollBar: function( ul ) {
		var self = this;
		$( "<li id='top'></li>" ).css({
			position: "absolute",
			width: "100%",
			background: "#EEEEEE url("+ENV.STATICPATH+"/images/jqueryui/ui-bg_highlight-soft_100_eeeeee_1x100.png) repeat-x scroll 50% top",
			top: 0,
			textAlign: "center",
			zIndex: 2,
			height: 22,
			overflow: "hidden"
		}).html('<div style="margin:0 auto; background:transparent url('+ENV.STATICPATH+'/images/jqueryui/ui-icons_ef8c08_256x240.png) 0px -16px;text-indent:-600px;width:20px;">top</div>')
			.appendTo( ul );

		$( "<li id='bottom'></li>" ).css({
			position: "absolute",
			width: "100%",
			background: "#EEEEEE url("+ENV.STATICPATH+"/images/jqueryui/ui-bg_highlight-soft_100_eeeeee_1x100.png) repeat-x scroll 50% bottom",
			backgroundColor: "#eeeeee",
			bottom: 0,
			zIndex: 2,
			height: 22,
			overflow: "hidden"
		}).html('<div style="margin:0 auto; background:transparent url('+ENV.STATICPATH+'/images/jqueryui/ui-icons_ef8c08_256x240.png) -64px -16px;text-indent:-600px;width:20px">bottom</div>')
			.appendTo( ul );


	},	
	_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>" + item.label + "</a>" )
			.appendTo( ul );
	},

	_move: function( direction, event ) {
		this.element.attr('focusMenu','true');

		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 ]();
	},

	widget: function() {
		return this.menu.element;
	}
});

$.extend( $.ui.autocomplete, {
	escapeRegex: function( value ) {
		return value.replace( /([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi, "\\$1" );
	}
});

})( 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 (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 *
 * 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: "menu",
				"aria-activedescendant": "ui-active-menuitem"
			})
			.click(function(e) {
				// temporary
				e.preventDefault();
				self.select();
			});

		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() {
				self.activate($(this).parent());
			});
	},

	activate: function(item) {
		
		this.deactivate();
		this.active = item.eq(0)
			.children("a")
				.addClass("ui-state-hover")
				.attr("id", "ui-active-menuitem")
			.end();
		this._trigger("focus", null, { item: item });
		if (this.hasScroll()) {
			var offset = item.offset().top - this.element.offset().top,
				scroll = this.element.attr("scrollTop"),
				elementHeight = this.element.height();
			if (offset < 0) {
				this.element.attr("scrollTop", scroll + offset);
			} else if (offset > elementHeight) {
				this.element.attr("scrollTop", scroll + offset - elementHeight + item.height());
			}
		}
		},

	deactivate: function() {
		if (!this.active) { return; }

		this.active.children("a")
			.removeClass("ui-state-hover")
			.removeAttr("id");
		this.active = null;
	},

	next: function() {
		this.move("next", "li:first");

	},

	previous: function() {
		this.move("prev", "li:last");

	},

	first: function() {
		return this.active && !this.active.prev().length;
	},

	last: function() {
		return this.active && !this.active.next().length;
	},

	move: function(direction, edge) {
		if (!this.active) {
			this.activate(this.element.children(edge));
//			return;
		}
		
		var next = this.active[direction]();

		if(next.eq(0).attr('id')=='top' || next.eq(0).attr('id')=='bottom') {
			this.active=next.eq(0);
			this.move(direction,edge);
			return;
		}

		if (next.length) {
			this.activate(next);
		} else {
			this.activate(this.element.children(edge));
		}
	},

	// TODO merge with previousPage
	nextPage: function() {
		if (this.hasScroll()) {
			// TODO merge with no-scroll-else
			if (!this.active || this.last()) {
				this.activate(this.element.children(":first"));
				return;
			}
			var base = this.active.offset().top,
				height = this.element.height(),
				result = this.element.children("li").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(":last");
			}
			this.activate(result);
		} else {
			this.activate(this.element.children(!this.active || this.last() ? ":first" : ":last"));
		}
	},

	// TODO merge with nextPage
	previousPage: function() {
		if (this.hasScroll()) {
			// TODO merge with no-scroll-else
			if (!this.active || this.first()) {
				this.activate(this.element.children(":last"));
				return;
			}

			var base = this.active.offset().top,
				height = this.element.height();
				result = this.element.children("li").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(":first");
			}
			this.activate(result);
		} else {
			this.activate(this.element.children(!this.active || this.first() ? ":last" : ":first"));
		}
	},

	hasScroll: function() {
		return this.element.height() < this.element.attr("scrollHeight");
	},

	select: function() {

		this._trigger("selected", null, { item: this.active });
	}
});

})(jQuery);

