1 /**
  2  * TAO API events utilities.
  3  * 
  4  * @author CRP Henri Tudor - TAO Team - {@link http://www.tao.lu}
  5  * @license GPLv2  http://www.opensource.org/licenses/gpl-2.0.php
  6  * @package taoItems
  7  * @requires jquery >= 1.4.0 {@link http://www.jquery.com}
  8  * 
  9  * @see NewarX#Core
 10  */
 11 
 12 /**
 13  *  
 14  * @class EventTracer
 15  * @property {Object} [options] 
 16  */
 17 function EventTracer (options){
 18 	
 19 	//keep the ref of the current instance for scopes traversing
 20 	var _this = this;
 21 	
 22 	/**
 23 	 * array of events arrays
 24 	 * @fieldOf EventTracer
 25 	 * @type {Array}
 26 	 */
 27 	this.eventPool = new Array();// 
 28 	
 29 	/**
 30 	 * array of strings
 31 	 * @fieldOf EventTracer
 32 	 * @type {Array}
 33 	 */
 34 	this.eventsToBeSend = new  Array();
 35 	
 36 	/**
 37 	 * The tracer common options
 38 	 * @fieldOf EventTracer
 39 	 * @type {Object}
 40 	 */
 41 	this.opts = {
 42 		POOL_SIZE : 500, // number of events to cache before sending
 43 		MIN_POOL_SIZE : 200,
 44 		MAX_POOL_SIZE : 5000,
 45 		time_limit_for_ajax_request : 2000,
 46 		eventsToBeSendCursor : -1,
 47 		ctrlPressed : false,
 48 		altPressed : false
 49 	};
 50 	
 51 	//extends the options on the object construction
 52 	if(options != null && options != undefined){
 53 		$.extend(this.opts, options);
 54 	}
 55 	
 56 	
 57 	/**
 58 	 * the list of events to be catched
 59 	 * @fieldOf EventTracer
 60 	 * @type {Object}
 61 	 */
 62 	this.EVENTS_TO_CATCH = new Object();
 63 	
 64 	/**
 65 	 * the list of attributes to be catched
 66 	 * @fieldOf EventTracer
 67 	 * @type {Object}
 68 	 */
 69 	this.ATTRIBUTES_TO_CATCH = new Array();
 70 
 71 	/**
 72 	 * The parameters defining how and where to load the events list to catch
 73 	 * @fieldOf EventTracer
 74 	 * @type {Object}
 75 	 */
 76 	this.sourceService = {
 77 		type:	'sync',										// (sync | manual)
 78 		data:	null,										//if type is manual, contains the data in JSON, else it should be null
 79 		url:	'/taoDelivery/ResultDelivery/getEvents',		//the url sending the events list
 80 		params: {},											//the common parameters to send to the service
 81 		method: 'post',										//sending method
 82 		format: 'json'										//the response format, now ONLY JSON is supported
 83 	};									
 84 	
 85 	/**
 86 	 * The parameters defining how and where to send the events
 87 	 * @fieldOf EventTracer
 88 	 * @type {Object}
 89 	 */
 90 	this.destinationService = {
 91 		url:	'/taoDelivery/ResultDelivery/traceEvents',			//the URL where to send the events
 92 		params: {},											//the common parameters to send to the service
 93 		method: 'post',										//sending method
 94 		format: 'json'										//the response format, now ONLY JSON is supported
 95 	};
 96 
 97 	/**
 98 	 * Initialize the service interface for the source service: 
 99 	 * how and where we retrieve the events to catch
100 	 * @methodOf EventTracer
101 	 * @param {Object} environment
102 	 */
103 	this.initSourceService = function(environment){
104 		
105 		//define the source service
106 		if($.isPlainObject(environment)){
107 			
108 			if($.inArray(environment.type, ['manual','sync']) > -1){
109 				
110 				this.sourceService.type = environment.type;
111 				
112 				//manual behaviour
113 				if(this.sourceService.type == 'manual' && $.isPlainObject(environment.data)){
114 					this.sourceService.data = environment.data;
115 				}
116 				else{ 	//remote behaviour
117 			
118 					if(source.url){
119 						if(/(\/[-a-z\d%_.~+]*)*(\?[;&a-z\d%_.~+=-]*)?(\#[-a-z\d_]*)?$/.test(environment.url)){	//test url
120 							this.sourceService.url = environment.url;		//set url
121 						}
122 					}
123 					//ADD parameters
124 					if($.isPlainObject(environment.params)){	
125 						for(key in environment.params){
126 							if(isScalar(environment.params[key])){
127 								this.sourceService.params[key] = environment.params[key]; 
128 							}
129 						}
130 					}
131 					if(environment.method){
132 						if(/^get|post$/i.test(environment.method)){
133 							this.sourceService.method = environment.method;
134 						}
135 					}
136 				}
137 			}
138 		}
139 		
140 		//we load now the events to catch
141 		
142 		//we load it manually by calling directly the method with the data
143 		if(this.sourceService.type == 'manual' && this.sourceService.data != null){
144 			this.EVENTS_TO_CATCH = this.setEventsToCatch(this.sourceService.data);
145 		}
146 		
147 		//we call the remote service 
148 		if(this.sourceService.type == 'sync' && this.sourceService.url != ''){
149 			received = $.parseJSON($.ajax({
150 				async		: false,
151 				url  		: this.sourceService.url,
152 				data 		: this.sourceService.params,
153 				type 		: this.sourceService.method
154 			}).responseText);
155 			if(received){		
156 				this.EVENTS_TO_CATCH = this.setEventsToCatch(received);
157 			}
158 		}	
159 		
160 		//we bind the events to be observed in the item
161 		if(this.EVENTS_TO_CATCH.bubbling != undefined){
162 			this.bind_platform();
163 		}
164 	};
165 	
166 	/**
167 	 * Initialize the service interface forthe destination service:  
168 	 * how and where we send the catched events
169 	 * @methodOf EventTracer
170 	 * @param {Object} environment
171 	 */
172 	this.initDestinationService = function(environment){
173 		if($.isPlainObject(environment)){
174 			if(environment.url){
175 				if(/(\/[-a-z\d%_.~+]*)*(\?[;&a-z\d%_.~+=-]*)?(\#[-a-z\d_]*)?$/.test(environment.url)){	//test url
176 					this.destinationService.url = environment.url;		//set url
177 				}
178 			}
179 			//ADD parameters
180 			if($.isPlainObject(environment.params)){	
181 				for(key in environment.params){
182 					if(isScalar(environment.params[key])){
183 						this.destinationService.params[key] = environment.params[key]; 
184 					}
185 				}
186 			}
187 			if(environment.method){
188 				if(/^get|post$/i.test(environment.method)){
189 					this.destinationService.method = environment.method;
190 				}
191 			}
192 		}
193 	};
194 	
195 	/**
196 	* @description record events of interaction between interviewee and the test
197 	* @methodOf EventTracer
198 	* @param {Object} data event type list
199 	* @returns {Object} the events to catch
200 	*/
201 	this.setEventsToCatch = function (data)
202 	{
203 		// retreive the list of events to catch or not to catch
204 		
205 		if (data.type.length > 0)
206 		{
207 			var EVENTS_TO_CATCH = {bubbling:[],nonBubbling:[]};
208 			if (data.type == 'catch')
209 			{
210 				for (i in data.list)
211 				{
212 					if ($.inArray(i,['click', 'dblclick', 'change', 'submit', 'select', 'mousedown', 'mouseup', 'mouseenter', 'mousemove', 'mouseout']) > -1)//if is bubbling event
213 					{
214 						EVENTS_TO_CATCH.bubbling.push(i);
215 					}
216 					else
217 					{
218 						EVENTS_TO_CATCH.nonBubbling.push(i);// else non bubbling event
219 					}
220 					this.ATTRIBUTES_TO_CATCH[i] = data.list[i];
221 				}
222 			}
223 			else
224 			{
225 				// no catch
226 				EVENTS_TO_CATCH = {bubbling:['click', 'dblclick', 'change', 'submit', 'select', 'mousedown', 'mouseup', 'mouseenter', 'mousemove', 'mouseout'], nonBubbling:['blur', 'focus', 'load', 'resize', 'scroll', 'keyup', 'keydown', 'keypress', 'unload', 'beforeunload', 'select', 'submit']};
227 				for (i in data.list)
228 				{
229 					remove_array(data.list[i].event,EVENTS_TO_CATCH.bubbling);
230 					remove_array(data.list[i].event,EVENTS_TO_CATCH.nonBubbling);
231 				}
232 			}
233 		}
234 		else
235 		{
236 			EVENTS_TO_CATCH = {bubbling:['click', 'dblclick', 'change', 'submit', 'select', 'mousedown', 'mouseup', 'mouseenter', 'mousemove', 'mouseout'], nonBubbling:['blur', 'focus', 'load', 'resize', 'scroll', 'keyup', 'keydown', 'keypress', 'unload', 'beforeunload', 'select', 'submit']};
237 		}
238 		return EVENTS_TO_CATCH;
239 	};
240 	
241 	/**
242 	* @description bind platform events
243 	* @methodOf EventTracer
244 	*/
245 	this.bind_platform = function()
246 	{
247 		// for non bubbling events, link them to all the listened element
248 		// it is still useful to use delegation since it will remains much less listeners in the memory (just 1 instead of #numberOfElements)
249 		$('body').bindDom(this);
250 
251 		// for bubbling events
252 		$('body').bind(this.EVENTS_TO_CATCH.bubbling.join(' ') , this.eventStation);
253 	};
254 	
255 	/**
256 	 * @description unbind platform events
257 	 * @methodOf EventTracer
258 	 */
259 	this.unbind_platform = function()
260 	{
261 		$('body').unbind(EVENTS_TO_CATCH.bubbling.join(' ') , this.eventStation);
262 		$('body').unBindDom(this);
263 	};
264 	
265 	
266 	/**
267 	 * @description set all information from the event to the pLoad
268 	 * @methodOf EventTracer
269 	 * @param {event} e dom event triggered
270 	 * @param {Object} pload callback function called when 'ok' clicked
271 	 */
272 	this.describeEvent = function(e,pload)
273 	{
274 		if (e.target && (typeof(e.target['value']) != 'undefined') && (e.target['value'] != -1) && (e.target['value'] != ''))
275 		{
276 			pload['value'] = e.target['value'];
277 		}
278 		// get everything about the event
279 		for (var i in e)
280 		{
281 			if ((typeof(e[i]) != 'undefined') && (typeof(e[i]) != 'object') && (typeof(e[i]) != 'function') && (e[i] != ''))
282 			{
283 				if ((i != 'cancelable') && (i != 'contentEditable') && (i != 'cancelable') && (i != 'bubbles') && (i.substr(0,6) != 'jQuery'))
284 				{
285 					pload[i] = e[i];
286 				}
287 			}
288 		}
289 	};
290 
291 
292 	/**
293 	* @description set all information from the target dom element to the pLoad
294 	* @methodOf EventTracer
295 	* @param {event} e dom event triggered
296 	* @param {Object} pload callback function called when 'ok' clicked
297 	*/
298 	this.describeElement = function(e,pload)
299 	{
300 		// take everything except useless attributes
301 		for (var i in e.target)
302 		{
303 			try
304 			{
305 				if (( (typeof(e.target[i]) == 'string') && (e.target[i] != '') ) | (typeof(e.target[i]) == 'number'))
306 				{
307 					if ( (!in_array(i,position_pload_array)) && (!in_array(i,ignored_pload_element_array)) && (i.substr(0,6) != 'jQuery') )
308 					{
309 						pload[i] = ''+e.target[i];
310 					}
311 				}
312 			}
313 			catch(e){}
314 		}
315 
316 		if (typeof(e.target.nodeName) != 'undefined')
317 		{
318 			switch(e.target.nodeName.toLowerCase())
319 			{
320 				case 'select':
321 				{
322 					pload['value'] = $(e.target).val();
323 					if (typeof(pload['value']) == 'array')
324 					{
325 						pload['value'] = pload['value'].join('|');
326 					}
327 					break;
328 				}
329 				case 'textarea':
330 				{
331 					pload['value'] = $(e.target).val();
332 					
333 					break;
334 				}
335 				case 'input':
336 				{
337 					pload['value'] = $(e.target).val();
338 					break;
339 				}
340 				case 'html':// case of iframe in design mode, equivalent of a textarea but with html
341 				{
342 					if (e.target.ownerDocument.designMode == 'on')
343 					{
344 						pload['text'] = $(e.target).contents('body').html();
345 					}
346 					break;
347 				}
348 			}
349 		}
350 	};
351 
352 	/**
353 	* @description set wanted information from the event to the pLoad
354 	* @methodOf EventTracer
355 	* @param {event} e dom event triggered
356 	* @param {Object} pload callback function called when 'ok' clicked
357 	*/
358 	this.setEventParameters = function (e,pload)
359 	{
360 		for (var i in this.ATTRIBUTES_TO_CATCH[e.type])
361 		{
362 			if (typeof(e[this.ATTRIBUTES_TO_CATCH[e.type][i]]) != 'undefined')
363 			{
364 				pload[this.ATTRIBUTES_TO_CATCH[e.type][i]] = e[this.ATTRIBUTES_TO_CATCH[e.type][i]];
365 			}
366 			else
367 			{
368 				if (typeof(e.target[this.ATTRIBUTES_TO_CATCH[e.type][i]]) != 'undefined')
369 				{
370 					pload[this.ATTRIBUTES_TO_CATCH[e.type][i]] = e.target[this.ATTRIBUTES_TO_CATCH[e.type][i]];
371 				}
372 			}
373 		}
374 	};
375 
376 
377 	/**
378 	 * @description return true if the event passed is a business event
379 	 * @methodOf EventTracer
380 	 * @param {event} e dom event triggered
381 	 * @returns {boolean}
382 	 */
383 	this.hooks = function(e){
384 		return (e.name == 'BUSINESS');
385 	};
386 
387 	/**
388 	 * @description controler that send events to feedtrace
389 	 * @methodOf EventTracer
390 	 * @param {event} e dom event triggered
391 	 */
392 	this.eventStation = function (e){
393 		var keyCode = e.keyCode ? e.keyCode : e.charCode;
394 		if (e.type == 'keypress')// kill f4,f5,ctrl+r,s,t,n,u,p,o alt+tab,left and right arrow, right and left window key
395 		{
396 			try
397 			{
398 				if ( (typeof(keyCode) != 'undefined') && ((keyCode == 116) | (keyCode == 115) | ((e.ctrlKey)&&((keyCode ==  114)|(keyCode ==  115)|(keyCode ==  116)|(keyCode ==  112)|(keyCode ==  110)|(keyCode ==  111)|(keyCode ==  79)) ) | ((e.altKey)&&(keyCode == 9 )) | (keyCode == 91) | (keyCode == 92)| (keyCode == 37)| (keyCode == 39) ) )
399 				{
400 					e.preventDefault();
401 					return false;
402 				}
403 			}
404 			catch(e){}
405 		}
406 
407 		var target_tag = e.target.nodeName ? e.target.nodeName.toLowerCase():e.target.type;
408 		var idElement;
409 
410 		if ((e.target.id) && (e.target.id.length > 0))
411 		{
412 			idElement = e.target.id;
413 		}
414 		else
415 		{
416 			idElement = 'noID';
417 		}
418 		var pload = {'id' : idElement};
419 
420 		if ((typeof(this.ATTRIBUTES_TO_CATCH)!= 'undefined') && (typeof(this.ATTRIBUTES_TO_CATCH[e.type])!= 'undefined') && (this.ATTRIBUTES_TO_CATCH[e.type].length > 0))
421 		{
422 			this.setEventParameters(e,pload);
423 		}
424 		else
425 		{
426 			if (typeof(this.describeEvent) != 'undefined')
427 			{
428 				this.describeEvent(e,pload);
429 			}
430 			if (typeof(this.describeElement) != 'undefined')
431 			{
432 				this.describeElement(e,pload);
433 			}
434 		}
435 		
436 		_this.feedTrace(target_tag, e.type, e.timeStamp, pload);
437 	};
438 
439 
440 	/**
441 	 * @description in the API to allow the unit creator to send events himself to the event log record events of interaction between interviewee and the test
442 	 * @example feedTrace('BUSINESS','start_drawing',getGlobalTime(), {'unitTime':getUnitTime()});
443 	 * @methodOf EventTracer
444 	 * @param {String} target_tag element type receiving the event.
445 	 * @param {String} event_type type of event being catched
446 	 * @param {Object} pLoad object containing various information about the event. you may put whatever you need in it.
447 	 */
448 	this.feedTrace = function (target_tag,event_type,time, pLoad)
449 	{
450 		var send_right_now = false;
451 		var event = '{"name":"'+target_tag+'","type":"'+event_type+'","time":"'+time+'"';
452 
453 		
454 		if (typeof(pLoad)=='string')
455 		{
456 			event = event+',"pLoad":"'+pLoad+'"';
457 		}
458 		else
459 		{
460 			for (var prop_name in pLoad)
461 			{
462 				event = event+',"'+prop_name+'":"'+pLoad[prop_name]+'"';
463 			}
464 		}
465 		event = event+'}';
466 		
467 		if (typeof(this.hooks) != "undefined")
468 		{
469 			send_right_now = this.hooks($.parseJSON(event));
470 		}
471 		
472 		this.eventPool.push(event);
473 		
474 		if ((this.eventPool.length > this.opts.POOL_SIZE) || (send_right_now))
475 		{
476 			this.prepareFeedTrace();
477 		}
478 	};
479 
480 
481 	/**
482 	 * @description prepare one block of stored traces for being sent
483 	 * @methodOf EventTracer
484 	 */
485 	this.prepareFeedTrace = function()
486 	{
487 		var currentLength = this.eventsToBeSend.length;
488 
489 		var temp_array = new Array();
490 
491 		for ( var i = 0 ; ((this.eventPool.length>0)&&(i < this.opts.POOL_SIZE )) ; i++ )
492 		{
493 			temp_array.push(this.eventPool.shift());
494 		}
495 		this.eventsToBeSend.push(temp_array);
496 		this.sendFeedTrace();
497 	};
498 
499 
500 	/**
501 	 * @description send one block of traces (non blocking)
502 	 * Does send the content of eventsToBeSend[0] to the server
503 	 * @methodOf EventTracer
504 	 */
505 	this.sendFeedTrace = function ()
506 	{
507 		var events = this.eventsToBeSend.pop();
508 		var sent_timeStamp = new Date().getTime();
509 		var params = $.extend({'events': events}, this.destinationService.params);
510 		
511 		$.ajax({
512 			url		: this.destinationService.url,
513 			data	: params,
514 			type	: this.destinationService.method,
515 			async	:true,
516 			datatype: this.destinationService.format,
517 			success : function(data, textStatus){ 
518 				_this.sendFeedTraceSucceed(data, textStatus, sent_timeStamp); 
519 			},
520 			error : function(xhr, errorString, exception){
521 				_this.sendFeedTraceFail(xhr, errorString, exception, events);
522 			}
523 		});
524 	};
525 
526 	/**
527 	* @description success callback after traces sent. does affinate the size of traces package sent
528 	* @methodOf EventTracer
529 	* @param {String} data response from server
530 	* @param {String} textStatus status of request
531 	* @param {int} sent_timeStamp time the request was sent
532 	*/
533 	this.sendFeedTraceSucceed = function (data, textStatus, sent_timeStamp)//callback for sendfeedtrace
534 	{
535 		// adaptation of the send frequence
536 		var request_time = (new Date()).getTime() - sent_timeStamp;
537 		if (request_time > this.opts.time_limit_for_ajax_request)
538 		{
539 			// it takes too long
540 			this.increaseEventsPoolSize();
541 		}
542 		else
543 		{
544 			// we can increase the frequency of events storing
545 			this.reduceEventsPoolSize();
546 		}
547 		if (data.saved)
548 		{
549 			this.eventsToBeSend.shift();// data send, we can delete at 0 index
550 		}
551 	};
552 
553 	/**
554 	 * @description the request took too much time, we increase the size of traces package, to have less frequent requests
555 	 * @methodOf EventTracer
556 	 */
557 	this.increaseEventsPoolSize = function ()
558 	{
559 		if ( this.opts.POOL_SIZE < this.opts.MAX_POOL_SIZE)
560 		{
561 			this.opts.POOL_SIZE = Math.floor(this.opts.POOL_SIZE * 2);
562 		}
563 	};
564 
565 	/**
566 	 * @description the request was fast enough, we increase the frequency of requests by reducing the size of traces package
567 	 * @methodOf EventTracer
568 	 */
569 	this.reduceEventsPoolSize = function ()
570 	{
571 		if ( this.opts.POOL_SIZE > this.opts.MIN_POOL_SIZE )
572 		{
573 			this.opts.POOL_SIZE = Math.floor(this.opts.POOL_SIZE * 0.75);
574 		}
575 	};
576 
577 	/**
578 	* @description callback function after request failed (TODO)
579 	* @methodOf EventTracer
580 	* @param {ressource} xhr ajax request ressource
581 	* @param {String} errorString error message
582 	* @param {exception} [exception] exception object thrown
583 	*/
584 	this.sendFeedTraceFail = function (xhr, errorString, exception, events)//callback for sendfeedtrace
585 	{
586 		this.increaseEventsPoolSize();
587 		
588 		this.eventsToBeSend.unshift(events);
589 		
590 		window.setInterval(this.sendAllFeedTrace_now, 2000);
591 	};
592 
593 
594 	/* no callback on success
595 	used when business events catched*/
596 	/**
597 	* @description send all traces with a blocking function
598 	* @methodOf EventTracer
599 	*/
600 	this.sendAllFeedTrace_now = function ()
601 	{
602 		var currentLength = this.eventsToBeSend.length;
603 
604 		this.eventsToBeSend[ currentLength ] = Array();
605 		for (  ; this.eventPool.length > 0 ;  )//  empty the whole eventPool array
606 		{
607 			this.eventsToBeSend[ currentLength ].push( this.eventPool.pop() );
608 		}
609 
610 		var events = new Array();
611 		for (var j in this.eventsToBeSend)
612 		{
613 			for (var i in this.eventsToBeSend[j])
614 			{
615 				events.push(this.eventsToBeSend[j][i]);
616 			}
617 		}
618 
619 		var params = $.extend({'events': events }, this.destinationService.params);
620 		var sent_timeStamp = new Date().getTime();
621 		
622 		$.ajax({
623 			url		: this.destinationService.url,
624 			data	: params,
625 			type	: this.destinationService.method,
626 			async	: false,
627 			datatype: this.destinationService.format,
628 			success : function(data, textStatus){ 
629 				_this.sendFeedTraceSucceed(data, textStatus, sent_timeStamp); 
630 			},
631 			error : function(xhr, errorString, exception){
632 				_this.sendFeedTraceFail(xhr, errorString, exception, events);
633 			}
634 		});
635 	};
636 	
637 }
638 
639  
640 /**
641  * @description bind every non bubbling events to dom elements.
642  * @methodOf EventTracer
643  */
644 jQuery.fn.bindDom = function(eventTracer)
645 {
646 	$(this).bind(eventTracer.EVENTS_TO_CATCH.nonBubbling.join(' ') , eventTracer.eventStation);
647 	var childrens = $(this).children();
648 	if (childrens.length)// stop condition
649 	{
650 		childrens.bindDom(eventTracer);
651 	}
652 };
653 
654 /**
655  * @description unbind platform events
656  * @methodOf EventTracer
657  */
658 jQuery.fn.unBindDom = function(eventTracer)
659 {
660 	
661 	$(this).unbind( eventTracer.EVENTS_TO_CATCH.nonBubbling.join(' ') , eventTracer.eventStation);
662 	var childrens = $(this).children();
663 	if (childrens.length)// stop condition
664 	{
665 		childrens.unBindDom(eventTracer);
666 	}
667 };
668 
669 // attributes set in the pos tag
670 var ignored_pload_element_array = new Array('contentEditable','localName','tagname','textContent','namespaceURI','baseURI','innerHTML','defaultStatus','fullScreen','UNITSMAP','PROCESSURI','LANGID'
671 ,'ITEMID','ACTIVITYID','DURATION','ELEMENT_NODE','ATTRIBUTE_NODE','TEXT_NODE','CDATA_SECTION_NODE','ENTITY_REFERENCE_NODE','ENTITY_NODE','PROCESSING_INSTRUCTION_NODE','COMMENT_NODE'
672 ,'DOCUMENT_NODE','DOCUMENT_TYPE_NODE','DOCUMENT_FRAGMENT_NODE','NOTATION_NODE','DOCUMENT_POSITION_PRECEDING','DOCUMENT_POSITION_FOLLOWING','DOCUMENT_POSITION_CONTAINS','DOCUMENT_POSITION_CONTAINED_BY'
673 ,'DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC','DOCUMENT_POSITION_DISCONNECTED','childElementCount','LAYOUT_DIRECTION','CURRENTSTIMULUS','CURRENTITEMEXTENSION','CURRENTSTIMULUSEXTENSION','nodeType','tabIndex');
674 var ignored_pload_event_array = new Array('cancelable','contentEditable','bubbles','tagName','localName','timeStamp','type');
675 
676 
677 /* custom events definition */
678 
679 /* changeCss
680 */
681 jQuery.event.special.changeCss = {setup:function(){},teardown:function(){}};
682 /* reloadMapEvent
683 order to reload the map */
684 jQuery.event.special.reloadMapEvent = {setup: function(){},teardown: function(){}};
685