includes/clientside/static/SpryAutoSuggest.js
changeset 581 5e8fd89c02ea
equal deleted inserted replaced
580:41c45314ac27 581:5e8fd89c02ea
       
     1 // SpryAutoSuggest.js - version 0.91 - Spry Pre-Release 1.6.1
       
     2 //
       
     3 // Copyright (c) 2006. Adobe Systems Incorporated.
       
     4 // All rights reserved.
       
     5 //
       
     6 // Redistribution and use in source and binary forms, with or without
       
     7 // modification, are permitted provided that the following conditions are met:
       
     8 //
       
     9 //   * Redistributions of source code must retain the above copyright notice,
       
    10 //     this list of conditions and the following disclaimer.
       
    11 //   * Redistributions in binary form must reproduce the above copyright notice,
       
    12 //     this list of conditions and the following disclaimer in the documentation
       
    13 //     and/or other materials provided with the distribution.
       
    14 //   * Neither the name of Adobe Systems Incorporated nor the names of its
       
    15 //     contributors may be used to endorse or promote products derived from this
       
    16 //     software without specific prior written permission.
       
    17 //
       
    18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
       
    19 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
       
    20 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
       
    21 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
       
    22 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
       
    23 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
       
    24 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
       
    25 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
       
    26 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
       
    27 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
       
    28 // POSSIBILITY OF SUCH DAMAGE.
       
    29 
       
    30 var Spry;
       
    31 if (!Spry) Spry = {};
       
    32 if (!Spry.Widget) Spry.Widget = {};
       
    33 
       
    34 Spry.Widget.BrowserSniff = function()
       
    35 {
       
    36 	var b = navigator.appName.toString();
       
    37 	var up = navigator.platform.toString();
       
    38 	var ua = navigator.userAgent.toString();
       
    39 
       
    40 	this.mozilla = this.ie = this.opera = this.safari = false;
       
    41 	var re_opera = /Opera.([0-9\.]*)/i;
       
    42 	var re_msie = /MSIE.([0-9\.]*)/i;
       
    43 	var re_gecko = /gecko/i;
       
    44 	var re_safari = /(applewebkit|safari)\/([\d\.]*)/i;
       
    45 	var r = false;
       
    46 
       
    47 	if ( (r = ua.match(re_opera))) {
       
    48 		this.opera = true;
       
    49 		this.version = parseFloat(r[1]);
       
    50 	} else if ( (r = ua.match(re_msie))) {
       
    51 		this.ie = true;
       
    52 		this.version = parseFloat(r[1]);
       
    53 	} else if ( (r = ua.match(re_safari))) {
       
    54 		this.safari = true;
       
    55 		this.version = parseFloat(r[2]);
       
    56 	} else if (ua.match(re_gecko)) {
       
    57 		var re_gecko_version = /rv:\s*([0-9\.]+)/i;
       
    58 		r = ua.match(re_gecko_version);
       
    59 		this.mozilla = true;
       
    60 		this.version = parseFloat(r[1]);
       
    61 	}
       
    62 	this.windows = this.mac = this.linux = false;
       
    63 
       
    64 	this.Platform = ua.match(/windows/i) ? "windows" :
       
    65 					(ua.match(/linux/i) ? "linux" :
       
    66 					(ua.match(/mac/i) ? "mac" :
       
    67 					ua.match(/unix/i)? "unix" : "unknown"));
       
    68 	this[this.Platform] = true;
       
    69 	this.v = this.version;
       
    70 
       
    71 	if (this.safari && this.mac && this.mozilla) {
       
    72 		this.mozilla = false;
       
    73 	}
       
    74 };
       
    75 
       
    76 Spry.is = new Spry.Widget.BrowserSniff();
       
    77 
       
    78 Spry.Widget.AutoSuggest = function(region, sRegion, dataset, field, options)
       
    79 {
       
    80 	if (!this.isBrowserSupported())
       
    81 		return;
       
    82 
       
    83 	options = options || {};
       
    84 
       
    85 	this.init(region, sRegion, dataset, field);
       
    86 	Spry.Widget.Utils.setOptions(this, options);
       
    87 
       
    88 	if (Spry.Widget.AutoSuggest.onloadDidFire)
       
    89 		this.attachBehaviors();
       
    90 	else 
       
    91 		Spry.Widget.AutoSuggest.loadQueue.push(this);
       
    92 
       
    93 	// when data is changing we will decide if we will have to show the suggestions
       
    94 	this.dataset.addObserver(this);
       
    95 	
       
    96 	// Set up an observer so we can attach our click behaviors whenever
       
    97 	// the region is regenerated.
       
    98 	var regionID = Spry.Widget.Utils.getElementID(sRegion);
       
    99 
       
   100 	var self = this;
       
   101 	this._notifyDataset = { onPostUpdate: function() {
       
   102 			self.attachClickBehaviors();
       
   103 	}, onPreUpdate: function(){
       
   104 			self.removeClickBehaviours();
       
   105 	}};
       
   106 
       
   107 	Spry.Data.Region.addObserver(regionID,this._notifyDataset);
       
   108 
       
   109 	// clean up the widget when on page unload
       
   110 	Spry.Widget.Utils.addEventListener(window, 'unload', function(){self.destroy()}, false);
       
   111 
       
   112 	// make the first computation in case the textfield is not empty
       
   113 	this.attachClickBehaviors();
       
   114 	this.handleKeyUp(null);
       
   115 	this.showSuggestions(false);
       
   116 };
       
   117 
       
   118 Spry.Widget.AutoSuggest.prototype.init = function(region, sRegion, dataset, field)
       
   119 {
       
   120 	this.region = Spry.Widget.Utils.getElement(region);
       
   121 	
       
   122 	if (!this.region)
       
   123 		return;
       
   124 	
       
   125 	this.minCharsType = false;
       
   126 	this.containsString = false;
       
   127 	this.loadFromServer = false;
       
   128 	this.urlParam = '';
       
   129 	this.suggestionIsVisible = false;
       
   130 	this.stopFocus = false;
       
   131 	this.hasFocus = false;
       
   132 	this.showSuggestClass = 'showSuggestClass';
       
   133 	this.hideSuggestClass = 'hideSuggestClass';
       
   134 	this.hoverSuggestClass = 'hoverSuggestClass';
       
   135 	this.movePrevKeyCode = Spry.Widget.AutoSuggest.KEY_UP;
       
   136 	this.moveNextKeyCode = Spry.Widget.AutoSuggest.KEY_DOWN;
       
   137 
       
   138 	this.textElement = Spry.Widget.Utils.getFirstChildWithNodeNameAtAnyLevel(this.region, "INPUT");
       
   139 	this.textElement.setAttribute('AutoComplete', 'off');
       
   140 	
       
   141 	this.suggestRegion = Spry.Widget.Utils.getElement(sRegion);
       
   142 	// prepare the suggest region
       
   143 	Spry.Widget.Utils.makePositioned(this.suggestRegion);
       
   144 	Spry.Widget.Utils.addClassName(this.suggestRegion, this.hideSuggestClass);
       
   145 
       
   146 	this.timerID = null;
       
   147 	if (typeof dataset == "string"){
       
   148 		this.dataset = window[dataset];
       
   149 	}else{
       
   150 		this.dataset = dataset;
       
   151 	}
       
   152 	this.field = field;
       
   153 	if (typeof field == 'string' && field.indexOf(',') != -1)
       
   154 	{
       
   155 		field = field.replace(/\s*,\s*/ig, ',');
       
   156 		this.field = field.split(',');
       
   157 	}
       
   158 };
       
   159 
       
   160 Spry.Widget.AutoSuggest.prototype.isBrowserSupported = function()
       
   161 {
       
   162 	return Spry.is.ie && Spry.is.v >= 5 && Spry.is.windows
       
   163 		||
       
   164 	Spry.is.mozilla && Spry.is.v >= 1.4
       
   165 		||
       
   166 	Spry.is.safari
       
   167 		||
       
   168 	Spry.is.opera && Spry.is.v >= 9;
       
   169 };
       
   170 
       
   171 Spry.Widget.AutoSuggest.prototype.getValue = function()
       
   172 {
       
   173 	if (!this.textElement)
       
   174 		return '';
       
   175 	return this.textElement.value;
       
   176 };
       
   177 
       
   178 Spry.Widget.AutoSuggest.prototype.setValue = function(str)
       
   179 {
       
   180 	if (!this.textElement)
       
   181 		return;
       
   182 	this.textElement.value = str;
       
   183 	this.showSuggestions(false);
       
   184 };
       
   185 
       
   186 Spry.Widget.AutoSuggest.prototype.focus = function()
       
   187 {
       
   188 	if (!this.textElement)
       
   189 		return;
       
   190 	this.textElement.focus();
       
   191 };
       
   192 
       
   193 Spry.Widget.AutoSuggest.prototype.showSuggestions = function(doShow)
       
   194 {
       
   195 	if (this.region && this.isVisibleSuggestion() != doShow)
       
   196 	{
       
   197 		if (doShow && this.hasFocus)
       
   198 		{
       
   199 				Spry.Widget.Utils.addClassName(this.region, this.showSuggestClass);
       
   200 				if (Spry.is.ie && Spry.is.version < 7)
       
   201 					this.createIframeLayer(this.suggestRegion);
       
   202 		}
       
   203 		else
       
   204 		{
       
   205 				if (Spry.is.ie && Spry.is.version < 7)
       
   206 					this.removeIframeLayer();
       
   207 				Spry.Widget.Utils.removeClassName(this.region, this.showSuggestClass);
       
   208 		}
       
   209 	}
       
   210 	this.suggestionIsVisible = Spry.Widget.Utils.hasClassName(this.region, this.showSuggestClass);
       
   211 };
       
   212 
       
   213 Spry.Widget.AutoSuggest.prototype.isVisibleSuggestion = function()
       
   214 {
       
   215 	return this.suggestionIsVisible;
       
   216 };
       
   217 
       
   218 Spry.Widget.AutoSuggest.prototype.onDataChanged = function(el)
       
   219 {
       
   220 		var data = el.getData(true);
       
   221 		var val = this.getValue();
       
   222 		this.showSuggestions(data && (!this.minCharsType || val.length >= this.minCharsType) && (data.length > 1 || (data.length == 1 && this.childs[0] && this.childs[0].attributes.getNamedItem("spry:suggest").value != this.getValue())));
       
   223 };
       
   224 Spry.Widget.AutoSuggest.prototype.nodeMouseOver = function(e, node)
       
   225 {
       
   226 	var l = this.childs.length;
       
   227 	for (var i=0; i<l; i++)
       
   228 		if (this.childs[i] != node && Spry.Widget.Utils.hasClassName(this.childs[i], this.hoverSuggestClass))
       
   229 		{
       
   230 			Spry.Widget.Utils.removeClassName(this.childs[i], this.hoverSuggestClass);
       
   231 			break;
       
   232 		}
       
   233 };
       
   234 Spry.Widget.AutoSuggest.prototype.nodeClick = function(e, value) 
       
   235 {
       
   236 	if (value)
       
   237 		this.setValue(value);
       
   238 };
       
   239 Spry.Widget.AutoSuggest.prototype.handleKeyUp = function(e)
       
   240 {
       
   241 	if (this.timerID)
       
   242 	{
       
   243 		clearTimeout(this.timerID);
       
   244 		this.timerID = null;
       
   245 	}
       
   246 
       
   247 	// If the user hit the escape key, hide the auto suggest menu!
       
   248 	if (e && this.isSpecialKey(e))
       
   249 	{
       
   250 		this.handleSpecialKeys(e);
       
   251 		return;
       
   252 	}
       
   253 
       
   254 	var self = this;
       
   255 	var func = function() { self.timerID = null; self.loadDataSet();};
       
   256 	if (!this.loadFromServer)
       
   257 		func = function() { self.timerID = null; self.filterDataSet();};
       
   258 
       
   259 	this.timerID = setTimeout(func, 200);
       
   260 	
       
   261 };
       
   262 
       
   263 Spry.Widget.AutoSuggest.prototype.scrollVisible = function(el)
       
   264 {
       
   265 	if (typeof this.scrolParent == 'undefined')
       
   266 	{
       
   267 		var currEl = el;
       
   268 		this.scrolParent = false;
       
   269 		while	(!this.scrolParent)
       
   270 		{
       
   271 			var overflow = Spry.Widget.Utils.getStyleProp(currEl, 'overflow');
       
   272 			if (!overflow || overflow.toLowerCase() == 'scroll')
       
   273 			{
       
   274 					this.scrolParent = currEl;
       
   275 					break;
       
   276 			}
       
   277 			if (currEl == this.region) 
       
   278 				break;
       
   279 			
       
   280 			currEl = currEl.parentNode;
       
   281 		}
       
   282 	}
       
   283 
       
   284 	if (this.scrolParent != false)
       
   285 	{
       
   286 		var h = parseInt(Spry.Widget.Utils.getStyleProp(this.scrolParent, 'height'), 10);
       
   287 		if (el.offsetTop < this.scrolParent.scrollTop)
       
   288 			this.scrolParent.scrollTop = el.offsetTop;
       
   289 		else if (el.offsetTop + el.offsetHeight > this.scrolParent.scrollTop + h)
       
   290 		{
       
   291 			// the 5 pixels make the latest option more visible.
       
   292 			this.scrolParent.scrollTop = el.offsetTop + el.offsetHeight - h + 5;
       
   293 			if (this.scrolParent.scrollTop < 0)
       
   294 				this.scrolParent.scrollTop = 0;	
       
   295 		}
       
   296 
       
   297 	}
       
   298 };
       
   299 
       
   300 Spry.Widget.AutoSuggest.KEY_UP = 38;
       
   301 Spry.Widget.AutoSuggest.KEY_DOWN = 40;
       
   302 
       
   303 Spry.Widget.AutoSuggest.prototype.handleSpecialKeys = function(e){
       
   304 
       
   305  	switch (e.keyCode)
       
   306 	{
       
   307 		case this.moveNextKeyCode: // Down key  
       
   308  		case this.movePrevKeyCode: // Up Key
       
   309 			if (!(this.childs.length > 0) || !this.getValue())
       
   310 				return;	
       
   311 
       
   312 			var prev = this.childs.length-1;
       
   313 			var next = false;
       
   314 			var found = false;
       
   315 			var data = this.dataset.getData();
       
   316 			if (this.childs.length > 1 || (data && data.length == 1 && this.childs[0] && this.childs[0].attributes.getNamedItem('spry:suggest').value != this.getValue()))
       
   317 			{
       
   318 				this.showSuggestions(true);
       
   319 			}
       
   320 			else
       
   321 				return;	
       
   322 			
       
   323 			var utils = Spry.Widget.Utils;
       
   324 			for (var k=0; k < this.childs.length; k++)
       
   325 			{
       
   326 				if (next)
       
   327 				{
       
   328 					utils.addClassName(this.childs[k], this.hoverSuggestClass);
       
   329 					this.scrollVisible(this.childs[k]);
       
   330 					break;
       
   331 				}
       
   332 				if (utils.hasClassName(this.childs[k], this.hoverSuggestClass))
       
   333 				{
       
   334 					utils.removeClassName(this.childs[k], this.hoverSuggestClass);
       
   335 					found = true;
       
   336 					if (e.keyCode == this.moveNextKeyCode)
       
   337 					{
       
   338 						next = true;
       
   339 						continue;
       
   340 					}
       
   341 					else
       
   342 					{
       
   343 						utils.addClassName(this.childs[prev], this.hoverSuggestClass);
       
   344 						this.scrollVisible(this.childs[prev]);
       
   345 						break;
       
   346 					}
       
   347 				}
       
   348 				prev = k;
       
   349 			}
       
   350 			if (!found || (next && k == this.childs.length))
       
   351 			{
       
   352 				utils.addClassName(this.childs[0], this.hoverSuggestClass);
       
   353 				this.scrollVisible(this.childs[0]);
       
   354 			}
       
   355 			utils.stopEvent(e);
       
   356 			break;
       
   357 		case 27: // ESC key
       
   358 			this.showSuggestions(false);
       
   359 			break;
       
   360 		case 13: //Enter Key
       
   361 			if (!this.isVisibleSuggestion()) 
       
   362 				return;
       
   363 			for (var k=0; k < this.childs.length; k++)
       
   364 				if (Spry.Widget.Utils.hasClassName(this.childs[k], this.hoverSuggestClass))
       
   365 				{
       
   366 					var attr = this.childs[k].attributes.getNamedItem('spry:suggest');
       
   367 					if (attr){
       
   368 						this.setValue(attr.value);
       
   369 						this.handleKeyUp(null);
       
   370 					}
       
   371 					// stop form submission
       
   372 					Spry.Widget.Utils.stopEvent(e);
       
   373 					return false;
       
   374 				}
       
   375 			break;
       
   376 		case 9: //Tab Key
       
   377 			this.showSuggestions(false);
       
   378 	}
       
   379 	return;
       
   380 };
       
   381 
       
   382 Spry.Widget.AutoSuggest.prototype.filterDataSet = function()
       
   383 {
       
   384 	var contains = this.containsString;
       
   385 	var columnName = this.field;
       
   386 	var val = this.getValue();
       
   387 
       
   388 	if (this.previousString && this.previousString == val)
       
   389 		return;
       
   390 
       
   391 	this.previousString = val;
       
   392 
       
   393 	if (!val || (this.minCharsType && this.minCharsType > val.length))
       
   394 	{
       
   395 		this.dataset.filter(function(ds, row, rowNumber) {return null;});
       
   396 		this.showSuggestions(false);
       
   397 		return;
       
   398 	}
       
   399 
       
   400 	var regExpStr = Spry.Widget.Utils.escapeRegExp(val);
       
   401 
       
   402 	if (!contains)
       
   403 	 	regExpStr = "^" + regExpStr;
       
   404 
       
   405 	var regExp = new RegExp(regExpStr, "ig");
       
   406 	
       
   407 	if (this.maxListItems > 0)
       
   408 		this.dataset.maxItems = this.maxListItems;
       
   409 
       
   410 	var filterFunc = function(ds, row, rowNumber)
       
   411 	{
       
   412 		if (ds.maxItems >0  && ds.maxItems <= ds.data.length)
       
   413 			return null;
       
   414 
       
   415 		if (typeof columnName == 'object')
       
   416 		{
       
   417 			var l = columnName.length;
       
   418 			for (var i=0; i < l; i++)
       
   419 			{
       
   420 				var str = row[columnName[i]];
       
   421 				if (str && str.search(regExp) != -1)
       
   422 					return row;
       
   423 			}
       
   424 		}
       
   425 		else
       
   426 		{
       
   427 			var str = row[columnName];
       
   428 			if (str && str.search(regExp) != -1)
       
   429 				return row;
       
   430 		}
       
   431 		return null; 
       
   432 	};
       
   433 
       
   434 	this.dataset.filter(filterFunc);
       
   435 	var data = this.dataset.getData();
       
   436 	this.showSuggestions(data && (!this.minCharsType || val.length >= this.minCharsType) && (data.length > 1 || (data.length == 1 && this.childs[0] && this.childs[0].attributes.getNamedItem('spry:suggest').value != val )));
       
   437 };
       
   438 
       
   439 Spry.Widget.AutoSuggest.prototype.loadDataSet = function()
       
   440 {
       
   441 	var val = this.getValue();
       
   442 	var ds = this.dataset;
       
   443 	ds.cancelLoadData();
       
   444 	ds.useCache = false;
       
   445 	
       
   446 	if (!val || (this.minCharsType && this.minCharsType > val.length))
       
   447 	{
       
   448 		this.showSuggestions(false);
       
   449 		return;
       
   450 	}
       
   451 	
       
   452 	if (this.previousString && this.previousString == val)
       
   453 	{
       
   454 		var data = ds.getData();
       
   455 		this.showSuggestions(data && (data.length > 1 || (data.length == 1 && this.childs[0].attributes.getNamedItem("spry:suggest").value != val)));
       
   456 		return;
       
   457 	}
       
   458 
       
   459 	this.previousString = val;
       
   460 
       
   461 	var url = Spry.Widget.Utils.addReplaceParam(ds.url, this.urlParam, val);
       
   462 	ds.setURL(url);
       
   463 	ds.loadData();
       
   464 };
       
   465 
       
   466 Spry.Widget.AutoSuggest.prototype.addMouseListener =  function(node, value)
       
   467 {
       
   468 	var self = this;
       
   469 	var addListener = Spry.Widget.Utils.addEventListener;
       
   470 	addListener(node, "click", function(e){ return self.nodeClick(e, value); self.handleKeyUp(null);}, false); 
       
   471 	addListener(node, "mouseover", function(e){ Spry.Widget.Utils.addClassName(node, self.hoverSuggestClass); self.nodeMouseOver(e, node)}, false); 
       
   472 	addListener(node, "mouseout", function(e){ Spry.Widget.Utils.removeClassName(node, self.hoverSuggestClass); self.nodeMouseOver(e, node)}, false); 
       
   473 };
       
   474 Spry.Widget.AutoSuggest.prototype.removeMouseListener =  function(node, value)
       
   475 {
       
   476 	var self = this;
       
   477 	var removeListener = Spry.Widget.Utils.removeEventListener;
       
   478 	removeListener(node, "click", function (e){ self.nodeClick(e, value); self.handleKeyUp(null);}, false); 
       
   479 	removeListener(node, "mouseover", function(e){ Spry.Widget.Utils.addClassName(node, self.hoverSuggestClass); self.nodeMouseOver(e, node)}, false); 
       
   480 	removeListener(node, "mouseout", function(e){ Spry.Widget.Utils.removeClassName(node, self.hoverSuggestClass); self.nodeMouseOver(e, node)}, false); 
       
   481 };
       
   482 Spry.Widget.AutoSuggest.prototype.attachClickBehaviors =  function()
       
   483 {
       
   484 	var self = this;
       
   485 	var valNodes = Spry.Utils.getNodesByFunc(this.region, function(node)
       
   486 	{
       
   487 		if (node.nodeType == 1) /* Node.ELEMENT_NODE */
       
   488 		{
       
   489 			var attr = node.attributes.getNamedItem("spry:suggest");
       
   490 			if (attr){
       
   491 				self.addMouseListener(node, attr.value);
       
   492 				return true;
       
   493 			}
       
   494 		}
       
   495 		return false;
       
   496 	});
       
   497 	this.childs = valNodes;
       
   498 };
       
   499 Spry.Widget.AutoSuggest.prototype.removeClickBehaviours = function()
       
   500 {
       
   501 	var self = this;
       
   502 	var valNodes = Spry.Utils.getNodesByFunc(this.region, function(node)
       
   503 	{
       
   504 		if (node.nodeType == 1) /* Node.ELEMENT_NODE */
       
   505 		{
       
   506 			var attr = node.attributes.getNamedItem("spry:suggest");
       
   507 			if (attr){
       
   508 				self.removeMouseListener(node, attr.value);
       
   509 				return true;
       
   510 			}
       
   511 		}
       
   512 		return false;
       
   513 	});
       
   514 };
       
   515 Spry.Widget.AutoSuggest.prototype.destroy = function(){
       
   516 
       
   517 	this.removeClickBehaviours();
       
   518 	Spry.Data.Region.removeObserver(Spry.Widget.Utils.getElementID(this.suggestRegion),this._notifyDataset);
       
   519 	
       
   520 	if (this.event_handlers)
       
   521 		for (var i=0; i<this.event_handlers.length; i++) {
       
   522 			Spry.Widget.Utils.removeEventListener(this.event_handlers[i][0], this.event_handlers[i][1], this.event_handlers[i][2], false);
       
   523 		}
       
   524 
       
   525 	for (var k in this)
       
   526 	{
       
   527 		if (typeof this[k] != 'function'){
       
   528 			try { delete this[k]; } catch(err) {}
       
   529 		}
       
   530 	}
       
   531 };
       
   532 
       
   533 Spry.Widget.AutoSuggest.onloadDidFire = false;
       
   534 Spry.Widget.AutoSuggest.loadQueue = [];
       
   535 
       
   536 Spry.Widget.AutoSuggest.processLoadQueue = function(handler)
       
   537 {
       
   538 	Spry.Widget.AutoSuggest.onloadDidFire = true;
       
   539 	var q = Spry.Widget.AutoSuggest.loadQueue;
       
   540 	var qlen = q.length;
       
   541 	for (var i = 0; i < qlen; i++)
       
   542 		q[i].attachBehaviors();
       
   543 };
       
   544 
       
   545 Spry.Widget.AutoSuggest.addLoadListener = function(handler)
       
   546 {
       
   547 	if (typeof window.addEventListener != 'undefined')
       
   548 		window.addEventListener('load', handler, false);
       
   549 	else if (typeof document.addEventListener != 'undefined')
       
   550 		document.addEventListener('load', handler, false);
       
   551 	else if (typeof window.attachEvent != 'undefined')
       
   552 		window.attachEvent('onload', handler);
       
   553 };
       
   554 
       
   555 Spry.Widget.AutoSuggest.addLoadListener(Spry.Widget.AutoSuggest.processLoadQueue);
       
   556 
       
   557 Spry.Widget.AutoSuggest.prototype.attachBehaviors = function()
       
   558 {
       
   559 	this.event_handlers = [];
       
   560 	var self = this;
       
   561 	// adding listeners to the text input to catch the text changes
       
   562 	var _notifyKeyUp = function(e){ self.handleKeyUp(e)};
       
   563 	this.event_handlers.push([this.textElement, "keydown", _notifyKeyUp]); 
       
   564 	this.event_handlers.push([this.textElement, "focus", function(e){ if (self.stopFocus){ self.handleKeyUp(e);} self.hasFocus = true; self.stopFocus = false;}]);
       
   565 	this.event_handlers.push([this.textElement, "drop", _notifyKeyUp]);
       
   566 	this.event_handlers.push([this.textElement, "dragdrop", _notifyKeyUp]);
       
   567 	
       
   568 	var _notifyBlur = false;
       
   569 	// on opera the blur is triggered before onclick
       
   570 	if (Spry.is.opera){
       
   571 		_notifyBlur = function(e) { setTimeout(function(){if (!self.clickInList){ self.showSuggestions(false); }else{ self.stopFocus = true; self.textElement.focus();} self.clickInList = false; self.hasFocus = false;}, 100); };
       
   572 	}else{
       
   573 		_notifyBlur = function(e) { if (!self.clickInList){ self.showSuggestions(false); }else{ self.stopFocus = true; self.textElement.focus();} self.clickInList = false; self.hasFocus = false;};
       
   574 	}
       
   575 	this.event_handlers.push([this.textElement, "blur", _notifyBlur]);
       
   576 
       
   577 	// we listen on the suggest region too
       
   578 	this.event_handlers.push([this.suggestRegion, "mousedown", function(e){ self.clickInList = true;}]);
       
   579 
       
   580 	for (var i=0; i<this.event_handlers.length; i++) 
       
   581 		Spry.Widget.Utils.addEventListener(this.event_handlers[i][0], this.event_handlers[i][1], this.event_handlers[i][2], false);
       
   582 };
       
   583 
       
   584 // createIframeLayer for Tooltip
       
   585 // creates an IFRAME underneath a tooltip element so that it will show above form controls and ActiveX
       
   586 Spry.Widget.AutoSuggest.prototype.createIframeLayer = function(element)
       
   587 {
       
   588 	if (typeof this.iframeLayer == 'undefined')
       
   589 	{
       
   590 		var layer = document.createElement('iframe');
       
   591 		layer.tabIndex = '-1';
       
   592 		layer.src = 'javascript:"";';
       
   593 		layer.scrolling = 'no';
       
   594 		layer.frameBorder = '0';
       
   595 		layer.className = 'iframeSuggest';
       
   596 		element.parentNode.appendChild(layer);
       
   597 		this.iframeLayer = layer;
       
   598 	}
       
   599 	this.iframeLayer.style.left = element.offsetLeft + 'px';
       
   600 	this.iframeLayer.style.top = element.offsetTop + 'px';
       
   601 	this.iframeLayer.style.width = element.offsetWidth + 'px';
       
   602 	this.iframeLayer.style.height = element.offsetHeight + 'px';
       
   603 	this.iframeLayer.style.display = 'block';	
       
   604 };
       
   605 
       
   606 // removeIframeLayer for Tooltip Element
       
   607 // removes an IFRAME underneath a tooltip to reveal any form controls and ActiveX
       
   608 Spry.Widget.AutoSuggest.prototype.removeIframeLayer =  function()
       
   609 {
       
   610 	if (this.iframeLayer)
       
   611 		this.iframeLayer.style.display = 'none';
       
   612 };
       
   613 
       
   614 //////////////////////////////////////////////////////////////////////
       
   615 //
       
   616 // Spry.Widget.Utils
       
   617 //
       
   618 //////////////////////////////////////////////////////////////////////
       
   619 if (!Spry.Widget.Utils)	Spry.Widget.Utils = {};
       
   620 
       
   621 Spry.Widget.Utils.specialSafariNavKeys = ",63232,63233,63234,63235,63272,63273,63275,63276,63277,63289,"; //left,up,rigtht,down arrows,delete,home,end,page up,page down,num lock
       
   622 Spry.Widget.Utils.specialCharacters = ",9,13,27,38,40,";              //suggest keys: tab,enter,escape,up arrow,down arrow
       
   623 Spry.Widget.Utils.specialCharacters += ",33,34,35,36,37,39,45,46,";   //edit keys: insert,delete,home,end,left arrow,right arrow,page up,page down
       
   624 Spry.Widget.Utils.specialCharacters += ",16,17,18,19,20,144,145,";    //control keys: shift,control,alt,pause,caps lock,num lock,scroll lock
       
   625 Spry.Widget.Utils.specialCharacters += ",112,113,114,115,116,117,118,119,120,121,122,123,"; //F1-F12
       
   626 Spry.Widget.Utils.specialCharacters += Spry.Widget.Utils.specialSafariNavKeys;
       
   627 
       
   628 Spry.Widget.AutoSuggest.prototype.isSpecialKey = function (ev)
       
   629 {
       
   630 	return Spry.Widget.Utils.specialCharacters.indexOf("," + ev.keyCode + ",") != -1 || this.moveNextKeyCode == ev.keyCode || this.movePrevKeyCode == ev.keyCode;
       
   631 };
       
   632 Spry.Widget.Utils.getElementID = function(el)
       
   633 {
       
   634 	if (typeof el == 'string' && el)
       
   635 		return el;
       
   636 	return el.getAttribute('id');
       
   637 };
       
   638 Spry.Widget.Utils.getElement = function(ele)
       
   639 {
       
   640 	if (ele && typeof ele == "string")
       
   641 		return document.getElementById(ele);
       
   642 	return ele;
       
   643 };
       
   644 Spry.Widget.Utils.addReplaceParam = function(url, param, paramValue)
       
   645 {
       
   646 	var uri ='';
       
   647 	var qstring = '';
       
   648 	var i = url.indexOf('?');
       
   649 	if ( i != -1)
       
   650 	{
       
   651 		uri = url.slice(0, i);
       
   652 		qstring = url.slice(i+1);
       
   653 	}
       
   654 	else 
       
   655 		uri = url;
       
   656 
       
   657 	// the list of parameters
       
   658 	qstring = qstring.replace('?', '');
       
   659 	var arg = qstring.split("&");
       
   660 
       
   661 	// prevent malicious use
       
   662 	if (param.lastIndexOf('/') != -1)
       
   663 		param = param.slice(param.lastIndexOf('/')+1);
       
   664 
       
   665 	// remove param from the list
       
   666 	for (i=0; i < arg.length ;i++)
       
   667 	{
       
   668 		var k = arg[i].split('=');
       
   669 		if ( (k[0] && k[0] == decodeURI(param)) || arg[i] == decodeURI(param))
       
   670 			arg[i] = null;
       
   671 	}
       
   672 
       
   673 	arg[arg.length] = encodeURIComponent(param) + '=' + encodeURIComponent(paramValue);
       
   674 	qstring = '';
       
   675 	// reconstruct the qstring
       
   676 	for (i=0; i < arg.length; i++)
       
   677 		if (arg[i])
       
   678 			qstring += '&'+arg[i];
       
   679 
       
   680 	// remove the first &
       
   681 	qstring = qstring.slice(1);
       
   682 
       
   683 	url = uri + '?' + qstring;
       
   684 	return url;
       
   685 };
       
   686 
       
   687 Spry.Widget.Utils.addClassName = function(ele, clssName)
       
   688 {
       
   689 	if (!ele) return;
       
   690 
       
   691 	if (!ele.className) ele.className = '';
       
   692 
       
   693 	if (!ele || ele.className.search(new RegExp("\\b" + clssName + "\\b")) != -1)
       
   694 	  return;
       
   695 
       
   696 	ele.className += ' ' + clssName;
       
   697 };
       
   698 
       
   699 Spry.Widget.Utils.removeClassName = function(ele, className)
       
   700 {
       
   701 	if (!ele) return;	
       
   702 
       
   703 	if (!ele.className)
       
   704 	{
       
   705 		ele.className = '';
       
   706 		return;
       
   707 	}
       
   708 	ele.className = ele.className.replace(new RegExp("\\s*\\b" + className + "\\b", "g"), '');
       
   709 };
       
   710 
       
   711 Spry.Widget.Utils.hasClassName = function (ele, className)
       
   712 {
       
   713 	if (!ele || !className)
       
   714 		return false;
       
   715 
       
   716 	if (!ele.className)
       
   717 		ele.className = '';
       
   718 
       
   719 	return ele.className.search(new RegExp("\\s*\\b" + className + "\\b")) != -1;
       
   720 };
       
   721 
       
   722 Spry.Widget.Utils.addEventListener = function(el, eventType, handler, capture)
       
   723 {
       
   724 	try
       
   725 	{
       
   726 		if (el.addEventListener)
       
   727 			el.addEventListener(eventType, handler, capture);
       
   728 		else if (el.attachEvent)
       
   729 			el.attachEvent("on" + eventType, handler, capture);
       
   730 	}catch (e) {}
       
   731 };
       
   732 
       
   733 Spry.Widget.Utils.removeEventListener = function(el, eventType, handler, capture)
       
   734 {
       
   735 	try
       
   736 	{
       
   737 		if (el.removeEventListener)
       
   738 			el.removeEventListener(eventType, handler, capture);
       
   739 		else if (el.detachEvent)
       
   740 			el.detachEvent("on" + eventType, handler, capture);
       
   741 	}catch (e) {}
       
   742 };
       
   743 
       
   744 Spry.Widget.Utils.stopEvent = function(ev)
       
   745 {
       
   746 	ev.cancelBubble = true;
       
   747 	ev.returnValue = false;
       
   748 
       
   749 	try
       
   750 	{
       
   751 		this.stopPropagation(ev);
       
   752 	}catch (e){}
       
   753 	try{
       
   754 		this.preventDefault(ev);
       
   755 	}catch(e){}
       
   756 };
       
   757 
       
   758 /**
       
   759  * Stops event propagation
       
   760  * @param {Event} ev the event
       
   761  */
       
   762 Spry.Widget.Utils.stopPropagation = function(ev)
       
   763 {
       
   764 	if (ev.stopPropagation)
       
   765 		ev.stopPropagation();
       
   766 	else
       
   767 		ev.cancelBubble = true;
       
   768 };
       
   769 
       
   770 /**
       
   771  * Prevents the default behavior of the event
       
   772  * @param {Event} ev the event
       
   773  */
       
   774 Spry.Widget.Utils.preventDefault = function(ev)
       
   775 {
       
   776 	if (ev.preventDefault)
       
   777 		ev.preventDefault();
       
   778 	else
       
   779 		ev.returnValue = false;
       
   780 };
       
   781 
       
   782 Spry.Widget.Utils.setOptions = function(obj, optionsObj, ignoreUndefinedProps)
       
   783 {
       
   784 	if (!optionsObj)
       
   785 		return;
       
   786 	for (var optionName in optionsObj)
       
   787 	{
       
   788 		if (typeof ignoreUndefinedProps != 'undefined' && ignoreUndefinedProps && typeof optionsObj[optionName] == 'undefined')
       
   789 			continue;
       
   790 		obj[optionName] = optionsObj[optionName];
       
   791 	}
       
   792 };
       
   793 
       
   794 Spry.Widget.Utils.firstValid = function()
       
   795 {
       
   796 	var ret = null;
       
   797 	for (var i=0; i < Spry.Widget.Utils.firstValid.arguments.length; i++)
       
   798 		if (typeof Spry.Widget.Utils.firstValid.arguments[i] != 'undefined')
       
   799 		{
       
   800 			ret = Spry.Widget.Utils.firstValid.arguments[i];
       
   801 			break;
       
   802 		}
       
   803 
       
   804 	return ret;
       
   805 };
       
   806 
       
   807 Spry.Widget.Utils.camelize = function(stringToCamelize)
       
   808 {
       
   809   var oStringList = stringToCamelize.split('-');
       
   810 	var isFirstEntry = true;
       
   811 	var camelizedString = '';
       
   812 
       
   813 	for(var i=0; i < oStringList.length; i++)
       
   814 	{
       
   815 		if(oStringList[i].length>0)
       
   816 		{
       
   817 			if(isFirstEntry)
       
   818 			{
       
   819 				camelizedString = oStringList[i];
       
   820 				isFirstEntry = false;
       
   821 			}
       
   822 			else
       
   823 			{
       
   824 				var s = oStringList[i];
       
   825 				camelizedString += s.charAt(0).toUpperCase() + s.substring(1);
       
   826 			}
       
   827 		}
       
   828 	}
       
   829 
       
   830 	return camelizedString;
       
   831 };
       
   832 
       
   833 Spry.Widget.Utils.getStyleProp = function(element, prop)
       
   834 {
       
   835 	var value;
       
   836 	var camel = Spry.Widget.Utils.camelize(prop);
       
   837 	try
       
   838 	{
       
   839 		value = element.style[camel];
       
   840 		if (!value)
       
   841 		{
       
   842 			if (document.defaultView && document.defaultView.getComputedStyle)
       
   843 			{
       
   844 				var css = document.defaultView.getComputedStyle(element, null);
       
   845 				value = css ? css.getPropertyValue(prop) : null;
       
   846 			}
       
   847 			else
       
   848 				if (element.currentStyle)
       
   849 					value = element.currentStyle[camel];
       
   850 		}
       
   851 	}
       
   852 	catch (e) {}
       
   853 
       
   854 	return value == 'auto' ? null : value;
       
   855 };
       
   856 Spry.Widget.Utils.makePositioned = function(element)
       
   857 {
       
   858 	var pos = Spry.Widget.Utils.getStyleProp(element, 'position');
       
   859 	if (!pos || pos == 'static')
       
   860 	{
       
   861 		element.style.position = 'relative';
       
   862 
       
   863 		// Opera returns the offset relative to the positioning context, when an
       
   864 		// element is position relative but top and left have not been defined
       
   865 		if (window.opera)
       
   866 		{
       
   867 			element.style.top = 0;
       
   868 			element.style.left = 0;
       
   869 		}
       
   870 	}
       
   871 };
       
   872 Spry.Widget.Utils.escapeRegExp = function(rexp)
       
   873 {
       
   874 	return rexp.replace(/([\.\/\]\[\{\}\(\)\\\$\^\?\*\|\!\=\+\-])/g, '\\$1');
       
   875 };
       
   876 Spry.Widget.Utils.getFirstChildWithNodeNameAtAnyLevel = function(node, nodeName)
       
   877 {
       
   878 	var elements  = node.getElementsByTagName(nodeName);
       
   879 	if (elements)
       
   880 		return elements[0];
       
   881 	
       
   882 	return null;
       
   883 };