Split confirm message from revdelete-text (bug 21264)
[lhc/web/wiklou.git] / js2 / js2stopgap.js
1 /*!
2 * jQuery JavaScript Library v1.3.2
3 * http://jquery.com/
4 *
5 * Copyright (c) 2009 John Resig
6 * Dual licensed under the MIT and GPL licenses.
7 * http://docs.jquery.com/License
8 *
9 * Date: 2009-02-19 17:34:21 -0500 (Thu, 19 Feb 2009)
10 * Revision: 6246
11 */
12 (function(){
13
14 var
15 // Will speed up references to window, and allows munging its name.
16 window = this,
17 // Will speed up references to undefined, and allows munging its name.
18 undefined,
19 // Map over jQuery in case of overwrite
20 _jQuery = window.jQuery,
21 // Map over the $ in case of overwrite
22 _$ = window.$,
23
24 jQuery = window.jQuery = window.$ = function( selector, context ) {
25 // The jQuery object is actually just the init constructor 'enhanced'
26 return new jQuery.fn.init( selector, context );
27 },
28
29 // A simple way to check for HTML strings or ID strings
30 // (both of which we optimize for)
31 quickExpr = /^[^<]*(<(.|\s)+>)[^>]*$|^#([\w-]+)$/,
32 // Is it a simple selector
33 isSimple = /^.[^:#\[\.,]*$/;
34
35 jQuery.fn = jQuery.prototype = {
36 init: function( selector, context ) {
37 // Make sure that a selection was provided
38 selector = selector || document;
39
40 // Handle $(DOMElement)
41 if ( selector.nodeType ) {
42 this[0] = selector;
43 this.length = 1;
44 this.context = selector;
45 return this;
46 }
47 // Handle HTML strings
48 if ( typeof selector === "string" ) {
49 // Are we dealing with HTML string or an ID?
50 var match = quickExpr.exec( selector );
51
52 // Verify a match, and that no context was specified for #id
53 if ( match && (match[1] || !context) ) {
54
55 // HANDLE: $(html) -> $(array)
56 if ( match[1] )
57 selector = jQuery.clean( [ match[1] ], context );
58
59 // HANDLE: $("#id")
60 else {
61 var elem = document.getElementById( match[3] );
62
63 // Handle the case where IE and Opera return items
64 // by name instead of ID
65 if ( elem && elem.id != match[3] )
66 return jQuery().find( selector );
67
68 // Otherwise, we inject the element directly into the jQuery object
69 var ret = jQuery( elem || [] );
70 ret.context = document;
71 ret.selector = selector;
72 return ret;
73 }
74
75 // HANDLE: $(expr, [context])
76 // (which is just equivalent to: $(content).find(expr)
77 } else
78 return jQuery( context ).find( selector );
79
80 // HANDLE: $(function)
81 // Shortcut for document ready
82 } else if ( jQuery.isFunction( selector ) )
83 return jQuery( document ).ready( selector );
84
85 // Make sure that old selector state is passed along
86 if ( selector.selector && selector.context ) {
87 this.selector = selector.selector;
88 this.context = selector.context;
89 }
90
91 return this.setArray(jQuery.isArray( selector ) ?
92 selector :
93 jQuery.makeArray(selector));
94 },
95
96 // Start with an empty selector
97 selector: "",
98
99 // The current version of jQuery being used
100 jquery: "1.3.2",
101
102 // The number of elements contained in the matched element set
103 size: function() {
104 return this.length;
105 },
106
107 // Get the Nth element in the matched element set OR
108 // Get the whole matched element set as a clean array
109 get: function( num ) {
110 return num === undefined ?
111
112 // Return a 'clean' array
113 Array.prototype.slice.call( this ) :
114
115 // Return just the object
116 this[ num ];
117 },
118
119 // Take an array of elements and push it onto the stack
120 // (returning the new matched element set)
121 pushStack: function( elems, name, selector ) {
122 // Build a new jQuery matched element set
123 var ret = jQuery( elems );
124
125 // Add the old object onto the stack (as a reference)
126 ret.prevObject = this;
127
128 ret.context = this.context;
129
130 if ( name === "find" )
131 ret.selector = this.selector + (this.selector ? " " : "") + selector;
132 else if ( name )
133 ret.selector = this.selector + "." + name + "(" + selector + ")";
134
135 // Return the newly-formed element set
136 return ret;
137 },
138
139 // Force the current matched set of elements to become
140 // the specified array of elements (destroying the stack in the process)
141 // You should use pushStack() in order to do this, but maintain the stack
142 setArray: function( elems ) {
143 // Resetting the length to 0, then using the native Array push
144 // is a super-fast way to populate an object with array-like properties
145 this.length = 0;
146 Array.prototype.push.apply( this, elems );
147
148 return this;
149 },
150
151 // Execute a callback for every element in the matched set.
152 // (You can seed the arguments with an array of args, but this is
153 // only used internally.)
154 each: function( callback, args ) {
155 return jQuery.each( this, callback, args );
156 },
157
158 // Determine the position of an element within
159 // the matched set of elements
160 index: function( elem ) {
161 // Locate the position of the desired element
162 return jQuery.inArray(
163 // If it receives a jQuery object, the first element is used
164 elem && elem.jquery ? elem[0] : elem
165 , this );
166 },
167
168 attr: function( name, value, type ) {
169 var options = name;
170
171 // Look for the case where we're accessing a style value
172 if ( typeof name === "string" )
173 if ( value === undefined )
174 return this[0] && jQuery[ type || "attr" ]( this[0], name );
175
176 else {
177 options = {};
178 options[ name ] = value;
179 }
180
181 // Check to see if we're setting style values
182 return this.each(function(i){
183 // Set all the styles
184 for ( name in options )
185 jQuery.attr(
186 type ?
187 this.style :
188 this,
189 name, jQuery.prop( this, options[ name ], type, i, name )
190 );
191 });
192 },
193
194 css: function( key, value ) {
195 // ignore negative width and height values
196 if ( (key == 'width' || key == 'height') && parseFloat(value) < 0 )
197 value = undefined;
198 return this.attr( key, value, "curCSS" );
199 },
200
201 text: function( text ) {
202 if ( typeof text !== "object" && text != null )
203 return this.empty().append( (this[0] && this[0].ownerDocument || document).createTextNode( text ) );
204
205 var ret = "";
206
207 jQuery.each( text || this, function(){
208 jQuery.each( this.childNodes, function(){
209 if ( this.nodeType != 8 )
210 ret += this.nodeType != 1 ?
211 this.nodeValue :
212 jQuery.fn.text( [ this ] );
213 });
214 });
215
216 return ret;
217 },
218
219 wrapAll: function( html ) {
220 if ( this[0] ) {
221 // The elements to wrap the target around
222 var wrap = jQuery( html, this[0].ownerDocument ).clone();
223
224 if ( this[0].parentNode )
225 wrap.insertBefore( this[0] );
226
227 wrap.map(function(){
228 var elem = this;
229
230 while ( elem.firstChild )
231 elem = elem.firstChild;
232
233 return elem;
234 }).append(this);
235 }
236
237 return this;
238 },
239
240 wrapInner: function( html ) {
241 return this.each(function(){
242 jQuery( this ).contents().wrapAll( html );
243 });
244 },
245
246 wrap: function( html ) {
247 return this.each(function(){
248 jQuery( this ).wrapAll( html );
249 });
250 },
251
252 append: function() {
253 return this.domManip(arguments, true, function(elem){
254 if (this.nodeType == 1)
255 this.appendChild( elem );
256 });
257 },
258
259 prepend: function() {
260 return this.domManip(arguments, true, function(elem){
261 if (this.nodeType == 1)
262 this.insertBefore( elem, this.firstChild );
263 });
264 },
265
266 before: function() {
267 return this.domManip(arguments, false, function(elem){
268 this.parentNode.insertBefore( elem, this );
269 });
270 },
271
272 after: function() {
273 return this.domManip(arguments, false, function(elem){
274 this.parentNode.insertBefore( elem, this.nextSibling );
275 });
276 },
277
278 end: function() {
279 return this.prevObject || jQuery( [] );
280 },
281
282 // For internal use only.
283 // Behaves like an Array's method, not like a jQuery method.
284 push: [].push,
285 sort: [].sort,
286 splice: [].splice,
287
288 find: function( selector ) {
289 if ( this.length === 1 ) {
290 var ret = this.pushStack( [], "find", selector );
291 ret.length = 0;
292 jQuery.find( selector, this[0], ret );
293 return ret;
294 } else {
295 return this.pushStack( jQuery.unique(jQuery.map(this, function(elem){
296 return jQuery.find( selector, elem );
297 })), "find", selector );
298 }
299 },
300
301 clone: function( events ) {
302 // Do the clone
303 var ret = this.map(function(){
304 if ( !jQuery.support.noCloneEvent && !jQuery.isXMLDoc(this) ) {
305 // IE copies events bound via attachEvent when
306 // using cloneNode. Calling detachEvent on the
307 // clone will also remove the events from the orignal
308 // In order to get around this, we use innerHTML.
309 // Unfortunately, this means some modifications to
310 // attributes in IE that are actually only stored
311 // as properties will not be copied (such as the
312 // the name attribute on an input).
313 var html = this.outerHTML;
314 if ( !html ) {
315 var div = this.ownerDocument.createElement("div");
316 div.appendChild( this.cloneNode(true) );
317 html = div.innerHTML;
318 }
319
320 return jQuery.clean([html.replace(/ jQuery\d+="(?:\d+|null)"/g, "").replace(/^\s*/, "")])[0];
321 } else
322 return this.cloneNode(true);
323 });
324
325 // Copy the events from the original to the clone
326 if ( events === true ) {
327 var orig = this.find("*").andSelf(), i = 0;
328
329 ret.find("*").andSelf().each(function(){
330 if ( this.nodeName !== orig[i].nodeName )
331 return;
332
333 var events = jQuery.data( orig[i], "events" );
334
335 for ( var type in events ) {
336 for ( var handler in events[ type ] ) {
337 jQuery.event.add( this, type, events[ type ][ handler ], events[ type ][ handler ].data );
338 }
339 }
340
341 i++;
342 });
343 }
344
345 // Return the cloned set
346 return ret;
347 },
348
349 filter: function( selector ) {
350 return this.pushStack(
351 jQuery.isFunction( selector ) &&
352 jQuery.grep(this, function(elem, i){
353 return selector.call( elem, i );
354 }) ||
355
356 jQuery.multiFilter( selector, jQuery.grep(this, function(elem){
357 return elem.nodeType === 1;
358 }) ), "filter", selector );
359 },
360
361 closest: function( selector ) {
362 var pos = jQuery.expr.match.POS.test( selector ) ? jQuery(selector) : null,
363 closer = 0;
364
365 return this.map(function(){
366 var cur = this;
367 while ( cur && cur.ownerDocument ) {
368 if ( pos ? pos.index(cur) > -1 : jQuery(cur).is(selector) ) {
369 jQuery.data(cur, "closest", closer);
370 return cur;
371 }
372 cur = cur.parentNode;
373 closer++;
374 }
375 });
376 },
377
378 not: function( selector ) {
379 if ( typeof selector === "string" )
380 // test special case where just one selector is passed in
381 if ( isSimple.test( selector ) )
382 return this.pushStack( jQuery.multiFilter( selector, this, true ), "not", selector );
383 else
384 selector = jQuery.multiFilter( selector, this );
385
386 var isArrayLike = selector.length && selector[selector.length - 1] !== undefined && !selector.nodeType;
387 return this.filter(function() {
388 return isArrayLike ? jQuery.inArray( this, selector ) < 0 : this != selector;
389 });
390 },
391
392 add: function( selector ) {
393 return this.pushStack( jQuery.unique( jQuery.merge(
394 this.get(),
395 typeof selector === "string" ?
396 jQuery( selector ) :
397 jQuery.makeArray( selector )
398 )));
399 },
400
401 is: function( selector ) {
402 return !!selector && jQuery.multiFilter( selector, this ).length > 0;
403 },
404
405 hasClass: function( selector ) {
406 return !!selector && this.is( "." + selector );
407 },
408
409 val: function( value ) {
410 if ( value === undefined ) {
411 var elem = this[0];
412
413 if ( elem ) {
414 if( jQuery.nodeName( elem, 'option' ) )
415 return (elem.attributes.value || {}).specified ? elem.value : elem.text;
416
417 // We need to handle select boxes special
418 if ( jQuery.nodeName( elem, "select" ) ) {
419 var index = elem.selectedIndex,
420 values = [],
421 options = elem.options,
422 one = elem.type == "select-one";
423
424 // Nothing was selected
425 if ( index < 0 )
426 return null;
427
428 // Loop through all the selected options
429 for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) {
430 var option = options[ i ];
431
432 if ( option.selected ) {
433 // Get the specifc value for the option
434 value = jQuery(option).val();
435
436 // We don't need an array for one selects
437 if ( one )
438 return value;
439
440 // Multi-Selects return an array
441 values.push( value );
442 }
443 }
444
445 return values;
446 }
447
448 // Everything else, we just grab the value
449 return (elem.value || "").replace(/\r/g, "");
450
451 }
452
453 return undefined;
454 }
455
456 if ( typeof value === "number" )
457 value += '';
458
459 return this.each(function(){
460 if ( this.nodeType != 1 )
461 return;
462
463 if ( jQuery.isArray(value) && /radio|checkbox/.test( this.type ) )
464 this.checked = (jQuery.inArray(this.value, value) >= 0 ||
465 jQuery.inArray(this.name, value) >= 0);
466
467 else if ( jQuery.nodeName( this, "select" ) ) {
468 var values = jQuery.makeArray(value);
469
470 jQuery( "option", this ).each(function(){
471 this.selected = (jQuery.inArray( this.value, values ) >= 0 ||
472 jQuery.inArray( this.text, values ) >= 0);
473 });
474
475 if ( !values.length )
476 this.selectedIndex = -1;
477
478 } else
479 this.value = value;
480 });
481 },
482
483 html: function( value ) {
484 return value === undefined ?
485 (this[0] ?
486 this[0].innerHTML.replace(/ jQuery\d+="(?:\d+|null)"/g, "") :
487 null) :
488 this.empty().append( value );
489 },
490
491 replaceWith: function( value ) {
492 return this.after( value ).remove();
493 },
494
495 eq: function( i ) {
496 return this.slice( i, +i + 1 );
497 },
498
499 slice: function() {
500 return this.pushStack( Array.prototype.slice.apply( this, arguments ),
501 "slice", Array.prototype.slice.call(arguments).join(",") );
502 },
503
504 map: function( callback ) {
505 return this.pushStack( jQuery.map(this, function(elem, i){
506 return callback.call( elem, i, elem );
507 }));
508 },
509
510 andSelf: function() {
511 return this.add( this.prevObject );
512 },
513
514 domManip: function( args, table, callback ) {
515 if ( this[0] ) {
516 var fragment = (this[0].ownerDocument || this[0]).createDocumentFragment(),
517 scripts = jQuery.clean( args, (this[0].ownerDocument || this[0]), fragment ),
518 first = fragment.firstChild;
519
520 if ( first )
521 for ( var i = 0, l = this.length; i < l; i++ )
522 callback.call( root(this[i], first), this.length > 1 || i > 0 ?
523 fragment.cloneNode(true) : fragment );
524
525 if ( scripts )
526 jQuery.each( scripts, evalScript );
527 }
528
529 return this;
530
531 function root( elem, cur ) {
532 return table && jQuery.nodeName(elem, "table") && jQuery.nodeName(cur, "tr") ?
533 (elem.getElementsByTagName("tbody")[0] ||
534 elem.appendChild(elem.ownerDocument.createElement("tbody"))) :
535 elem;
536 }
537 }
538 };
539
540 // Give the init function the jQuery prototype for later instantiation
541 jQuery.fn.init.prototype = jQuery.fn;
542
543 function evalScript( i, elem ) {
544 if ( elem.src )
545 jQuery.ajax({
546 url: elem.src,
547 async: false,
548 dataType: "script"
549 });
550
551 else
552 jQuery.globalEval( elem.text || elem.textContent || elem.innerHTML || "" );
553
554 if ( elem.parentNode )
555 elem.parentNode.removeChild( elem );
556 }
557
558 function now(){
559 return +new Date;
560 }
561
562 jQuery.extend = jQuery.fn.extend = function() {
563 // copy reference to target object
564 var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options;
565
566 // Handle a deep copy situation
567 if ( typeof target === "boolean" ) {
568 deep = target;
569 target = arguments[1] || {};
570 // skip the boolean and the target
571 i = 2;
572 }
573
574 // Handle case when target is a string or something (possible in deep copy)
575 if ( typeof target !== "object" && !jQuery.isFunction(target) )
576 target = {};
577
578 // extend jQuery itself if only one argument is passed
579 if ( length == i ) {
580 target = this;
581 --i;
582 }
583
584 for ( ; i < length; i++ )
585 // Only deal with non-null/undefined values
586 if ( (options = arguments[ i ]) != null )
587 // Extend the base object
588 for ( var name in options ) {
589 var src = target[ name ], copy = options[ name ];
590
591 // Prevent never-ending loop
592 if ( target === copy )
593 continue;
594
595 // Recurse if we're merging object values
596 if ( deep && copy && typeof copy === "object" && !copy.nodeType )
597 target[ name ] = jQuery.extend( deep,
598 // Never move original objects, clone them
599 src || ( copy.length != null ? [ ] : { } )
600 , copy );
601
602 // Don't bring in undefined values
603 else if ( copy !== undefined )
604 target[ name ] = copy;
605
606 }
607
608 // Return the modified object
609 return target;
610 };
611
612 // exclude the following css properties to add px
613 var exclude = /z-?index|font-?weight|opacity|zoom|line-?height/i,
614 // cache defaultView
615 defaultView = document.defaultView || {},
616 toString = Object.prototype.toString;
617
618 jQuery.extend({
619 noConflict: function( deep ) {
620 window.$ = _$;
621
622 if ( deep )
623 window.jQuery = _jQuery;
624
625 return jQuery;
626 },
627
628 // See test/unit/core.js for details concerning isFunction.
629 // Since version 1.3, DOM methods and functions like alert
630 // aren't supported. They return false on IE (#2968).
631 isFunction: function( obj ) {
632 return toString.call(obj) === "[object Function]";
633 },
634
635 isArray: function( obj ) {
636 return toString.call(obj) === "[object Array]";
637 },
638
639 // check if an element is in a (or is an) XML document
640 isXMLDoc: function( elem ) {
641 return elem.nodeType === 9 && elem.documentElement.nodeName !== "HTML" ||
642 !!elem.ownerDocument && jQuery.isXMLDoc( elem.ownerDocument );
643 },
644
645 // Evalulates a script in a global context
646 globalEval: function( data ) {
647 if ( data && /\S/.test(data) ) {
648 // Inspired by code by Andrea Giammarchi
649 // http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom.html
650 var head = document.getElementsByTagName("head")[0] || document.documentElement,
651 script = document.createElement("script");
652
653 script.type = "text/javascript";
654 if ( jQuery.support.scriptEval )
655 script.appendChild( document.createTextNode( data ) );
656 else
657 script.text = data;
658
659 // Use insertBefore instead of appendChild to circumvent an IE6 bug.
660 // This arises when a base node is used (#2709).
661 head.insertBefore( script, head.firstChild );
662 head.removeChild( script );
663 }
664 },
665
666 nodeName: function( elem, name ) {
667 return elem.nodeName && elem.nodeName.toUpperCase() == name.toUpperCase();
668 },
669
670 // args is for internal usage only
671 each: function( object, callback, args ) {
672 var name, i = 0, length = object.length;
673
674 if ( args ) {
675 if ( length === undefined ) {
676 for ( name in object )
677 if ( callback.apply( object[ name ], args ) === false )
678 break;
679 } else
680 for ( ; i < length; )
681 if ( callback.apply( object[ i++ ], args ) === false )
682 break;
683
684 // A special, fast, case for the most common use of each
685 } else {
686 if ( length === undefined ) {
687 for ( name in object )
688 if ( callback.call( object[ name ], name, object[ name ] ) === false )
689 break;
690 } else
691 for ( var value = object[0];
692 i < length && callback.call( value, i, value ) !== false; value = object[++i] ){}
693 }
694
695 return object;
696 },
697
698 prop: function( elem, value, type, i, name ) {
699 // Handle executable functions
700 if ( jQuery.isFunction( value ) )
701 value = value.call( elem, i );
702
703 // Handle passing in a number to a CSS property
704 return typeof value === "number" && type == "curCSS" && !exclude.test( name ) ?
705 value + "px" :
706 value;
707 },
708
709 className: {
710 // internal only, use addClass("class")
711 add: function( elem, classNames ) {
712 jQuery.each((classNames || "").split(/\s+/), function(i, className){
713 if ( elem.nodeType == 1 && !jQuery.className.has( elem.className, className ) )
714 elem.className += (elem.className ? " " : "") + className;
715 });
716 },
717
718 // internal only, use removeClass("class")
719 remove: function( elem, classNames ) {
720 if (elem.nodeType == 1)
721 elem.className = classNames !== undefined ?
722 jQuery.grep(elem.className.split(/\s+/), function(className){
723 return !jQuery.className.has( classNames, className );
724 }).join(" ") :
725 "";
726 },
727
728 // internal only, use hasClass("class")
729 has: function( elem, className ) {
730 return elem && jQuery.inArray( className, (elem.className || elem).toString().split(/\s+/) ) > -1;
731 }
732 },
733
734 // A method for quickly swapping in/out CSS properties to get correct calculations
735 swap: function( elem, options, callback ) {
736 var old = {};
737 // Remember the old values, and insert the new ones
738 for ( var name in options ) {
739 old[ name ] = elem.style[ name ];
740 elem.style[ name ] = options[ name ];
741 }
742
743 callback.call( elem );
744
745 // Revert the old values
746 for ( var name in options )
747 elem.style[ name ] = old[ name ];
748 },
749
750 css: function( elem, name, force, extra ) {
751 if ( name == "width" || name == "height" ) {
752 var val, props = { position: "absolute", visibility: "hidden", display:"block" }, which = name == "width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ];
753
754 function getWH() {
755 val = name == "width" ? elem.offsetWidth : elem.offsetHeight;
756
757 if ( extra === "border" )
758 return;
759
760 jQuery.each( which, function() {
761 if ( !extra )
762 val -= parseFloat(jQuery.curCSS( elem, "padding" + this, true)) || 0;
763 if ( extra === "margin" )
764 val += parseFloat(jQuery.curCSS( elem, "margin" + this, true)) || 0;
765 else
766 val -= parseFloat(jQuery.curCSS( elem, "border" + this + "Width", true)) || 0;
767 });
768 }
769
770 if ( elem.offsetWidth !== 0 )
771 getWH();
772 else
773 jQuery.swap( elem, props, getWH );
774
775 return Math.max(0, Math.round(val));
776 }
777
778 return jQuery.curCSS( elem, name, force );
779 },
780
781 curCSS: function( elem, name, force ) {
782 var ret, style = elem.style;
783
784 // We need to handle opacity special in IE
785 if ( name == "opacity" && !jQuery.support.opacity ) {
786 ret = jQuery.attr( style, "opacity" );
787
788 return ret == "" ?
789 "1" :
790 ret;
791 }
792
793 // Make sure we're using the right name for getting the float value
794 if ( name.match( /float/i ) )
795 name = styleFloat;
796
797 if ( !force && style && style[ name ] )
798 ret = style[ name ];
799
800 else if ( defaultView.getComputedStyle ) {
801
802 // Only "float" is needed here
803 if ( name.match( /float/i ) )
804 name = "float";
805
806 name = name.replace( /([A-Z])/g, "-$1" ).toLowerCase();
807
808 var computedStyle = defaultView.getComputedStyle( elem, null );
809
810 if ( computedStyle )
811 ret = computedStyle.getPropertyValue( name );
812
813 // We should always get a number back from opacity
814 if ( name == "opacity" && ret == "" )
815 ret = "1";
816
817 } else if ( elem.currentStyle ) {
818 var camelCase = name.replace(/\-(\w)/g, function(all, letter){
819 return letter.toUpperCase();
820 });
821
822 ret = elem.currentStyle[ name ] || elem.currentStyle[ camelCase ];
823
824 // From the awesome hack by Dean Edwards
825 // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
826
827 // If we're not dealing with a regular pixel number
828 // but a number that has a weird ending, we need to convert it to pixels
829 if ( !/^\d+(px)?$/i.test( ret ) && /^\d/.test( ret ) ) {
830 // Remember the original values
831 var left = style.left, rsLeft = elem.runtimeStyle.left;
832
833 // Put in the new values to get a computed value out
834 elem.runtimeStyle.left = elem.currentStyle.left;
835 style.left = ret || 0;
836 ret = style.pixelLeft + "px";
837
838 // Revert the changed values
839 style.left = left;
840 elem.runtimeStyle.left = rsLeft;
841 }
842 }
843
844 return ret;
845 },
846
847 clean: function( elems, context, fragment ) {
848 context = context || document;
849
850 // !context.createElement fails in IE with an error but returns typeof 'object'
851 if ( typeof context.createElement === "undefined" )
852 context = context.ownerDocument || context[0] && context[0].ownerDocument || document;
853
854 // If a single string is passed in and it's a single tag
855 // just do a createElement and skip the rest
856 if ( !fragment && elems.length === 1 && typeof elems[0] === "string" ) {
857 var match = /^<(\w+)\s*\/?>$/.exec(elems[0]);
858 if ( match )
859 return [ context.createElement( match[1] ) ];
860 }
861
862 var ret = [], scripts = [], div = context.createElement("div");
863
864 jQuery.each(elems, function(i, elem){
865 if ( typeof elem === "number" )
866 elem += '';
867
868 if ( !elem )
869 return;
870
871 // Convert html string into DOM nodes
872 if ( typeof elem === "string" ) {
873 // Fix "XHTML"-style tags in all browsers
874 elem = elem.replace(/(<(\w+)[^>]*?)\/>/g, function(all, front, tag){
875 return tag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i) ?
876 all :
877 front + "></" + tag + ">";
878 });
879
880 // Trim whitespace, otherwise indexOf won't work as expected
881 var tags = elem.replace(/^\s+/, "").substring(0, 10).toLowerCase();
882
883 var wrap =
884 // option or optgroup
885 !tags.indexOf("<opt") &&
886 [ 1, "<select multiple='multiple'>", "</select>" ] ||
887
888 !tags.indexOf("<leg") &&
889 [ 1, "<fieldset>", "</fieldset>" ] ||
890
891 tags.match(/^<(thead|tbody|tfoot|colg|cap)/) &&
892 [ 1, "<table>", "</table>" ] ||
893
894 !tags.indexOf("<tr") &&
895 [ 2, "<table><tbody>", "</tbody></table>" ] ||
896
897 // <thead> matched above
898 (!tags.indexOf("<td") || !tags.indexOf("<th")) &&
899 [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ] ||
900
901 !tags.indexOf("<col") &&
902 [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ] ||
903
904 // IE can't serialize <link> and <script> tags normally
905 !jQuery.support.htmlSerialize &&
906 [ 1, "div<div>", "</div>" ] ||
907
908 [ 0, "", "" ];
909
910 // Go to html and back, then peel off extra wrappers
911 div.innerHTML = wrap[1] + elem + wrap[2];
912
913 // Move to the right depth
914 while ( wrap[0]-- )
915 div = div.lastChild;
916
917 // Remove IE's autoinserted <tbody> from table fragments
918 if ( !jQuery.support.tbody ) {
919
920 // String was a <table>, *may* have spurious <tbody>
921 var hasBody = /<tbody/i.test(elem),
922 tbody = !tags.indexOf("<table") && !hasBody ?
923 div.firstChild && div.firstChild.childNodes :
924
925 // String was a bare <thead> or <tfoot>
926 wrap[1] == "<table>" && !hasBody ?
927 div.childNodes :
928 [];
929
930 for ( var j = tbody.length - 1; j >= 0 ; --j )
931 if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length )
932 tbody[ j ].parentNode.removeChild( tbody[ j ] );
933
934 }
935
936 // IE completely kills leading whitespace when innerHTML is used
937 if ( !jQuery.support.leadingWhitespace && /^\s/.test( elem ) )
938 div.insertBefore( context.createTextNode( elem.match(/^\s*/)[0] ), div.firstChild );
939
940 elem = jQuery.makeArray( div.childNodes );
941 }
942
943 if ( elem.nodeType )
944 ret.push( elem );
945 else
946 ret = jQuery.merge( ret, elem );
947
948 });
949
950 if ( fragment ) {
951 for ( var i = 0; ret[i]; i++ ) {
952 if ( jQuery.nodeName( ret[i], "script" ) && (!ret[i].type || ret[i].type.toLowerCase() === "text/javascript") ) {
953 scripts.push( ret[i].parentNode ? ret[i].parentNode.removeChild( ret[i] ) : ret[i] );
954 } else {
955 if ( ret[i].nodeType === 1 )
956 ret.splice.apply( ret, [i + 1, 0].concat(jQuery.makeArray(ret[i].getElementsByTagName("script"))) );
957 fragment.appendChild( ret[i] );
958 }
959 }
960
961 return scripts;
962 }
963
964 return ret;
965 },
966
967 attr: function( elem, name, value ) {
968 // don't set attributes on text and comment nodes
969 if (!elem || elem.nodeType == 3 || elem.nodeType == 8)
970 return undefined;
971
972 var notxml = !jQuery.isXMLDoc( elem ),
973 // Whether we are setting (or getting)
974 set = value !== undefined;
975
976 // Try to normalize/fix the name
977 name = notxml && jQuery.props[ name ] || name;
978
979 // Only do all the following if this is a node (faster for style)
980 // IE elem.getAttribute passes even for style
981 if ( elem.tagName ) {
982
983 // These attributes require special treatment
984 var special = /href|src|style/.test( name );
985
986 // Safari mis-reports the default selected property of a hidden option
987 // Accessing the parent's selectedIndex property fixes it
988 if ( name == "selected" && elem.parentNode )
989 elem.parentNode.selectedIndex;
990
991 // If applicable, access the attribute via the DOM 0 way
992 if ( name in elem && notxml && !special ) {
993 if ( set ){
994 // We can't allow the type property to be changed (since it causes problems in IE)
995 if ( name == "type" && jQuery.nodeName( elem, "input" ) && elem.parentNode )
996 throw "type property can't be changed";
997
998 elem[ name ] = value;
999 }
1000
1001 // browsers index elements by id/name on forms, give priority to attributes.
1002 if( jQuery.nodeName( elem, "form" ) && elem.getAttributeNode(name) )
1003 return elem.getAttributeNode( name ).nodeValue;
1004
1005 // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set
1006 // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
1007 if ( name == "tabIndex" ) {
1008 var attributeNode = elem.getAttributeNode( "tabIndex" );
1009 return attributeNode && attributeNode.specified
1010 ? attributeNode.value
1011 : elem.nodeName.match(/(button|input|object|select|textarea)/i)
1012 ? 0
1013 : elem.nodeName.match(/^(a|area)$/i) && elem.href
1014 ? 0
1015 : undefined;
1016 }
1017
1018 return elem[ name ];
1019 }
1020
1021 if ( !jQuery.support.style && notxml && name == "style" )
1022 return jQuery.attr( elem.style, "cssText", value );
1023
1024 if ( set )
1025 // convert the value to a string (all browsers do this but IE) see #1070
1026 elem.setAttribute( name, "" + value );
1027
1028 var attr = !jQuery.support.hrefNormalized && notxml && special
1029 // Some attributes require a special call on IE
1030 ? elem.getAttribute( name, 2 )
1031 : elem.getAttribute( name );
1032
1033 // Non-existent attributes return null, we normalize to undefined
1034 return attr === null ? undefined : attr;
1035 }
1036
1037 // elem is actually elem.style ... set the style
1038
1039 // IE uses filters for opacity
1040 if ( !jQuery.support.opacity && name == "opacity" ) {
1041 if ( set ) {
1042 // IE has trouble with opacity if it does not have layout
1043 // Force it by setting the zoom level
1044 elem.zoom = 1;
1045
1046 // Set the alpha filter to set the opacity
1047 elem.filter = (elem.filter || "").replace( /alpha\([^)]*\)/, "" ) +
1048 (parseInt( value ) + '' == "NaN" ? "" : "alpha(opacity=" + value * 100 + ")");
1049 }
1050
1051 return elem.filter && elem.filter.indexOf("opacity=") >= 0 ?
1052 (parseFloat( elem.filter.match(/opacity=([^)]*)/)[1] ) / 100) + '':
1053 "";
1054 }
1055
1056 name = name.replace(/-([a-z])/ig, function(all, letter){
1057 return letter.toUpperCase();
1058 });
1059
1060 if ( set )
1061 elem[ name ] = value;
1062
1063 return elem[ name ];
1064 },
1065
1066 trim: function( text ) {
1067 return (text || "").replace( /^\s+|\s+$/g, "" );
1068 },
1069
1070 makeArray: function( array ) {
1071 var ret = [];
1072
1073 if( array != null ){
1074 var i = array.length;
1075 // The window, strings (and functions) also have 'length'
1076 if( i == null || typeof array === "string" || jQuery.isFunction(array) || array.setInterval )
1077 ret[0] = array;
1078 else
1079 while( i )
1080 ret[--i] = array[i];
1081 }
1082
1083 return ret;
1084 },
1085
1086 inArray: function( elem, array ) {
1087 for ( var i = 0, length = array.length; i < length; i++ )
1088 // Use === because on IE, window == document
1089 if ( array[ i ] === elem )
1090 return i;
1091
1092 return -1;
1093 },
1094
1095 merge: function( first, second ) {
1096 // We have to loop this way because IE & Opera overwrite the length
1097 // expando of getElementsByTagName
1098 var i = 0, elem, pos = first.length;
1099 // Also, we need to make sure that the correct elements are being returned
1100 // (IE returns comment nodes in a '*' query)
1101 if ( !jQuery.support.getAll ) {
1102 while ( (elem = second[ i++ ]) != null )
1103 if ( elem.nodeType != 8 )
1104 first[ pos++ ] = elem;
1105
1106 } else
1107 while ( (elem = second[ i++ ]) != null )
1108 first[ pos++ ] = elem;
1109
1110 return first;
1111 },
1112
1113 unique: function( array ) {
1114 var ret = [], done = {};
1115
1116 try {
1117
1118 for ( var i = 0, length = array.length; i < length; i++ ) {
1119 var id = jQuery.data( array[ i ] );
1120
1121 if ( !done[ id ] ) {
1122 done[ id ] = true;
1123 ret.push( array[ i ] );
1124 }
1125 }
1126
1127 } catch( e ) {
1128 ret = array;
1129 }
1130
1131 return ret;
1132 },
1133
1134 grep: function( elems, callback, inv ) {
1135 var ret = [];
1136
1137 // Go through the array, only saving the items
1138 // that pass the validator function
1139 for ( var i = 0, length = elems.length; i < length; i++ )
1140 if ( !inv != !callback( elems[ i ], i ) )
1141 ret.push( elems[ i ] );
1142
1143 return ret;
1144 },
1145
1146 map: function( elems, callback ) {
1147 var ret = [];
1148
1149 // Go through the array, translating each of the items to their
1150 // new value (or values).
1151 for ( var i = 0, length = elems.length; i < length; i++ ) {
1152 var value = callback( elems[ i ], i );
1153
1154 if ( value != null )
1155 ret[ ret.length ] = value;
1156 }
1157
1158 return ret.concat.apply( [], ret );
1159 }
1160 });
1161
1162 // Use of jQuery.browser is deprecated.
1163 // It's included for backwards compatibility and plugins,
1164 // although they should work to migrate away.
1165
1166 var userAgent = navigator.userAgent.toLowerCase();
1167
1168 // Figure out what browser is being used
1169 jQuery.browser = {
1170 version: (userAgent.match( /.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/ ) || [0,'0'])[1],
1171 safari: /webkit/.test( userAgent ),
1172 opera: /opera/.test( userAgent ),
1173 msie: /msie/.test( userAgent ) && !/opera/.test( userAgent ),
1174 mozilla: /mozilla/.test( userAgent ) && !/(compatible|webkit)/.test( userAgent )
1175 };
1176
1177 jQuery.each({
1178 parent: function(elem){return elem.parentNode;},
1179 parents: function(elem){return jQuery.dir(elem,"parentNode");},
1180 next: function(elem){return jQuery.nth(elem,2,"nextSibling");},
1181 prev: function(elem){return jQuery.nth(elem,2,"previousSibling");},
1182 nextAll: function(elem){return jQuery.dir(elem,"nextSibling");},
1183 prevAll: function(elem){return jQuery.dir(elem,"previousSibling");},
1184 siblings: function(elem){return jQuery.sibling(elem.parentNode.firstChild,elem);},
1185 children: function(elem){return jQuery.sibling(elem.firstChild);},
1186 contents: function(elem){return jQuery.nodeName(elem,"iframe")?elem.contentDocument||elem.contentWindow.document:jQuery.makeArray(elem.childNodes);}
1187 }, function(name, fn){
1188 jQuery.fn[ name ] = function( selector ) {
1189 var ret = jQuery.map( this, fn );
1190
1191 if ( selector && typeof selector == "string" )
1192 ret = jQuery.multiFilter( selector, ret );
1193
1194 return this.pushStack( jQuery.unique( ret ), name, selector );
1195 };
1196 });
1197
1198 jQuery.each({
1199 appendTo: "append",
1200 prependTo: "prepend",
1201 insertBefore: "before",
1202 insertAfter: "after",
1203 replaceAll: "replaceWith"
1204 }, function(name, original){
1205 jQuery.fn[ name ] = function( selector ) {
1206 var ret = [], insert = jQuery( selector );
1207
1208 for ( var i = 0, l = insert.length; i < l; i++ ) {
1209 var elems = (i > 0 ? this.clone(true) : this).get();
1210 jQuery.fn[ original ].apply( jQuery(insert[i]), elems );
1211 ret = ret.concat( elems );
1212 }
1213
1214 return this.pushStack( ret, name, selector );
1215 };
1216 });
1217
1218 jQuery.each({
1219 removeAttr: function( name ) {
1220 jQuery.attr( this, name, "" );
1221 if (this.nodeType == 1)
1222 this.removeAttribute( name );
1223 },
1224
1225 addClass: function( classNames ) {
1226 jQuery.className.add( this, classNames );
1227 },
1228
1229 removeClass: function( classNames ) {
1230 jQuery.className.remove( this, classNames );
1231 },
1232
1233 toggleClass: function( classNames, state ) {
1234 if( typeof state !== "boolean" )
1235 state = !jQuery.className.has( this, classNames );
1236 jQuery.className[ state ? "add" : "remove" ]( this, classNames );
1237 },
1238
1239 remove: function( selector ) {
1240 if ( !selector || jQuery.filter( selector, [ this ] ).length ) {
1241 // Prevent memory leaks
1242 jQuery( "*", this ).add([this]).each(function(){
1243 jQuery.event.remove(this);
1244 jQuery.removeData(this);
1245 });
1246 if (this.parentNode)
1247 this.parentNode.removeChild( this );
1248 }
1249 },
1250
1251 empty: function() {
1252 // Remove element nodes and prevent memory leaks
1253 jQuery(this).children().remove();
1254
1255 // Remove any remaining nodes
1256 while ( this.firstChild )
1257 this.removeChild( this.firstChild );
1258 }
1259 }, function(name, fn){
1260 jQuery.fn[ name ] = function(){
1261 return this.each( fn, arguments );
1262 };
1263 });
1264
1265 // Helper function used by the dimensions and offset modules
1266 function num(elem, prop) {
1267 return elem[0] && parseInt( jQuery.curCSS(elem[0], prop, true), 10 ) || 0;
1268 }
1269 var expando = "jQuery" + now(), uuid = 0, windowData = {};
1270
1271 jQuery.extend({
1272 cache: {},
1273
1274 data: function( elem, name, data ) {
1275 elem = elem == window ?
1276 windowData :
1277 elem;
1278
1279 var id = elem[ expando ];
1280
1281 // Compute a unique ID for the element
1282 if ( !id )
1283 id = elem[ expando ] = ++uuid;
1284
1285 // Only generate the data cache if we're
1286 // trying to access or manipulate it
1287 if ( name && !jQuery.cache[ id ] )
1288 jQuery.cache[ id ] = {};
1289
1290 // Prevent overriding the named cache with undefined values
1291 if ( data !== undefined )
1292 jQuery.cache[ id ][ name ] = data;
1293
1294 // Return the named cache data, or the ID for the element
1295 return name ?
1296 jQuery.cache[ id ][ name ] :
1297 id;
1298 },
1299
1300 removeData: function( elem, name ) {
1301 elem = elem == window ?
1302 windowData :
1303 elem;
1304
1305 var id = elem[ expando ];
1306
1307 // If we want to remove a specific section of the element's data
1308 if ( name ) {
1309 if ( jQuery.cache[ id ] ) {
1310 // Remove the section of cache data
1311 delete jQuery.cache[ id ][ name ];
1312
1313 // If we've removed all the data, remove the element's cache
1314 name = "";
1315
1316 for ( name in jQuery.cache[ id ] )
1317 break;
1318
1319 if ( !name )
1320 jQuery.removeData( elem );
1321 }
1322
1323 // Otherwise, we want to remove all of the element's data
1324 } else {
1325 // Clean up the element expando
1326 try {
1327 delete elem[ expando ];
1328 } catch(e){
1329 // IE has trouble directly removing the expando
1330 // but it's ok with using removeAttribute
1331 if ( elem.removeAttribute )
1332 elem.removeAttribute( expando );
1333 }
1334
1335 // Completely remove the data cache
1336 delete jQuery.cache[ id ];
1337 }
1338 },
1339 queue: function( elem, type, data ) {
1340 if ( elem ){
1341
1342 type = (type || "fx") + "queue";
1343
1344 var q = jQuery.data( elem, type );
1345
1346 if ( !q || jQuery.isArray(data) )
1347 q = jQuery.data( elem, type, jQuery.makeArray(data) );
1348 else if( data )
1349 q.push( data );
1350
1351 }
1352 return q;
1353 },
1354
1355 dequeue: function( elem, type ){
1356 var queue = jQuery.queue( elem, type ),
1357 fn = queue.shift();
1358
1359 if( !type || type === "fx" )
1360 fn = queue[0];
1361
1362 if( fn !== undefined )
1363 fn.call(elem);
1364 }
1365 });
1366
1367 jQuery.fn.extend({
1368 data: function( key, value ){
1369 var parts = key.split(".");
1370 parts[1] = parts[1] ? "." + parts[1] : "";
1371
1372 if ( value === undefined ) {
1373 var data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]);
1374
1375 if ( data === undefined && this.length )
1376 data = jQuery.data( this[0], key );
1377
1378 return data === undefined && parts[1] ?
1379 this.data( parts[0] ) :
1380 data;
1381 } else
1382 return this.trigger("setData" + parts[1] + "!", [parts[0], value]).each(function(){
1383 jQuery.data( this, key, value );
1384 });
1385 },
1386
1387 removeData: function( key ){
1388 return this.each(function(){
1389 jQuery.removeData( this, key );
1390 });
1391 },
1392 queue: function(type, data){
1393 if ( typeof type !== "string" ) {
1394 data = type;
1395 type = "fx";
1396 }
1397
1398 if ( data === undefined )
1399 return jQuery.queue( this[0], type );
1400
1401 return this.each(function(){
1402 var queue = jQuery.queue( this, type, data );
1403
1404 if( type == "fx" && queue.length == 1 )
1405 queue[0].call(this);
1406 });
1407 },
1408 dequeue: function(type){
1409 return this.each(function(){
1410 jQuery.dequeue( this, type );
1411 });
1412 }
1413 });/*!
1414 * Sizzle CSS Selector Engine - v0.9.3
1415 * Copyright 2009, The Dojo Foundation
1416 * Released under the MIT, BSD, and GPL Licenses.
1417 * More information: http://sizzlejs.com/
1418 */
1419 (function(){
1420
1421 var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?/g,
1422 done = 0,
1423 toString = Object.prototype.toString;
1424
1425 var Sizzle = function(selector, context, results, seed) {
1426 results = results || [];
1427 context = context || document;
1428
1429 if ( context.nodeType !== 1 && context.nodeType !== 9 )
1430 return [];
1431
1432 if ( !selector || typeof selector !== "string" ) {
1433 return results;
1434 }
1435
1436 var parts = [], m, set, checkSet, check, mode, extra, prune = true;
1437
1438 // Reset the position of the chunker regexp (start from head)
1439 chunker.lastIndex = 0;
1440
1441 while ( (m = chunker.exec(selector)) !== null ) {
1442 parts.push( m[1] );
1443
1444 if ( m[2] ) {
1445 extra = RegExp.rightContext;
1446 break;
1447 }
1448 }
1449
1450 if ( parts.length > 1 && origPOS.exec( selector ) ) {
1451 if ( parts.length === 2 && Expr.relative[ parts[0] ] ) {
1452 set = posProcess( parts[0] + parts[1], context );
1453 } else {
1454 set = Expr.relative[ parts[0] ] ?
1455 [ context ] :
1456 Sizzle( parts.shift(), context );
1457
1458 while ( parts.length ) {
1459 selector = parts.shift();
1460
1461 if ( Expr.relative[ selector ] )
1462 selector += parts.shift();
1463
1464 set = posProcess( selector, set );
1465 }
1466 }
1467 } else {
1468 var ret = seed ?
1469 { expr: parts.pop(), set: makeArray(seed) } :
1470 Sizzle.find( parts.pop(), parts.length === 1 && context.parentNode ? context.parentNode : context, isXML(context) );
1471 set = Sizzle.filter( ret.expr, ret.set );
1472
1473 if ( parts.length > 0 ) {
1474 checkSet = makeArray(set);
1475 } else {
1476 prune = false;
1477 }
1478
1479 while ( parts.length ) {
1480 var cur = parts.pop(), pop = cur;
1481
1482 if ( !Expr.relative[ cur ] ) {
1483 cur = "";
1484 } else {
1485 pop = parts.pop();
1486 }
1487
1488 if ( pop == null ) {
1489 pop = context;
1490 }
1491
1492 Expr.relative[ cur ]( checkSet, pop, isXML(context) );
1493 }
1494 }
1495
1496 if ( !checkSet ) {
1497 checkSet = set;
1498 }
1499
1500 if ( !checkSet ) {
1501 throw "Syntax error, unrecognized expression: " + (cur || selector);
1502 }
1503
1504 if ( toString.call(checkSet) === "[object Array]" ) {
1505 if ( !prune ) {
1506 results.push.apply( results, checkSet );
1507 } else if ( context.nodeType === 1 ) {
1508 for ( var i = 0; checkSet[i] != null; i++ ) {
1509 if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && contains(context, checkSet[i])) ) {
1510 results.push( set[i] );
1511 }
1512 }
1513 } else {
1514 for ( var i = 0; checkSet[i] != null; i++ ) {
1515 if ( checkSet[i] && checkSet[i].nodeType === 1 ) {
1516 results.push( set[i] );
1517 }
1518 }
1519 }
1520 } else {
1521 makeArray( checkSet, results );
1522 }
1523
1524 if ( extra ) {
1525 Sizzle( extra, context, results, seed );
1526
1527 if ( sortOrder ) {
1528 hasDuplicate = false;
1529 results.sort(sortOrder);
1530
1531 if ( hasDuplicate ) {
1532 for ( var i = 1; i < results.length; i++ ) {
1533 if ( results[i] === results[i-1] ) {
1534 results.splice(i--, 1);
1535 }
1536 }
1537 }
1538 }
1539 }
1540
1541 return results;
1542 };
1543
1544 Sizzle.matches = function(expr, set){
1545 return Sizzle(expr, null, null, set);
1546 };
1547
1548 Sizzle.find = function(expr, context, isXML){
1549 var set, match;
1550
1551 if ( !expr ) {
1552 return [];
1553 }
1554
1555 for ( var i = 0, l = Expr.order.length; i < l; i++ ) {
1556 var type = Expr.order[i], match;
1557
1558 if ( (match = Expr.match[ type ].exec( expr )) ) {
1559 var left = RegExp.leftContext;
1560
1561 if ( left.substr( left.length - 1 ) !== "\\" ) {
1562 match[1] = (match[1] || "").replace(/\\/g, "");
1563 set = Expr.find[ type ]( match, context, isXML );
1564 if ( set != null ) {
1565 expr = expr.replace( Expr.match[ type ], "" );
1566 break;
1567 }
1568 }
1569 }
1570 }
1571
1572 if ( !set ) {
1573 set = context.getElementsByTagName("*");
1574 }
1575
1576 return {set: set, expr: expr};
1577 };
1578
1579 Sizzle.filter = function(expr, set, inplace, not){
1580 var old = expr, result = [], curLoop = set, match, anyFound,
1581 isXMLFilter = set && set[0] && isXML(set[0]);
1582
1583 while ( expr && set.length ) {
1584 for ( var type in Expr.filter ) {
1585 if ( (match = Expr.match[ type ].exec( expr )) != null ) {
1586 var filter = Expr.filter[ type ], found, item;
1587 anyFound = false;
1588
1589 if ( curLoop == result ) {
1590 result = [];
1591 }
1592
1593 if ( Expr.preFilter[ type ] ) {
1594 match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter );
1595
1596 if ( !match ) {
1597 anyFound = found = true;
1598 } else if ( match === true ) {
1599 continue;
1600 }
1601 }
1602
1603 if ( match ) {
1604 for ( var i = 0; (item = curLoop[i]) != null; i++ ) {
1605 if ( item ) {
1606 found = filter( item, match, i, curLoop );
1607 var pass = not ^ !!found;
1608
1609 if ( inplace && found != null ) {
1610 if ( pass ) {
1611 anyFound = true;
1612 } else {
1613 curLoop[i] = false;
1614 }
1615 } else if ( pass ) {
1616 result.push( item );
1617 anyFound = true;
1618 }
1619 }
1620 }
1621 }
1622
1623 if ( found !== undefined ) {
1624 if ( !inplace ) {
1625 curLoop = result;
1626 }
1627
1628 expr = expr.replace( Expr.match[ type ], "" );
1629
1630 if ( !anyFound ) {
1631 return [];
1632 }
1633
1634 break;
1635 }
1636 }
1637 }
1638
1639 // Improper expression
1640 if ( expr == old ) {
1641 if ( anyFound == null ) {
1642 throw "Syntax error, unrecognized expression: " + expr;
1643 } else {
1644 break;
1645 }
1646 }
1647
1648 old = expr;
1649 }
1650
1651 return curLoop;
1652 };
1653
1654 var Expr = Sizzle.selectors = {
1655 order: [ "ID", "NAME", "TAG" ],
1656 match: {
1657 ID: /#((?:[\w\u00c0-\uFFFF_-]|\\.)+)/,
1658 CLASS: /\.((?:[\w\u00c0-\uFFFF_-]|\\.)+)/,
1659 NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF_-]|\\.)+)['"]*\]/,
1660 ATTR: /\[\s*((?:[\w\u00c0-\uFFFF_-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,
1661 TAG: /^((?:[\w\u00c0-\uFFFF\*_-]|\\.)+)/,
1662 CHILD: /:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,
1663 POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,
1664 PSEUDO: /:((?:[\w\u00c0-\uFFFF_-]|\\.)+)(?:\((['"]*)((?:\([^\)]+\)|[^\2\(\)]*)+)\2\))?/
1665 },
1666 attrMap: {
1667 "class": "className",
1668 "for": "htmlFor"
1669 },
1670 attrHandle: {
1671 href: function(elem){
1672 return elem.getAttribute("href");
1673 }
1674 },
1675 relative: {
1676 "+": function(checkSet, part, isXML){
1677 var isPartStr = typeof part === "string",
1678 isTag = isPartStr && !/\W/.test(part),
1679 isPartStrNotTag = isPartStr && !isTag;
1680
1681 if ( isTag && !isXML ) {
1682 part = part.toUpperCase();
1683 }
1684
1685 for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) {
1686 if ( (elem = checkSet[i]) ) {
1687 while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {}
1688
1689 checkSet[i] = isPartStrNotTag || elem && elem.nodeName === part ?
1690 elem || false :
1691 elem === part;
1692 }
1693 }
1694
1695 if ( isPartStrNotTag ) {
1696 Sizzle.filter( part, checkSet, true );
1697 }
1698 },
1699 ">": function(checkSet, part, isXML){
1700 var isPartStr = typeof part === "string";
1701
1702 if ( isPartStr && !/\W/.test(part) ) {
1703 part = isXML ? part : part.toUpperCase();
1704
1705 for ( var i = 0, l = checkSet.length; i < l; i++ ) {
1706 var elem = checkSet[i];
1707 if ( elem ) {
1708 var parent = elem.parentNode;
1709 checkSet[i] = parent.nodeName === part ? parent : false;
1710 }
1711 }
1712 } else {
1713 for ( var i = 0, l = checkSet.length; i < l; i++ ) {
1714 var elem = checkSet[i];
1715 if ( elem ) {
1716 checkSet[i] = isPartStr ?
1717 elem.parentNode :
1718 elem.parentNode === part;
1719 }
1720 }
1721
1722 if ( isPartStr ) {
1723 Sizzle.filter( part, checkSet, true );
1724 }
1725 }
1726 },
1727 "": function(checkSet, part, isXML){
1728 var doneName = done++, checkFn = dirCheck;
1729
1730 if ( !part.match(/\W/) ) {
1731 var nodeCheck = part = isXML ? part : part.toUpperCase();
1732 checkFn = dirNodeCheck;
1733 }
1734
1735 checkFn("parentNode", part, doneName, checkSet, nodeCheck, isXML);
1736 },
1737 "~": function(checkSet, part, isXML){
1738 var doneName = done++, checkFn = dirCheck;
1739
1740 if ( typeof part === "string" && !part.match(/\W/) ) {
1741 var nodeCheck = part = isXML ? part : part.toUpperCase();
1742 checkFn = dirNodeCheck;
1743 }
1744
1745 checkFn("previousSibling", part, doneName, checkSet, nodeCheck, isXML);
1746 }
1747 },
1748 find: {
1749 ID: function(match, context, isXML){
1750 if ( typeof context.getElementById !== "undefined" && !isXML ) {
1751 var m = context.getElementById(match[1]);
1752 return m ? [m] : [];
1753 }
1754 },
1755 NAME: function(match, context, isXML){
1756 if ( typeof context.getElementsByName !== "undefined" ) {
1757 var ret = [], results = context.getElementsByName(match[1]);
1758
1759 for ( var i = 0, l = results.length; i < l; i++ ) {
1760 if ( results[i].getAttribute("name") === match[1] ) {
1761 ret.push( results[i] );
1762 }
1763 }
1764
1765 return ret.length === 0 ? null : ret;
1766 }
1767 },
1768 TAG: function(match, context){
1769 return context.getElementsByTagName(match[1]);
1770 }
1771 },
1772 preFilter: {
1773 CLASS: function(match, curLoop, inplace, result, not, isXML){
1774 match = " " + match[1].replace(/\\/g, "") + " ";
1775
1776 if ( isXML ) {
1777 return match;
1778 }
1779
1780 for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) {
1781 if ( elem ) {
1782 if ( not ^ (elem.className && (" " + elem.className + " ").indexOf(match) >= 0) ) {
1783 if ( !inplace )
1784 result.push( elem );
1785 } else if ( inplace ) {
1786 curLoop[i] = false;
1787 }
1788 }
1789 }
1790
1791 return false;
1792 },
1793 ID: function(match){
1794 return match[1].replace(/\\/g, "");
1795 },
1796 TAG: function(match, curLoop){
1797 for ( var i = 0; curLoop[i] === false; i++ ){}
1798 return curLoop[i] && isXML(curLoop[i]) ? match[1] : match[1].toUpperCase();
1799 },
1800 CHILD: function(match){
1801 if ( match[1] == "nth" ) {
1802 // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'
1803 var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec(
1804 match[2] == "even" && "2n" || match[2] == "odd" && "2n+1" ||
1805 !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]);
1806
1807 // calculate the numbers (first)n+(last) including if they are negative
1808 match[2] = (test[1] + (test[2] || 1)) - 0;
1809 match[3] = test[3] - 0;
1810 }
1811
1812 // TODO: Move to normal caching system
1813 match[0] = done++;
1814
1815 return match;
1816 },
1817 ATTR: function(match, curLoop, inplace, result, not, isXML){
1818 var name = match[1].replace(/\\/g, "");
1819
1820 if ( !isXML && Expr.attrMap[name] ) {
1821 match[1] = Expr.attrMap[name];
1822 }
1823
1824 if ( match[2] === "~=" ) {
1825 match[4] = " " + match[4] + " ";
1826 }
1827
1828 return match;
1829 },
1830 PSEUDO: function(match, curLoop, inplace, result, not){
1831 if ( match[1] === "not" ) {
1832 // If we're dealing with a complex expression, or a simple one
1833 if ( match[3].match(chunker).length > 1 || /^\w/.test(match[3]) ) {
1834 match[3] = Sizzle(match[3], null, null, curLoop);
1835 } else {
1836 var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not);
1837 if ( !inplace ) {
1838 result.push.apply( result, ret );
1839 }
1840 return false;
1841 }
1842 } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) {
1843 return true;
1844 }
1845
1846 return match;
1847 },
1848 POS: function(match){
1849 match.unshift( true );
1850 return match;
1851 }
1852 },
1853 filters: {
1854 enabled: function(elem){
1855 return elem.disabled === false && elem.type !== "hidden";
1856 },
1857 disabled: function(elem){
1858 return elem.disabled === true;
1859 },
1860 checked: function(elem){
1861 return elem.checked === true;
1862 },
1863 selected: function(elem){
1864 // Accessing this property makes selected-by-default
1865 // options in Safari work properly
1866 elem.parentNode.selectedIndex;
1867 return elem.selected === true;
1868 },
1869 parent: function(elem){
1870 return !!elem.firstChild;
1871 },
1872 empty: function(elem){
1873 return !elem.firstChild;
1874 },
1875 has: function(elem, i, match){
1876 return !!Sizzle( match[3], elem ).length;
1877 },
1878 header: function(elem){
1879 return /h\d/i.test( elem.nodeName );
1880 },
1881 text: function(elem){
1882 return "text" === elem.type;
1883 },
1884 radio: function(elem){
1885 return "radio" === elem.type;
1886 },
1887 checkbox: function(elem){
1888 return "checkbox" === elem.type;
1889 },
1890 file: function(elem){
1891 return "file" === elem.type;
1892 },
1893 password: function(elem){
1894 return "password" === elem.type;
1895 },
1896 submit: function(elem){
1897 return "submit" === elem.type;
1898 },
1899 image: function(elem){
1900 return "image" === elem.type;
1901 },
1902 reset: function(elem){
1903 return "reset" === elem.type;
1904 },
1905 button: function(elem){
1906 return "button" === elem.type || elem.nodeName.toUpperCase() === "BUTTON";
1907 },
1908 input: function(elem){
1909 return /input|select|textarea|button/i.test(elem.nodeName);
1910 }
1911 },
1912 setFilters: {
1913 first: function(elem, i){
1914 return i === 0;
1915 },
1916 last: function(elem, i, match, array){
1917 return i === array.length - 1;
1918 },
1919 even: function(elem, i){
1920 return i % 2 === 0;
1921 },
1922 odd: function(elem, i){
1923 return i % 2 === 1;
1924 },
1925 lt: function(elem, i, match){
1926 return i < match[3] - 0;
1927 },
1928 gt: function(elem, i, match){
1929 return i > match[3] - 0;
1930 },
1931 nth: function(elem, i, match){
1932 return match[3] - 0 == i;
1933 },
1934 eq: function(elem, i, match){
1935 return match[3] - 0 == i;
1936 }
1937 },
1938 filter: {
1939 PSEUDO: function(elem, match, i, array){
1940 var name = match[1], filter = Expr.filters[ name ];
1941
1942 if ( filter ) {
1943 return filter( elem, i, match, array );
1944 } else if ( name === "contains" ) {
1945 return (elem.textContent || elem.innerText || "").indexOf(match[3]) >= 0;
1946 } else if ( name === "not" ) {
1947 var not = match[3];
1948
1949 for ( var i = 0, l = not.length; i < l; i++ ) {
1950 if ( not[i] === elem ) {
1951 return false;
1952 }
1953 }
1954
1955 return true;
1956 }
1957 },
1958 CHILD: function(elem, match){
1959 var type = match[1], node = elem;
1960 switch (type) {
1961 case 'only':
1962 case 'first':
1963 while (node = node.previousSibling) {
1964 if ( node.nodeType === 1 ) return false;
1965 }
1966 if ( type == 'first') return true;
1967 node = elem;
1968 case 'last':
1969 while (node = node.nextSibling) {
1970 if ( node.nodeType === 1 ) return false;
1971 }
1972 return true;
1973 case 'nth':
1974 var first = match[2], last = match[3];
1975
1976 if ( first == 1 && last == 0 ) {
1977 return true;
1978 }
1979
1980 var doneName = match[0],
1981 parent = elem.parentNode;
1982
1983 if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) {
1984 var count = 0;
1985 for ( node = parent.firstChild; node; node = node.nextSibling ) {
1986 if ( node.nodeType === 1 ) {
1987 node.nodeIndex = ++count;
1988 }
1989 }
1990 parent.sizcache = doneName;
1991 }
1992
1993 var diff = elem.nodeIndex - last;
1994 if ( first == 0 ) {
1995 return diff == 0;
1996 } else {
1997 return ( diff % first == 0 && diff / first >= 0 );
1998 }
1999 }
2000 },
2001 ID: function(elem, match){
2002 return elem.nodeType === 1 && elem.getAttribute("id") === match;
2003 },
2004 TAG: function(elem, match){
2005 return (match === "*" && elem.nodeType === 1) || elem.nodeName === match;
2006 },
2007 CLASS: function(elem, match){
2008 return (" " + (elem.className || elem.getAttribute("class")) + " ")
2009 .indexOf( match ) > -1;
2010 },
2011 ATTR: function(elem, match){
2012 var name = match[1],
2013 result = Expr.attrHandle[ name ] ?
2014 Expr.attrHandle[ name ]( elem ) :
2015 elem[ name ] != null ?
2016 elem[ name ] :
2017 elem.getAttribute( name ),
2018 value = result + "",
2019 type = match[2],
2020 check = match[4];
2021
2022 return result == null ?
2023 type === "!=" :
2024 type === "=" ?
2025 value === check :
2026 type === "*=" ?
2027 value.indexOf(check) >= 0 :
2028 type === "~=" ?
2029 (" " + value + " ").indexOf(check) >= 0 :
2030 !check ?
2031 value && result !== false :
2032 type === "!=" ?
2033 value != check :
2034 type === "^=" ?
2035 value.indexOf(check) === 0 :
2036 type === "$=" ?
2037 value.substr(value.length - check.length) === check :
2038 type === "|=" ?
2039 value === check || value.substr(0, check.length + 1) === check + "-" :
2040 false;
2041 },
2042 POS: function(elem, match, i, array){
2043 var name = match[2], filter = Expr.setFilters[ name ];
2044
2045 if ( filter ) {
2046 return filter( elem, i, match, array );
2047 }
2048 }
2049 }
2050 };
2051
2052 var origPOS = Expr.match.POS;
2053
2054 for ( var type in Expr.match ) {
2055 Expr.match[ type ] = RegExp( Expr.match[ type ].source + /(?![^\[]*\])(?![^\(]*\))/.source );
2056 }
2057
2058 var makeArray = function(array, results) {
2059 array = Array.prototype.slice.call( array );
2060
2061 if ( results ) {
2062 results.push.apply( results, array );
2063 return results;
2064 }
2065
2066 return array;
2067 };
2068
2069 // Perform a simple check to determine if the browser is capable of
2070 // converting a NodeList to an array using builtin methods.
2071 try {
2072 Array.prototype.slice.call( document.documentElement.childNodes );
2073
2074 // Provide a fallback method if it does not work
2075 } catch(e){
2076 makeArray = function(array, results) {
2077 var ret = results || [];
2078
2079 if ( toString.call(array) === "[object Array]" ) {
2080 Array.prototype.push.apply( ret, array );
2081 } else {
2082 if ( typeof array.length === "number" ) {
2083 for ( var i = 0, l = array.length; i < l; i++ ) {
2084 ret.push( array[i] );
2085 }
2086 } else {
2087 for ( var i = 0; array[i]; i++ ) {
2088 ret.push( array[i] );
2089 }
2090 }
2091 }
2092
2093 return ret;
2094 };
2095 }
2096
2097 var sortOrder;
2098
2099 if ( document.documentElement.compareDocumentPosition ) {
2100 sortOrder = function( a, b ) {
2101 var ret = a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1;
2102 if ( ret === 0 ) {
2103 hasDuplicate = true;
2104 }
2105 return ret;
2106 };
2107 } else if ( "sourceIndex" in document.documentElement ) {
2108 sortOrder = function( a, b ) {
2109 var ret = a.sourceIndex - b.sourceIndex;
2110 if ( ret === 0 ) {
2111 hasDuplicate = true;
2112 }
2113 return ret;
2114 };
2115 } else if ( document.createRange ) {
2116 sortOrder = function( a, b ) {
2117 var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange();
2118 aRange.selectNode(a);
2119 aRange.collapse(true);
2120 bRange.selectNode(b);
2121 bRange.collapse(true);
2122 var ret = aRange.compareBoundaryPoints(Range.START_TO_END, bRange);
2123 if ( ret === 0 ) {
2124 hasDuplicate = true;
2125 }
2126 return ret;
2127 };
2128 }
2129
2130 // Check to see if the browser returns elements by name when
2131 // querying by getElementById (and provide a workaround)
2132 (function(){
2133 // We're going to inject a fake input element with a specified name
2134 var form = document.createElement("form"),
2135 id = "script" + (new Date).getTime();
2136 form.innerHTML = "<input name='" + id + "'/>";
2137
2138 // Inject it into the root element, check its status, and remove it quickly
2139 var root = document.documentElement;
2140 root.insertBefore( form, root.firstChild );
2141
2142 // The workaround has to do additional checks after a getElementById
2143 // Which slows things down for other browsers (hence the branching)
2144 if ( !!document.getElementById( id ) ) {
2145 Expr.find.ID = function(match, context, isXML){
2146 if ( typeof context.getElementById !== "undefined" && !isXML ) {
2147 var m = context.getElementById(match[1]);
2148 return m ? m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? [m] : undefined : [];
2149 }
2150 };
2151
2152 Expr.filter.ID = function(elem, match){
2153 var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id");
2154 return elem.nodeType === 1 && node && node.nodeValue === match;
2155 };
2156 }
2157
2158 root.removeChild( form );
2159 })();
2160
2161 (function(){
2162 // Check to see if the browser returns only elements
2163 // when doing getElementsByTagName("*")
2164
2165 // Create a fake element
2166 var div = document.createElement("div");
2167 div.appendChild( document.createComment("") );
2168
2169 // Make sure no comments are found
2170 if ( div.getElementsByTagName("*").length > 0 ) {
2171 Expr.find.TAG = function(match, context){
2172 var results = context.getElementsByTagName(match[1]);
2173
2174 // Filter out possible comments
2175 if ( match[1] === "*" ) {
2176 var tmp = [];
2177
2178 for ( var i = 0; results[i]; i++ ) {
2179 if ( results[i].nodeType === 1 ) {
2180 tmp.push( results[i] );
2181 }
2182 }
2183
2184 results = tmp;
2185 }
2186
2187 return results;
2188 };
2189 }
2190
2191 // Check to see if an attribute returns normalized href attributes
2192 div.innerHTML = "<a href='#'></a>";
2193 if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" &&
2194 div.firstChild.getAttribute("href") !== "#" ) {
2195 Expr.attrHandle.href = function(elem){
2196 return elem.getAttribute("href", 2);
2197 };
2198 }
2199 })();
2200
2201 if ( document.querySelectorAll ) (function(){
2202 var oldSizzle = Sizzle, div = document.createElement("div");
2203 div.innerHTML = "<p class='TEST'></p>";
2204
2205 // Safari can't handle uppercase or unicode characters when
2206 // in quirks mode.
2207 if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) {
2208 return;
2209 }
2210
2211 Sizzle = function(query, context, extra, seed){
2212 context = context || document;
2213
2214 // Only use querySelectorAll on non-XML documents
2215 // (ID selectors don't work in non-HTML documents)
2216 if ( !seed && context.nodeType === 9 && !isXML(context) ) {
2217 try {
2218 return makeArray( context.querySelectorAll(query), extra );
2219 } catch(e){}
2220 }
2221
2222 return oldSizzle(query, context, extra, seed);
2223 };
2224
2225 Sizzle.find = oldSizzle.find;
2226 Sizzle.filter = oldSizzle.filter;
2227 Sizzle.selectors = oldSizzle.selectors;
2228 Sizzle.matches = oldSizzle.matches;
2229 })();
2230
2231 if ( document.getElementsByClassName && document.documentElement.getElementsByClassName ) (function(){
2232 var div = document.createElement("div");
2233 div.innerHTML = "<div class='test e'></div><div class='test'></div>";
2234
2235 // Opera can't find a second classname (in 9.6)
2236 if ( div.getElementsByClassName("e").length === 0 )
2237 return;
2238
2239 // Safari caches class attributes, doesn't catch changes (in 3.2)
2240 div.lastChild.className = "e";
2241
2242 if ( div.getElementsByClassName("e").length === 1 )
2243 return;
2244
2245 Expr.order.splice(1, 0, "CLASS");
2246 Expr.find.CLASS = function(match, context, isXML) {
2247 if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) {
2248 return context.getElementsByClassName(match[1]);
2249 }
2250 };
2251 })();
2252
2253 function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
2254 var sibDir = dir == "previousSibling" && !isXML;
2255 for ( var i = 0, l = checkSet.length; i < l; i++ ) {
2256 var elem = checkSet[i];
2257 if ( elem ) {
2258 if ( sibDir && elem.nodeType === 1 ){
2259 elem.sizcache = doneName;
2260 elem.sizset = i;
2261 }
2262 elem = elem[dir];
2263 var match = false;
2264
2265 while ( elem ) {
2266 if ( elem.sizcache === doneName ) {
2267 match = checkSet[elem.sizset];
2268 break;
2269 }
2270
2271 if ( elem.nodeType === 1 && !isXML ){
2272 elem.sizcache = doneName;
2273 elem.sizset = i;
2274 }
2275
2276 if ( elem.nodeName === cur ) {
2277 match = elem;
2278 break;
2279 }
2280
2281 elem = elem[dir];
2282 }
2283
2284 checkSet[i] = match;
2285 }
2286 }
2287 }
2288
2289 function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
2290 var sibDir = dir == "previousSibling" && !isXML;
2291 for ( var i = 0, l = checkSet.length; i < l; i++ ) {
2292 var elem = checkSet[i];
2293 if ( elem ) {
2294 if ( sibDir && elem.nodeType === 1 ) {
2295 elem.sizcache = doneName;
2296 elem.sizset = i;
2297 }
2298 elem = elem[dir];
2299 var match = false;
2300
2301 while ( elem ) {
2302 if ( elem.sizcache === doneName ) {
2303 match = checkSet[elem.sizset];
2304 break;
2305 }
2306
2307 if ( elem.nodeType === 1 ) {
2308 if ( !isXML ) {
2309 elem.sizcache = doneName;
2310 elem.sizset = i;
2311 }
2312 if ( typeof cur !== "string" ) {
2313 if ( elem === cur ) {
2314 match = true;
2315 break;
2316 }
2317
2318 } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) {
2319 match = elem;
2320 break;
2321 }
2322 }
2323
2324 elem = elem[dir];
2325 }
2326
2327 checkSet[i] = match;
2328 }
2329 }
2330 }
2331
2332 var contains = document.compareDocumentPosition ? function(a, b){
2333 return a.compareDocumentPosition(b) & 16;
2334 } : function(a, b){
2335 return a !== b && (a.contains ? a.contains(b) : true);
2336 };
2337
2338 var isXML = function(elem){
2339 return elem.nodeType === 9 && elem.documentElement.nodeName !== "HTML" ||
2340 !!elem.ownerDocument && isXML( elem.ownerDocument );
2341 };
2342
2343 var posProcess = function(selector, context){
2344 var tmpSet = [], later = "", match,
2345 root = context.nodeType ? [context] : context;
2346
2347 // Position selectors must be done after the filter
2348 // And so must :not(positional) so we move all PSEUDOs to the end
2349 while ( (match = Expr.match.PSEUDO.exec( selector )) ) {
2350 later += match[0];
2351 selector = selector.replace( Expr.match.PSEUDO, "" );
2352 }
2353
2354 selector = Expr.relative[selector] ? selector + "*" : selector;
2355
2356 for ( var i = 0, l = root.length; i < l; i++ ) {
2357 Sizzle( selector, root[i], tmpSet );
2358 }
2359
2360 return Sizzle.filter( later, tmpSet );
2361 };
2362
2363 // EXPOSE
2364 jQuery.find = Sizzle;
2365 jQuery.filter = Sizzle.filter;
2366 jQuery.expr = Sizzle.selectors;
2367 jQuery.expr[":"] = jQuery.expr.filters;
2368
2369 Sizzle.selectors.filters.hidden = function(elem){
2370 return elem.offsetWidth === 0 || elem.offsetHeight === 0;
2371 };
2372
2373 Sizzle.selectors.filters.visible = function(elem){
2374 return elem.offsetWidth > 0 || elem.offsetHeight > 0;
2375 };
2376
2377 Sizzle.selectors.filters.animated = function(elem){
2378 return jQuery.grep(jQuery.timers, function(fn){
2379 return elem === fn.elem;
2380 }).length;
2381 };
2382
2383 jQuery.multiFilter = function( expr, elems, not ) {
2384 if ( not ) {
2385 expr = ":not(" + expr + ")";
2386 }
2387
2388 return Sizzle.matches(expr, elems);
2389 };
2390
2391 jQuery.dir = function( elem, dir ){
2392 var matched = [], cur = elem[dir];
2393 while ( cur && cur != document ) {
2394 if ( cur.nodeType == 1 )
2395 matched.push( cur );
2396 cur = cur[dir];
2397 }
2398 return matched;
2399 };
2400
2401 jQuery.nth = function(cur, result, dir, elem){
2402 result = result || 1;
2403 var num = 0;
2404
2405 for ( ; cur; cur = cur[dir] )
2406 if ( cur.nodeType == 1 && ++num == result )
2407 break;
2408
2409 return cur;
2410 };
2411
2412 jQuery.sibling = function(n, elem){
2413 var r = [];
2414
2415 for ( ; n; n = n.nextSibling ) {
2416 if ( n.nodeType == 1 && n != elem )
2417 r.push( n );
2418 }
2419
2420 return r;
2421 };
2422
2423 return;
2424
2425 window.Sizzle = Sizzle;
2426
2427 })();
2428 /*
2429 * A number of helper functions used for managing events.
2430 * Many of the ideas behind this code originated from
2431 * Dean Edwards' addEvent library.
2432 */
2433 jQuery.event = {
2434
2435 // Bind an event to an element
2436 // Original by Dean Edwards
2437 add: function(elem, types, handler, data) {
2438 if ( elem.nodeType == 3 || elem.nodeType == 8 )
2439 return;
2440
2441 // For whatever reason, IE has trouble passing the window object
2442 // around, causing it to be cloned in the process
2443 if ( elem.setInterval && elem != window )
2444 elem = window;
2445
2446 // Make sure that the function being executed has a unique ID
2447 if ( !handler.guid )
2448 handler.guid = this.guid++;
2449
2450 // if data is passed, bind to handler
2451 if ( data !== undefined ) {
2452 // Create temporary function pointer to original handler
2453 var fn = handler;
2454
2455 // Create unique handler function, wrapped around original handler
2456 handler = this.proxy( fn );
2457
2458 // Store data in unique handler
2459 handler.data = data;
2460 }
2461
2462 // Init the element's event structure
2463 var events = jQuery.data(elem, "events") || jQuery.data(elem, "events", {}),
2464 handle = jQuery.data(elem, "handle") || jQuery.data(elem, "handle", function(){
2465 // Handle the second event of a trigger and when
2466 // an event is called after a page has unloaded
2467 return typeof jQuery !== "undefined" && !jQuery.event.triggered ?
2468 jQuery.event.handle.apply(arguments.callee.elem, arguments) :
2469 undefined;
2470 });
2471 // Add elem as a property of the handle function
2472 // This is to prevent a memory leak with non-native
2473 // event in IE.
2474 handle.elem = elem;
2475
2476 // Handle multiple events separated by a space
2477 // jQuery(...).bind("mouseover mouseout", fn);
2478 jQuery.each(types.split(/\s+/), function(index, type) {
2479 // Namespaced event handlers
2480 var namespaces = type.split(".");
2481 type = namespaces.shift();
2482 handler.type = namespaces.slice().sort().join(".");
2483
2484 // Get the current list of functions bound to this event
2485 var handlers = events[type];
2486
2487 if ( jQuery.event.specialAll[type] )
2488 jQuery.event.specialAll[type].setup.call(elem, data, namespaces);
2489
2490 // Init the event handler queue
2491 if (!handlers) {
2492 handlers = events[type] = {};
2493
2494 // Check for a special event handler
2495 // Only use addEventListener/attachEvent if the special
2496 // events handler returns false
2497 if ( !jQuery.event.special[type] || jQuery.event.special[type].setup.call(elem, data, namespaces) === false ) {
2498 // Bind the global event handler to the element
2499 if (elem.addEventListener)
2500 elem.addEventListener(type, handle, false);
2501 else if (elem.attachEvent)
2502 elem.attachEvent("on" + type, handle);
2503 }
2504 }
2505
2506 // Add the function to the element's handler list
2507 handlers[handler.guid] = handler;
2508
2509 // Keep track of which events have been used, for global triggering
2510 jQuery.event.global[type] = true;
2511 });
2512
2513 // Nullify elem to prevent memory leaks in IE
2514 elem = null;
2515 },
2516
2517 guid: 1,
2518 global: {},
2519
2520 // Detach an event or set of events from an element
2521 remove: function(elem, types, handler) {
2522 // don't do events on text and comment nodes
2523 if ( elem.nodeType == 3 || elem.nodeType == 8 )
2524 return;
2525
2526 var events = jQuery.data(elem, "events"), ret, index;
2527
2528 if ( events ) {
2529 // Unbind all events for the element
2530 if ( types === undefined || (typeof types === "string" && types.charAt(0) == ".") )
2531 for ( var type in events )
2532 this.remove( elem, type + (types || "") );
2533 else {
2534 // types is actually an event object here
2535 if ( types.type ) {
2536 handler = types.handler;
2537 types = types.type;
2538 }
2539
2540 // Handle multiple events seperated by a space
2541 // jQuery(...).unbind("mouseover mouseout", fn);
2542 jQuery.each(types.split(/\s+/), function(index, type){
2543 // Namespaced event handlers
2544 var namespaces = type.split(".");
2545 type = namespaces.shift();
2546 var namespace = RegExp("(^|\\.)" + namespaces.slice().sort().join(".*\\.") + "(\\.|$)");
2547
2548 if ( events[type] ) {
2549 // remove the given handler for the given type
2550 if ( handler )
2551 delete events[type][handler.guid];
2552
2553 // remove all handlers for the given type
2554 else
2555 for ( var handle in events[type] )
2556 // Handle the removal of namespaced events
2557 if ( namespace.test(events[type][handle].type) )
2558 delete events[type][handle];
2559
2560 if ( jQuery.event.specialAll[type] )
2561 jQuery.event.specialAll[type].teardown.call(elem, namespaces);
2562
2563 // remove generic event handler if no more handlers exist
2564 for ( ret in events[type] ) break;
2565 if ( !ret ) {
2566 if ( !jQuery.event.special[type] || jQuery.event.special[type].teardown.call(elem, namespaces) === false ) {
2567 if (elem.removeEventListener)
2568 elem.removeEventListener(type, jQuery.data(elem, "handle"), false);
2569 else if (elem.detachEvent)
2570 elem.detachEvent("on" + type, jQuery.data(elem, "handle"));
2571 }
2572 ret = null;
2573 delete events[type];
2574 }
2575 }
2576 });
2577 }
2578
2579 // Remove the expando if it's no longer used
2580 for ( ret in events ) break;
2581 if ( !ret ) {
2582 var handle = jQuery.data( elem, "handle" );
2583 if ( handle ) handle.elem = null;
2584 jQuery.removeData( elem, "events" );
2585 jQuery.removeData( elem, "handle" );
2586 }
2587 }
2588 },
2589
2590 // bubbling is internal
2591 trigger: function( event, data, elem, bubbling ) {
2592 // Event object or event type
2593 var type = event.type || event;
2594
2595 if( !bubbling ){
2596 event = typeof event === "object" ?
2597 // jQuery.Event object
2598 event[expando] ? event :
2599 // Object literal
2600 jQuery.extend( jQuery.Event(type), event ) :
2601 // Just the event type (string)
2602 jQuery.Event(type);
2603
2604 if ( type.indexOf("!") >= 0 ) {
2605 event.type = type = type.slice(0, -1);
2606 event.exclusive = true;
2607 }
2608
2609 // Handle a global trigger
2610 if ( !elem ) {
2611 // Don't bubble custom events when global (to avoid too much overhead)
2612 event.stopPropagation();
2613 // Only trigger if we've ever bound an event for it
2614 if ( this.global[type] )
2615 jQuery.each( jQuery.cache, function(){
2616 if ( this.events && this.events[type] )
2617 jQuery.event.trigger( event, data, this.handle.elem );
2618 });
2619 }
2620
2621 // Handle triggering a single element
2622
2623 // don't do events on text and comment nodes
2624 if ( !elem || elem.nodeType == 3 || elem.nodeType == 8 )
2625 return undefined;
2626
2627 // Clean up in case it is reused
2628 event.result = undefined;
2629 event.target = elem;
2630
2631 // Clone the incoming data, if any
2632 data = jQuery.makeArray(data);
2633 data.unshift( event );
2634 }
2635
2636 event.currentTarget = elem;
2637
2638 // Trigger the event, it is assumed that "handle" is a function
2639 var handle = jQuery.data(elem, "handle");
2640 if ( handle )
2641 handle.apply( elem, data );
2642
2643 // Handle triggering native .onfoo handlers (and on links since we don't call .click() for links)
2644 if ( (!elem[type] || (jQuery.nodeName(elem, 'a') && type == "click")) && elem["on"+type] && elem["on"+type].apply( elem, data ) === false )
2645 event.result = false;
2646
2647 // Trigger the native events (except for clicks on links)
2648 if ( !bubbling && elem[type] && !event.isDefaultPrevented() && !(jQuery.nodeName(elem, 'a') && type == "click") ) {
2649 this.triggered = true;
2650 try {
2651 elem[ type ]();
2652 // prevent IE from throwing an error for some hidden elements
2653 } catch (e) {}
2654 }
2655
2656 this.triggered = false;
2657
2658 if ( !event.isPropagationStopped() ) {
2659 var parent = elem.parentNode || elem.ownerDocument;
2660 if ( parent )
2661 jQuery.event.trigger(event, data, parent, true);
2662 }
2663 },
2664
2665 handle: function(event) {
2666 // returned undefined or false
2667 var all, handlers;
2668
2669 event = arguments[0] = jQuery.event.fix( event || window.event );
2670 event.currentTarget = this;
2671
2672 // Namespaced event handlers
2673 var namespaces = event.type.split(".");
2674 event.type = namespaces.shift();
2675
2676 // Cache this now, all = true means, any handler
2677 all = !namespaces.length && !event.exclusive;
2678
2679 var namespace = RegExp("(^|\\.)" + namespaces.slice().sort().join(".*\\.") + "(\\.|$)");
2680
2681 handlers = ( jQuery.data(this, "events") || {} )[event.type];
2682
2683 for ( var j in handlers ) {
2684 var handler = handlers[j];
2685
2686 // Filter the functions by class
2687 if ( all || namespace.test(handler.type) ) {
2688 // Pass in a reference to the handler function itself
2689 // So that we can later remove it
2690 event.handler = handler;
2691 event.data = handler.data;
2692
2693 var ret = handler.apply(this, arguments);
2694
2695 if( ret !== undefined ){
2696 event.result = ret;
2697 if ( ret === false ) {
2698 event.preventDefault();
2699 event.stopPropagation();
2700 }
2701 }
2702
2703 if( event.isImmediatePropagationStopped() )
2704 break;
2705
2706 }
2707 }
2708 },
2709
2710 props: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode metaKey newValue originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
2711
2712 fix: function(event) {
2713 if ( event[expando] )
2714 return event;
2715
2716 // store a copy of the original event object
2717 // and "clone" to set read-only properties
2718 var originalEvent = event;
2719 event = jQuery.Event( originalEvent );
2720
2721 for ( var i = this.props.length, prop; i; ){
2722 prop = this.props[ --i ];
2723 event[ prop ] = originalEvent[ prop ];
2724 }
2725
2726 // Fix target property, if necessary
2727 if ( !event.target )
2728 event.target = event.srcElement || document; // Fixes #1925 where srcElement might not be defined either
2729
2730 // check if target is a textnode (safari)
2731 if ( event.target.nodeType == 3 )
2732 event.target = event.target.parentNode;
2733
2734 // Add relatedTarget, if necessary
2735 if ( !event.relatedTarget && event.fromElement )
2736 event.relatedTarget = event.fromElement == event.target ? event.toElement : event.fromElement;
2737
2738 // Calculate pageX/Y if missing and clientX/Y available
2739 if ( event.pageX == null && event.clientX != null ) {
2740 var doc = document.documentElement, body = document.body;
2741 event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc.clientLeft || 0);
2742 event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc.clientTop || 0);
2743 }
2744
2745 // Add which for key events
2746 if ( !event.which && ((event.charCode || event.charCode === 0) ? event.charCode : event.keyCode) )
2747 event.which = event.charCode || event.keyCode;
2748
2749 // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
2750 if ( !event.metaKey && event.ctrlKey )
2751 event.metaKey = event.ctrlKey;
2752
2753 // Add which for click: 1 == left; 2 == middle; 3 == right
2754 // Note: button is not normalized, so don't use it
2755 if ( !event.which && event.button )
2756 event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));
2757
2758 return event;
2759 },
2760
2761 proxy: function( fn, proxy ){
2762 proxy = proxy || function(){ return fn.apply(this, arguments); };
2763 // Set the guid of unique handler to the same of original handler, so it can be removed
2764 proxy.guid = fn.guid = fn.guid || proxy.guid || this.guid++;
2765 // So proxy can be declared as an argument
2766 return proxy;
2767 },
2768
2769 special: {
2770 ready: {
2771 // Make sure the ready event is setup
2772 setup: bindReady,
2773 teardown: function() {}
2774 }
2775 },
2776
2777 specialAll: {
2778 live: {
2779 setup: function( selector, namespaces ){
2780 jQuery.event.add( this, namespaces[0], liveHandler );
2781 },
2782 teardown: function( namespaces ){
2783 if ( namespaces.length ) {
2784 var remove = 0, name = RegExp("(^|\\.)" + namespaces[0] + "(\\.|$)");
2785
2786 jQuery.each( (jQuery.data(this, "events").live || {}), function(){
2787 if ( name.test(this.type) )
2788 remove++;
2789 });
2790
2791 if ( remove < 1 )
2792 jQuery.event.remove( this, namespaces[0], liveHandler );
2793 }
2794 }
2795 }
2796 }
2797 };
2798
2799 jQuery.Event = function( src ){
2800 // Allow instantiation without the 'new' keyword
2801 if( !this.preventDefault )
2802 return new jQuery.Event(src);
2803
2804 // Event object
2805 if( src && src.type ){
2806 this.originalEvent = src;
2807 this.type = src.type;
2808 // Event type
2809 }else
2810 this.type = src;
2811
2812 // timeStamp is buggy for some events on Firefox(#3843)
2813 // So we won't rely on the native value
2814 this.timeStamp = now();
2815
2816 // Mark it as fixed
2817 this[expando] = true;
2818 };
2819
2820 function returnFalse(){
2821 return false;
2822 }
2823 function returnTrue(){
2824 return true;
2825 }
2826
2827 // jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
2828 // http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
2829 jQuery.Event.prototype = {
2830 preventDefault: function() {
2831 this.isDefaultPrevented = returnTrue;
2832
2833 var e = this.originalEvent;
2834 if( !e )
2835 return;
2836 // if preventDefault exists run it on the original event
2837 if (e.preventDefault)
2838 e.preventDefault();
2839 // otherwise set the returnValue property of the original event to false (IE)
2840 e.returnValue = false;
2841 },
2842 stopPropagation: function() {
2843 this.isPropagationStopped = returnTrue;
2844
2845 var e = this.originalEvent;
2846 if( !e )
2847 return;
2848 // if stopPropagation exists run it on the original event
2849 if (e.stopPropagation)
2850 e.stopPropagation();
2851 // otherwise set the cancelBubble property of the original event to true (IE)
2852 e.cancelBubble = true;
2853 },
2854 stopImmediatePropagation:function(){
2855 this.isImmediatePropagationStopped = returnTrue;
2856 this.stopPropagation();
2857 },
2858 isDefaultPrevented: returnFalse,
2859 isPropagationStopped: returnFalse,
2860 isImmediatePropagationStopped: returnFalse
2861 };
2862 // Checks if an event happened on an element within another element
2863 // Used in jQuery.event.special.mouseenter and mouseleave handlers
2864 var withinElement = function(event) {
2865 // Check if mouse(over|out) are still within the same parent element
2866 var parent = event.relatedTarget;
2867 // Traverse up the tree
2868 while ( parent && parent != this )
2869 try { parent = parent.parentNode; }
2870 catch(e) { parent = this; }
2871
2872 if( parent != this ){
2873 // set the correct event type
2874 event.type = event.data;
2875 // handle event if we actually just moused on to a non sub-element
2876 jQuery.event.handle.apply( this, arguments );
2877 }
2878 };
2879
2880 jQuery.each({
2881 mouseover: 'mouseenter',
2882 mouseout: 'mouseleave'
2883 }, function( orig, fix ){
2884 jQuery.event.special[ fix ] = {
2885 setup: function(){
2886 jQuery.event.add( this, orig, withinElement, fix );
2887 },
2888 teardown: function(){
2889 jQuery.event.remove( this, orig, withinElement );
2890 }
2891 };
2892 });
2893
2894 jQuery.fn.extend({
2895 bind: function( type, data, fn ) {
2896 return type == "unload" ? this.one(type, data, fn) : this.each(function(){
2897 jQuery.event.add( this, type, fn || data, fn && data );
2898 });
2899 },
2900
2901 one: function( type, data, fn ) {
2902 var one = jQuery.event.proxy( fn || data, function(event) {
2903 jQuery(this).unbind(event, one);
2904 return (fn || data).apply( this, arguments );
2905 });
2906 return this.each(function(){
2907 jQuery.event.add( this, type, one, fn && data);
2908 });
2909 },
2910
2911 unbind: function( type, fn ) {
2912 return this.each(function(){
2913 jQuery.event.remove( this, type, fn );
2914 });
2915 },
2916
2917 trigger: function( type, data ) {
2918 return this.each(function(){
2919 jQuery.event.trigger( type, data, this );
2920 });
2921 },
2922
2923 triggerHandler: function( type, data ) {
2924 if( this[0] ){
2925 var event = jQuery.Event(type);
2926 event.preventDefault();
2927 event.stopPropagation();
2928 jQuery.event.trigger( event, data, this[0] );
2929 return event.result;
2930 }
2931 },
2932
2933 toggle: function( fn ) {
2934 // Save reference to arguments for access in closure
2935 var args = arguments, i = 1;
2936
2937 // link all the functions, so any of them can unbind this click handler
2938 while( i < args.length )
2939 jQuery.event.proxy( fn, args[i++] );
2940
2941 return this.click( jQuery.event.proxy( fn, function(event) {
2942 // Figure out which function to execute
2943 this.lastToggle = ( this.lastToggle || 0 ) % i;
2944
2945 // Make sure that clicks stop
2946 event.preventDefault();
2947
2948 // and execute the function
2949 return args[ this.lastToggle++ ].apply( this, arguments ) || false;
2950 }));
2951 },
2952
2953 hover: function(fnOver, fnOut) {
2954 return this.mouseenter(fnOver).mouseleave(fnOut);
2955 },
2956
2957 ready: function(fn) {
2958 // Attach the listeners
2959 bindReady();
2960
2961 // If the DOM is already ready
2962 if ( jQuery.isReady )
2963 // Execute the function immediately
2964 fn.call( document, jQuery );
2965
2966 // Otherwise, remember the function for later
2967 else
2968 // Add the function to the wait list
2969 jQuery.readyList.push( fn );
2970
2971 return this;
2972 },
2973
2974 live: function( type, fn ){
2975 var proxy = jQuery.event.proxy( fn );
2976 proxy.guid += this.selector + type;
2977
2978 jQuery(document).bind( liveConvert(type, this.selector), this.selector, proxy );
2979
2980 return this;
2981 },
2982
2983 die: function( type, fn ){
2984 jQuery(document).unbind( liveConvert(type, this.selector), fn ? { guid: fn.guid + this.selector + type } : null );
2985 return this;
2986 }
2987 });
2988
2989 function liveHandler( event ){
2990 var check = RegExp("(^|\\.)" + event.type + "(\\.|$)"),
2991 stop = true,
2992 elems = [];
2993
2994 jQuery.each(jQuery.data(this, "events").live || [], function(i, fn){
2995 if ( check.test(fn.type) ) {
2996 var elem = jQuery(event.target).closest(fn.data)[0];
2997 if ( elem )
2998 elems.push({ elem: elem, fn: fn });
2999 }
3000 });
3001
3002 elems.sort(function(a,b) {
3003 return jQuery.data(a.elem, "closest") - jQuery.data(b.elem, "closest");
3004 });
3005
3006 jQuery.each(elems, function(){
3007 if ( this.fn.call(this.elem, event, this.fn.data) === false )
3008 return (stop = false);
3009 });
3010
3011 return stop;
3012 }
3013
3014 function liveConvert(type, selector){
3015 return ["live", type, selector.replace(/\./g, "`").replace(/ /g, "|")].join(".");
3016 }
3017
3018 jQuery.extend({
3019 isReady: false,
3020 readyList: [],
3021 // Handle when the DOM is ready
3022 ready: function() {
3023 // Make sure that the DOM is not already loaded
3024 if ( !jQuery.isReady ) {
3025 // Remember that the DOM is ready
3026 jQuery.isReady = true;
3027
3028 // If there are functions bound, to execute
3029 if ( jQuery.readyList ) {
3030 // Execute all of them
3031 jQuery.each( jQuery.readyList, function(){
3032 this.call( document, jQuery );
3033 });
3034
3035 // Reset the list of functions
3036 jQuery.readyList = null;
3037 }
3038
3039 // Trigger any bound ready events
3040 jQuery(document).triggerHandler("ready");
3041 }
3042 }
3043 });
3044
3045 var readyBound = false;
3046
3047 function bindReady(){
3048 if ( readyBound ) return;
3049 readyBound = true;
3050
3051 // Mozilla, Opera and webkit nightlies currently support this event
3052 if ( document.addEventListener ) {
3053 // Use the handy event callback
3054 document.addEventListener( "DOMContentLoaded", function(){
3055 document.removeEventListener( "DOMContentLoaded", arguments.callee, false );
3056 jQuery.ready();
3057 }, false );
3058
3059 // If IE event model is used
3060 } else if ( document.attachEvent ) {
3061 // ensure firing before onload,
3062 // maybe late but safe also for iframes
3063 document.attachEvent("onreadystatechange", function(){
3064 if ( document.readyState === "complete" ) {
3065 document.detachEvent( "onreadystatechange", arguments.callee );
3066 jQuery.ready();
3067 }
3068 });
3069
3070 // If IE and not an iframe
3071 // continually check to see if the document is ready
3072 if ( document.documentElement.doScroll && window == window.top ) (function(){
3073 if ( jQuery.isReady ) return;
3074
3075 try {
3076 // If IE is used, use the trick by Diego Perini
3077 // http://javascript.nwbox.com/IEContentLoaded/
3078 document.documentElement.doScroll("left");
3079 } catch( error ) {
3080 setTimeout( arguments.callee, 0 );
3081 return;
3082 }
3083
3084 // and execute any waiting functions
3085 jQuery.ready();
3086 })();
3087 }
3088
3089 // A fallback to window.onload, that will always work
3090 jQuery.event.add( window, "load", jQuery.ready );
3091 }
3092
3093 jQuery.each( ("blur,focus,load,resize,scroll,unload,click,dblclick," +
3094 "mousedown,mouseup,mousemove,mouseover,mouseout,mouseenter,mouseleave," +
3095 "change,select,submit,keydown,keypress,keyup,error").split(","), function(i, name){
3096
3097 // Handle event binding
3098 jQuery.fn[name] = function(fn){
3099 return fn ? this.bind(name, fn) : this.trigger(name);
3100 };
3101 });
3102
3103 // Prevent memory leaks in IE
3104 // And prevent errors on refresh with events like mouseover in other browsers
3105 // Window isn't included so as not to unbind existing unload events
3106 jQuery( window ).bind( 'unload', function(){
3107 for ( var id in jQuery.cache )
3108 // Skip the window
3109 if ( id != 1 && jQuery.cache[ id ].handle )
3110 jQuery.event.remove( jQuery.cache[ id ].handle.elem );
3111 });
3112 (function(){
3113
3114 jQuery.support = {};
3115
3116 var root = document.documentElement,
3117 script = document.createElement("script"),
3118 div = document.createElement("div"),
3119 id = "script" + (new Date).getTime();
3120
3121 div.style.display = "none";
3122 div.innerHTML = ' <link/><table></table><a href="/a" style="color:red;float:left;opacity:.5;">a</a><select><option>text</option></select><object><param/></object>';
3123
3124 var all = div.getElementsByTagName("*"),
3125 a = div.getElementsByTagName("a")[0];
3126
3127 // Can't get basic test support
3128 if ( !all || !all.length || !a ) {
3129 return;
3130 }
3131
3132 jQuery.support = {
3133 // IE strips leading whitespace when .innerHTML is used
3134 leadingWhitespace: div.firstChild.nodeType == 3,
3135
3136 // Make sure that tbody elements aren't automatically inserted
3137 // IE will insert them into empty tables
3138 tbody: !div.getElementsByTagName("tbody").length,
3139
3140 // Make sure that you can get all elements in an <object> element
3141 // IE 7 always returns no results
3142 objectAll: !!div.getElementsByTagName("object")[0]
3143 .getElementsByTagName("*").length,
3144
3145 // Make sure that link elements get serialized correctly by innerHTML
3146 // This requires a wrapper element in IE
3147 htmlSerialize: !!div.getElementsByTagName("link").length,
3148
3149 // Get the style information from getAttribute
3150 // (IE uses .cssText insted)
3151 style: /red/.test( a.getAttribute("style") ),
3152
3153 // Make sure that URLs aren't manipulated
3154 // (IE normalizes it by default)
3155 hrefNormalized: a.getAttribute("href") === "/a",
3156
3157 // Make sure that element opacity exists
3158 // (IE uses filter instead)
3159 opacity: a.style.opacity === "0.5",
3160
3161 // Verify style float existence
3162 // (IE uses styleFloat instead of cssFloat)
3163 cssFloat: !!a.style.cssFloat,
3164
3165 // Will be defined later
3166 scriptEval: false,
3167 noCloneEvent: true,
3168 boxModel: null
3169 };
3170
3171 script.type = "text/javascript";
3172 try {
3173 script.appendChild( document.createTextNode( "window." + id + "=1;" ) );
3174 } catch(e){}
3175
3176 root.insertBefore( script, root.firstChild );
3177
3178 // Make sure that the execution of code works by injecting a script
3179 // tag with appendChild/createTextNode
3180 // (IE doesn't support this, fails, and uses .text instead)
3181 if ( window[ id ] ) {
3182 jQuery.support.scriptEval = true;
3183 delete window[ id ];
3184 }
3185
3186 root.removeChild( script );
3187
3188 if ( div.attachEvent && div.fireEvent ) {
3189 div.attachEvent("onclick", function(){
3190 // Cloning a node shouldn't copy over any
3191 // bound event handlers (IE does this)
3192 jQuery.support.noCloneEvent = false;
3193 div.detachEvent("onclick", arguments.callee);
3194 });
3195 div.cloneNode(true).fireEvent("onclick");
3196 }
3197
3198 // Figure out if the W3C box model works as expected
3199 // document.body must exist before we can do this
3200 jQuery(function(){
3201 var div = document.createElement("div");
3202 div.style.width = div.style.paddingLeft = "1px";
3203
3204 document.body.appendChild( div );
3205 jQuery.boxModel = jQuery.support.boxModel = div.offsetWidth === 2;
3206 document.body.removeChild( div ).style.display = 'none';
3207 });
3208 })();
3209
3210 var styleFloat = jQuery.support.cssFloat ? "cssFloat" : "styleFloat";
3211
3212 jQuery.props = {
3213 "for": "htmlFor",
3214 "class": "className",
3215 "float": styleFloat,
3216 cssFloat: styleFloat,
3217 styleFloat: styleFloat,
3218 readonly: "readOnly",
3219 maxlength: "maxLength",
3220 cellspacing: "cellSpacing",
3221 rowspan: "rowSpan",
3222 tabindex: "tabIndex"
3223 };
3224 jQuery.fn.extend({
3225 // Keep a copy of the old load
3226 _load: jQuery.fn.load,
3227
3228 load: function( url, params, callback ) {
3229 if ( typeof url !== "string" )
3230 return this._load( url );
3231
3232 var off = url.indexOf(" ");
3233 if ( off >= 0 ) {
3234 var selector = url.slice(off, url.length);
3235 url = url.slice(0, off);
3236 }
3237
3238 // Default to a GET request
3239 var type = "GET";
3240
3241 // If the second parameter was provided
3242 if ( params )
3243 // If it's a function
3244 if ( jQuery.isFunction( params ) ) {
3245 // We assume that it's the callback
3246 callback = params;
3247 params = null;
3248
3249 // Otherwise, build a param string
3250 } else if( typeof params === "object" ) {
3251 params = jQuery.param( params );
3252 type = "POST";
3253 }
3254
3255 var self = this;
3256
3257 // Request the remote document
3258 jQuery.ajax({
3259 url: url,
3260 type: type,
3261 dataType: "html",
3262 data: params,
3263 complete: function(res, status){
3264 // If successful, inject the HTML into all the matched elements
3265 if ( status == "success" || status == "notmodified" )
3266 // See if a selector was specified
3267 self.html( selector ?
3268 // Create a dummy div to hold the results
3269 jQuery("<div/>")
3270 // inject the contents of the document in, removing the scripts
3271 // to avoid any 'Permission Denied' errors in IE
3272 .append(res.responseText.replace(/<script(.|\s)*?\/script>/g, ""))
3273
3274 // Locate the specified elements
3275 .find(selector) :
3276
3277 // If not, just inject the full result
3278 res.responseText );
3279
3280 if( callback )
3281 self.each( callback, [res.responseText, status, res] );
3282 }
3283 });
3284 return this;
3285 },
3286
3287 serialize: function() {
3288 return jQuery.param(this.serializeArray());
3289 },
3290 serializeArray: function() {
3291 return this.map(function(){
3292 return this.elements ? jQuery.makeArray(this.elements) : this;
3293 })
3294 .filter(function(){
3295 return this.name && !this.disabled &&
3296 (this.checked || /select|textarea/i.test(this.nodeName) ||
3297 /text|hidden|password|search/i.test(this.type));
3298 })
3299 .map(function(i, elem){
3300 var val = jQuery(this).val();
3301 return val == null ? null :
3302 jQuery.isArray(val) ?
3303 jQuery.map( val, function(val, i){
3304 return {name: elem.name, value: val};
3305 }) :
3306 {name: elem.name, value: val};
3307 }).get();
3308 }
3309 });
3310
3311 // Attach a bunch of functions for handling common AJAX events
3312 jQuery.each( "ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","), function(i,o){
3313 jQuery.fn[o] = function(f){
3314 return this.bind(o, f);
3315 };
3316 });
3317
3318 var jsc = now();
3319
3320 jQuery.extend({
3321
3322 get: function( url, data, callback, type ) {
3323 // shift arguments if data argument was ommited
3324 if ( jQuery.isFunction( data ) ) {
3325 callback = data;
3326 data = null;
3327 }
3328
3329 return jQuery.ajax({
3330 type: "GET",
3331 url: url,
3332 data: data,
3333 success: callback,
3334 dataType: type
3335 });
3336 },
3337
3338 getScript: function( url, callback ) {
3339 return jQuery.get(url, null, callback, "script");
3340 },
3341
3342 getJSON: function( url, data, callback ) {
3343 return jQuery.get(url, data, callback, "json");
3344 },
3345
3346 post: function( url, data, callback, type ) {
3347 if ( jQuery.isFunction( data ) ) {
3348 callback = data;
3349 data = {};
3350 }
3351
3352 return jQuery.ajax({
3353 type: "POST",
3354 url: url,
3355 data: data,
3356 success: callback,
3357 dataType: type
3358 });
3359 },
3360
3361 ajaxSetup: function( settings ) {
3362 jQuery.extend( jQuery.ajaxSettings, settings );
3363 },
3364
3365 ajaxSettings: {
3366 url: location.href,
3367 global: true,
3368 type: "GET",
3369 contentType: "application/x-www-form-urlencoded",
3370 processData: true,
3371 async: true,
3372 /*
3373 timeout: 0,
3374 data: null,
3375 username: null,
3376 password: null,
3377 */
3378 // Create the request object; Microsoft failed to properly
3379 // implement the XMLHttpRequest in IE7, so we use the ActiveXObject when it is available
3380 // This function can be overriden by calling jQuery.ajaxSetup
3381 xhr:function(){
3382 return window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : new XMLHttpRequest();
3383 },
3384 accepts: {
3385 xml: "application/xml, text/xml",
3386 html: "text/html",
3387 script: "text/javascript, application/javascript",
3388 json: "application/json, text/javascript",
3389 text: "text/plain",
3390 _default: "*/*"
3391 }
3392 },
3393
3394 // Last-Modified header cache for next request
3395 lastModified: {},
3396
3397 ajax: function( s ) {
3398 // Extend the settings, but re-extend 's' so that it can be
3399 // checked again later (in the test suite, specifically)
3400 s = jQuery.extend(true, s, jQuery.extend(true, {}, jQuery.ajaxSettings, s));
3401
3402 var jsonp, jsre = /=\?(&|$)/g, status, data,
3403 type = s.type.toUpperCase();
3404
3405 // convert data if not already a string
3406 if ( s.data && s.processData && typeof s.data !== "string" )
3407 s.data = jQuery.param(s.data);
3408
3409 // Handle JSONP Parameter Callbacks
3410 if ( s.dataType == "jsonp" ) {
3411 if ( type == "GET" ) {
3412 if ( !s.url.match(jsre) )
3413 s.url += (s.url.match(/\?/) ? "&" : "?") + (s.jsonp || "callback") + "=?";
3414 } else if ( !s.data || !s.data.match(jsre) )
3415 s.data = (s.data ? s.data + "&" : "") + (s.jsonp || "callback") + "=?";
3416 s.dataType = "json";
3417 }
3418
3419 // Build temporary JSONP function
3420 if ( s.dataType == "json" && (s.data && s.data.match(jsre) || s.url.match(jsre)) ) {
3421 jsonp = "jsonp" + jsc++;
3422
3423 // Replace the =? sequence both in the query string and the data
3424 if ( s.data )
3425 s.data = (s.data + "").replace(jsre, "=" + jsonp + "$1");
3426 s.url = s.url.replace(jsre, "=" + jsonp + "$1");
3427
3428 // We need to make sure
3429 // that a JSONP style response is executed properly
3430 s.dataType = "script";
3431
3432 // Handle JSONP-style loading
3433 window[ jsonp ] = function(tmp){
3434 data = tmp;
3435 success();
3436 complete();
3437 // Garbage collect
3438 window[ jsonp ] = undefined;
3439 try{ delete window[ jsonp ]; } catch(e){}
3440 if ( head )
3441 head.removeChild( script );
3442 };
3443 }
3444
3445 if ( s.dataType == "script" && s.cache == null )
3446 s.cache = false;
3447
3448 if ( s.cache === false && type == "GET" ) {
3449 var ts = now();
3450 // try replacing _= if it is there
3451 var ret = s.url.replace(/(\?|&)_=.*?(&|$)/, "$1_=" + ts + "$2");
3452 // if nothing was replaced, add timestamp to the end
3453 s.url = ret + ((ret == s.url) ? (s.url.match(/\?/) ? "&" : "?") + "_=" + ts : "");
3454 }
3455
3456 // If data is available, append data to url for get requests
3457 if ( s.data && type == "GET" ) {
3458 s.url += (s.url.match(/\?/) ? "&" : "?") + s.data;
3459
3460 // IE likes to send both get and post data, prevent this
3461 s.data = null;
3462 }
3463
3464 // Watch for a new set of requests
3465 if ( s.global && ! jQuery.active++ )
3466 jQuery.event.trigger( "ajaxStart" );
3467
3468 // Matches an absolute URL, and saves the domain
3469 var parts = /^(\w+:)?\/\/([^\/?#]+)/.exec( s.url );
3470
3471 // If we're requesting a remote document
3472 // and trying to load JSON or Script with a GET
3473 if ( s.dataType == "script" && type == "GET" && parts
3474 && ( parts[1] && parts[1] != location.protocol || parts[2] != location.host )){
3475
3476 var head = document.getElementsByTagName("head")[0];
3477 var script = document.createElement("script");
3478 script.src = s.url;
3479 if (s.scriptCharset)
3480 script.charset = s.scriptCharset;
3481
3482 // Handle Script loading
3483 if ( !jsonp ) {
3484 var done = false;
3485
3486 // Attach handlers for all browsers
3487 script.onload = script.onreadystatechange = function(){
3488 if ( !done && (!this.readyState ||
3489 this.readyState == "loaded" || this.readyState == "complete") ) {
3490 done = true;
3491 success();
3492 complete();
3493
3494 // Handle memory leak in IE
3495 script.onload = script.onreadystatechange = null;
3496 head.removeChild( script );
3497 }
3498 };
3499 }
3500
3501 head.appendChild(script);
3502
3503 // We handle everything using the script element injection
3504 return undefined;
3505 }
3506
3507 var requestDone = false;
3508
3509 // Create the request object
3510 var xhr = s.xhr();
3511
3512 // Open the socket
3513 // Passing null username, generates a login popup on Opera (#2865)
3514 if( s.username )
3515 xhr.open(type, s.url, s.async, s.username, s.password);
3516 else
3517 xhr.open(type, s.url, s.async);
3518
3519 // Need an extra try/catch for cross domain requests in Firefox 3
3520 try {
3521 // Set the correct header, if data is being sent
3522 if ( s.data )
3523 xhr.setRequestHeader("Content-Type", s.contentType);
3524
3525 // Set the If-Modified-Since header, if ifModified mode.
3526 if ( s.ifModified )
3527 xhr.setRequestHeader("If-Modified-Since",
3528 jQuery.lastModified[s.url] || "Thu, 01 Jan 1970 00:00:00 GMT" );
3529
3530 // Set header so the called script knows that it's an XMLHttpRequest
3531 xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
3532
3533 // Set the Accepts header for the server, depending on the dataType
3534 xhr.setRequestHeader("Accept", s.dataType && s.accepts[ s.dataType ] ?
3535 s.accepts[ s.dataType ] + ", */*" :
3536 s.accepts._default );
3537 } catch(e){}
3538
3539 // Allow custom headers/mimetypes and early abort
3540 if ( s.beforeSend && s.beforeSend(xhr, s) === false ) {
3541 // Handle the global AJAX counter
3542 if ( s.global && ! --jQuery.active )
3543 jQuery.event.trigger( "ajaxStop" );
3544 // close opended socket
3545 xhr.abort();
3546 return false;
3547 }
3548
3549 if ( s.global )
3550 jQuery.event.trigger("ajaxSend", [xhr, s]);
3551
3552 // Wait for a response to come back
3553 var onreadystatechange = function(isTimeout){
3554 // The request was aborted, clear the interval and decrement jQuery.active
3555 if (xhr.readyState == 0) {
3556 if (ival) {
3557 // clear poll interval
3558 clearInterval(ival);
3559 ival = null;
3560 // Handle the global AJAX counter
3561 if ( s.global && ! --jQuery.active )
3562 jQuery.event.trigger( "ajaxStop" );
3563 }
3564 // The transfer is complete and the data is available, or the request timed out
3565 } else if ( !requestDone && xhr && (xhr.readyState == 4 || isTimeout == "timeout") ) {
3566 requestDone = true;
3567
3568 // clear poll interval
3569 if (ival) {
3570 clearInterval(ival);
3571 ival = null;
3572 }
3573
3574 status = isTimeout == "timeout" ? "timeout" :
3575 !jQuery.httpSuccess( xhr ) ? "error" :
3576 s.ifModified && jQuery.httpNotModified( xhr, s.url ) ? "notmodified" :
3577 "success";
3578
3579 if ( status == "success" ) {
3580 // Watch for, and catch, XML document parse errors
3581 try {
3582 // process the data (runs the xml through httpData regardless of callback)
3583 data = jQuery.httpData( xhr, s.dataType, s );
3584 } catch(e) {
3585 status = "parsererror";
3586 }
3587 }
3588
3589 // Make sure that the request was successful or notmodified
3590 if ( status == "success" ) {
3591 // Cache Last-Modified header, if ifModified mode.
3592 var modRes;
3593 try {
3594 modRes = xhr.getResponseHeader("Last-Modified");
3595 } catch(e) {} // swallow exception thrown by FF if header is not available
3596
3597 if ( s.ifModified && modRes )
3598 jQuery.lastModified[s.url] = modRes;
3599
3600 // JSONP handles its own success callback
3601 if ( !jsonp )
3602 success();
3603 } else
3604 jQuery.handleError(s, xhr, status);
3605
3606 // Fire the complete handlers
3607 complete();
3608
3609 if ( isTimeout )
3610 xhr.abort();
3611
3612 // Stop memory leaks
3613 if ( s.async )
3614 xhr = null;
3615 }
3616 };
3617
3618 if ( s.async ) {
3619 // don't attach the handler to the request, just poll it instead
3620 var ival = setInterval(onreadystatechange, 13);
3621
3622 // Timeout checker
3623 if ( s.timeout > 0 )
3624 setTimeout(function(){
3625 // Check to see if the request is still happening
3626 if ( xhr && !requestDone )
3627 onreadystatechange( "timeout" );
3628 }, s.timeout);
3629 }
3630
3631 // Send the data
3632 try {
3633 xhr.send(s.data);
3634 } catch(e) {
3635 jQuery.handleError(s, xhr, null, e);
3636 }
3637
3638 // firefox 1.5 doesn't fire statechange for sync requests
3639 if ( !s.async )
3640 onreadystatechange();
3641
3642 function success(){
3643 // If a local callback was specified, fire it and pass it the data
3644 if ( s.success )
3645 s.success( data, status );
3646
3647 // Fire the global callback
3648 if ( s.global )
3649 jQuery.event.trigger( "ajaxSuccess", [xhr, s] );
3650 }
3651
3652 function complete(){
3653 // Process result
3654 if ( s.complete )
3655 s.complete(xhr, status);
3656
3657 // The request was completed
3658 if ( s.global )
3659 jQuery.event.trigger( "ajaxComplete", [xhr, s] );
3660
3661 // Handle the global AJAX counter
3662 if ( s.global && ! --jQuery.active )
3663 jQuery.event.trigger( "ajaxStop" );
3664 }
3665
3666 // return XMLHttpRequest to allow aborting the request etc.
3667 return xhr;
3668 },
3669
3670 handleError: function( s, xhr, status, e ) {
3671 // If a local callback was specified, fire it
3672 if ( s.error ) s.error( xhr, status, e );
3673
3674 // Fire the global callback
3675 if ( s.global )
3676 jQuery.event.trigger( "ajaxError", [xhr, s, e] );
3677 },
3678
3679 // Counter for holding the number of active queries
3680 active: 0,
3681
3682 // Determines if an XMLHttpRequest was successful or not
3683 httpSuccess: function( xhr ) {
3684 try {
3685 // IE error sometimes returns 1223 when it should be 204 so treat it as success, see #1450
3686 return !xhr.status && location.protocol == "file:" ||
3687 ( xhr.status >= 200 && xhr.status < 300 ) || xhr.status == 304 || xhr.status == 1223;
3688 } catch(e){}
3689 return false;
3690 },
3691
3692 // Determines if an XMLHttpRequest returns NotModified
3693 httpNotModified: function( xhr, url ) {
3694 try {
3695 var xhrRes = xhr.getResponseHeader("Last-Modified");
3696
3697 // Firefox always returns 200. check Last-Modified date
3698 return xhr.status == 304 || xhrRes == jQuery.lastModified[url];
3699 } catch(e){}
3700 return false;
3701 },
3702
3703 httpData: function( xhr, type, s ) {
3704 var ct = xhr.getResponseHeader("content-type"),
3705 xml = type == "xml" || !type && ct && ct.indexOf("xml") >= 0,
3706 data = xml ? xhr.responseXML : xhr.responseText;
3707
3708 if ( xml && data.documentElement.tagName == "parsererror" )
3709 throw "parsererror";
3710
3711 // Allow a pre-filtering function to sanitize the response
3712 // s != null is checked to keep backwards compatibility
3713 if( s && s.dataFilter )
3714 data = s.dataFilter( data, type );
3715
3716 // The filter can actually parse the response
3717 if( typeof data === "string" ){
3718
3719 // If the type is "script", eval it in global context
3720 if ( type == "script" )
3721 jQuery.globalEval( data );
3722
3723 // Get the JavaScript object, if JSON is used.
3724 if ( type == "json" )
3725 data = window["eval"]("(" + data + ")");
3726 }
3727
3728 return data;
3729 },
3730
3731 // Serialize an array of form elements or a set of
3732 // key/values into a query string
3733 param: function( a ) {
3734 var s = [ ];
3735
3736 function add( key, value ){
3737 s[ s.length ] = encodeURIComponent(key) + '=' + encodeURIComponent(value);
3738 };
3739
3740 // If an array was passed in, assume that it is an array
3741 // of form elements
3742 if ( jQuery.isArray(a) || a.jquery )
3743 // Serialize the form elements
3744 jQuery.each( a, function(){
3745 add( this.name, this.value );
3746 });
3747
3748 // Otherwise, assume that it's an object of key/value pairs
3749 else
3750 // Serialize the key/values
3751 for ( var j in a )
3752 // If the value is an array then the key names need to be repeated
3753 if ( jQuery.isArray(a[j]) )
3754 jQuery.each( a[j], function(){
3755 add( j, this );
3756 });
3757 else
3758 add( j, jQuery.isFunction(a[j]) ? a[j]() : a[j] );
3759
3760 // Return the resulting serialization
3761 return s.join("&").replace(/%20/g, "+");
3762 }
3763
3764 });
3765 var elemdisplay = {},
3766 timerId,
3767 fxAttrs = [
3768 // height animations
3769 [ "height", "marginTop", "marginBottom", "paddingTop", "paddingBottom" ],
3770 // width animations
3771 [ "width", "marginLeft", "marginRight", "paddingLeft", "paddingRight" ],
3772 // opacity animations
3773 [ "opacity" ]
3774 ];
3775
3776 function genFx( type, num ){
3777 var obj = {};
3778 jQuery.each( fxAttrs.concat.apply([], fxAttrs.slice(0,num)), function(){
3779 obj[ this ] = type;
3780 });
3781 return obj;
3782 }
3783
3784 jQuery.fn.extend({
3785 show: function(speed,callback){
3786 if ( speed ) {
3787 return this.animate( genFx("show", 3), speed, callback);
3788 } else {
3789 for ( var i = 0, l = this.length; i < l; i++ ){
3790 var old = jQuery.data(this[i], "olddisplay");
3791
3792 this[i].style.display = old || "";
3793
3794 if ( jQuery.css(this[i], "display") === "none" ) {
3795 var tagName = this[i].tagName, display;
3796
3797 if ( elemdisplay[ tagName ] ) {
3798 display = elemdisplay[ tagName ];
3799 } else {
3800 var elem = jQuery("<" + tagName + " />").appendTo("body");
3801
3802 display = elem.css("display");
3803 if ( display === "none" )
3804 display = "block";
3805
3806 elem.remove();
3807
3808 elemdisplay[ tagName ] = display;
3809 }
3810
3811 jQuery.data(this[i], "olddisplay", display);
3812 }
3813 }
3814
3815 // Set the display of the elements in a second loop
3816 // to avoid the constant reflow
3817 for ( var i = 0, l = this.length; i < l; i++ ){
3818 this[i].style.display = jQuery.data(this[i], "olddisplay") || "";
3819 }
3820
3821 return this;
3822 }
3823 },
3824
3825 hide: function(speed,callback){
3826 if ( speed ) {
3827 return this.animate( genFx("hide", 3), speed, callback);
3828 } else {
3829 for ( var i = 0, l = this.length; i < l; i++ ){
3830 var old = jQuery.data(this[i], "olddisplay");
3831 if ( !old && old !== "none" )
3832 jQuery.data(this[i], "olddisplay", jQuery.css(this[i], "display"));
3833 }
3834
3835 // Set the display of the elements in a second loop
3836 // to avoid the constant reflow
3837 for ( var i = 0, l = this.length; i < l; i++ ){
3838 this[i].style.display = "none";
3839 }
3840
3841 return this;
3842 }
3843 },
3844
3845 // Save the old toggle function
3846 _toggle: jQuery.fn.toggle,
3847
3848 toggle: function( fn, fn2 ){
3849 var bool = typeof fn === "boolean";
3850
3851 return jQuery.isFunction(fn) && jQuery.isFunction(fn2) ?
3852 this._toggle.apply( this, arguments ) :
3853 fn == null || bool ?
3854 this.each(function(){
3855 var state = bool ? fn : jQuery(this).is(":hidden");
3856 jQuery(this)[ state ? "show" : "hide" ]();
3857 }) :
3858 this.animate(genFx("toggle", 3), fn, fn2);
3859 },
3860
3861 fadeTo: function(speed,to,callback){
3862 return this.animate({opacity: to}, speed, callback);
3863 },
3864
3865 animate: function( prop, speed, easing, callback ) {
3866 var optall = jQuery.speed(speed, easing, callback);
3867
3868 return this[ optall.queue === false ? "each" : "queue" ](function(){
3869
3870 var opt = jQuery.extend({}, optall), p,
3871 hidden = this.nodeType == 1 && jQuery(this).is(":hidden"),
3872 self = this;
3873
3874 for ( p in prop ) {
3875 if ( prop[p] == "hide" && hidden || prop[p] == "show" && !hidden )
3876 return opt.complete.call(this);
3877
3878 if ( ( p == "height" || p == "width" ) && this.style ) {
3879 // Store display property
3880 opt.display = jQuery.css(this, "display");
3881
3882 // Make sure that nothing sneaks out
3883 opt.overflow = this.style.overflow;
3884 }
3885 }
3886
3887 if ( opt.overflow != null )
3888 this.style.overflow = "hidden";
3889
3890 opt.curAnim = jQuery.extend({}, prop);
3891
3892 jQuery.each( prop, function(name, val){
3893 var e = new jQuery.fx( self, opt, name );
3894
3895 if ( /toggle|show|hide/.test(val) )
3896 e[ val == "toggle" ? hidden ? "show" : "hide" : val ]( prop );
3897 else {
3898 var parts = val.toString().match(/^([+-]=)?([\d+-.]+)(.*)$/),
3899 start = e.cur(true) || 0;
3900
3901 if ( parts ) {
3902 var end = parseFloat(parts[2]),
3903 unit = parts[3] || "px";
3904
3905 // We need to compute starting value
3906 if ( unit != "px" ) {
3907 self.style[ name ] = (end || 1) + unit;
3908 start = ((end || 1) / e.cur(true)) * start;
3909 self.style[ name ] = start + unit;
3910 }
3911
3912 // If a +=/-= token was provided, we're doing a relative animation
3913 if ( parts[1] )
3914 end = ((parts[1] == "-=" ? -1 : 1) * end) + start;
3915
3916 e.custom( start, end, unit );
3917 } else
3918 e.custom( start, val, "" );
3919 }
3920 });
3921
3922 // For JS strict compliance
3923 return true;
3924 });
3925 },
3926
3927 stop: function(clearQueue, gotoEnd){
3928 var timers = jQuery.timers;
3929
3930 if (clearQueue)
3931 this.queue([]);
3932
3933 this.each(function(){
3934 // go in reverse order so anything added to the queue during the loop is ignored
3935 for ( var i = timers.length - 1; i >= 0; i-- )
3936 if ( timers[i].elem == this ) {
3937 if (gotoEnd)
3938 // force the next step to be the last
3939 timers[i](true);
3940 timers.splice(i, 1);
3941 }
3942 });
3943
3944 // start the next in the queue if the last step wasn't forced
3945 if (!gotoEnd)
3946 this.dequeue();
3947
3948 return this;
3949 }
3950
3951 });
3952
3953 // Generate shortcuts for custom animations
3954 jQuery.each({
3955 slideDown: genFx("show", 1),
3956 slideUp: genFx("hide", 1),
3957 slideToggle: genFx("toggle", 1),
3958 fadeIn: { opacity: "show" },
3959 fadeOut: { opacity: "hide" }
3960 }, function( name, props ){
3961 jQuery.fn[ name ] = function( speed, callback ){
3962 return this.animate( props, speed, callback );
3963 };
3964 });
3965
3966 jQuery.extend({
3967
3968 speed: function(speed, easing, fn) {
3969 var opt = typeof speed === "object" ? speed : {
3970 complete: fn || !fn && easing ||
3971 jQuery.isFunction( speed ) && speed,
3972 duration: speed,
3973 easing: fn && easing || easing && !jQuery.isFunction(easing) && easing
3974 };
3975
3976 opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
3977 jQuery.fx.speeds[opt.duration] || jQuery.fx.speeds._default;
3978
3979 // Queueing
3980 opt.old = opt.complete;
3981 opt.complete = function(){
3982 if ( opt.queue !== false )
3983 jQuery(this).dequeue();
3984 if ( jQuery.isFunction( opt.old ) )
3985 opt.old.call( this );
3986 };
3987
3988 return opt;
3989 },
3990
3991 easing: {
3992 linear: function( p, n, firstNum, diff ) {
3993 return firstNum + diff * p;
3994 },
3995 swing: function( p, n, firstNum, diff ) {
3996 return ((-Math.cos(p*Math.PI)/2) + 0.5) * diff + firstNum;
3997 }
3998 },
3999
4000 timers: [],
4001
4002 fx: function( elem, options, prop ){
4003 this.options = options;
4004 this.elem = elem;
4005 this.prop = prop;
4006
4007 if ( !options.orig )
4008 options.orig = {};
4009 }
4010
4011 });
4012
4013 jQuery.fx.prototype = {
4014
4015 // Simple function for setting a style value
4016 update: function(){
4017 if ( this.options.step )
4018 this.options.step.call( this.elem, this.now, this );
4019
4020 (jQuery.fx.step[this.prop] || jQuery.fx.step._default)( this );
4021
4022 // Set display property to block for height/width animations
4023 if ( ( this.prop == "height" || this.prop == "width" ) && this.elem.style )
4024 this.elem.style.display = "block";
4025 },
4026
4027 // Get the current size
4028 cur: function(force){
4029 if ( this.elem[this.prop] != null && (!this.elem.style || this.elem.style[this.prop] == null) )
4030 return this.elem[ this.prop ];
4031
4032 var r = parseFloat(jQuery.css(this.elem, this.prop, force));
4033 return r && r > -10000 ? r : parseFloat(jQuery.curCSS(this.elem, this.prop)) || 0;
4034 },
4035
4036 // Start an animation from one number to another
4037 custom: function(from, to, unit){
4038 this.startTime = now();
4039 this.start = from;
4040 this.end = to;
4041 this.unit = unit || this.unit || "px";
4042 this.now = this.start;
4043 this.pos = this.state = 0;
4044
4045 var self = this;
4046 function t(gotoEnd){
4047 return self.step(gotoEnd);
4048 }
4049
4050 t.elem = this.elem;
4051
4052 if ( t() && jQuery.timers.push(t) && !timerId ) {
4053 timerId = setInterval(function(){
4054 var timers = jQuery.timers;
4055
4056 for ( var i = 0; i < timers.length; i++ )
4057 if ( !timers[i]() )
4058 timers.splice(i--, 1);
4059
4060 if ( !timers.length ) {
4061 clearInterval( timerId );
4062 timerId = undefined;
4063 }
4064 }, 13);
4065 }
4066 },
4067
4068 // Simple 'show' function
4069 show: function(){
4070 // Remember where we started, so that we can go back to it later
4071 this.options.orig[this.prop] = jQuery.attr( this.elem.style, this.prop );
4072 this.options.show = true;
4073
4074 // Begin the animation
4075 // Make sure that we start at a small width/height to avoid any
4076 // flash of content
4077 this.custom(this.prop == "width" || this.prop == "height" ? 1 : 0, this.cur());
4078
4079 // Start by showing the element
4080 jQuery(this.elem).show();
4081 },
4082
4083 // Simple 'hide' function
4084 hide: function(){
4085 // Remember where we started, so that we can go back to it later
4086 this.options.orig[this.prop] = jQuery.attr( this.elem.style, this.prop );
4087 this.options.hide = true;
4088
4089 // Begin the animation
4090 this.custom(this.cur(), 0);
4091 },
4092
4093 // Each step of an animation
4094 step: function(gotoEnd){
4095 var t = now();
4096
4097 if ( gotoEnd || t >= this.options.duration + this.startTime ) {
4098 this.now = this.end;
4099 this.pos = this.state = 1;
4100 this.update();
4101
4102 this.options.curAnim[ this.prop ] = true;
4103
4104 var done = true;
4105 for ( var i in this.options.curAnim )
4106 if ( this.options.curAnim[i] !== true )
4107 done = false;
4108
4109 if ( done ) {
4110 if ( this.options.display != null ) {
4111 // Reset the overflow
4112 this.elem.style.overflow = this.options.overflow;
4113
4114 // Reset the display
4115 this.elem.style.display = this.options.display;
4116 if ( jQuery.css(this.elem, "display") == "none" )
4117 this.elem.style.display = "block";
4118 }
4119
4120 // Hide the element if the "hide" operation was done
4121 if ( this.options.hide )
4122 jQuery(this.elem).hide();
4123
4124 // Reset the properties, if the item has been hidden or shown
4125 if ( this.options.hide || this.options.show )
4126 for ( var p in this.options.curAnim )
4127 jQuery.attr(this.elem.style, p, this.options.orig[p]);
4128
4129 // Execute the complete function
4130 this.options.complete.call( this.elem );
4131 }
4132
4133 return false;
4134 } else {
4135 var n = t - this.startTime;
4136 this.state = n / this.options.duration;
4137
4138 // Perform the easing function, defaults to swing
4139 this.pos = jQuery.easing[this.options.easing || (jQuery.easing.swing ? "swing" : "linear")](this.state, n, 0, 1, this.options.duration);
4140 this.now = this.start + ((this.end - this.start) * this.pos);
4141
4142 // Perform the next step of the animation
4143 this.update();
4144 }
4145
4146 return true;
4147 }
4148
4149 };
4150
4151 jQuery.extend( jQuery.fx, {
4152 speeds:{
4153 slow: 600,
4154 fast: 200,
4155 // Default speed
4156 _default: 400
4157 },
4158 step: {
4159
4160 opacity: function(fx){
4161 jQuery.attr(fx.elem.style, "opacity", fx.now);
4162 },
4163
4164 _default: function(fx){
4165 if ( fx.elem.style && fx.elem.style[ fx.prop ] != null )
4166 fx.elem.style[ fx.prop ] = fx.now + fx.unit;
4167 else
4168 fx.elem[ fx.prop ] = fx.now;
4169 }
4170 }
4171 });
4172 if ( document.documentElement["getBoundingClientRect"] )
4173 jQuery.fn.offset = function() {
4174 if ( !this[0] ) return { top: 0, left: 0 };
4175 if ( this[0] === this[0].ownerDocument.body ) return jQuery.offset.bodyOffset( this[0] );
4176 var box = this[0].getBoundingClientRect(), doc = this[0].ownerDocument, body = doc.body, docElem = doc.documentElement,
4177 clientTop = docElem.clientTop || body.clientTop || 0, clientLeft = docElem.clientLeft || body.clientLeft || 0,
4178 top = box.top + (self.pageYOffset || jQuery.boxModel && docElem.scrollTop || body.scrollTop ) - clientTop,
4179 left = box.left + (self.pageXOffset || jQuery.boxModel && docElem.scrollLeft || body.scrollLeft) - clientLeft;
4180 return { top: top, left: left };
4181 };
4182 else
4183 jQuery.fn.offset = function() {
4184 if ( !this[0] ) return { top: 0, left: 0 };
4185 if ( this[0] === this[0].ownerDocument.body ) return jQuery.offset.bodyOffset( this[0] );
4186 jQuery.offset.initialized || jQuery.offset.initialize();
4187
4188 var elem = this[0], offsetParent = elem.offsetParent, prevOffsetParent = elem,
4189 doc = elem.ownerDocument, computedStyle, docElem = doc.documentElement,
4190 body = doc.body, defaultView = doc.defaultView,
4191 prevComputedStyle = defaultView.getComputedStyle(elem, null),
4192 top = elem.offsetTop, left = elem.offsetLeft;
4193
4194 while ( (elem = elem.parentNode) && elem !== body && elem !== docElem ) {
4195 computedStyle = defaultView.getComputedStyle(elem, null);
4196 top -= elem.scrollTop, left -= elem.scrollLeft;
4197 if ( elem === offsetParent ) {
4198 top += elem.offsetTop, left += elem.offsetLeft;
4199 if ( jQuery.offset.doesNotAddBorder && !(jQuery.offset.doesAddBorderForTableAndCells && /^t(able|d|h)$/i.test(elem.tagName)) )
4200 top += parseInt( computedStyle.borderTopWidth, 10) || 0,
4201 left += parseInt( computedStyle.borderLeftWidth, 10) || 0;
4202 prevOffsetParent = offsetParent, offsetParent = elem.offsetParent;
4203 }
4204 if ( jQuery.offset.subtractsBorderForOverflowNotVisible && computedStyle.overflow !== "visible" )
4205 top += parseInt( computedStyle.borderTopWidth, 10) || 0,
4206 left += parseInt( computedStyle.borderLeftWidth, 10) || 0;
4207 prevComputedStyle = computedStyle;
4208 }
4209
4210 if ( prevComputedStyle.position === "relative" || prevComputedStyle.position === "static" )
4211 top += body.offsetTop,
4212 left += body.offsetLeft;
4213
4214 if ( prevComputedStyle.position === "fixed" )
4215 top += Math.max(docElem.scrollTop, body.scrollTop),
4216 left += Math.max(docElem.scrollLeft, body.scrollLeft);
4217
4218 return { top: top, left: left };
4219 };
4220
4221 jQuery.offset = {
4222 initialize: function() {
4223 if ( this.initialized ) return;
4224 var body = document.body, container = document.createElement('div'), innerDiv, checkDiv, table, td, rules, prop, bodyMarginTop = body.style.marginTop,
4225 html = '<div style="position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;"><div></div></div><table style="position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;" cellpadding="0" cellspacing="0"><tr><td></td></tr></table>';
4226
4227 rules = { position: 'absolute', top: 0, left: 0, margin: 0, border: 0, width: '1px', height: '1px', visibility: 'hidden' };
4228 for ( prop in rules ) container.style[prop] = rules[prop];
4229
4230 container.innerHTML = html;
4231 body.insertBefore(container, body.firstChild);
4232 innerDiv = container.firstChild, checkDiv = innerDiv.firstChild, td = innerDiv.nextSibling.firstChild.firstChild;
4233
4234 this.doesNotAddBorder = (checkDiv.offsetTop !== 5);
4235 this.doesAddBorderForTableAndCells = (td.offsetTop === 5);
4236
4237 innerDiv.style.overflow = 'hidden', innerDiv.style.position = 'relative';
4238 this.subtractsBorderForOverflowNotVisible = (checkDiv.offsetTop === -5);
4239
4240 body.style.marginTop = '1px';
4241 this.doesNotIncludeMarginInBodyOffset = (body.offsetTop === 0);
4242 body.style.marginTop = bodyMarginTop;
4243
4244 body.removeChild(container);
4245 this.initialized = true;
4246 },
4247
4248 bodyOffset: function(body) {
4249 jQuery.offset.initialized || jQuery.offset.initialize();
4250 var top = body.offsetTop, left = body.offsetLeft;
4251 if ( jQuery.offset.doesNotIncludeMarginInBodyOffset )
4252 top += parseInt( jQuery.curCSS(body, 'marginTop', true), 10 ) || 0,
4253 left += parseInt( jQuery.curCSS(body, 'marginLeft', true), 10 ) || 0;
4254 return { top: top, left: left };
4255 }
4256 };
4257
4258
4259 jQuery.fn.extend({
4260 position: function() {
4261 var left = 0, top = 0, results;
4262
4263 if ( this[0] ) {
4264 // Get *real* offsetParent
4265 var offsetParent = this.offsetParent(),
4266
4267 // Get correct offsets
4268 offset = this.offset(),
4269 parentOffset = /^body|html$/i.test(offsetParent[0].tagName) ? { top: 0, left: 0 } : offsetParent.offset();
4270
4271 // Subtract element margins
4272 // note: when an element has margin: auto the offsetLeft and marginLeft
4273 // are the same in Safari causing offset.left to incorrectly be 0
4274 offset.top -= num( this, 'marginTop' );
4275 offset.left -= num( this, 'marginLeft' );
4276
4277 // Add offsetParent borders
4278 parentOffset.top += num( offsetParent, 'borderTopWidth' );
4279 parentOffset.left += num( offsetParent, 'borderLeftWidth' );
4280
4281 // Subtract the two offsets
4282 results = {
4283 top: offset.top - parentOffset.top,
4284 left: offset.left - parentOffset.left
4285 };
4286 }
4287
4288 return results;
4289 },
4290
4291 offsetParent: function() {
4292 var offsetParent = this[0].offsetParent || document.body;
4293 while ( offsetParent && (!/^body|html$/i.test(offsetParent.tagName) && jQuery.css(offsetParent, 'position') == 'static') )
4294 offsetParent = offsetParent.offsetParent;
4295 return jQuery(offsetParent);
4296 }
4297 });
4298
4299
4300 // Create scrollLeft and scrollTop methods
4301 jQuery.each( ['Left', 'Top'], function(i, name) {
4302 var method = 'scroll' + name;
4303
4304 jQuery.fn[ method ] = function(val) {
4305 if (!this[0]) return null;
4306
4307 return val !== undefined ?
4308
4309 // Set the scroll offset
4310 this.each(function() {
4311 this == window || this == document ?
4312 window.scrollTo(
4313 !i ? val : jQuery(window).scrollLeft(),
4314 i ? val : jQuery(window).scrollTop()
4315 ) :
4316 this[ method ] = val;
4317 }) :
4318
4319 // Return the scroll offset
4320 this[0] == window || this[0] == document ?
4321 self[ i ? 'pageYOffset' : 'pageXOffset' ] ||
4322 jQuery.boxModel && document.documentElement[ method ] ||
4323 document.body[ method ] :
4324 this[0][ method ];
4325 };
4326 });
4327 // Create innerHeight, innerWidth, outerHeight and outerWidth methods
4328 jQuery.each([ "Height", "Width" ], function(i, name){
4329
4330 var tl = i ? "Left" : "Top", // top or left
4331 br = i ? "Right" : "Bottom", // bottom or right
4332 lower = name.toLowerCase();
4333
4334 // innerHeight and innerWidth
4335 jQuery.fn["inner" + name] = function(){
4336 return this[0] ?
4337 jQuery.css( this[0], lower, false, "padding" ) :
4338 null;
4339 };
4340
4341 // outerHeight and outerWidth
4342 jQuery.fn["outer" + name] = function(margin) {
4343 return this[0] ?
4344 jQuery.css( this[0], lower, false, margin ? "margin" : "border" ) :
4345 null;
4346 };
4347
4348 var type = name.toLowerCase();
4349
4350 jQuery.fn[ type ] = function( size ) {
4351 // Get window width or height
4352 return this[0] == window ?
4353 // Everyone else use document.documentElement or document.body depending on Quirks vs Standards mode
4354 document.compatMode == "CSS1Compat" && document.documentElement[ "client" + name ] ||
4355 document.body[ "client" + name ] :
4356
4357 // Get document width or height
4358 this[0] == document ?
4359 // Either scroll[Width/Height] or offset[Width/Height], whichever is greater
4360 Math.max(
4361 document.documentElement["client" + name],
4362 document.body["scroll" + name], document.documentElement["scroll" + name],
4363 document.body["offset" + name], document.documentElement["offset" + name]
4364 ) :
4365
4366 // Get or set width or height on the element
4367 size === undefined ?
4368 // Get width or height on the element
4369 (this.length ? jQuery.css( this[0], type ) : null) :
4370
4371 // Set the width or height on the element (default to pixels if value is unitless)
4372 this.css( type, typeof size === "string" ? size : size + "px" );
4373 };
4374
4375 });
4376 })();
4377 /*
4378 * jQuery UI 1.7.2
4379 *
4380 * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
4381 * Dual licensed under the MIT (MIT-LICENSE.txt)
4382 * and GPL (GPL-LICENSE.txt) licenses.
4383 *
4384 * http://docs.jquery.com/UI
4385 */
4386 ;jQuery.ui || (function($) {
4387
4388 var _remove = $.fn.remove,
4389 isFF2 = $.browser.mozilla && (parseFloat($.browser.version) < 1.9);
4390
4391 //Helper functions and ui object
4392 $.ui = {
4393 version: "1.7.2",
4394
4395 // $.ui.plugin is deprecated. Use the proxy pattern instead.
4396 plugin: {
4397 add: function(module, option, set) {
4398 var proto = $.ui[module].prototype;
4399 for(var i in set) {
4400 proto.plugins[i] = proto.plugins[i] || [];
4401 proto.plugins[i].push([option, set[i]]);
4402 }
4403 },
4404 call: function(instance, name, args) {
4405 var set = instance.plugins[name];
4406 if(!set || !instance.element[0].parentNode) { return; }
4407
4408 for (var i = 0; i < set.length; i++) {
4409 if (instance.options[set[i][0]]) {
4410 set[i][1].apply(instance.element, args);
4411 }
4412 }
4413 }
4414 },
4415
4416 contains: function(a, b) {
4417 return document.compareDocumentPosition
4418 ? a.compareDocumentPosition(b) & 16
4419 : a !== b && a.contains(b);
4420 },
4421
4422 hasScroll: function(el, a) {
4423
4424 //If overflow is hidden, the element might have extra content, but the user wants to hide it
4425 if ($(el).css('overflow') == 'hidden') { return false; }
4426
4427 var scroll = (a && a == 'left') ? 'scrollLeft' : 'scrollTop',
4428 has = false;
4429
4430 if (el[scroll] > 0) { return true; }
4431
4432 // TODO: determine which cases actually cause this to happen
4433 // if the element doesn't have the scroll set, see if it's possible to
4434 // set the scroll
4435 el[scroll] = 1;
4436 has = (el[scroll] > 0);
4437 el[scroll] = 0;
4438 return has;
4439 },
4440
4441 isOverAxis: function(x, reference, size) {
4442 //Determines when x coordinate is over "b" element axis
4443 return (x > reference) && (x < (reference + size));
4444 },
4445
4446 isOver: function(y, x, top, left, height, width) {
4447 //Determines when x, y coordinates is over "b" element
4448 return $.ui.isOverAxis(y, top, height) && $.ui.isOverAxis(x, left, width);
4449 },
4450
4451 keyCode: {
4452 BACKSPACE: 8,
4453 CAPS_LOCK: 20,
4454 COMMA: 188,
4455 CONTROL: 17,
4456 DELETE: 46,
4457 DOWN: 40,
4458 END: 35,
4459 ENTER: 13,
4460 ESCAPE: 27,
4461 HOME: 36,
4462 INSERT: 45,
4463 LEFT: 37,
4464 NUMPAD_ADD: 107,
4465 NUMPAD_DECIMAL: 110,
4466 NUMPAD_DIVIDE: 111,
4467 NUMPAD_ENTER: 108,
4468 NUMPAD_MULTIPLY: 106,
4469 NUMPAD_SUBTRACT: 109,
4470 PAGE_DOWN: 34,
4471 PAGE_UP: 33,
4472 PERIOD: 190,
4473 RIGHT: 39,
4474 SHIFT: 16,
4475 SPACE: 32,
4476 TAB: 9,
4477 UP: 38
4478 }
4479 };
4480
4481 // WAI-ARIA normalization
4482 if (isFF2) {
4483 var attr = $.attr,
4484 removeAttr = $.fn.removeAttr,
4485 ariaNS = "http://www.w3.org/2005/07/aaa",
4486 ariaState = /^aria-/,
4487 ariaRole = /^wairole:/;
4488
4489 $.attr = function(elem, name, value) {
4490 var set = value !== undefined;
4491
4492 return (name == 'role'
4493 ? (set
4494 ? attr.call(this, elem, name, "wairole:" + value)
4495 : (attr.apply(this, arguments) || "").replace(ariaRole, ""))
4496 : (ariaState.test(name)
4497 ? (set
4498 ? elem.setAttributeNS(ariaNS,
4499 name.replace(ariaState, "aaa:"), value)
4500 : attr.call(this, elem, name.replace(ariaState, "aaa:")))
4501 : attr.apply(this, arguments)));
4502 };
4503
4504 $.fn.removeAttr = function(name) {
4505 return (ariaState.test(name)
4506 ? this.each(function() {
4507 this.removeAttributeNS(ariaNS, name.replace(ariaState, ""));
4508 }) : removeAttr.call(this, name));
4509 };
4510 }
4511
4512 //jQuery plugins
4513 $.fn.extend({
4514 remove: function() {
4515 // Safari has a native remove event which actually removes DOM elements,
4516 // so we have to use triggerHandler instead of trigger (#3037).
4517 $("*", this).add(this).each(function() {
4518 $(this).triggerHandler("remove");
4519 });
4520 return _remove.apply(this, arguments );
4521 },
4522
4523 enableSelection: function() {
4524 return this
4525 .attr('unselectable', 'off')
4526 .css('MozUserSelect', '')
4527 .unbind('selectstart.ui');
4528 },
4529
4530 disableSelection: function() {
4531 return this
4532 .attr('unselectable', 'on')
4533 .css('MozUserSelect', 'none')
4534 .bind('selectstart.ui', function() { return false; });
4535 },
4536
4537 scrollParent: function() {
4538 var scrollParent;
4539 if(($.browser.msie && (/(static|relative)/).test(this.css('position'))) || (/absolute/).test(this.css('position'))) {
4540 scrollParent = this.parents().filter(function() {
4541 return (/(relative|absolute|fixed)/).test($.curCSS(this,'position',1)) && (/(auto|scroll)/).test($.curCSS(this,'overflow',1)+$.curCSS(this,'overflow-y',1)+$.curCSS(this,'overflow-x',1));
4542 }).eq(0);
4543 } else {
4544 scrollParent = this.parents().filter(function() {
4545 return (/(auto|scroll)/).test($.curCSS(this,'overflow',1)+$.curCSS(this,'overflow-y',1)+$.curCSS(this,'overflow-x',1));
4546 }).eq(0);
4547 }
4548
4549 return (/fixed/).test(this.css('position')) || !scrollParent.length ? $(document) : scrollParent;
4550 }
4551 });
4552
4553
4554 //Additional selectors
4555 $.extend($.expr[':'], {
4556 data: function(elem, i, match) {
4557 return !!$.data(elem, match[3]);
4558 },
4559
4560 focusable: function(element) {
4561 var nodeName = element.nodeName.toLowerCase(),
4562 tabIndex = $.attr(element, 'tabindex');
4563 return (/input|select|textarea|button|object/.test(nodeName)
4564 ? !element.disabled
4565 : 'a' == nodeName || 'area' == nodeName
4566 ? element.href || !isNaN(tabIndex)
4567 : !isNaN(tabIndex))
4568 // the element and all of its ancestors must be visible
4569 // the browser may report that the area is hidden
4570 && !$(element)['area' == nodeName ? 'parents' : 'closest'](':hidden').length;
4571 },
4572
4573 tabbable: function(element) {
4574 var tabIndex = $.attr(element, 'tabindex');
4575 return (isNaN(tabIndex) || tabIndex >= 0) && $(element).is(':focusable');
4576 }
4577 });
4578
4579
4580 // $.widget is a factory to create jQuery plugins
4581 // taking some boilerplate code out of the plugin code
4582 function getter(namespace, plugin, method, args) {
4583 function getMethods(type) {
4584 var methods = $[namespace][plugin][type] || [];
4585 return (typeof methods == 'string' ? methods.split(/,?\s+/) : methods);
4586 }
4587
4588 var methods = getMethods('getter');
4589 if (args.length == 1 && typeof args[0] == 'string') {
4590 methods = methods.concat(getMethods('getterSetter'));
4591 }
4592 return ($.inArray(method, methods) != -1);
4593 }
4594
4595 $.widget = function(name, prototype) {
4596 var namespace = name.split(".")[0];
4597 name = name.split(".")[1];
4598
4599 // create plugin method
4600 $.fn[name] = function(options) {
4601 var isMethodCall = (typeof options == 'string'),
4602 args = Array.prototype.slice.call(arguments, 1);
4603
4604 // prevent calls to internal methods
4605 if (isMethodCall && options.substring(0, 1) == '_') {
4606 return this;
4607 }
4608
4609 // handle getter methods
4610 if (isMethodCall && getter(namespace, name, options, args)) {
4611 var instance = $.data(this[0], name);
4612 return (instance ? instance[options].apply(instance, args)
4613 : undefined);
4614 }
4615
4616 // handle initialization and non-getter methods
4617 return this.each(function() {
4618 var instance = $.data(this, name);
4619
4620 // constructor
4621 (!instance && !isMethodCall &&
4622 $.data(this, name, new $[namespace][name](this, options))._init());
4623
4624 // method call
4625 (instance && isMethodCall && $.isFunction(instance[options]) &&
4626 instance[options].apply(instance, args));
4627 });
4628 };
4629
4630 // create widget constructor
4631 $[namespace] = $[namespace] || {};
4632 $[namespace][name] = function(element, options) {
4633 var self = this;
4634
4635 this.namespace = namespace;
4636 this.widgetName = name;
4637 this.widgetEventPrefix = $[namespace][name].eventPrefix || name;
4638 this.widgetBaseClass = namespace + '-' + name;
4639
4640 this.options = $.extend({},
4641 $.widget.defaults,
4642 $[namespace][name].defaults,
4643 $.metadata && $.metadata.get(element)[name],
4644 options);
4645
4646 this.element = $(element)
4647 .bind('setData.' + name, function(event, key, value) {
4648 if (event.target == element) {
4649 return self._setData(key, value);
4650 }
4651 })
4652 .bind('getData.' + name, function(event, key) {
4653 if (event.target == element) {
4654 return self._getData(key);
4655 }
4656 })
4657 .bind('remove', function() {
4658 return self.destroy();
4659 });
4660 };
4661
4662 // add widget prototype
4663 $[namespace][name].prototype = $.extend({}, $.widget.prototype, prototype);
4664
4665 // TODO: merge getter and getterSetter properties from widget prototype
4666 // and plugin prototype
4667 $[namespace][name].getterSetter = 'option';
4668 };
4669
4670 $.widget.prototype = {
4671 _init: function() {},
4672 destroy: function() {
4673 this.element.removeData(this.widgetName)
4674 .removeClass(this.widgetBaseClass + '-disabled' + ' ' + this.namespace + '-state-disabled')
4675 .removeAttr('aria-disabled');
4676 },
4677
4678 option: function(key, value) {
4679 var options = key,
4680 self = this;
4681
4682 if (typeof key == "string") {
4683 if (value === undefined) {
4684 return this._getData(key);
4685 }
4686 options = {};
4687 options[key] = value;
4688 }
4689
4690 $.each(options, function(key, value) {
4691 self._setData(key, value);
4692 });
4693 },
4694 _getData: function(key) {
4695 return this.options[key];
4696 },
4697 _setData: function(key, value) {
4698 this.options[key] = value;
4699
4700 if (key == 'disabled') {
4701 this.element
4702 [value ? 'addClass' : 'removeClass'](
4703 this.widgetBaseClass + '-disabled' + ' ' +
4704 this.namespace + '-state-disabled')
4705 .attr("aria-disabled", value);
4706 }
4707 },
4708
4709 enable: function() {
4710 this._setData('disabled', false);
4711 },
4712 disable: function() {
4713 this._setData('disabled', true);
4714 },
4715
4716 _trigger: function(type, event, data) {
4717 var callback = this.options[type],
4718 eventName = (type == this.widgetEventPrefix
4719 ? type : this.widgetEventPrefix + type);
4720
4721 event = $.Event(event);
4722 event.type = eventName;
4723
4724 // copy original event properties over to the new event
4725 // this would happen if we could call $.event.fix instead of $.Event
4726 // but we don't have a way to force an event to be fixed multiple times
4727 if (event.originalEvent) {
4728 for (var i = $.event.props.length, prop; i;) {
4729 prop = $.event.props[--i];
4730 event[prop] = event.originalEvent[prop];
4731 }
4732 }
4733
4734 this.element.trigger(event, data);
4735
4736 return !($.isFunction(callback) && callback.call(this.element[0], event, data) === false
4737 || event.isDefaultPrevented());
4738 }
4739 };
4740
4741 $.widget.defaults = {
4742 disabled: false
4743 };
4744
4745
4746 /** Mouse Interaction Plugin **/
4747
4748 $.ui.mouse = {
4749 _mouseInit: function() {
4750 var self = this;
4751
4752 this.element
4753 .bind('mousedown.'+this.widgetName, function(event) {
4754 return self._mouseDown(event);
4755 })
4756 .bind('click.'+this.widgetName, function(event) {
4757 if(self._preventClickEvent) {
4758 self._preventClickEvent = false;
4759 event.stopImmediatePropagation();
4760 return false;
4761 }
4762 });
4763
4764 // Prevent text selection in IE
4765 if ($.browser.msie) {
4766 this._mouseUnselectable = this.element.attr('unselectable');
4767 this.element.attr('unselectable', 'on');
4768 }
4769
4770 this.started = false;
4771 },
4772
4773 // TODO: make sure destroying one instance of mouse doesn't mess with
4774 // other instances of mouse
4775 _mouseDestroy: function() {
4776 this.element.unbind('.'+this.widgetName);
4777
4778 // Restore text selection in IE
4779 ($.browser.msie
4780 && this.element.attr('unselectable', this._mouseUnselectable));
4781 },
4782
4783 _mouseDown: function(event) {
4784 // don't let more than one widget handle mouseStart
4785 // TODO: figure out why we have to use originalEvent
4786 event.originalEvent = event.originalEvent || {};
4787 if (event.originalEvent.mouseHandled) { return; }
4788
4789 // we may have missed mouseup (out of window)
4790 (this._mouseStarted && this._mouseUp(event));
4791
4792 this._mouseDownEvent = event;
4793
4794 var self = this,
4795 btnIsLeft = (event.which == 1),
4796 elIsCancel = (typeof this.options.cancel == "string" ? $(event.target).parents().add(event.target).filter(this.options.cancel).length : false);
4797 if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) {
4798 return true;
4799 }
4800
4801 this.mouseDelayMet = !this.options.delay;
4802 if (!this.mouseDelayMet) {
4803 this._mouseDelayTimer = setTimeout(function() {
4804 self.mouseDelayMet = true;
4805 }, this.options.delay);
4806 }
4807
4808 if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
4809 this._mouseStarted = (this._mouseStart(event) !== false);
4810 if (!this._mouseStarted) {
4811 event.preventDefault();
4812 return true;
4813 }
4814 }
4815
4816 // these delegates are required to keep context
4817 this._mouseMoveDelegate = function(event) {
4818 return self._mouseMove(event);
4819 };
4820 this._mouseUpDelegate = function(event) {
4821 return self._mouseUp(event);
4822 };
4823 $(document)
4824 .bind('mousemove.'+this.widgetName, this._mouseMoveDelegate)
4825 .bind('mouseup.'+this.widgetName, this._mouseUpDelegate);
4826
4827 // preventDefault() is used to prevent the selection of text here -
4828 // however, in Safari, this causes select boxes not to be selectable
4829 // anymore, so this fix is needed
4830 ($.browser.safari || event.preventDefault());
4831
4832 event.originalEvent.mouseHandled = true;
4833 return true;
4834 },
4835
4836 _mouseMove: function(event) {
4837 // IE mouseup check - mouseup happened when mouse was out of window
4838 if ($.browser.msie && !event.button) {
4839 return this._mouseUp(event);
4840 }
4841
4842 if (this._mouseStarted) {
4843 this._mouseDrag(event);
4844 return event.preventDefault();
4845 }
4846
4847 if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
4848 this._mouseStarted =
4849 (this._mouseStart(this._mouseDownEvent, event) !== false);
4850 (this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event));
4851 }
4852
4853 return !this._mouseStarted;
4854 },
4855
4856 _mouseUp: function(event) {
4857 $(document)
4858 .unbind('mousemove.'+this.widgetName, this._mouseMoveDelegate)
4859 .unbind('mouseup.'+this.widgetName, this._mouseUpDelegate);
4860
4861 if (this._mouseStarted) {
4862 this._mouseStarted = false;
4863 this._preventClickEvent = (event.target == this._mouseDownEvent.target);
4864 this._mouseStop(event);
4865 }
4866
4867 return false;
4868 },
4869
4870 _mouseDistanceMet: function(event) {
4871 return (Math.max(
4872 Math.abs(this._mouseDownEvent.pageX - event.pageX),
4873 Math.abs(this._mouseDownEvent.pageY - event.pageY)
4874 ) >= this.options.distance
4875 );
4876 },
4877
4878 _mouseDelayMet: function(event) {
4879 return this.mouseDelayMet;
4880 },
4881
4882 // These are placeholder methods, to be overriden by extending plugin
4883 _mouseStart: function(event) {},
4884 _mouseDrag: function(event) {},
4885 _mouseStop: function(event) {},
4886 _mouseCapture: function(event) { return true; }
4887 };
4888
4889 $.ui.mouse.defaults = {
4890 cancel: null,
4891 distance: 1,
4892 delay: 0
4893 };
4894
4895 })(jQuery);
4896 /*
4897 * jQuery UI Draggable 1.7.2
4898 *
4899 * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
4900 * Dual licensed under the MIT (MIT-LICENSE.txt)
4901 * and GPL (GPL-LICENSE.txt) licenses.
4902 *
4903 * http://docs.jquery.com/UI/Draggables
4904 *
4905 * Depends:
4906 * ui.core.js
4907 */
4908 (function($) {
4909
4910 $.widget("ui.draggable", $.extend({}, $.ui.mouse, {
4911
4912 _init: function() {
4913
4914 if (this.options.helper == 'original' && !(/^(?:r|a|f)/).test(this.element.css("position")))
4915 this.element[0].style.position = 'relative';
4916
4917 (this.options.addClasses && this.element.addClass("ui-draggable"));
4918 (this.options.disabled && this.element.addClass("ui-draggable-disabled"));
4919
4920 this._mouseInit();
4921
4922 },
4923
4924 destroy: function() {
4925 if(!this.element.data('draggable')) return;
4926 this.element
4927 .removeData("draggable")
4928 .unbind(".draggable")
4929 .removeClass("ui-draggable"
4930 + " ui-draggable-dragging"
4931 + " ui-draggable-disabled");
4932 this._mouseDestroy();
4933 },
4934
4935 _mouseCapture: function(event) {
4936
4937 var o = this.options;
4938
4939 if (this.helper || o.disabled || $(event.target).is('.ui-resizable-handle'))
4940 return false;
4941
4942 //Quit if we're not on a valid handle
4943 this.handle = this._getHandle(event);
4944 if (!this.handle)
4945 return false;
4946
4947 return true;
4948
4949 },
4950
4951 _mouseStart: function(event) {
4952
4953 var o = this.options;
4954
4955 //Create and append the visible helper
4956 this.helper = this._createHelper(event);
4957
4958 //Cache the helper size
4959 this._cacheHelperProportions();
4960
4961 //If ddmanager is used for droppables, set the global draggable
4962 if($.ui.ddmanager)
4963 $.ui.ddmanager.current = this;
4964
4965 /*
4966 * - Position generation -
4967 * This block generates everything position related - it's the core of draggables.
4968 */
4969
4970 //Cache the margins of the original element
4971 this._cacheMargins();
4972
4973 //Store the helper's css position
4974 this.cssPosition = this.helper.css("position");
4975 this.scrollParent = this.helper.scrollParent();
4976
4977 //The element's absolute position on the page minus margins
4978 this.offset = this.element.offset();
4979 this.offset = {
4980 top: this.offset.top - this.margins.top,
4981 left: this.offset.left - this.margins.left
4982 };
4983
4984 $.extend(this.offset, {
4985 click: { //Where the click happened, relative to the element
4986 left: event.pageX - this.offset.left,
4987 top: event.pageY - this.offset.top
4988 },
4989 parent: this._getParentOffset(),
4990 relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper
4991 });
4992
4993 //Generate the original position
4994 this.originalPosition = this._generatePosition(event);
4995 this.originalPageX = event.pageX;
4996 this.originalPageY = event.pageY;
4997
4998 //Adjust the mouse offset relative to the helper if 'cursorAt' is supplied
4999 if(o.cursorAt)
5000 this._adjustOffsetFromHelper(o.cursorAt);
5001
5002 //Set a containment if given in the options
5003 if(o.containment)
5004 this._setContainment();
5005
5006 //Call plugins and callbacks
5007 this._trigger("start", event);
5008
5009 //Recache the helper size
5010 this._cacheHelperProportions();
5011
5012 //Prepare the droppable offsets
5013 if ($.ui.ddmanager && !o.dropBehaviour)
5014 $.ui.ddmanager.prepareOffsets(this, event);
5015
5016 this.helper.addClass("ui-draggable-dragging");
5017 this._mouseDrag(event, true); //Execute the drag once - this causes the helper not to be visible before getting its correct position
5018 return true;
5019 },
5020
5021 _mouseDrag: function(event, noPropagation) {
5022
5023 //Compute the helpers position
5024 this.position = this._generatePosition(event);
5025 this.positionAbs = this._convertPositionTo("absolute");
5026
5027 //Call plugins and callbacks and use the resulting position if something is returned
5028 if (!noPropagation) {
5029 var ui = this._uiHash();
5030 this._trigger('drag', event, ui);
5031 this.position = ui.position;
5032 }
5033
5034 if(!this.options.axis || this.options.axis != "y") this.helper[0].style.left = this.position.left+'px';
5035 if(!this.options.axis || this.options.axis != "x") this.helper[0].style.top = this.position.top+'px';
5036 if($.ui.ddmanager) $.ui.ddmanager.drag(this, event);
5037
5038 return false;
5039 },
5040
5041 _mouseStop: function(event) {
5042
5043 //If we are using droppables, inform the manager about the drop
5044 var dropped = false;
5045 if ($.ui.ddmanager && !this.options.dropBehaviour)
5046 dropped = $.ui.ddmanager.drop(this, event);
5047
5048 //if a drop comes from outside (a sortable)
5049 if(this.dropped) {
5050 dropped = this.dropped;
5051 this.dropped = false;
5052 }
5053
5054 if((this.options.revert == "invalid" && !dropped) || (this.options.revert == "valid" && dropped) || this.options.revert === true || ($.isFunction(this.options.revert) && this.options.revert.call(this.element, dropped))) {
5055 var self = this;
5056 $(this.helper).animate(this.originalPosition, parseInt(this.options.revertDuration, 10), function() {
5057 self._trigger("stop", event);
5058 self._clear();
5059 });
5060 } else {
5061 this._trigger("stop", event);
5062 this._clear();
5063 }
5064
5065 return false;
5066 },
5067
5068 _getHandle: function(event) {
5069
5070 var handle = !this.options.handle || !$(this.options.handle, this.element).length ? true : false;
5071 $(this.options.handle, this.element)
5072 .find("*")
5073 .andSelf()
5074 .each(function() {
5075 if(this == event.target) handle = true;
5076 });
5077
5078 return handle;
5079
5080 },
5081
5082 _createHelper: function(event) {
5083
5084 var o = this.options;
5085 var helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event])) : (o.helper == 'clone' ? this.element.clone() : this.element);
5086
5087 if(!helper.parents('body').length)
5088 helper.appendTo((o.appendTo == 'parent' ? this.element[0].parentNode : o.appendTo));
5089
5090 if(helper[0] != this.element[0] && !(/(fixed|absolute)/).test(helper.css("position")))
5091 helper.css("position", "absolute");
5092
5093 return helper;
5094
5095 },
5096
5097 _adjustOffsetFromHelper: function(obj) {
5098 if(obj.left != undefined) this.offset.click.left = obj.left + this.margins.left;
5099 if(obj.right != undefined) this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
5100 if(obj.top != undefined) this.offset.click.top = obj.top + this.margins.top;
5101 if(obj.bottom != undefined) this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
5102 },
5103
5104 _getParentOffset: function() {
5105
5106 //Get the offsetParent and cache its position
5107 this.offsetParent = this.helper.offsetParent();
5108 var po = this.offsetParent.offset();
5109
5110 // This is a special case where we need to modify a offset calculated on start, since the following happened:
5111 // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
5112 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
5113 // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
5114 if(this.cssPosition == 'absolute' && this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) {
5115 po.left += this.scrollParent.scrollLeft();
5116 po.top += this.scrollParent.scrollTop();
5117 }
5118
5119 if((this.offsetParent[0] == document.body) //This needs to be actually done for all browsers, since pageX/pageY includes this information
5120 || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() == 'html' && $.browser.msie)) //Ugly IE fix
5121 po = { top: 0, left: 0 };
5122
5123 return {
5124 top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0),
5125 left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0)
5126 };
5127
5128 },
5129
5130 _getRelativeOffset: function() {
5131
5132 if(this.cssPosition == "relative") {
5133 var p = this.element.position();
5134 return {
5135 top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(),
5136 left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft()
5137 };
5138 } else {
5139 return { top: 0, left: 0 };
5140 }
5141
5142 },
5143
5144 _cacheMargins: function() {
5145 this.margins = {
5146 left: (parseInt(this.element.css("marginLeft"),10) || 0),
5147 top: (parseInt(this.element.css("marginTop"),10) || 0)
5148 };
5149 },
5150
5151 _cacheHelperProportions: function() {
5152 this.helperProportions = {
5153 width: this.helper.outerWidth(),
5154 height: this.helper.outerHeight()
5155 };
5156 },
5157
5158 _setContainment: function() {
5159
5160 var o = this.options;
5161 if(o.containment == 'parent') o.containment = this.helper[0].parentNode;
5162 if(o.containment == 'document' || o.containment == 'window') this.containment = [
5163 0 - this.offset.relative.left - this.offset.parent.left,
5164 0 - this.offset.relative.top - this.offset.parent.top,
5165 $(o.containment == 'document' ? document : window).width() - this.helperProportions.width - this.margins.left,
5166 ($(o.containment == 'document' ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top
5167 ];
5168
5169 if(!(/^(document|window|parent)$/).test(o.containment) && o.containment.constructor != Array) {
5170 var ce = $(o.containment)[0]; if(!ce) return;
5171 var co = $(o.containment).offset();
5172 var over = ($(ce).css("overflow") != 'hidden');
5173
5174 this.containment = [
5175 co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0) - this.margins.left,
5176 co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0) - this.margins.top,
5177 co.left+(over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css("borderLeftWidth"),10) || 0) - (parseInt($(ce).css("paddingRight"),10) || 0) - this.helperProportions.width - this.margins.left,
5178 co.top+(over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css("borderTopWidth"),10) || 0) - (parseInt($(ce).css("paddingBottom"),10) || 0) - this.helperProportions.height - this.margins.top
5179 ];
5180 } else if(o.containment.constructor == Array) {
5181 this.containment = o.containment;
5182 }
5183
5184 },
5185
5186 _convertPositionTo: function(d, pos) {
5187
5188 if(!pos) pos = this.position;
5189 var mod = d == "absolute" ? 1 : -1;
5190 var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
5191
5192 return {
5193 top: (
5194 pos.top // The absolute mouse position
5195 + this.offset.relative.top * mod // Only for relative positioned nodes: Relative offset from element to offset parent
5196 + this.offset.parent.top * mod // The offsetParent's offset without borders (offset + border)
5197 - ($.browser.safari && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod)
5198 ),
5199 left: (
5200 pos.left // The absolute mouse position
5201 + this.offset.relative.left * mod // Only for relative positioned nodes: Relative offset from element to offset parent
5202 + this.offset.parent.left * mod // The offsetParent's offset without borders (offset + border)
5203 - ($.browser.safari && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod)
5204 )
5205 };
5206
5207 },
5208
5209 _generatePosition: function(event) {
5210
5211 var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
5212
5213 // This is another very weird special case that only happens for relative elements:
5214 // 1. If the css position is relative
5215 // 2. and the scroll parent is the document or similar to the offset parent
5216 // we have to refresh the relative offset during the scroll so there are no jumps
5217 if(this.cssPosition == 'relative' && !(this.scrollParent[0] != document && this.scrollParent[0] != this.offsetParent[0])) {
5218 this.offset.relative = this._getRelativeOffset();
5219 }
5220
5221 var pageX = event.pageX;
5222 var pageY = event.pageY;
5223
5224 /*
5225 * - Position constraining -
5226 * Constrain the position to a mix of grid, containment.
5227 */
5228
5229 if(this.originalPosition) { //If we are not dragging yet, we won't check for options
5230
5231 if(this.containment) {
5232 if(event.pageX - this.offset.click.left < this.containment[0]) pageX = this.containment[0] + this.offset.click.left;
5233 if(event.pageY - this.offset.click.top < this.containment[1]) pageY = this.containment[1] + this.offset.click.top;
5234 if(event.pageX - this.offset.click.left > this.containment[2]) pageX = this.containment[2] + this.offset.click.left;
5235 if(event.pageY - this.offset.click.top > this.containment[3]) pageY = this.containment[3] + this.offset.click.top;
5236 }
5237
5238 if(o.grid) {
5239 var top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1];
5240 pageY = this.containment ? (!(top - this.offset.click.top < this.containment[1] || top - this.offset.click.top > this.containment[3]) ? top : (!(top - this.offset.click.top < this.containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top;
5241
5242 var left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0];
5243 pageX = this.containment ? (!(left - this.offset.click.left < this.containment[0] || left - this.offset.click.left > this.containment[2]) ? left : (!(left - this.offset.click.left < this.containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left;
5244 }
5245
5246 }
5247
5248 return {
5249 top: (
5250 pageY // The absolute mouse position
5251 - this.offset.click.top // Click offset (relative to the element)
5252 - this.offset.relative.top // Only for relative positioned nodes: Relative offset from element to offset parent
5253 - this.offset.parent.top // The offsetParent's offset without borders (offset + border)
5254 + ($.browser.safari && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ))
5255 ),
5256 left: (
5257 pageX // The absolute mouse position
5258 - this.offset.click.left // Click offset (relative to the element)
5259 - this.offset.relative.left // Only for relative positioned nodes: Relative offset from element to offset parent
5260 - this.offset.parent.left // The offsetParent's offset without borders (offset + border)
5261 + ($.browser.safari && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ))
5262 )
5263 };
5264
5265 },
5266
5267 _clear: function() {
5268 this.helper.removeClass("ui-draggable-dragging");
5269 if(this.helper[0] != this.element[0] && !this.cancelHelperRemoval) this.helper.remove();
5270 //if($.ui.ddmanager) $.ui.ddmanager.current = null;
5271 this.helper = null;
5272 this.cancelHelperRemoval = false;
5273 },
5274
5275 // From now on bulk stuff - mainly helpers
5276
5277 _trigger: function(type, event, ui) {
5278 ui = ui || this._uiHash();
5279 $.ui.plugin.call(this, type, [event, ui]);
5280 if(type == "drag") this.positionAbs = this._convertPositionTo("absolute"); //The absolute position has to be recalculated after plugins
5281 return $.widget.prototype._trigger.call(this, type, event, ui);
5282 },
5283
5284 plugins: {},
5285
5286 _uiHash: function(event) {
5287 return {
5288 helper: this.helper,
5289 position: this.position,
5290 absolutePosition: this.positionAbs, //deprecated
5291 offset: this.positionAbs
5292 };
5293 }
5294
5295 }));
5296
5297 $.extend($.ui.draggable, {
5298 version: "1.7.2",
5299 eventPrefix: "drag",
5300 defaults: {
5301 addClasses: true,
5302 appendTo: "parent",
5303 axis: false,
5304 cancel: ":input,option",
5305 connectToSortable: false,
5306 containment: false,
5307 cursor: "auto",
5308 cursorAt: false,
5309 delay: 0,
5310 distance: 1,
5311 grid: false,
5312 handle: false,
5313 helper: "original",
5314 iframeFix: false,
5315 opacity: false,
5316 refreshPositions: false,
5317 revert: false,
5318 revertDuration: 500,
5319 scope: "default",
5320 scroll: true,
5321 scrollSensitivity: 20,
5322 scrollSpeed: 20,
5323 snap: false,
5324 snapMode: "both",
5325 snapTolerance: 20,
5326 stack: false,
5327 zIndex: false
5328 }
5329 });
5330
5331 $.ui.plugin.add("draggable", "connectToSortable", {
5332 start: function(event, ui) {
5333
5334 var inst = $(this).data("draggable"), o = inst.options,
5335 uiSortable = $.extend({}, ui, { item: inst.element });
5336 inst.sortables = [];
5337 $(o.connectToSortable).each(function() {
5338 var sortable = $.data(this, 'sortable');
5339 if (sortable && !sortable.options.disabled) {
5340 inst.sortables.push({
5341 instance: sortable,
5342 shouldRevert: sortable.options.revert
5343 });
5344 sortable._refreshItems(); //Do a one-time refresh at start to refresh the containerCache
5345 sortable._trigger("activate", event, uiSortable);
5346 }
5347 });
5348
5349 },
5350 stop: function(event, ui) {
5351
5352 //If we are still over the sortable, we fake the stop event of the sortable, but also remove helper
5353 var inst = $(this).data("draggable"),
5354 uiSortable = $.extend({}, ui, { item: inst.element });
5355
5356 $.each(inst.sortables, function() {
5357 if(this.instance.isOver) {
5358
5359 this.instance.isOver = 0;
5360
5361 inst.cancelHelperRemoval = true; //Don't remove the helper in the draggable instance
5362 this.instance.cancelHelperRemoval = false; //Remove it in the sortable instance (so sortable plugins like revert still work)
5363
5364 //The sortable revert is supported, and we have to set a temporary dropped variable on the draggable to support revert: 'valid/invalid'
5365 if(this.shouldRevert) this.instance.options.revert = true;
5366
5367 //Trigger the stop of the sortable
5368 this.instance._mouseStop(event);
5369
5370 this.instance.options.helper = this.instance.options._helper;
5371
5372 //If the helper has been the original item, restore properties in the sortable
5373 if(inst.options.helper == 'original')
5374 this.instance.currentItem.css({ top: 'auto', left: 'auto' });
5375
5376 } else {
5377 this.instance.cancelHelperRemoval = false; //Remove the helper in the sortable instance
5378 this.instance._trigger("deactivate", event, uiSortable);
5379 }
5380
5381 });
5382
5383 },
5384 drag: function(event, ui) {
5385
5386 var inst = $(this).data("draggable"), self = this;
5387
5388 var checkPos = function(o) {
5389 var dyClick = this.offset.click.top, dxClick = this.offset.click.left;
5390 var helperTop = this.positionAbs.top, helperLeft = this.positionAbs.left;
5391 var itemHeight = o.height, itemWidth = o.width;
5392 var itemTop = o.top, itemLeft = o.left;
5393
5394 return $.ui.isOver(helperTop + dyClick, helperLeft + dxClick, itemTop, itemLeft, itemHeight, itemWidth);
5395 };
5396
5397 $.each(inst.sortables, function(i) {
5398
5399 //Copy over some variables to allow calling the sortable's native _intersectsWith
5400 this.instance.positionAbs = inst.positionAbs;
5401 this.instance.helperProportions = inst.helperProportions;
5402 this.instance.offset.click = inst.offset.click;
5403
5404 if(this.instance._intersectsWith(this.instance.containerCache)) {
5405
5406 //If it intersects, we use a little isOver variable and set it once, so our move-in stuff gets fired only once
5407 if(!this.instance.isOver) {
5408
5409 this.instance.isOver = 1;
5410 //Now we fake the start of dragging for the sortable instance,
5411 //by cloning the list group item, appending it to the sortable and using it as inst.currentItem
5412 //We can then fire the start event of the sortable with our passed browser event, and our own helper (so it doesn't create a new one)
5413 this.instance.currentItem = $(self).clone().appendTo(this.instance.element).data("sortable-item", true);
5414 this.instance.options._helper = this.instance.options.helper; //Store helper option to later restore it
5415 this.instance.options.helper = function() { return ui.helper[0]; };
5416
5417 event.target = this.instance.currentItem[0];
5418 this.instance._mouseCapture(event, true);
5419 this.instance._mouseStart(event, true, true);
5420
5421 //Because the browser event is way off the new appended portlet, we modify a couple of variables to reflect the changes
5422 this.instance.offset.click.top = inst.offset.click.top;
5423 this.instance.offset.click.left = inst.offset.click.left;
5424 this.instance.offset.parent.left -= inst.offset.parent.left - this.instance.offset.parent.left;
5425 this.instance.offset.parent.top -= inst.offset.parent.top - this.instance.offset.parent.top;
5426
5427 inst._trigger("toSortable", event);
5428 inst.dropped = this.instance.element; //draggable revert needs that
5429 //hack so receive/update callbacks work (mostly)
5430 inst.currentItem = inst.element;
5431 this.instance.fromOutside = inst;
5432
5433 }
5434
5435 //Provided we did all the previous steps, we can fire the drag event of the sortable on every draggable drag, when it intersects with the sortable
5436 if(this.instance.currentItem) this.instance._mouseDrag(event);
5437
5438 } else {
5439
5440 //If it doesn't intersect with the sortable, and it intersected before,
5441 //we fake the drag stop of the sortable, but make sure it doesn't remove the helper by using cancelHelperRemoval
5442 if(this.instance.isOver) {
5443
5444 this.instance.isOver = 0;
5445 this.instance.cancelHelperRemoval = true;
5446
5447 //Prevent reverting on this forced stop
5448 this.instance.options.revert = false;
5449
5450 // The out event needs to be triggered independently
5451 this.instance._trigger('out', event, this.instance._uiHash(this.instance));
5452
5453 this.instance._mouseStop(event, true);
5454 this.instance.options.helper = this.instance.options._helper;
5455
5456 //Now we remove our currentItem, the list group clone again, and the placeholder, and animate the helper back to it's original size
5457 this.instance.currentItem.remove();
5458 if(this.instance.placeholder) this.instance.placeholder.remove();
5459
5460 inst._trigger("fromSortable", event);
5461 inst.dropped = false; //draggable revert needs that
5462 }
5463
5464 };
5465
5466 });
5467
5468 }
5469 });
5470
5471 $.ui.plugin.add("draggable", "cursor", {
5472 start: function(event, ui) {
5473 var t = $('body'), o = $(this).data('draggable').options;
5474 if (t.css("cursor")) o._cursor = t.css("cursor");
5475 t.css("cursor", o.cursor);
5476 },
5477 stop: function(event, ui) {
5478 var o = $(this).data('draggable').options;
5479 if (o._cursor) $('body').css("cursor", o._cursor);
5480 }
5481 });
5482
5483 $.ui.plugin.add("draggable", "iframeFix", {
5484 start: function(event, ui) {
5485 var o = $(this).data('draggable').options;
5486 $(o.iframeFix === true ? "iframe" : o.iframeFix).each(function() {
5487 $('<div class="ui-draggable-iframeFix" style="background: #fff;"></div>')
5488 .css({
5489 width: this.offsetWidth+"px", height: this.offsetHeight+"px",
5490 position: "absolute", opacity: "0.001", zIndex: 1000
5491 })
5492 .css($(this).offset())
5493 .appendTo("body");
5494 });
5495 },
5496 stop: function(event, ui) {
5497 $("div.ui-draggable-iframeFix").each(function() { this.parentNode.removeChild(this); }); //Remove frame helpers
5498 }
5499 });
5500
5501 $.ui.plugin.add("draggable", "opacity", {
5502 start: function(event, ui) {
5503 var t = $(ui.helper), o = $(this).data('draggable').options;
5504 if(t.css("opacity")) o._opacity = t.css("opacity");
5505 t.css('opacity', o.opacity);
5506 },
5507 stop: function(event, ui) {
5508 var o = $(this).data('draggable').options;
5509 if(o._opacity) $(ui.helper).css('opacity', o._opacity);
5510 }
5511 });
5512
5513 $.ui.plugin.add("draggable", "scroll", {
5514 start: function(event, ui) {
5515 var i = $(this).data("draggable");
5516 if(i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') i.overflowOffset = i.scrollParent.offset();
5517 },
5518 drag: function(event, ui) {
5519
5520 var i = $(this).data("draggable"), o = i.options, scrolled = false;
5521
5522 if(i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') {
5523
5524 if(!o.axis || o.axis != 'x') {
5525 if((i.overflowOffset.top + i.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity)
5526 i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop + o.scrollSpeed;
5527 else if(event.pageY - i.overflowOffset.top < o.scrollSensitivity)
5528 i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop - o.scrollSpeed;
5529 }
5530
5531 if(!o.axis || o.axis != 'y') {
5532 if((i.overflowOffset.left + i.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity)
5533 i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft + o.scrollSpeed;
5534 else if(event.pageX - i.overflowOffset.left < o.scrollSensitivity)
5535 i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft - o.scrollSpeed;
5536 }
5537
5538 } else {
5539
5540 if(!o.axis || o.axis != 'x') {
5541 if(event.pageY - $(document).scrollTop() < o.scrollSensitivity)
5542 scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
5543 else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity)
5544 scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
5545 }
5546
5547 if(!o.axis || o.axis != 'y') {
5548 if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity)
5549 scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
5550 else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity)
5551 scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
5552 }
5553
5554 }
5555
5556 if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour)
5557 $.ui.ddmanager.prepareOffsets(i, event);
5558
5559 }
5560 });
5561
5562 $.ui.plugin.add("draggable", "snap", {
5563 start: function(event, ui) {
5564
5565 var i = $(this).data("draggable"), o = i.options;
5566 i.snapElements = [];
5567
5568 $(o.snap.constructor != String ? ( o.snap.items || ':data(draggable)' ) : o.snap).each(function() {
5569 var $t = $(this); var $o = $t.offset();
5570 if(this != i.element[0]) i.snapElements.push({
5571 item: this,
5572 width: $t.outerWidth(), height: $t.outerHeight(),
5573 top: $o.top, left: $o.left
5574 });
5575 });
5576
5577 },
5578 drag: function(event, ui) {
5579
5580 var inst = $(this).data("draggable"), o = inst.options;
5581 var d = o.snapTolerance;
5582
5583 var x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width,
5584 y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height;
5585
5586 for (var i = inst.snapElements.length - 1; i >= 0; i--){
5587
5588 var l = inst.snapElements[i].left, r = l + inst.snapElements[i].width,
5589 t = inst.snapElements[i].top, b = t + inst.snapElements[i].height;
5590
5591 //Yes, I know, this is insane ;)
5592 if(!((l-d < x1 && x1 < r+d && t-d < y1 && y1 < b+d) || (l-d < x1 && x1 < r+d && t-d < y2 && y2 < b+d) || (l-d < x2 && x2 < r+d && t-d < y1 && y1 < b+d) || (l-d < x2 && x2 < r+d && t-d < y2 && y2 < b+d))) {
5593 if(inst.snapElements[i].snapping) (inst.options.snap.release && inst.options.snap.release.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
5594 inst.snapElements[i].snapping = false;
5595 continue;
5596 }
5597
5598 if(o.snapMode != 'inner') {
5599 var ts = Math.abs(t - y2) <= d;
5600 var bs = Math.abs(b - y1) <= d;
5601 var ls = Math.abs(l - x2) <= d;
5602 var rs = Math.abs(r - x1) <= d;
5603 if(ts) ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top - inst.margins.top;
5604 if(bs) ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top - inst.margins.top;
5605 if(ls) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left - inst.margins.left;
5606 if(rs) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left - inst.margins.left;
5607 }
5608
5609 var first = (ts || bs || ls || rs);
5610
5611 if(o.snapMode != 'outer') {
5612 var ts = Math.abs(t - y1) <= d;
5613 var bs = Math.abs(b - y2) <= d;
5614 var ls = Math.abs(l - x1) <= d;
5615 var rs = Math.abs(r - x2) <= d;
5616 if(ts) ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top - inst.margins.top;
5617 if(bs) ui.position.top = inst._convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top - inst.margins.top;
5618 if(ls) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left - inst.margins.left;
5619 if(rs) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left - inst.margins.left;
5620 }
5621
5622 if(!inst.snapElements[i].snapping && (ts || bs || ls || rs || first))
5623 (inst.options.snap.snap && inst.options.snap.snap.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
5624 inst.snapElements[i].snapping = (ts || bs || ls || rs || first);
5625
5626 };
5627
5628 }
5629 });
5630
5631 $.ui.plugin.add("draggable", "stack", {
5632 start: function(event, ui) {
5633
5634 var o = $(this).data("draggable").options;
5635
5636 var group = $.makeArray($(o.stack.group)).sort(function(a,b) {
5637 return (parseInt($(a).css("zIndex"),10) || o.stack.min) - (parseInt($(b).css("zIndex"),10) || o.stack.min);
5638 });
5639
5640 $(group).each(function(i) {
5641 this.style.zIndex = o.stack.min + i;
5642 });
5643
5644 this[0].style.zIndex = o.stack.min + group.length;
5645
5646 }
5647 });
5648
5649 $.ui.plugin.add("draggable", "zIndex", {
5650 start: function(event, ui) {
5651 var t = $(ui.helper), o = $(this).data("draggable").options;
5652 if(t.css("zIndex")) o._zIndex = t.css("zIndex");
5653 t.css('zIndex', o.zIndex);
5654 },
5655 stop: function(event, ui) {
5656 var o = $(this).data("draggable").options;
5657 if(o._zIndex) $(ui.helper).css('zIndex', o._zIndex);
5658 }
5659 });
5660
5661 })(jQuery);
5662 /*
5663 * jQuery UI Resizable 1.7.2
5664 *
5665 * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
5666 * Dual licensed under the MIT (MIT-LICENSE.txt)
5667 * and GPL (GPL-LICENSE.txt) licenses.
5668 *
5669 * http://docs.jquery.com/UI/Resizables
5670 *
5671 * Depends:
5672 * ui.core.js
5673 */
5674 (function($) {
5675
5676 $.widget("ui.resizable", $.extend({}, $.ui.mouse, {
5677
5678 _init: function() {
5679
5680 var self = this, o = this.options;
5681 this.element.addClass("ui-resizable");
5682
5683 $.extend(this, {
5684 _aspectRatio: !!(o.aspectRatio),
5685 aspectRatio: o.aspectRatio,
5686 originalElement: this.element,
5687 _proportionallyResizeElements: [],
5688 _helper: o.helper || o.ghost || o.animate ? o.helper || 'ui-resizable-helper' : null
5689 });
5690
5691 //Wrap the element if it cannot hold child nodes
5692 if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)) {
5693
5694 //Opera fix for relative positioning
5695 if (/relative/.test(this.element.css('position')) && $.browser.opera)
5696 this.element.css({ position: 'relative', top: 'auto', left: 'auto' });
5697
5698 //Create a wrapper element and set the wrapper to the new current internal element
5699 this.element.wrap(
5700 $('<div class="ui-wrapper" style="overflow: hidden;"></div>').css({
5701 position: this.element.css('position'),
5702 width: this.element.outerWidth(),
5703 height: this.element.outerHeight(),
5704 top: this.element.css('top'),
5705 left: this.element.css('left')
5706 })
5707 );
5708
5709 //Overwrite the original this.element
5710 this.element = this.element.parent().data(
5711 "resizable", this.element.data('resizable')
5712 );
5713
5714 this.elementIsWrapper = true;
5715
5716 //Move margins to the wrapper
5717 this.element.css({ marginLeft: this.originalElement.css("marginLeft"), marginTop: this.originalElement.css("marginTop"), marginRight: this.originalElement.css("marginRight"), marginBottom: this.originalElement.css("marginBottom") });
5718 this.originalElement.css({ marginLeft: 0, marginTop: 0, marginRight: 0, marginBottom: 0});
5719
5720 //Prevent Safari textarea resize
5721 this.originalResizeStyle = this.originalElement.css('resize');
5722 this.originalElement.css('resize', 'none');
5723
5724 //Push the actual element to our proportionallyResize internal array
5725 this._proportionallyResizeElements.push(this.originalElement.css({ position: 'static', zoom: 1, display: 'block' }));
5726
5727 // avoid IE jump (hard set the margin)
5728 this.originalElement.css({ margin: this.originalElement.css('margin') });
5729
5730 // fix handlers offset
5731 this._proportionallyResize();
5732
5733 }
5734
5735 this.handles = o.handles || (!$('.ui-resizable-handle', this.element).length ? "e,s,se" : { n: '.ui-resizable-n', e: '.ui-resizable-e', s: '.ui-resizable-s', w: '.ui-resizable-w', se: '.ui-resizable-se', sw: '.ui-resizable-sw', ne: '.ui-resizable-ne', nw: '.ui-resizable-nw' });
5736 if(this.handles.constructor == String) {
5737
5738 if(this.handles == 'all') this.handles = 'n,e,s,w,se,sw,ne,nw';
5739 var n = this.handles.split(","); this.handles = {};
5740
5741 for(var i = 0; i < n.length; i++) {
5742
5743 var handle = $.trim(n[i]), hname = 'ui-resizable-'+handle;
5744 var axis = $('<div class="ui-resizable-handle ' + hname + '"></div>');
5745
5746 // increase zIndex of sw, se, ne, nw axis
5747 //TODO : this modifies original option
5748 if(/sw|se|ne|nw/.test(handle)) axis.css({ zIndex: ++o.zIndex });
5749
5750 //TODO : What's going on here?
5751 if ('se' == handle) {
5752 axis.addClass('ui-icon ui-icon-gripsmall-diagonal-se');
5753 };
5754
5755 //Insert into internal handles object and append to element
5756 this.handles[handle] = '.ui-resizable-'+handle;
5757 this.element.append(axis);
5758 }
5759
5760 }
5761
5762 this._renderAxis = function(target) {
5763
5764 target = target || this.element;
5765
5766 for(var i in this.handles) {
5767
5768 if(this.handles[i].constructor == String)
5769 this.handles[i] = $(this.handles[i], this.element).show();
5770
5771 //Apply pad to wrapper element, needed to fix axis position (textarea, inputs, scrolls)
5772 if (this.elementIsWrapper && this.originalElement[0].nodeName.match(/textarea|input|select|button/i)) {
5773
5774 var axis = $(this.handles[i], this.element), padWrapper = 0;
5775
5776 //Checking the correct pad and border
5777 padWrapper = /sw|ne|nw|se|n|s/.test(i) ? axis.outerHeight() : axis.outerWidth();
5778
5779 //The padding type i have to apply...
5780 var padPos = [ 'padding',
5781 /ne|nw|n/.test(i) ? 'Top' :
5782 /se|sw|s/.test(i) ? 'Bottom' :
5783 /^e$/.test(i) ? 'Right' : 'Left' ].join("");
5784
5785 target.css(padPos, padWrapper);
5786
5787 this._proportionallyResize();
5788
5789 }
5790
5791 //TODO: What's that good for? There's not anything to be executed left
5792 if(!$(this.handles[i]).length)
5793 continue;
5794
5795 }
5796 };
5797
5798 //TODO: make renderAxis a prototype function
5799 this._renderAxis(this.element);
5800
5801 this._handles = $('.ui-resizable-handle', this.element)
5802 .disableSelection();
5803
5804 //Matching axis name
5805 this._handles.mouseover(function() {
5806 if (!self.resizing) {
5807 if (this.className)
5808 var axis = this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);
5809 //Axis, default = se
5810 self.axis = axis && axis[1] ? axis[1] : 'se';
5811 }
5812 });
5813
5814 //If we want to auto hide the elements
5815 if (o.autoHide) {
5816 this._handles.hide();
5817 $(this.element)
5818 .addClass("ui-resizable-autohide")
5819 .hover(function() {
5820 $(this).removeClass("ui-resizable-autohide");
5821 self._handles.show();
5822 },
5823 function(){
5824 if (!self.resizing) {
5825 $(this).addClass("ui-resizable-autohide");
5826 self._handles.hide();
5827 }
5828 });
5829 }
5830
5831 //Initialize the mouse interaction
5832 this._mouseInit();
5833
5834 },
5835
5836 destroy: function() {
5837
5838 this._mouseDestroy();
5839
5840 var _destroy = function(exp) {
5841 $(exp).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing")
5842 .removeData("resizable").unbind(".resizable").find('.ui-resizable-handle').remove();
5843 };
5844
5845 //TODO: Unwrap at same DOM position
5846 if (this.elementIsWrapper) {
5847 _destroy(this.element);
5848 var wrapper = this.element;
5849 wrapper.parent().append(
5850 this.originalElement.css({
5851 position: wrapper.css('position'),
5852 width: wrapper.outerWidth(),
5853 height: wrapper.outerHeight(),
5854 top: wrapper.css('top'),
5855 left: wrapper.css('left')
5856 })
5857 ).end().remove();
5858 }
5859
5860 this.originalElement.css('resize', this.originalResizeStyle);
5861 _destroy(this.originalElement);
5862
5863 },
5864
5865 _mouseCapture: function(event) {
5866
5867 var handle = false;
5868 for(var i in this.handles) {
5869 if($(this.handles[i])[0] == event.target) handle = true;
5870 }
5871
5872 return this.options.disabled || !!handle;
5873
5874 },
5875
5876 _mouseStart: function(event) {
5877
5878 var o = this.options, iniPos = this.element.position(), el = this.element;
5879
5880 this.resizing = true;
5881 this.documentScroll = { top: $(document).scrollTop(), left: $(document).scrollLeft() };
5882
5883 // bugfix for http://dev.jquery.com/ticket/1749
5884 if (el.is('.ui-draggable') || (/absolute/).test(el.css('position'))) {
5885 el.css({ position: 'absolute', top: iniPos.top, left: iniPos.left });
5886 }
5887
5888 //Opera fixing relative position
5889 if ($.browser.opera && (/relative/).test(el.css('position')))
5890 el.css({ position: 'relative', top: 'auto', left: 'auto' });
5891
5892 this._renderProxy();
5893
5894 var curleft = num(this.helper.css('left')), curtop = num(this.helper.css('top'));
5895
5896 if (o.containment) {
5897 curleft += $(o.containment).scrollLeft() || 0;
5898 curtop += $(o.containment).scrollTop() || 0;
5899 }
5900
5901 //Store needed variables
5902 this.offset = this.helper.offset();
5903 this.position = { left: curleft, top: curtop };
5904 this.size = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() };
5905 this.originalSize = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() };
5906 this.originalPosition = { left: curleft, top: curtop };
5907 this.sizeDiff = { width: el.outerWidth() - el.width(), height: el.outerHeight() - el.height() };
5908 this.originalMousePosition = { left: event.pageX, top: event.pageY };
5909
5910 //Aspect Ratio
5911 this.aspectRatio = (typeof o.aspectRatio == 'number') ? o.aspectRatio : ((this.originalSize.width / this.originalSize.height) || 1);
5912
5913 var cursor = $('.ui-resizable-' + this.axis).css('cursor');
5914 $('body').css('cursor', cursor == 'auto' ? this.axis + '-resize' : cursor);
5915
5916 el.addClass("ui-resizable-resizing");
5917 this._propagate("start", event);
5918 return true;
5919 },
5920
5921 _mouseDrag: function(event) {
5922
5923 //Increase performance, avoid regex
5924 var el = this.helper, o = this.options, props = {},
5925 self = this, smp = this.originalMousePosition, a = this.axis;
5926
5927 var dx = (event.pageX-smp.left)||0, dy = (event.pageY-smp.top)||0;
5928 var trigger = this._change[a];
5929 if (!trigger) return false;
5930
5931 // Calculate the attrs that will be change
5932 var data = trigger.apply(this, [event, dx, dy]), ie6 = $.browser.msie && $.browser.version < 7, csdif = this.sizeDiff;
5933
5934 if (this._aspectRatio || event.shiftKey)
5935 data = this._updateRatio(data, event);
5936
5937 data = this._respectSize(data, event);
5938
5939 // plugins callbacks need to be called first
5940 this._propagate("resize", event);
5941
5942 el.css({
5943 top: this.position.top + "px", left: this.position.left + "px",
5944 width: this.size.width + "px", height: this.size.height + "px"
5945 });
5946
5947 if (!this._helper && this._proportionallyResizeElements.length)
5948 this._proportionallyResize();
5949
5950 this._updateCache(data);
5951
5952 // calling the user callback at the end
5953 this._trigger('resize', event, this.ui());
5954
5955 return false;
5956 },
5957
5958 _mouseStop: function(event) {
5959
5960 this.resizing = false;
5961 var o = this.options, self = this;
5962
5963 if(this._helper) {
5964 var pr = this._proportionallyResizeElements, ista = pr.length && (/textarea/i).test(pr[0].nodeName),
5965 soffseth = ista && $.ui.hasScroll(pr[0], 'left') /* TODO - jump height */ ? 0 : self.sizeDiff.height,
5966 soffsetw = ista ? 0 : self.sizeDiff.width;
5967
5968 var s = { width: (self.size.width - soffsetw), height: (self.size.height - soffseth) },
5969 left = (parseInt(self.element.css('left'), 10) + (self.position.left - self.originalPosition.left)) || null,
5970 top = (parseInt(self.element.css('top'), 10) + (self.position.top - self.originalPosition.top)) || null;
5971
5972 if (!o.animate)
5973 this.element.css($.extend(s, { top: top, left: left }));
5974
5975 self.helper.height(self.size.height);
5976 self.helper.width(self.size.width);
5977
5978 if (this._helper && !o.animate) this._proportionallyResize();
5979 }
5980
5981 $('body').css('cursor', 'auto');
5982
5983 this.element.removeClass("ui-resizable-resizing");
5984
5985 this._propagate("stop", event);
5986
5987 if (this._helper) this.helper.remove();
5988 return false;
5989
5990 },
5991
5992 _updateCache: function(data) {
5993 var o = this.options;
5994 this.offset = this.helper.offset();
5995 if (isNumber(data.left)) this.position.left = data.left;
5996 if (isNumber(data.top)) this.position.top = data.top;
5997 if (isNumber(data.height)) this.size.height = data.height;
5998 if (isNumber(data.width)) this.size.width = data.width;
5999 },
6000
6001 _updateRatio: function(data, event) {
6002
6003 var o = this.options, cpos = this.position, csize = this.size, a = this.axis;
6004
6005 if (data.height) data.width = (csize.height * this.aspectRatio);
6006 else if (data.width) data.height = (csize.width / this.aspectRatio);
6007
6008 if (a == 'sw') {
6009 data.left = cpos.left + (csize.width - data.width);
6010 data.top = null;
6011 }
6012 if (a == 'nw') {
6013 data.top = cpos.top + (csize.height - data.height);
6014 data.left = cpos.left + (csize.width - data.width);
6015 }
6016
6017 return data;
6018 },
6019
6020 _respectSize: function(data, event) {
6021
6022 var el = this.helper, o = this.options, pRatio = this._aspectRatio || event.shiftKey, a = this.axis,
6023 ismaxw = isNumber(data.width) && o.maxWidth && (o.maxWidth < data.width), ismaxh = isNumber(data.height) && o.maxHeight && (o.maxHeight < data.height),
6024 isminw = isNumber(data.width) && o.minWidth && (o.minWidth > data.width), isminh = isNumber(data.height) && o.minHeight && (o.minHeight > data.height);
6025
6026 if (isminw) data.width = o.minWidth;
6027 if (isminh) data.height = o.minHeight;
6028 if (ismaxw) data.width = o.maxWidth;
6029 if (ismaxh) data.height = o.maxHeight;
6030
6031 var dw = this.originalPosition.left + this.originalSize.width, dh = this.position.top + this.size.height;
6032 var cw = /sw|nw|w/.test(a), ch = /nw|ne|n/.test(a);
6033
6034 if (isminw && cw) data.left = dw - o.minWidth;
6035 if (ismaxw && cw) data.left = dw - o.maxWidth;
6036 if (isminh && ch) data.top = dh - o.minHeight;
6037 if (ismaxh && ch) data.top = dh - o.maxHeight;
6038
6039 // fixing jump error on top/left - bug #2330
6040 var isNotwh = !data.width && !data.height;
6041 if (isNotwh && !data.left && data.top) data.top = null;
6042 else if (isNotwh && !data.top && data.left) data.left = null;
6043
6044 return data;
6045 },
6046
6047 _proportionallyResize: function() {
6048
6049 var o = this.options;
6050 if (!this._proportionallyResizeElements.length) return;
6051 var element = this.helper || this.element;
6052
6053 for (var i=0; i < this._proportionallyResizeElements.length; i++) {
6054
6055 var prel = this._proportionallyResizeElements[i];
6056
6057 if (!this.borderDif) {
6058 var b = [prel.css('borderTopWidth'), prel.css('borderRightWidth'), prel.css('borderBottomWidth'), prel.css('borderLeftWidth')],
6059 p = [prel.css('paddingTop'), prel.css('paddingRight'), prel.css('paddingBottom'), prel.css('paddingLeft')];
6060
6061 this.borderDif = $.map(b, function(v, i) {
6062 var border = parseInt(v,10)||0, padding = parseInt(p[i],10)||0;
6063 return border + padding;
6064 });
6065 }
6066
6067 if ($.browser.msie && !(!($(element).is(':hidden') || $(element).parents(':hidden').length)))
6068 continue;
6069
6070 prel.css({
6071 height: (element.height() - this.borderDif[0] - this.borderDif[2]) || 0,
6072 width: (element.width() - this.borderDif[1] - this.borderDif[3]) || 0
6073 });
6074
6075 };
6076
6077 },
6078
6079 _renderProxy: function() {
6080
6081 var el = this.element, o = this.options;
6082 this.elementOffset = el.offset();
6083
6084 if(this._helper) {
6085
6086 this.helper = this.helper || $('<div style="overflow:hidden;"></div>');
6087
6088 // fix ie6 offset TODO: This seems broken
6089 var ie6 = $.browser.msie && $.browser.version < 7, ie6offset = (ie6 ? 1 : 0),
6090 pxyoffset = ( ie6 ? 2 : -1 );
6091
6092 this.helper.addClass(this._helper).css({
6093 width: this.element.outerWidth() + pxyoffset,
6094 height: this.element.outerHeight() + pxyoffset,
6095 position: 'absolute',
6096 left: this.elementOffset.left - ie6offset +'px',
6097 top: this.elementOffset.top - ie6offset +'px',
6098 zIndex: ++o.zIndex //TODO: Don't modify option
6099 });
6100
6101 this.helper
6102 .appendTo("body")
6103 .disableSelection();
6104
6105 } else {
6106 this.helper = this.element;
6107 }
6108
6109 },
6110
6111 _change: {
6112 e: function(event, dx, dy) {
6113 return { width: this.originalSize.width + dx };
6114 },
6115 w: function(event, dx, dy) {
6116 var o = this.options, cs = this.originalSize, sp = this.originalPosition;
6117 return { left: sp.left + dx, width: cs.width - dx };
6118 },
6119 n: function(event, dx, dy) {
6120 var o = this.options, cs = this.originalSize, sp = this.originalPosition;
6121 return { top: sp.top + dy, height: cs.height - dy };
6122 },
6123 s: function(event, dx, dy) {
6124 return { height: this.originalSize.height + dy };
6125 },
6126 se: function(event, dx, dy) {
6127 return $.extend(this._change.s.apply(this, arguments), this._change.e.apply(this, [event, dx, dy]));
6128 },
6129 sw: function(event, dx, dy) {
6130 return $.extend(this._change.s.apply(this, arguments), this._change.w.apply(this, [event, dx, dy]));
6131 },
6132 ne: function(event, dx, dy) {
6133 return $.extend(this._change.n.apply(this, arguments), this._change.e.apply(this, [event, dx, dy]));
6134 },
6135 nw: function(event, dx, dy) {
6136 return $.extend(this._change.n.apply(this, arguments), this._change.w.apply(this, [event, dx, dy]));
6137 }
6138 },
6139
6140 _propagate: function(n, event) {
6141 $.ui.plugin.call(this, n, [event, this.ui()]);
6142 (n != "resize" && this._trigger(n, event, this.ui()));
6143 },
6144
6145 plugins: {},
6146
6147 ui: function() {
6148 return {
6149 originalElement: this.originalElement,
6150 element: this.element,
6151 helper: this.helper,
6152 position: this.position,
6153 size: this.size,
6154 originalSize: this.originalSize,
6155 originalPosition: this.originalPosition
6156 };
6157 }
6158
6159 }));
6160
6161 $.extend($.ui.resizable, {
6162 version: "1.7.2",
6163 eventPrefix: "resize",
6164 defaults: {
6165 alsoResize: false,
6166 animate: false,
6167 animateDuration: "slow",
6168 animateEasing: "swing",
6169 aspectRatio: false,
6170 autoHide: false,
6171 cancel: ":input,option",
6172 containment: false,
6173 delay: 0,
6174 distance: 1,
6175 ghost: false,
6176 grid: false,
6177 handles: "e,s,se",
6178 helper: false,
6179 maxHeight: null,
6180 maxWidth: null,
6181 minHeight: 10,
6182 minWidth: 10,
6183 zIndex: 1000
6184 }
6185 });
6186
6187 /*
6188 * Resizable Extensions
6189 */
6190
6191 $.ui.plugin.add("resizable", "alsoResize", {
6192
6193 start: function(event, ui) {
6194
6195 var self = $(this).data("resizable"), o = self.options;
6196
6197 _store = function(exp) {
6198 $(exp).each(function() {
6199 $(this).data("resizable-alsoresize", {
6200 width: parseInt($(this).width(), 10), height: parseInt($(this).height(), 10),
6201 left: parseInt($(this).css('left'), 10), top: parseInt($(this).css('top'), 10)
6202 });
6203 });
6204 };
6205
6206 if (typeof(o.alsoResize) == 'object' && !o.alsoResize.parentNode) {
6207 if (o.alsoResize.length) { o.alsoResize = o.alsoResize[0]; _store(o.alsoResize); }
6208 else { $.each(o.alsoResize, function(exp, c) { _store(exp); }); }
6209 }else{
6210 _store(o.alsoResize);
6211 }
6212 },
6213
6214 resize: function(event, ui){
6215 var self = $(this).data("resizable"), o = self.options, os = self.originalSize, op = self.originalPosition;
6216
6217 var delta = {
6218 height: (self.size.height - os.height) || 0, width: (self.size.width - os.width) || 0,
6219 top: (self.position.top - op.top) || 0, left: (self.position.left - op.left) || 0
6220 },
6221
6222 _alsoResize = function(exp, c) {
6223 $(exp).each(function() {
6224 var el = $(this), start = $(this).data("resizable-alsoresize"), style = {}, css = c && c.length ? c : ['width', 'height', 'top', 'left'];
6225
6226 $.each(css || ['width', 'height', 'top', 'left'], function(i, prop) {
6227 var sum = (start[prop]||0) + (delta[prop]||0);
6228 if (sum && sum >= 0)
6229 style[prop] = sum || null;
6230 });
6231
6232 //Opera fixing relative position
6233 if (/relative/.test(el.css('position')) && $.browser.opera) {
6234 self._revertToRelativePosition = true;
6235 el.css({ position: 'absolute', top: 'auto', left: 'auto' });
6236 }
6237
6238 el.css(style);
6239 });
6240 };
6241
6242 if (typeof(o.alsoResize) == 'object' && !o.alsoResize.nodeType) {
6243 $.each(o.alsoResize, function(exp, c) { _alsoResize(exp, c); });
6244 }else{
6245 _alsoResize(o.alsoResize);
6246 }
6247 },
6248
6249 stop: function(event, ui){
6250 var self = $(this).data("resizable");
6251
6252 //Opera fixing relative position
6253 if (self._revertToRelativePosition && $.browser.opera) {
6254 self._revertToRelativePosition = false;
6255 el.css({ position: 'relative' });
6256 }
6257
6258 $(this).removeData("resizable-alsoresize-start");
6259 }
6260 });
6261
6262 $.ui.plugin.add("resizable", "animate", {
6263
6264 stop: function(event, ui) {
6265 var self = $(this).data("resizable"), o = self.options;
6266
6267 var pr = self._proportionallyResizeElements, ista = pr.length && (/textarea/i).test(pr[0].nodeName),
6268 soffseth = ista && $.ui.hasScroll(pr[0], 'left') /* TODO - jump height */ ? 0 : self.sizeDiff.height,
6269 soffsetw = ista ? 0 : self.sizeDiff.width;
6270
6271 var style = { width: (self.size.width - soffsetw), height: (self.size.height - soffseth) },
6272 left = (parseInt(self.element.css('left'), 10) + (self.position.left - self.originalPosition.left)) || null,
6273 top = (parseInt(self.element.css('top'), 10) + (self.position.top - self.originalPosition.top)) || null;
6274
6275 self.element.animate(
6276 $.extend(style, top && left ? { top: top, left: left } : {}), {
6277 duration: o.animateDuration,
6278 easing: o.animateEasing,
6279 step: function() {
6280
6281 var data = {
6282 width: parseInt(self.element.css('width'), 10),
6283 height: parseInt(self.element.css('height'), 10),
6284 top: parseInt(self.element.css('top'), 10),
6285 left: parseInt(self.element.css('left'), 10)
6286 };
6287
6288 if (pr && pr.length) $(pr[0]).css({ width: data.width, height: data.height });
6289
6290 // propagating resize, and updating values for each animation step
6291 self._updateCache(data);
6292 self._propagate("resize", event);
6293
6294 }
6295 }
6296 );
6297 }
6298
6299 });
6300
6301 $.ui.plugin.add("resizable", "containment", {
6302
6303 start: function(event, ui) {
6304 var self = $(this).data("resizable"), o = self.options, el = self.element;
6305 var oc = o.containment, ce = (oc instanceof $) ? oc.get(0) : (/parent/.test(oc)) ? el.parent().get(0) : oc;
6306 if (!ce) return;
6307
6308 self.containerElement = $(ce);
6309
6310 if (/document/.test(oc) || oc == document) {
6311 self.containerOffset = { left: 0, top: 0 };
6312 self.containerPosition = { left: 0, top: 0 };
6313
6314 self.parentData = {
6315 element: $(document), left: 0, top: 0,
6316 width: $(document).width(), height: $(document).height() || document.body.parentNode.scrollHeight
6317 };
6318 }
6319
6320 // i'm a node, so compute top, left, right, bottom
6321 else {
6322 var element = $(ce), p = [];
6323 $([ "Top", "Right", "Left", "Bottom" ]).each(function(i, name) { p[i] = num(element.css("padding" + name)); });
6324
6325 self.containerOffset = element.offset();
6326 self.containerPosition = element.position();
6327 self.containerSize = { height: (element.innerHeight() - p[3]), width: (element.innerWidth() - p[1]) };
6328
6329 var co = self.containerOffset, ch = self.containerSize.height, cw = self.containerSize.width,
6330 width = ($.ui.hasScroll(ce, "left") ? ce.scrollWidth : cw ), height = ($.ui.hasScroll(ce) ? ce.scrollHeight : ch);
6331
6332 self.parentData = {
6333 element: ce, left: co.left, top: co.top, width: width, height: height
6334 };
6335 }
6336 },
6337
6338 resize: function(event, ui) {
6339 var self = $(this).data("resizable"), o = self.options,
6340 ps = self.containerSize, co = self.containerOffset, cs = self.size, cp = self.position,
6341 pRatio = self._aspectRatio || event.shiftKey, cop = { top:0, left:0 }, ce = self.containerElement;
6342
6343 if (ce[0] != document && (/static/).test(ce.css('position'))) cop = co;
6344
6345 if (cp.left < (self._helper ? co.left : 0)) {
6346 self.size.width = self.size.width + (self._helper ? (self.position.left - co.left) : (self.position.left - cop.left));
6347 if (pRatio) self.size.height = self.size.width / o.aspectRatio;
6348 self.position.left = o.helper ? co.left : 0;
6349 }
6350
6351 if (cp.top < (self._helper ? co.top : 0)) {
6352 self.size.height = self.size.height + (self._helper ? (self.position.top - co.top) : self.position.top);
6353 if (pRatio) self.size.width = self.size.height * o.aspectRatio;
6354 self.position.top = self._helper ? co.top : 0;
6355 }
6356
6357 self.offset.left = self.parentData.left+self.position.left;
6358 self.offset.top = self.parentData.top+self.position.top;
6359
6360 var woset = Math.abs( (self._helper ? self.offset.left - cop.left : (self.offset.left - cop.left)) + self.sizeDiff.width ),
6361 hoset = Math.abs( (self._helper ? self.offset.top - cop.top : (self.offset.top - co.top)) + self.sizeDiff.height );
6362
6363 var isParent = self.containerElement.get(0) == self.element.parent().get(0),
6364 isOffsetRelative = /relative|absolute/.test(self.containerElement.css('position'));
6365
6366 if(isParent && isOffsetRelative) woset -= self.parentData.left;
6367
6368 if (woset + self.size.width >= self.parentData.width) {
6369 self.size.width = self.parentData.width - woset;
6370 if (pRatio) self.size.height = self.size.width / self.aspectRatio;
6371 }
6372
6373 if (hoset + self.size.height >= self.parentData.height) {
6374 self.size.height = self.parentData.height - hoset;
6375 if (pRatio) self.size.width = self.size.height * self.aspectRatio;
6376 }
6377 },
6378
6379 stop: function(event, ui){
6380 var self = $(this).data("resizable"), o = self.options, cp = self.position,
6381 co = self.containerOffset, cop = self.containerPosition, ce = self.containerElement;
6382
6383 var helper = $(self.helper), ho = helper.offset(), w = helper.outerWidth() - self.sizeDiff.width, h = helper.outerHeight() - self.sizeDiff.height;
6384
6385 if (self._helper && !o.animate && (/relative/).test(ce.css('position')))
6386 $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h });
6387
6388 if (self._helper && !o.animate && (/static/).test(ce.css('position')))
6389 $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h });
6390
6391 }
6392 });
6393
6394 $.ui.plugin.add("resizable", "ghost", {
6395
6396 start: function(event, ui) {
6397
6398 var self = $(this).data("resizable"), o = self.options, cs = self.size;
6399
6400 self.ghost = self.originalElement.clone();
6401 self.ghost
6402 .css({ opacity: .25, display: 'block', position: 'relative', height: cs.height, width: cs.width, margin: 0, left: 0, top: 0 })
6403 .addClass('ui-resizable-ghost')
6404 .addClass(typeof o.ghost == 'string' ? o.ghost : '');
6405
6406 self.ghost.appendTo(self.helper);
6407
6408 },
6409
6410 resize: function(event, ui){
6411 var self = $(this).data("resizable"), o = self.options;
6412 if (self.ghost) self.ghost.css({ position: 'relative', height: self.size.height, width: self.size.width });
6413 },
6414
6415 stop: function(event, ui){
6416 var self = $(this).data("resizable"), o = self.options;
6417 if (self.ghost && self.helper) self.helper.get(0).removeChild(self.ghost.get(0));
6418 }
6419
6420 });
6421
6422 $.ui.plugin.add("resizable", "grid", {
6423
6424 resize: function(event, ui) {
6425 var self = $(this).data("resizable"), o = self.options, cs = self.size, os = self.originalSize, op = self.originalPosition, a = self.axis, ratio = o._aspectRatio || event.shiftKey;
6426 o.grid = typeof o.grid == "number" ? [o.grid, o.grid] : o.grid;
6427 var ox = Math.round((cs.width - os.width) / (o.grid[0]||1)) * (o.grid[0]||1), oy = Math.round((cs.height - os.height) / (o.grid[1]||1)) * (o.grid[1]||1);
6428
6429 if (/^(se|s|e)$/.test(a)) {
6430 self.size.width = os.width + ox;
6431 self.size.height = os.height + oy;
6432 }
6433 else if (/^(ne)$/.test(a)) {
6434 self.size.width = os.width + ox;
6435 self.size.height = os.height + oy;
6436 self.position.top = op.top - oy;
6437 }
6438 else if (/^(sw)$/.test(a)) {
6439 self.size.width = os.width + ox;
6440 self.size.height = os.height + oy;
6441 self.position.left = op.left - ox;
6442 }
6443 else {
6444 self.size.width = os.width + ox;
6445 self.size.height = os.height + oy;
6446 self.position.top = op.top - oy;
6447 self.position.left = op.left - ox;
6448 }
6449 }
6450
6451 });
6452
6453 var num = function(v) {
6454 return parseInt(v, 10) || 0;
6455 };
6456
6457 var isNumber = function(value) {
6458 return !isNaN(parseInt(value, 10));
6459 };
6460
6461 })(jQuery);
6462 /*
6463 * jQuery UI Dialog 1.7.2
6464 *
6465 * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
6466 * Dual licensed under the MIT (MIT-LICENSE.txt)
6467 * and GPL (GPL-LICENSE.txt) licenses.
6468 *
6469 * http://docs.jquery.com/UI/Dialog
6470 *
6471 * Depends:
6472 * ui.core.js
6473 * ui.draggable.js
6474 * ui.resizable.js
6475 */
6476 (function($) {
6477
6478 var setDataSwitch = {
6479 dragStart: "start.draggable",
6480 drag: "drag.draggable",
6481 dragStop: "stop.draggable",
6482 maxHeight: "maxHeight.resizable",
6483 minHeight: "minHeight.resizable",
6484 maxWidth: "maxWidth.resizable",
6485 minWidth: "minWidth.resizable",
6486 resizeStart: "start.resizable",
6487 resize: "drag.resizable",
6488 resizeStop: "stop.resizable"
6489 },
6490
6491 uiDialogClasses =
6492 'ui-dialog ' +
6493 'ui-widget ' +
6494 'ui-widget-content ' +
6495 'ui-corner-all ';
6496
6497 $.widget("ui.dialog", {
6498
6499 _init: function() {
6500 this.originalTitle = this.element.attr('title');
6501
6502 var self = this,
6503 options = this.options,
6504
6505 title = options.title || this.originalTitle || '&nbsp;',
6506 titleId = $.ui.dialog.getTitleId(this.element),
6507
6508 uiDialog = (this.uiDialog = $('<div/>'))
6509 .appendTo(document.body)
6510 .hide()
6511 .addClass(uiDialogClasses + options.dialogClass)
6512 .css({
6513 position: 'absolute',
6514 overflow: 'hidden',
6515 zIndex: options.zIndex
6516 })
6517 // setting tabIndex makes the div focusable
6518 // setting outline to 0 prevents a border on focus in Mozilla
6519 .attr('tabIndex', -1).css('outline', 0).keydown(function(event) {
6520 (options.closeOnEscape && event.keyCode
6521 && event.keyCode == $.ui.keyCode.ESCAPE && self.close(event));
6522 })
6523 .attr({
6524 role: 'dialog',
6525 'aria-labelledby': titleId
6526 })
6527 .mousedown(function(event) {
6528 self.moveToTop(false, event);
6529 }),
6530
6531 uiDialogContent = this.element
6532 .show()
6533 .removeAttr('title')
6534 .addClass(
6535 'ui-dialog-content ' +
6536 'ui-widget-content')
6537 .appendTo(uiDialog),
6538
6539 uiDialogTitlebar = (this.uiDialogTitlebar = $('<div></div>'))
6540 .addClass(
6541 'ui-dialog-titlebar ' +
6542 'ui-widget-header ' +
6543 'ui-corner-all ' +
6544 'ui-helper-clearfix'
6545 )
6546 .prependTo(uiDialog),
6547
6548 uiDialogTitlebarClose = $('<a href="#"/>')
6549 .addClass(
6550 'ui-dialog-titlebar-close ' +
6551 'ui-corner-all'
6552 )
6553 .attr('role', 'button')
6554 .hover(
6555 function() {
6556 uiDialogTitlebarClose.addClass('ui-state-hover');
6557 },
6558 function() {
6559 uiDialogTitlebarClose.removeClass('ui-state-hover');
6560 }
6561 )
6562 .focus(function() {
6563 uiDialogTitlebarClose.addClass('ui-state-focus');
6564 })
6565 .blur(function() {
6566 uiDialogTitlebarClose.removeClass('ui-state-focus');
6567 })
6568 .mousedown(function(ev) {
6569 ev.stopPropagation();
6570 })
6571 .click(function(event) {
6572 self.close(event);
6573 return false;
6574 })
6575 .appendTo(uiDialogTitlebar),
6576
6577 uiDialogTitlebarCloseText = (this.uiDialogTitlebarCloseText = $('<span/>'))
6578 .addClass(
6579 'ui-icon ' +
6580 'ui-icon-closethick'
6581 )
6582 .text(options.closeText)
6583 .appendTo(uiDialogTitlebarClose),
6584
6585 uiDialogTitle = $('<span/>')
6586 .addClass('ui-dialog-title')
6587 .attr('id', titleId)
6588 .html(title)
6589 .prependTo(uiDialogTitlebar);
6590
6591 uiDialogTitlebar.find("*").add(uiDialogTitlebar).disableSelection();
6592
6593 (options.draggable && $.fn.draggable && this._makeDraggable());
6594 (options.resizable && $.fn.resizable && this._makeResizable());
6595
6596 this._createButtons(options.buttons);
6597 this._isOpen = false;
6598
6599 (options.bgiframe && $.fn.bgiframe && uiDialog.bgiframe());
6600 (options.autoOpen && this.open());
6601
6602 },
6603
6604 destroy: function() {
6605 (this.overlay && this.overlay.destroy());
6606 this.uiDialog.hide();
6607 this.element
6608 .unbind('.dialog')
6609 .removeData('dialog')
6610 .removeClass('ui-dialog-content ui-widget-content')
6611 .hide().appendTo('body');
6612 this.uiDialog.remove();
6613
6614 (this.originalTitle && this.element.attr('title', this.originalTitle));
6615 },
6616
6617 close: function(event) {
6618 var self = this;
6619
6620 if (false === self._trigger('beforeclose', event)) {
6621 return;
6622 }
6623
6624 (self.overlay && self.overlay.destroy());
6625 self.uiDialog.unbind('keypress.ui-dialog');
6626
6627 (self.options.hide
6628 ? self.uiDialog.hide(self.options.hide, function() {
6629 self._trigger('close', event);
6630 })
6631 : self.uiDialog.hide() && self._trigger('close', event));
6632
6633 $.ui.dialog.overlay.resize();
6634
6635 self._isOpen = false;
6636
6637 // adjust the maxZ to allow other modal dialogs to continue to work (see #4309)
6638 if (self.options.modal) {
6639 var maxZ = 0;
6640 $('.ui-dialog').each(function() {
6641 if (this != self.uiDialog[0]) {
6642 maxZ = Math.max(maxZ, $(this).css('z-index'));
6643 }
6644 });
6645 $.ui.dialog.maxZ = maxZ;
6646 }
6647 },
6648
6649 isOpen: function() {
6650 return this._isOpen;
6651 },
6652
6653 // the force parameter allows us to move modal dialogs to their correct
6654 // position on open
6655 moveToTop: function(force, event) {
6656
6657 if ((this.options.modal && !force)
6658 || (!this.options.stack && !this.options.modal)) {
6659 return this._trigger('focus', event);
6660 }
6661
6662 if (this.options.zIndex > $.ui.dialog.maxZ) {
6663 $.ui.dialog.maxZ = this.options.zIndex;
6664 }
6665 (this.overlay && this.overlay.$el.css('z-index', $.ui.dialog.overlay.maxZ = ++$.ui.dialog.maxZ));
6666
6667 //Save and then restore scroll since Opera 9.5+ resets when parent z-Index is changed.
6668 // http://ui.jquery.com/bugs/ticket/3193
6669 var saveScroll = { scrollTop: this.element.attr('scrollTop'), scrollLeft: this.element.attr('scrollLeft') };
6670 this.uiDialog.css('z-index', ++$.ui.dialog.maxZ);
6671 this.element.attr(saveScroll);
6672 this._trigger('focus', event);
6673 },
6674
6675 open: function() {
6676 if (this._isOpen) { return; }
6677
6678 var options = this.options,
6679 uiDialog = this.uiDialog;
6680
6681 this.overlay = options.modal ? new $.ui.dialog.overlay(this) : null;
6682 (uiDialog.next().length && uiDialog.appendTo('body'));
6683 this._size();
6684 this._position(options.position);
6685 uiDialog.show(options.show);
6686 this.moveToTop(true);
6687
6688 // prevent tabbing out of modal dialogs
6689 (options.modal && uiDialog.bind('keypress.ui-dialog', function(event) {
6690 if (event.keyCode != $.ui.keyCode.TAB) {
6691 return;
6692 }
6693
6694 var tabbables = $(':tabbable', this),
6695 first = tabbables.filter(':first')[0],
6696 last = tabbables.filter(':last')[0];
6697
6698 if (event.target == last && !event.shiftKey) {
6699 setTimeout(function() {
6700 first.focus();
6701 }, 1);
6702 } else if (event.target == first && event.shiftKey) {
6703 setTimeout(function() {
6704 last.focus();
6705 }, 1);
6706 }
6707 }));
6708
6709 // set focus to the first tabbable element in the content area or the first button
6710 // if there are no tabbable elements, set focus on the dialog itself
6711 $([])
6712 .add(uiDialog.find('.ui-dialog-content :tabbable:first'))
6713 .add(uiDialog.find('.ui-dialog-buttonpane :tabbable:first'))
6714 .add(uiDialog)
6715 .filter(':first')
6716 .focus();
6717
6718 this._trigger('open');
6719 this._isOpen = true;
6720 },
6721
6722 _createButtons: function(buttons) {
6723 var self = this,
6724 hasButtons = false,
6725 uiDialogButtonPane = $('<div></div>')
6726 .addClass(
6727 'ui-dialog-buttonpane ' +
6728 'ui-widget-content ' +
6729 'ui-helper-clearfix'
6730 );
6731
6732 // if we already have a button pane, remove it
6733 this.uiDialog.find('.ui-dialog-buttonpane').remove();
6734
6735 (typeof buttons == 'object' && buttons !== null &&
6736 $.each(buttons, function() { return !(hasButtons = true); }));
6737 if (hasButtons) {
6738 $.each(buttons, function(name, fn) {
6739 $('<button type="button"></button>')
6740 .addClass(
6741 'ui-state-default ' +
6742 'ui-corner-all'
6743 )
6744 .text(name)
6745 .click(function() { fn.apply(self.element[0], arguments); })
6746 .hover(
6747 function() {
6748 $(this).addClass('ui-state-hover');
6749 },
6750 function() {
6751 $(this).removeClass('ui-state-hover');
6752 }
6753 )
6754 .focus(function() {
6755 $(this).addClass('ui-state-focus');
6756 })
6757 .blur(function() {
6758 $(this).removeClass('ui-state-focus');
6759 })
6760 .appendTo(uiDialogButtonPane);
6761 });
6762 uiDialogButtonPane.appendTo(this.uiDialog);
6763 }
6764 },
6765
6766 _makeDraggable: function() {
6767 var self = this,
6768 options = this.options,
6769 heightBeforeDrag;
6770
6771 this.uiDialog.draggable({
6772 cancel: '.ui-dialog-content',
6773 handle: '.ui-dialog-titlebar',
6774 containment: 'document',
6775 start: function() {
6776 heightBeforeDrag = options.height;
6777 $(this).height($(this).height()).addClass("ui-dialog-dragging");
6778 (options.dragStart && options.dragStart.apply(self.element[0], arguments));
6779 },
6780 drag: function() {
6781 (options.drag && options.drag.apply(self.element[0], arguments));
6782 },
6783 stop: function() {
6784 $(this).removeClass("ui-dialog-dragging").height(heightBeforeDrag);
6785 (options.dragStop && options.dragStop.apply(self.element[0], arguments));
6786 $.ui.dialog.overlay.resize();
6787 }
6788 });
6789 },
6790
6791 _makeResizable: function(handles) {
6792 handles = (handles === undefined ? this.options.resizable : handles);
6793 var self = this,
6794 options = this.options,
6795 resizeHandles = typeof handles == 'string'
6796 ? handles
6797 : 'n,e,s,w,se,sw,ne,nw';
6798
6799 this.uiDialog.resizable({
6800 cancel: '.ui-dialog-content',
6801 alsoResize: this.element,
6802 maxWidth: options.maxWidth,
6803 maxHeight: options.maxHeight,
6804 minWidth: options.minWidth,
6805 minHeight: options.minHeight,
6806 start: function() {
6807 $(this).addClass("ui-dialog-resizing");
6808 (options.resizeStart && options.resizeStart.apply(self.element[0], arguments));
6809 },
6810 resize: function() {
6811 (options.resize && options.resize.apply(self.element[0], arguments));
6812 },
6813 handles: resizeHandles,
6814 stop: function() {
6815 $(this).removeClass("ui-dialog-resizing");
6816 options.height = $(this).height();
6817 options.width = $(this).width();
6818 (options.resizeStop && options.resizeStop.apply(self.element[0], arguments));
6819 $.ui.dialog.overlay.resize();
6820 }
6821 })
6822 .find('.ui-resizable-se').addClass('ui-icon ui-icon-grip-diagonal-se');
6823 },
6824
6825 _position: function(pos) {
6826 var wnd = $(window), doc = $(document),
6827 pTop = doc.scrollTop(), pLeft = doc.scrollLeft(),
6828 minTop = pTop;
6829
6830 if ($.inArray(pos, ['center','top','right','bottom','left']) >= 0) {
6831 pos = [
6832 pos == 'right' || pos == 'left' ? pos : 'center',
6833 pos == 'top' || pos == 'bottom' ? pos : 'middle'
6834 ];
6835 }
6836 if (pos.constructor != Array) {
6837 pos = ['center', 'middle'];
6838 }
6839 if (pos[0].constructor == Number) {
6840 pLeft += pos[0];
6841 } else {
6842 switch (pos[0]) {
6843 case 'left':
6844 pLeft += 0;
6845 break;
6846 case 'right':
6847 pLeft += wnd.width() - this.uiDialog.outerWidth();
6848 break;
6849 default:
6850 case 'center':
6851 pLeft += (wnd.width() - this.uiDialog.outerWidth()) / 2;
6852 }
6853 }
6854 if (pos[1].constructor == Number) {
6855 pTop += pos[1];
6856 } else {
6857 switch (pos[1]) {
6858 case 'top':
6859 pTop += 0;
6860 break;
6861 case 'bottom':
6862 pTop += wnd.height() - this.uiDialog.outerHeight();
6863 break;
6864 default:
6865 case 'middle':
6866 pTop += (wnd.height() - this.uiDialog.outerHeight()) / 2;
6867 }
6868 }
6869
6870 // prevent the dialog from being too high (make sure the titlebar
6871 // is accessible)
6872 pTop = Math.max(pTop, minTop);
6873 this.uiDialog.css({top: pTop, left: pLeft});
6874 },
6875
6876 _setData: function(key, value){
6877 (setDataSwitch[key] && this.uiDialog.data(setDataSwitch[key], value));
6878 switch (key) {
6879 case "buttons":
6880 this._createButtons(value);
6881 break;
6882 case "closeText":
6883 this.uiDialogTitlebarCloseText.text(value);
6884 break;
6885 case "dialogClass":
6886 this.uiDialog
6887 .removeClass(this.options.dialogClass)
6888 .addClass(uiDialogClasses + value);
6889 break;
6890 case "draggable":
6891 (value
6892 ? this._makeDraggable()
6893 : this.uiDialog.draggable('destroy'));
6894 break;
6895 case "height":
6896 this.uiDialog.height(value);
6897 break;
6898 case "position":
6899 this._position(value);
6900 break;
6901 case "resizable":
6902 var uiDialog = this.uiDialog,
6903 isResizable = this.uiDialog.is(':data(resizable)');
6904
6905 // currently resizable, becoming non-resizable
6906 (isResizable && !value && uiDialog.resizable('destroy'));
6907
6908 // currently resizable, changing handles
6909 (isResizable && typeof value == 'string' &&
6910 uiDialog.resizable('option', 'handles', value));
6911
6912 // currently non-resizable, becoming resizable
6913 (isResizable || this._makeResizable(value));
6914 break;
6915 case "title":
6916 $(".ui-dialog-title", this.uiDialogTitlebar).html(value || '&nbsp;');
6917 break;
6918 case "width":
6919 this.uiDialog.width(value);
6920 break;
6921 }
6922
6923 $.widget.prototype._setData.apply(this, arguments);
6924 },
6925
6926 _size: function() {
6927 /* If the user has resized the dialog, the .ui-dialog and .ui-dialog-content
6928 * divs will both have width and height set, so we need to reset them
6929 */
6930 var options = this.options;
6931
6932 // reset content sizing
6933 this.element.css({
6934 height: 0,
6935 minHeight: 0,
6936 width: 'auto'
6937 });
6938
6939 // reset wrapper sizing
6940 // determine the height of all the non-content elements
6941 var nonContentHeight = this.uiDialog.css({
6942 height: 'auto',
6943 width: options.width
6944 })
6945 .height();
6946
6947 this.element
6948 .css({
6949 minHeight: Math.max(options.minHeight - nonContentHeight, 0),
6950 height: options.height == 'auto'
6951 ? 'auto'
6952 : Math.max(options.height - nonContentHeight, 0)
6953 });
6954 }
6955 });
6956
6957 $.extend($.ui.dialog, {
6958 version: "1.7.2",
6959 defaults: {
6960 autoOpen: true,
6961 bgiframe: false,
6962 buttons: {},
6963 closeOnEscape: true,
6964 closeText: 'close',
6965 dialogClass: '',
6966 draggable: true,
6967 hide: null,
6968 height: 'auto',
6969 maxHeight: false,
6970 maxWidth: false,
6971 minHeight: 150,
6972 minWidth: 150,
6973 modal: false,
6974 position: 'center',
6975 resizable: true,
6976 show: null,
6977 stack: true,
6978 title: '',
6979 width: 300,
6980 zIndex: 1000
6981 },
6982
6983 getter: 'isOpen',
6984
6985 uuid: 0,
6986 maxZ: 0,
6987
6988 getTitleId: function($el) {
6989 return 'ui-dialog-title-' + ($el.attr('id') || ++this.uuid);
6990 },
6991
6992 overlay: function(dialog) {
6993 this.$el = $.ui.dialog.overlay.create(dialog);
6994 }
6995 });
6996
6997 $.extend($.ui.dialog.overlay, {
6998 instances: [],
6999 maxZ: 0,
7000 events: $.map('focus,mousedown,mouseup,keydown,keypress,click'.split(','),
7001 function(event) { return event + '.dialog-overlay'; }).join(' '),
7002 create: function(dialog) {
7003 if (this.instances.length === 0) {
7004 // prevent use of anchors and inputs
7005 // we use a setTimeout in case the overlay is created from an
7006 // event that we're going to be cancelling (see #2804)
7007 setTimeout(function() {
7008 // handle $(el).dialog().dialog('close') (see #4065)
7009 if ($.ui.dialog.overlay.instances.length) {
7010 $(document).bind($.ui.dialog.overlay.events, function(event) {
7011 var dialogZ = $(event.target).parents('.ui-dialog').css('zIndex') || 0;
7012 return (dialogZ > $.ui.dialog.overlay.maxZ);
7013 });
7014 }
7015 }, 1);
7016
7017 // allow closing by pressing the escape key
7018 $(document).bind('keydown.dialog-overlay', function(event) {
7019 (dialog.options.closeOnEscape && event.keyCode
7020 && event.keyCode == $.ui.keyCode.ESCAPE && dialog.close(event));
7021 });
7022
7023 // handle window resize
7024 $(window).bind('resize.dialog-overlay', $.ui.dialog.overlay.resize);
7025 }
7026
7027 var $el = $('<div></div>').appendTo(document.body)
7028 .addClass('ui-widget-overlay').css({
7029 width: this.width(),
7030 height: this.height()
7031 });
7032
7033 (dialog.options.bgiframe && $.fn.bgiframe && $el.bgiframe());
7034
7035 this.instances.push($el);
7036 return $el;
7037 },
7038
7039 destroy: function($el) {
7040 this.instances.splice($.inArray(this.instances, $el), 1);
7041
7042 if (this.instances.length === 0) {
7043 $([document, window]).unbind('.dialog-overlay');
7044 }
7045
7046 $el.remove();
7047
7048 // adjust the maxZ to allow other modal dialogs to continue to work (see #4309)
7049 var maxZ = 0;
7050 $.each(this.instances, function() {
7051 maxZ = Math.max(maxZ, this.css('z-index'));
7052 });
7053 this.maxZ = maxZ;
7054 },
7055
7056 height: function() {
7057 // handle IE 6
7058 if ($.browser.msie && $.browser.version < 7) {
7059 var scrollHeight = Math.max(
7060 document.documentElement.scrollHeight,
7061 document.body.scrollHeight
7062 );
7063 var offsetHeight = Math.max(
7064 document.documentElement.offsetHeight,
7065 document.body.offsetHeight
7066 );
7067
7068 if (scrollHeight < offsetHeight) {
7069 return $(window).height() + 'px';
7070 } else {
7071 return scrollHeight + 'px';
7072 }
7073 // handle "good" browsers
7074 } else {
7075 return $(document).height() + 'px';
7076 }
7077 },
7078
7079 width: function() {
7080 // handle IE 6
7081 if ($.browser.msie && $.browser.version < 7) {
7082 var scrollWidth = Math.max(
7083 document.documentElement.scrollWidth,
7084 document.body.scrollWidth
7085 );
7086 var offsetWidth = Math.max(
7087 document.documentElement.offsetWidth,
7088 document.body.offsetWidth
7089 );
7090
7091 if (scrollWidth < offsetWidth) {
7092 return $(window).width() + 'px';
7093 } else {
7094 return scrollWidth + 'px';
7095 }
7096 // handle "good" browsers
7097 } else {
7098 return $(document).width() + 'px';
7099 }
7100 },
7101
7102 resize: function() {
7103 /* If the dialog is draggable and the user drags it past the
7104 * right edge of the window, the document becomes wider so we
7105 * need to stretch the overlay. If the user then drags the
7106 * dialog back to the left, the document will become narrower,
7107 * so we need to shrink the overlay to the appropriate size.
7108 * This is handled by shrinking the overlay before setting it
7109 * to the full document size.
7110 */
7111 var $overlays = $([]);
7112 $.each($.ui.dialog.overlay.instances, function() {
7113 $overlays = $overlays.add(this);
7114 });
7115
7116 $overlays.css({
7117 width: 0,
7118 height: 0
7119 }).css({
7120 width: $.ui.dialog.overlay.width(),
7121 height: $.ui.dialog.overlay.height()
7122 });
7123 }
7124 });
7125
7126 $.extend($.ui.dialog.overlay.prototype, {
7127 destroy: function() {
7128 $.ui.dialog.overlay.destroy(this.$el);
7129 }
7130 });
7131
7132 })(jQuery);
7133 /*
7134 * jQuery UI Tabs 1.7.2
7135 *
7136 * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
7137 * Dual licensed under the MIT (MIT-LICENSE.txt)
7138 * and GPL (GPL-LICENSE.txt) licenses.
7139 *
7140 * http://docs.jquery.com/UI/Tabs
7141 *
7142 * Depends:
7143 * ui.core.js
7144 */
7145 (function($) {
7146
7147 $.widget("ui.tabs", {
7148
7149 _init: function() {
7150 if (this.options.deselectable !== undefined) {
7151 this.options.collapsible = this.options.deselectable;
7152 }
7153 this._tabify(true);
7154 },
7155
7156 _setData: function(key, value) {
7157 if (key == 'selected') {
7158 if (this.options.collapsible && value == this.options.selected) {
7159 return;
7160 }
7161 this.select(value);
7162 }
7163 else {
7164 this.options[key] = value;
7165 if (key == 'deselectable') {
7166 this.options.collapsible = value;
7167 }
7168 this._tabify();
7169 }
7170 },
7171
7172 _tabId: function(a) {
7173 return a.title && a.title.replace(/\s/g, '_').replace(/[^A-Za-z0-9\-_:\.]/g, '') ||
7174 this.options.idPrefix + $.data(a);
7175 },
7176
7177 _sanitizeSelector: function(hash) {
7178 return hash.replace(/:/g, '\\:'); // we need this because an id may contain a ":"
7179 },
7180
7181 _cookie: function() {
7182 var cookie = this.cookie || (this.cookie = this.options.cookie.name || 'ui-tabs-' + $.data(this.list[0]));
7183 return $.cookie.apply(null, [cookie].concat($.makeArray(arguments)));
7184 },
7185
7186 _ui: function(tab, panel) {
7187 return {
7188 tab: tab,
7189 panel: panel,
7190 index: this.anchors.index(tab)
7191 };
7192 },
7193
7194 _cleanup: function() {
7195 // restore all former loading tabs labels
7196 this.lis.filter('.ui-state-processing').removeClass('ui-state-processing')
7197 .find('span:data(label.tabs)')
7198 .each(function() {
7199 var el = $(this);
7200 el.html(el.data('label.tabs')).removeData('label.tabs');
7201 });
7202 },
7203
7204 _tabify: function(init) {
7205
7206 this.list = this.element.children('ul:first');
7207 this.lis = $('li:has(a[href])', this.list);
7208 this.anchors = this.lis.map(function() { return $('a', this)[0]; });
7209 this.panels = $([]);
7210
7211 var self = this, o = this.options;
7212
7213 var fragmentId = /^#.+/; // Safari 2 reports '#' for an empty hash
7214 this.anchors.each(function(i, a) {
7215 var href = $(a).attr('href');
7216
7217 // For dynamically created HTML that contains a hash as href IE < 8 expands
7218 // such href to the full page url with hash and then misinterprets tab as ajax.
7219 // Same consideration applies for an added tab with a fragment identifier
7220 // since a[href=#fragment-identifier] does unexpectedly not match.
7221 // Thus normalize href attribute...
7222 var hrefBase = href.split('#')[0], baseEl;
7223 if (hrefBase && (hrefBase === location.toString().split('#')[0] ||
7224 (baseEl = $('base')[0]) && hrefBase === baseEl.href)) {
7225 href = a.hash;
7226 a.href = href;
7227 }
7228
7229 // inline tab
7230 if (fragmentId.test(href)) {
7231 self.panels = self.panels.add(self._sanitizeSelector(href));
7232 }
7233
7234 // remote tab
7235 else if (href != '#') { // prevent loading the page itself if href is just "#"
7236 $.data(a, 'href.tabs', href); // required for restore on destroy
7237
7238 // TODO until #3808 is fixed strip fragment identifier from url
7239 // (IE fails to load from such url)
7240 $.data(a, 'load.tabs', href.replace(/#.*$/, '')); // mutable data
7241
7242 var id = self._tabId(a);
7243 a.href = '#' + id;
7244 var $panel = $('#' + id);
7245 if (!$panel.length) {
7246 $panel = $(o.panelTemplate).attr('id', id).addClass('ui-tabs-panel ui-widget-content ui-corner-bottom')
7247 .insertAfter(self.panels[i - 1] || self.list);
7248 $panel.data('destroy.tabs', true);
7249 }
7250 self.panels = self.panels.add($panel);
7251 }
7252
7253 // invalid tab href
7254 else {
7255 o.disabled.push(i);
7256 }
7257 });
7258
7259 // initialization from scratch
7260 if (init) {
7261
7262 // attach necessary classes for styling
7263 this.element.addClass('ui-tabs ui-widget ui-widget-content ui-corner-all');
7264 this.list.addClass('ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all');
7265 this.lis.addClass('ui-state-default ui-corner-top');
7266 this.panels.addClass('ui-tabs-panel ui-widget-content ui-corner-bottom');
7267
7268 // Selected tab
7269 // use "selected" option or try to retrieve:
7270 // 1. from fragment identifier in url
7271 // 2. from cookie
7272 // 3. from selected class attribute on <li>
7273 if (o.selected === undefined) {
7274 if (location.hash) {
7275 this.anchors.each(function(i, a) {
7276 if (a.hash == location.hash) {
7277 o.selected = i;
7278 return false; // break
7279 }
7280 });
7281 }
7282 if (typeof o.selected != 'number' && o.cookie) {
7283 o.selected = parseInt(self._cookie(), 10);
7284 }
7285 if (typeof o.selected != 'number' && this.lis.filter('.ui-tabs-selected').length) {
7286 o.selected = this.lis.index(this.lis.filter('.ui-tabs-selected'));
7287 }
7288 o.selected = o.selected || 0;
7289 }
7290 else if (o.selected === null) { // usage of null is deprecated, TODO remove in next release
7291 o.selected = -1;
7292 }
7293
7294 // sanity check - default to first tab...
7295 o.selected = ((o.selected >= 0 && this.anchors[o.selected]) || o.selected < 0) ? o.selected : 0;
7296
7297 // Take disabling tabs via class attribute from HTML
7298 // into account and update option properly.
7299 // A selected tab cannot become disabled.
7300 o.disabled = $.unique(o.disabled.concat(
7301 $.map(this.lis.filter('.ui-state-disabled'),
7302 function(n, i) { return self.lis.index(n); } )
7303 )).sort();
7304
7305 if ($.inArray(o.selected, o.disabled) != -1) {
7306 o.disabled.splice($.inArray(o.selected, o.disabled), 1);
7307 }
7308
7309 // highlight selected tab
7310 this.panels.addClass('ui-tabs-hide');
7311 this.lis.removeClass('ui-tabs-selected ui-state-active');
7312 if (o.selected >= 0 && this.anchors.length) { // check for length avoids error when initializing empty list
7313 this.panels.eq(o.selected).removeClass('ui-tabs-hide');
7314 this.lis.eq(o.selected).addClass('ui-tabs-selected ui-state-active');
7315
7316 // seems to be expected behavior that the show callback is fired
7317 self.element.queue("tabs", function() {
7318 self._trigger('show', null, self._ui(self.anchors[o.selected], self.panels[o.selected]));
7319 });
7320
7321 this.load(o.selected);
7322 }
7323
7324 // clean up to avoid memory leaks in certain versions of IE 6
7325 $(window).bind('unload', function() {
7326 self.lis.add(self.anchors).unbind('.tabs');
7327 self.lis = self.anchors = self.panels = null;
7328 });
7329
7330 }
7331 // update selected after add/remove
7332 else {
7333 o.selected = this.lis.index(this.lis.filter('.ui-tabs-selected'));
7334 }
7335
7336 // update collapsible
7337 this.element[o.collapsible ? 'addClass' : 'removeClass']('ui-tabs-collapsible');
7338
7339 // set or update cookie after init and add/remove respectively
7340 if (o.cookie) {
7341 this._cookie(o.selected, o.cookie);
7342 }
7343
7344 // disable tabs
7345 for (var i = 0, li; (li = this.lis[i]); i++) {
7346 $(li)[$.inArray(i, o.disabled) != -1 &&
7347 !$(li).hasClass('ui-tabs-selected') ? 'addClass' : 'removeClass']('ui-state-disabled');
7348 }
7349
7350 // reset cache if switching from cached to not cached
7351 if (o.cache === false) {
7352 this.anchors.removeData('cache.tabs');
7353 }
7354
7355 // remove all handlers before, tabify may run on existing tabs after add or option change
7356 this.lis.add(this.anchors).unbind('.tabs');
7357
7358 if (o.event != 'mouseover') {
7359 var addState = function(state, el) {
7360 if (el.is(':not(.ui-state-disabled)')) {
7361 el.addClass('ui-state-' + state);
7362 }
7363 };
7364 var removeState = function(state, el) {
7365 el.removeClass('ui-state-' + state);
7366 };
7367 this.lis.bind('mouseover.tabs', function() {
7368 addState('hover', $(this));
7369 });
7370 this.lis.bind('mouseout.tabs', function() {
7371 removeState('hover', $(this));
7372 });
7373 this.anchors.bind('focus.tabs', function() {
7374 addState('focus', $(this).closest('li'));
7375 });
7376 this.anchors.bind('blur.tabs', function() {
7377 removeState('focus', $(this).closest('li'));
7378 });
7379 }
7380
7381 // set up animations
7382 var hideFx, showFx;
7383 if (o.fx) {
7384 if ($.isArray(o.fx)) {
7385 hideFx = o.fx[0];
7386 showFx = o.fx[1];
7387 }
7388 else {
7389 hideFx = showFx = o.fx;
7390 }
7391 }
7392
7393 // Reset certain styles left over from animation
7394 // and prevent IE's ClearType bug...
7395 function resetStyle($el, fx) {
7396 $el.css({ display: '' });
7397 if ($.browser.msie && fx.opacity) {
7398 $el[0].style.removeAttribute('filter');
7399 }
7400 }
7401
7402 // Show a tab...
7403 var showTab = showFx ?
7404 function(clicked, $show) {
7405 $(clicked).closest('li').removeClass('ui-state-default').addClass('ui-tabs-selected ui-state-active');
7406 $show.hide().removeClass('ui-tabs-hide') // avoid flicker that way
7407 .animate(showFx, showFx.duration || 'normal', function() {
7408 resetStyle($show, showFx);
7409 self._trigger('show', null, self._ui(clicked, $show[0]));
7410 });
7411 } :
7412 function(clicked, $show) {
7413 $(clicked).closest('li').removeClass('ui-state-default').addClass('ui-tabs-selected ui-state-active');
7414 $show.removeClass('ui-tabs-hide');
7415 self._trigger('show', null, self._ui(clicked, $show[0]));
7416 };
7417
7418 // Hide a tab, $show is optional...
7419 var hideTab = hideFx ?
7420 function(clicked, $hide) {
7421 $hide.animate(hideFx, hideFx.duration || 'normal', function() {
7422 self.lis.removeClass('ui-tabs-selected ui-state-active').addClass('ui-state-default');
7423 $hide.addClass('ui-tabs-hide');
7424 resetStyle($hide, hideFx);
7425 self.element.dequeue("tabs");
7426 });
7427 } :
7428 function(clicked, $hide, $show) {
7429 self.lis.removeClass('ui-tabs-selected ui-state-active').addClass('ui-state-default');
7430 $hide.addClass('ui-tabs-hide');
7431 self.element.dequeue("tabs");
7432 };
7433
7434 // attach tab event handler, unbind to avoid duplicates from former tabifying...
7435 this.anchors.bind(o.event + '.tabs', function() {
7436 var el = this, $li = $(this).closest('li'), $hide = self.panels.filter(':not(.ui-tabs-hide)'),
7437 $show = $(self._sanitizeSelector(this.hash));
7438
7439 // If tab is already selected and not collapsible or tab disabled or
7440 // or is already loading or click callback returns false stop here.
7441 // Check if click handler returns false last so that it is not executed
7442 // for a disabled or loading tab!
7443 if (($li.hasClass('ui-tabs-selected') && !o.collapsible) ||
7444 $li.hasClass('ui-state-disabled') ||
7445 $li.hasClass('ui-state-processing') ||
7446 self._trigger('select', null, self._ui(this, $show[0])) === false) {
7447 this.blur();
7448 return false;
7449 }
7450
7451 o.selected = self.anchors.index(this);
7452
7453 self.abort();
7454
7455 // if tab may be closed
7456 if (o.collapsible) {
7457 if ($li.hasClass('ui-tabs-selected')) {
7458 o.selected = -1;
7459
7460 if (o.cookie) {
7461 self._cookie(o.selected, o.cookie);
7462 }
7463
7464 self.element.queue("tabs", function() {
7465 hideTab(el, $hide);
7466 }).dequeue("tabs");
7467
7468 this.blur();
7469 return false;
7470 }
7471 else if (!$hide.length) {
7472 if (o.cookie) {
7473 self._cookie(o.selected, o.cookie);
7474 }
7475
7476 self.element.queue("tabs", function() {
7477 showTab(el, $show);
7478 });
7479
7480 self.load(self.anchors.index(this)); // TODO make passing in node possible, see also http://dev.jqueryui.com/ticket/3171
7481
7482 this.blur();
7483 return false;
7484 }
7485 }
7486
7487 if (o.cookie) {
7488 self._cookie(o.selected, o.cookie);
7489 }
7490
7491 // show new tab
7492 if ($show.length) {
7493 if ($hide.length) {
7494 self.element.queue("tabs", function() {
7495 hideTab(el, $hide);
7496 });
7497 }
7498 self.element.queue("tabs", function() {
7499 showTab(el, $show);
7500 });
7501
7502 self.load(self.anchors.index(this));
7503 }
7504 else {
7505 throw 'jQuery UI Tabs: Mismatching fragment identifier.';
7506 }
7507
7508 // Prevent IE from keeping other link focussed when using the back button
7509 // and remove dotted border from clicked link. This is controlled via CSS
7510 // in modern browsers; blur() removes focus from address bar in Firefox
7511 // which can become a usability and annoying problem with tabs('rotate').
7512 if ($.browser.msie) {
7513 this.blur();
7514 }
7515
7516 });
7517
7518 // disable click in any case
7519 this.anchors.bind('click.tabs', function(){return false;});
7520
7521 },
7522
7523 destroy: function() {
7524 var o = this.options;
7525
7526 this.abort();
7527
7528 this.element.unbind('.tabs')
7529 .removeClass('ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible')
7530 .removeData('tabs');
7531
7532 this.list.removeClass('ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all');
7533
7534 this.anchors.each(function() {
7535 var href = $.data(this, 'href.tabs');
7536 if (href) {
7537 this.href = href;
7538 }
7539 var $this = $(this).unbind('.tabs');
7540 $.each(['href', 'load', 'cache'], function(i, prefix) {
7541 $this.removeData(prefix + '.tabs');
7542 });
7543 });
7544
7545 this.lis.unbind('.tabs').add(this.panels).each(function() {
7546 if ($.data(this, 'destroy.tabs')) {
7547 $(this).remove();
7548 }
7549 else {
7550 $(this).removeClass([
7551 'ui-state-default',
7552 'ui-corner-top',
7553 'ui-tabs-selected',
7554 'ui-state-active',
7555 'ui-state-hover',
7556 'ui-state-focus',
7557 'ui-state-disabled',
7558 'ui-tabs-panel',
7559 'ui-widget-content',
7560 'ui-corner-bottom',
7561 'ui-tabs-hide'
7562 ].join(' '));
7563 }
7564 });
7565
7566 if (o.cookie) {
7567 this._cookie(null, o.cookie);
7568 }
7569 },
7570
7571 add: function(url, label, index) {
7572 if (index === undefined) {
7573 index = this.anchors.length; // append by default
7574 }
7575
7576 var self = this, o = this.options,
7577 $li = $(o.tabTemplate.replace(/#\{href\}/g, url).replace(/#\{label\}/g, label)),
7578 id = !url.indexOf('#') ? url.replace('#', '') : this._tabId($('a', $li)[0]);
7579
7580 $li.addClass('ui-state-default ui-corner-top').data('destroy.tabs', true);
7581
7582 // try to find an existing element before creating a new one
7583 var $panel = $('#' + id);
7584 if (!$panel.length) {
7585 $panel = $(o.panelTemplate).attr('id', id).data('destroy.tabs', true);
7586 }
7587 $panel.addClass('ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide');
7588
7589 if (index >= this.lis.length) {
7590 $li.appendTo(this.list);
7591 $panel.appendTo(this.list[0].parentNode);
7592 }
7593 else {
7594 $li.insertBefore(this.lis[index]);
7595 $panel.insertBefore(this.panels[index]);
7596 }
7597
7598 o.disabled = $.map(o.disabled,
7599 function(n, i) { return n >= index ? ++n : n; });
7600
7601 this._tabify();
7602
7603 if (this.anchors.length == 1) { // after tabify
7604 $li.addClass('ui-tabs-selected ui-state-active');
7605 $panel.removeClass('ui-tabs-hide');
7606 this.element.queue("tabs", function() {
7607 self._trigger('show', null, self._ui(self.anchors[0], self.panels[0]));
7608 });
7609
7610 this.load(0);
7611 }
7612
7613 // callback
7614 this._trigger('add', null, this._ui(this.anchors[index], this.panels[index]));
7615 },
7616
7617 remove: function(index) {
7618 var o = this.options, $li = this.lis.eq(index).remove(),
7619 $panel = this.panels.eq(index).remove();
7620
7621 // If selected tab was removed focus tab to the right or
7622 // in case the last tab was removed the tab to the left.
7623 if ($li.hasClass('ui-tabs-selected') && this.anchors.length > 1) {
7624 this.select(index + (index + 1 < this.anchors.length ? 1 : -1));
7625 }
7626
7627 o.disabled = $.map($.grep(o.disabled, function(n, i) { return n != index; }),
7628 function(n, i) { return n >= index ? --n : n; });
7629
7630 this._tabify();
7631
7632 // callback
7633 this._trigger('remove', null, this._ui($li.find('a')[0], $panel[0]));
7634 },
7635
7636 enable: function(index) {
7637 var o = this.options;
7638 if ($.inArray(index, o.disabled) == -1) {
7639 return;
7640 }
7641
7642 this.lis.eq(index).removeClass('ui-state-disabled');
7643 o.disabled = $.grep(o.disabled, function(n, i) { return n != index; });
7644
7645 // callback
7646 this._trigger('enable', null, this._ui(this.anchors[index], this.panels[index]));
7647 },
7648
7649 disable: function(index) {
7650 var self = this, o = this.options;
7651 if (index != o.selected) { // cannot disable already selected tab
7652 this.lis.eq(index).addClass('ui-state-disabled');
7653
7654 o.disabled.push(index);
7655 o.disabled.sort();
7656
7657 // callback
7658 this._trigger('disable', null, this._ui(this.anchors[index], this.panels[index]));
7659 }
7660 },
7661
7662 select: function(index) {
7663 if (typeof index == 'string') {
7664 index = this.anchors.index(this.anchors.filter('[href$=' + index + ']'));
7665 }
7666 else if (index === null) { // usage of null is deprecated, TODO remove in next release
7667 index = -1;
7668 }
7669 if (index == -1 && this.options.collapsible) {
7670 index = this.options.selected;
7671 }
7672
7673 this.anchors.eq(index).trigger(this.options.event + '.tabs');
7674 },
7675
7676 load: function(index) {
7677 var self = this, o = this.options, a = this.anchors.eq(index)[0], url = $.data(a, 'load.tabs');
7678
7679 this.abort();
7680
7681 // not remote or from cache
7682 if (!url || this.element.queue("tabs").length !== 0 && $.data(a, 'cache.tabs')) {
7683 this.element.dequeue("tabs");
7684 return;
7685 }
7686
7687 // load remote from here on
7688 this.lis.eq(index).addClass('ui-state-processing');
7689
7690 if (o.spinner) {
7691 var span = $('span', a);
7692 span.data('label.tabs', span.html()).html(o.spinner);
7693 }
7694
7695 this.xhr = $.ajax($.extend({}, o.ajaxOptions, {
7696 url: url,
7697 success: function(r, s) {
7698 $(self._sanitizeSelector(a.hash)).html(r);
7699
7700 // take care of tab labels
7701 self._cleanup();
7702
7703 if (o.cache) {
7704 $.data(a, 'cache.tabs', true); // if loaded once do not load them again
7705 }
7706
7707 // callbacks
7708 self._trigger('load', null, self._ui(self.anchors[index], self.panels[index]));
7709 try {
7710 o.ajaxOptions.success(r, s);
7711 }
7712 catch (e) {}
7713
7714 // last, so that load event is fired before show...
7715 self.element.dequeue("tabs");
7716 }
7717 }));
7718 },
7719
7720 abort: function() {
7721 // stop possibly running animations
7722 this.element.queue([]);
7723 this.panels.stop(false, true);
7724
7725 // terminate pending requests from other tabs
7726 if (this.xhr) {
7727 this.xhr.abort();
7728 delete this.xhr;
7729 }
7730
7731 // take care of tab labels
7732 this._cleanup();
7733
7734 },
7735
7736 url: function(index, url) {
7737 this.anchors.eq(index).removeData('cache.tabs').data('load.tabs', url);
7738 },
7739
7740 length: function() {
7741 return this.anchors.length;
7742 }
7743
7744 });
7745
7746 $.extend($.ui.tabs, {
7747 version: '1.7.2',
7748 getter: 'length',
7749 defaults: {
7750 ajaxOptions: null,
7751 cache: false,
7752 cookie: null, // e.g. { expires: 7, path: '/', domain: 'jquery.com', secure: true }
7753 collapsible: false,
7754 disabled: [],
7755 event: 'click',
7756 fx: null, // e.g. { height: 'toggle', opacity: 'toggle', duration: 200 }
7757 idPrefix: 'ui-tabs-',
7758 panelTemplate: '<div></div>',
7759 spinner: '<em>Loading&#8230;</em>',
7760 tabTemplate: '<li><a href="#{href}"><span>#{label}</span></a></li>'
7761 }
7762 });
7763
7764 /*
7765 * Tabs Extensions
7766 */
7767
7768 /*
7769 * Rotate
7770 */
7771 $.extend($.ui.tabs.prototype, {
7772 rotation: null,
7773 rotate: function(ms, continuing) {
7774
7775 var self = this, o = this.options;
7776
7777 var rotate = self._rotate || (self._rotate = function(e) {
7778 clearTimeout(self.rotation);
7779 self.rotation = setTimeout(function() {
7780 var t = o.selected;
7781 self.select( ++t < self.anchors.length ? t : 0 );
7782 }, ms);
7783
7784 if (e) {
7785 e.stopPropagation();
7786 }
7787 });
7788
7789 var stop = self._unrotate || (self._unrotate = !continuing ?
7790 function(e) {
7791 if (e.clientX) { // in case of a true click
7792 self.rotate(null);
7793 }
7794 } :
7795 function(e) {
7796 t = o.selected;
7797 rotate();
7798 });
7799
7800 // start rotation
7801 if (ms) {
7802 this.element.bind('tabsshow', rotate);
7803 this.anchors.bind(o.event + '.tabs', stop);
7804 rotate();
7805 }
7806 // stop rotation
7807 else {
7808 clearTimeout(self.rotation);
7809 this.element.unbind('tabsshow', rotate);
7810 this.anchors.unbind(o.event + '.tabs', stop);
7811 delete this._rotate;
7812 delete this._unrotate;
7813 }
7814 }
7815 });
7816
7817 })(jQuery);
7818 /*
7819 * jQuery UI Datepicker 1.7.2
7820 *
7821 * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
7822 * Dual licensed under the MIT (MIT-LICENSE.txt)
7823 * and GPL (GPL-LICENSE.txt) licenses.
7824 *
7825 * http://docs.jquery.com/UI/Datepicker
7826 *
7827 * Depends:
7828 * ui.core.js
7829 */
7830
7831 (function($) { // hide the namespace
7832
7833 $.extend($.ui, { datepicker: { version: "1.7.2" } });
7834
7835 var PROP_NAME = 'datepicker';
7836
7837 /* Date picker manager.
7838 Use the singleton instance of this class, $.datepicker, to interact with the date picker.
7839 Settings for (groups of) date pickers are maintained in an instance object,
7840 allowing multiple different settings on the same page. */
7841
7842 function Datepicker() {
7843 this.debug = false; // Change this to true to start debugging
7844 this._curInst = null; // The current instance in use
7845 this._keyEvent = false; // If the last event was a key event
7846 this._disabledInputs = []; // List of date picker inputs that have been disabled
7847 this._datepickerShowing = false; // True if the popup picker is showing , false if not
7848 this._inDialog = false; // True if showing within a "dialog", false if not
7849 this._mainDivId = 'ui-datepicker-div'; // The ID of the main datepicker division
7850 this._inlineClass = 'ui-datepicker-inline'; // The name of the inline marker class
7851 this._appendClass = 'ui-datepicker-append'; // The name of the append marker class
7852 this._triggerClass = 'ui-datepicker-trigger'; // The name of the trigger marker class
7853 this._dialogClass = 'ui-datepicker-dialog'; // The name of the dialog marker class
7854 this._disableClass = 'ui-datepicker-disabled'; // The name of the disabled covering marker class
7855 this._unselectableClass = 'ui-datepicker-unselectable'; // The name of the unselectable cell marker class
7856 this._currentClass = 'ui-datepicker-current-day'; // The name of the current day marker class
7857 this._dayOverClass = 'ui-datepicker-days-cell-over'; // The name of the day hover marker class
7858 this.regional = []; // Available regional settings, indexed by language code
7859 this.regional[''] = { // Default regional settings
7860 closeText: 'Done', // Display text for close link
7861 prevText: 'Prev', // Display text for previous month link
7862 nextText: 'Next', // Display text for next month link
7863 currentText: 'Today', // Display text for current month link
7864 monthNames: ['January','February','March','April','May','June',
7865 'July','August','September','October','November','December'], // Names of months for drop-down and formatting
7866 monthNamesShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], // For formatting
7867 dayNames: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], // For formatting
7868 dayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], // For formatting
7869 dayNamesMin: ['Su','Mo','Tu','We','Th','Fr','Sa'], // Column headings for days starting at Sunday
7870 dateFormat: 'mm/dd/yy', // See format options on parseDate
7871 firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ...
7872 isRTL: false // True if right-to-left language, false if left-to-right
7873 };
7874 this._defaults = { // Global defaults for all the date picker instances
7875 showOn: 'focus', // 'focus' for popup on focus,
7876 // 'button' for trigger button, or 'both' for either
7877 showAnim: 'show', // Name of jQuery animation for popup
7878 showOptions: {}, // Options for enhanced animations
7879 defaultDate: null, // Used when field is blank: actual date,
7880 // +/-number for offset from today, null for today
7881 appendText: '', // Display text following the input box, e.g. showing the format
7882 buttonText: '...', // Text for trigger button
7883 buttonImage: '', // URL for trigger button image
7884 buttonImageOnly: false, // True if the image appears alone, false if it appears on a button
7885 hideIfNoPrevNext: false, // True to hide next/previous month links
7886 // if not applicable, false to just disable them
7887 navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links
7888 gotoCurrent: false, // True if today link goes back to current selection instead
7889 changeMonth: false, // True if month can be selected directly, false if only prev/next
7890 changeYear: false, // True if year can be selected directly, false if only prev/next
7891 showMonthAfterYear: false, // True if the year select precedes month, false for month then year
7892 yearRange: '-10:+10', // Range of years to display in drop-down,
7893 // either relative to current year (-nn:+nn) or absolute (nnnn:nnnn)
7894 showOtherMonths: false, // True to show dates in other months, false to leave blank
7895 calculateWeek: this.iso8601Week, // How to calculate the week of the year,
7896 // takes a Date and returns the number of the week for it
7897 shortYearCutoff: '+10', // Short year values < this are in the current century,
7898 // > this are in the previous century,
7899 // string value starting with '+' for current year + value
7900 minDate: null, // The earliest selectable date, or null for no limit
7901 maxDate: null, // The latest selectable date, or null for no limit
7902 duration: 'normal', // Duration of display/closure
7903 beforeShowDay: null, // Function that takes a date and returns an array with
7904 // [0] = true if selectable, false if not, [1] = custom CSS class name(s) or '',
7905 // [2] = cell title (optional), e.g. $.datepicker.noWeekends
7906 beforeShow: null, // Function that takes an input field and
7907 // returns a set of custom settings for the date picker
7908 onSelect: null, // Define a callback function when a date is selected
7909 onChangeMonthYear: null, // Define a callback function when the month or year is changed
7910 onClose: null, // Define a callback function when the datepicker is closed
7911 numberOfMonths: 1, // Number of months to show at a time
7912 showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0)
7913 stepMonths: 1, // Number of months to step back/forward
7914 stepBigMonths: 12, // Number of months to step back/forward for the big links
7915 altField: '', // Selector for an alternate field to store selected dates into
7916 altFormat: '', // The date format to use for the alternate field
7917 constrainInput: true, // The input is constrained by the current date format
7918 showButtonPanel: false // True to show button panel, false to not show it
7919 };
7920 $.extend(this._defaults, this.regional['']);
7921 this.dpDiv = $('<div id="' + this._mainDivId + '" class="ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all ui-helper-hidden-accessible"></div>');
7922 }
7923
7924 $.extend(Datepicker.prototype, {
7925 /* Class name added to elements to indicate already configured with a date picker. */
7926 markerClassName: 'hasDatepicker',
7927
7928 /* Debug logging (if enabled). */
7929 log: function () {
7930 if (this.debug)
7931 console.log.apply('', arguments);
7932 },
7933
7934 /* Override the default settings for all instances of the date picker.
7935 @param settings object - the new settings to use as defaults (anonymous object)
7936 @return the manager object */
7937 setDefaults: function(settings) {
7938 extendRemove(this._defaults, settings || {});
7939 return this;
7940 },
7941
7942 /* Attach the date picker to a jQuery selection.
7943 @param target element - the target input field or division or span
7944 @param settings object - the new settings to use for this date picker instance (anonymous) */
7945 _attachDatepicker: function(target, settings) {
7946 // check for settings on the control itself - in namespace 'date:'
7947 var inlineSettings = null;
7948 for (var attrName in this._defaults) {
7949 var attrValue = target.getAttribute('date:' + attrName);
7950 if (attrValue) {
7951 inlineSettings = inlineSettings || {};
7952 try {
7953 inlineSettings[attrName] = eval(attrValue);
7954 } catch (err) {
7955 inlineSettings[attrName] = attrValue;
7956 }
7957 }
7958 }
7959 var nodeName = target.nodeName.toLowerCase();
7960 var inline = (nodeName == 'div' || nodeName == 'span');
7961 if (!target.id)
7962 target.id = 'dp' + (++this.uuid);
7963 var inst = this._newInst($(target), inline);
7964 inst.settings = $.extend({}, settings || {}, inlineSettings || {});
7965 if (nodeName == 'input') {
7966 this._connectDatepicker(target, inst);
7967 } else if (inline) {
7968 this._inlineDatepicker(target, inst);
7969 }
7970 },
7971
7972 /* Create a new instance object. */
7973 _newInst: function(target, inline) {
7974 var id = target[0].id.replace(/([:\[\]\.])/g, '\\\\$1'); // escape jQuery meta chars
7975 return {id: id, input: target, // associated target
7976 selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection
7977 drawMonth: 0, drawYear: 0, // month being drawn
7978 inline: inline, // is datepicker inline or not
7979 dpDiv: (!inline ? this.dpDiv : // presentation div
7980 $('<div class="' + this._inlineClass + ' ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>'))};
7981 },
7982
7983 /* Attach the date picker to an input field. */
7984 _connectDatepicker: function(target, inst) {
7985 var input = $(target);
7986 inst.append = $([]);
7987 inst.trigger = $([]);
7988 if (input.hasClass(this.markerClassName))
7989 return;
7990 var appendText = this._get(inst, 'appendText');
7991 var isRTL = this._get(inst, 'isRTL');
7992 if (appendText) {
7993 inst.append = $('<span class="' + this._appendClass + '">' + appendText + '</span>');
7994 input[isRTL ? 'before' : 'after'](inst.append);
7995 }
7996 var showOn = this._get(inst, 'showOn');
7997 if (showOn == 'focus' || showOn == 'both') // pop-up date picker when in the marked field
7998 input.focus(this._showDatepicker);
7999 if (showOn == 'button' || showOn == 'both') { // pop-up date picker when button clicked
8000 var buttonText = this._get(inst, 'buttonText');
8001 var buttonImage = this._get(inst, 'buttonImage');
8002 inst.trigger = $(this._get(inst, 'buttonImageOnly') ?
8003 $('<img/>').addClass(this._triggerClass).
8004 attr({ src: buttonImage, alt: buttonText, title: buttonText }) :
8005 $('<button type="button"></button>').addClass(this._triggerClass).
8006 html(buttonImage == '' ? buttonText : $('<img/>').attr(
8007 { src:buttonImage, alt:buttonText, title:buttonText })));
8008 input[isRTL ? 'before' : 'after'](inst.trigger);
8009 inst.trigger.click(function() {
8010 if ($.datepicker._datepickerShowing && $.datepicker._lastInput == target)
8011 $.datepicker._hideDatepicker();
8012 else
8013 $.datepicker._showDatepicker(target);
8014 return false;
8015 });
8016 }
8017 input.addClass(this.markerClassName).keydown(this._doKeyDown).keypress(this._doKeyPress).
8018 bind("setData.datepicker", function(event, key, value) {
8019 inst.settings[key] = value;
8020 }).bind("getData.datepicker", function(event, key) {
8021 return this._get(inst, key);
8022 });
8023 $.data(target, PROP_NAME, inst);
8024 },
8025
8026 /* Attach an inline date picker to a div. */
8027 _inlineDatepicker: function(target, inst) {
8028 var divSpan = $(target);
8029 if (divSpan.hasClass(this.markerClassName))
8030 return;
8031 divSpan.addClass(this.markerClassName).append(inst.dpDiv).
8032 bind("setData.datepicker", function(event, key, value){
8033 inst.settings[key] = value;
8034 }).bind("getData.datepicker", function(event, key){
8035 return this._get(inst, key);
8036 });
8037 $.data(target, PROP_NAME, inst);
8038 this._setDate(inst, this._getDefaultDate(inst));
8039 this._updateDatepicker(inst);
8040 this._updateAlternate(inst);
8041 },
8042
8043 /* Pop-up the date picker in a "dialog" box.
8044 @param input element - ignored
8045 @param dateText string - the initial date to display (in the current format)
8046 @param onSelect function - the function(dateText) to call when a date is selected
8047 @param settings object - update the dialog date picker instance's settings (anonymous object)
8048 @param pos int[2] - coordinates for the dialog's position within the screen or
8049 event - with x/y coordinates or
8050 leave empty for default (screen centre)
8051 @return the manager object */
8052 _dialogDatepicker: function(input, dateText, onSelect, settings, pos) {
8053 var inst = this._dialogInst; // internal instance
8054 if (!inst) {
8055 var id = 'dp' + (++this.uuid);
8056 this._dialogInput = $('<input type="text" id="' + id +
8057 '" size="1" style="position: absolute; top: -100px;"/>');
8058 this._dialogInput.keydown(this._doKeyDown);
8059 $('body').append(this._dialogInput);
8060 inst = this._dialogInst = this._newInst(this._dialogInput, false);
8061 inst.settings = {};
8062 $.data(this._dialogInput[0], PROP_NAME, inst);
8063 }
8064 extendRemove(inst.settings, settings || {});
8065 this._dialogInput.val(dateText);
8066
8067 this._pos = (pos ? (pos.length ? pos : [pos.pageX, pos.pageY]) : null);
8068 if (!this._pos) {
8069 var browserWidth = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
8070 var browserHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
8071 var scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
8072 var scrollY = document.documentElement.scrollTop || document.body.scrollTop;
8073 this._pos = // should use actual width/height below
8074 [(browserWidth / 2) - 100 + scrollX, (browserHeight / 2) - 150 + scrollY];
8075 }
8076
8077 // move input on screen for focus, but hidden behind dialog
8078 this._dialogInput.css('left', this._pos[0] + 'px').css('top', this._pos[1] + 'px');
8079 inst.settings.onSelect = onSelect;
8080 this._inDialog = true;
8081 this.dpDiv.addClass(this._dialogClass);
8082 this._showDatepicker(this._dialogInput[0]);
8083 if ($.blockUI)
8084 $.blockUI(this.dpDiv);
8085 $.data(this._dialogInput[0], PROP_NAME, inst);
8086 return this;
8087 },
8088
8089 /* Detach a datepicker from its control.
8090 @param target element - the target input field or division or span */
8091 _destroyDatepicker: function(target) {
8092 var $target = $(target);
8093 var inst = $.data(target, PROP_NAME);
8094 if (!$target.hasClass(this.markerClassName)) {
8095 return;
8096 }
8097 var nodeName = target.nodeName.toLowerCase();
8098 $.removeData(target, PROP_NAME);
8099 if (nodeName == 'input') {
8100 inst.append.remove();
8101 inst.trigger.remove();
8102 $target.removeClass(this.markerClassName).
8103 unbind('focus', this._showDatepicker).
8104 unbind('keydown', this._doKeyDown).
8105 unbind('keypress', this._doKeyPress);
8106 } else if (nodeName == 'div' || nodeName == 'span')
8107 $target.removeClass(this.markerClassName).empty();
8108 },
8109
8110 /* Enable the date picker to a jQuery selection.
8111 @param target element - the target input field or division or span */
8112 _enableDatepicker: function(target) {
8113 var $target = $(target);
8114 var inst = $.data(target, PROP_NAME);
8115 if (!$target.hasClass(this.markerClassName)) {
8116 return;
8117 }
8118 var nodeName = target.nodeName.toLowerCase();
8119 if (nodeName == 'input') {
8120 target.disabled = false;
8121 inst.trigger.filter('button').
8122 each(function() { this.disabled = false; }).end().
8123 filter('img').css({opacity: '1.0', cursor: ''});
8124 }
8125 else if (nodeName == 'div' || nodeName == 'span') {
8126 var inline = $target.children('.' + this._inlineClass);
8127 inline.children().removeClass('ui-state-disabled');
8128 }
8129 this._disabledInputs = $.map(this._disabledInputs,
8130 function(value) { return (value == target ? null : value); }); // delete entry
8131 },
8132
8133 /* Disable the date picker to a jQuery selection.
8134 @param target element - the target input field or division or span */
8135 _disableDatepicker: function(target) {
8136 var $target = $(target);
8137 var inst = $.data(target, PROP_NAME);
8138 if (!$target.hasClass(this.markerClassName)) {
8139 return;
8140 }
8141 var nodeName = target.nodeName.toLowerCase();
8142 if (nodeName == 'input') {
8143 target.disabled = true;
8144 inst.trigger.filter('button').
8145 each(function() { this.disabled = true; }).end().
8146 filter('img').css({opacity: '0.5', cursor: 'default'});
8147 }
8148 else if (nodeName == 'div' || nodeName == 'span') {
8149 var inline = $target.children('.' + this._inlineClass);
8150 inline.children().addClass('ui-state-disabled');
8151 }
8152 this._disabledInputs = $.map(this._disabledInputs,
8153 function(value) { return (value == target ? null : value); }); // delete entry
8154 this._disabledInputs[this._disabledInputs.length] = target;
8155 },
8156
8157 /* Is the first field in a jQuery collection disabled as a datepicker?
8158 @param target element - the target input field or division or span
8159 @return boolean - true if disabled, false if enabled */
8160 _isDisabledDatepicker: function(target) {
8161 if (!target) {
8162 return false;
8163 }
8164 for (var i = 0; i < this._disabledInputs.length; i++) {
8165 if (this._disabledInputs[i] == target)
8166 return true;
8167 }
8168 return false;
8169 },
8170
8171 /* Retrieve the instance data for the target control.
8172 @param target element - the target input field or division or span
8173 @return object - the associated instance data
8174 @throws error if a jQuery problem getting data */
8175 _getInst: function(target) {
8176 try {
8177 return $.data(target, PROP_NAME);
8178 }
8179 catch (err) {
8180 throw 'Missing instance data for this datepicker';
8181 }
8182 },
8183
8184 /* Update or retrieve the settings for a date picker attached to an input field or division.
8185 @param target element - the target input field or division or span
8186 @param name object - the new settings to update or
8187 string - the name of the setting to change or retrieve,
8188 when retrieving also 'all' for all instance settings or
8189 'defaults' for all global defaults
8190 @param value any - the new value for the setting
8191 (omit if above is an object or to retrieve a value) */
8192 _optionDatepicker: function(target, name, value) {
8193 var inst = this._getInst(target);
8194 if (arguments.length == 2 && typeof name == 'string') {
8195 return (name == 'defaults' ? $.extend({}, $.datepicker._defaults) :
8196 (inst ? (name == 'all' ? $.extend({}, inst.settings) :
8197 this._get(inst, name)) : null));
8198 }
8199 var settings = name || {};
8200 if (typeof name == 'string') {
8201 settings = {};
8202 settings[name] = value;
8203 }
8204 if (inst) {
8205 if (this._curInst == inst) {
8206 this._hideDatepicker(null);
8207 }
8208 var date = this._getDateDatepicker(target);
8209 extendRemove(inst.settings, settings);
8210 this._setDateDatepicker(target, date);
8211 this._updateDatepicker(inst);
8212 }
8213 },
8214
8215 // change method deprecated
8216 _changeDatepicker: function(target, name, value) {
8217 this._optionDatepicker(target, name, value);
8218 },
8219
8220 /* Redraw the date picker attached to an input field or division.
8221 @param target element - the target input field or division or span */
8222 _refreshDatepicker: function(target) {
8223 var inst = this._getInst(target);
8224 if (inst) {
8225 this._updateDatepicker(inst);
8226 }
8227 },
8228
8229 /* Set the dates for a jQuery selection.
8230 @param target element - the target input field or division or span
8231 @param date Date - the new date
8232 @param endDate Date - the new end date for a range (optional) */
8233 _setDateDatepicker: function(target, date, endDate) {
8234 var inst = this._getInst(target);
8235 if (inst) {
8236 this._setDate(inst, date, endDate);
8237 this._updateDatepicker(inst);
8238 this._updateAlternate(inst);
8239 }
8240 },
8241
8242 /* Get the date(s) for the first entry in a jQuery selection.
8243 @param target element - the target input field or division or span
8244 @return Date - the current date or
8245 Date[2] - the current dates for a range */
8246 _getDateDatepicker: function(target) {
8247 var inst = this._getInst(target);
8248 if (inst && !inst.inline)
8249 this._setDateFromField(inst);
8250 return (inst ? this._getDate(inst) : null);
8251 },
8252
8253 /* Handle keystrokes. */
8254 _doKeyDown: function(event) {
8255 var inst = $.datepicker._getInst(event.target);
8256 var handled = true;
8257 var isRTL = inst.dpDiv.is('.ui-datepicker-rtl');
8258 inst._keyEvent = true;
8259 if ($.datepicker._datepickerShowing)
8260 switch (event.keyCode) {
8261 case 9: $.datepicker._hideDatepicker(null, '');
8262 break; // hide on tab out
8263 case 13: var sel = $('td.' + $.datepicker._dayOverClass +
8264 ', td.' + $.datepicker._currentClass, inst.dpDiv);
8265 if (sel[0])
8266 $.datepicker._selectDay(event.target, inst.selectedMonth, inst.selectedYear, sel[0]);
8267 else
8268 $.datepicker._hideDatepicker(null, $.datepicker._get(inst, 'duration'));
8269 return false; // don't submit the form
8270 break; // select the value on enter
8271 case 27: $.datepicker._hideDatepicker(null, $.datepicker._get(inst, 'duration'));
8272 break; // hide on escape
8273 case 33: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
8274 -$.datepicker._get(inst, 'stepBigMonths') :
8275 -$.datepicker._get(inst, 'stepMonths')), 'M');
8276 break; // previous month/year on page up/+ ctrl
8277 case 34: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
8278 +$.datepicker._get(inst, 'stepBigMonths') :
8279 +$.datepicker._get(inst, 'stepMonths')), 'M');
8280 break; // next month/year on page down/+ ctrl
8281 case 35: if (event.ctrlKey || event.metaKey) $.datepicker._clearDate(event.target);
8282 handled = event.ctrlKey || event.metaKey;
8283 break; // clear on ctrl or command +end
8284 case 36: if (event.ctrlKey || event.metaKey) $.datepicker._gotoToday(event.target);
8285 handled = event.ctrlKey || event.metaKey;
8286 break; // current on ctrl or command +home
8287 case 37: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, (isRTL ? +1 : -1), 'D');
8288 handled = event.ctrlKey || event.metaKey;
8289 // -1 day on ctrl or command +left
8290 if (event.originalEvent.altKey) $.datepicker._adjustDate(event.target, (event.ctrlKey ?
8291 -$.datepicker._get(inst, 'stepBigMonths') :
8292 -$.datepicker._get(inst, 'stepMonths')), 'M');
8293 // next month/year on alt +left on Mac
8294 break;
8295 case 38: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, -7, 'D');
8296 handled = event.ctrlKey || event.metaKey;
8297 break; // -1 week on ctrl or command +up
8298 case 39: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, (isRTL ? -1 : +1), 'D');
8299 handled = event.ctrlKey || event.metaKey;
8300 // +1 day on ctrl or command +right
8301 if (event.originalEvent.altKey) $.datepicker._adjustDate(event.target, (event.ctrlKey ?
8302 +$.datepicker._get(inst, 'stepBigMonths') :
8303 +$.datepicker._get(inst, 'stepMonths')), 'M');
8304 // next month/year on alt +right
8305 break;
8306 case 40: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, +7, 'D');
8307 handled = event.ctrlKey || event.metaKey;
8308 break; // +1 week on ctrl or command +down
8309 default: handled = false;
8310 }
8311 else if (event.keyCode == 36 && event.ctrlKey) // display the date picker on ctrl+home
8312 $.datepicker._showDatepicker(this);
8313 else {
8314 handled = false;
8315 }
8316 if (handled) {
8317 event.preventDefault();
8318 event.stopPropagation();
8319 }
8320 },
8321
8322 /* Filter entered characters - based on date format. */
8323 _doKeyPress: function(event) {
8324 var inst = $.datepicker._getInst(event.target);
8325 if ($.datepicker._get(inst, 'constrainInput')) {
8326 var chars = $.datepicker._possibleChars($.datepicker._get(inst, 'dateFormat'));
8327 var chr = String.fromCharCode(event.charCode == undefined ? event.keyCode : event.charCode);
8328 return event.ctrlKey || (chr < ' ' || !chars || chars.indexOf(chr) > -1);
8329 }
8330 },
8331
8332 /* Pop-up the date picker for a given input field.
8333 @param input element - the input field attached to the date picker or
8334 event - if triggered by focus */
8335 _showDatepicker: function(input) {
8336 input = input.target || input;
8337 if (input.nodeName.toLowerCase() != 'input') // find from button/image trigger
8338 input = $('input', input.parentNode)[0];
8339 if ($.datepicker._isDisabledDatepicker(input) || $.datepicker._lastInput == input) // already here
8340 return;
8341 var inst = $.datepicker._getInst(input);
8342 var beforeShow = $.datepicker._get(inst, 'beforeShow');
8343 extendRemove(inst.settings, (beforeShow ? beforeShow.apply(input, [input, inst]) : {}));
8344 $.datepicker._hideDatepicker(null, '');
8345 $.datepicker._lastInput = input;
8346 $.datepicker._setDateFromField(inst);
8347 if ($.datepicker._inDialog) // hide cursor
8348 input.value = '';
8349 if (!$.datepicker._pos) { // position below input
8350 $.datepicker._pos = $.datepicker._findPos(input);
8351 $.datepicker._pos[1] += input.offsetHeight; // add the height
8352 }
8353 var isFixed = false;
8354 $(input).parents().each(function() {
8355 isFixed |= $(this).css('position') == 'fixed';
8356 return !isFixed;
8357 });
8358 if (isFixed && $.browser.opera) { // correction for Opera when fixed and scrolled
8359 $.datepicker._pos[0] -= document.documentElement.scrollLeft;
8360 $.datepicker._pos[1] -= document.documentElement.scrollTop;
8361 }
8362 var offset = {left: $.datepicker._pos[0], top: $.datepicker._pos[1]};
8363 $.datepicker._pos = null;
8364 inst.rangeStart = null;
8365 // determine sizing offscreen
8366 inst.dpDiv.css({position: 'absolute', display: 'block', top: '-1000px'});
8367 $.datepicker._updateDatepicker(inst);
8368 // fix width for dynamic number of date pickers
8369 // and adjust position before showing
8370 offset = $.datepicker._checkOffset(inst, offset, isFixed);
8371 inst.dpDiv.css({position: ($.datepicker._inDialog && $.blockUI ?
8372 'static' : (isFixed ? 'fixed' : 'absolute')), display: 'none',
8373 left: offset.left + 'px', top: offset.top + 'px'});
8374 if (!inst.inline) {
8375 var showAnim = $.datepicker._get(inst, 'showAnim') || 'show';
8376 var duration = $.datepicker._get(inst, 'duration');
8377 var postProcess = function() {
8378 $.datepicker._datepickerShowing = true;
8379 if ($.browser.msie && parseInt($.browser.version,10) < 7) // fix IE < 7 select problems
8380 $('iframe.ui-datepicker-cover').css({width: inst.dpDiv.width() + 4,
8381 height: inst.dpDiv.height() + 4});
8382 };
8383 if ($.effects && $.effects[showAnim])
8384 inst.dpDiv.show(showAnim, $.datepicker._get(inst, 'showOptions'), duration, postProcess);
8385 else
8386 inst.dpDiv[showAnim](duration, postProcess);
8387 if (duration == '')
8388 postProcess();
8389 if (inst.input[0].type != 'hidden')
8390 inst.input[0].focus();
8391 $.datepicker._curInst = inst;
8392 }
8393 },
8394
8395 /* Generate the date picker content. */
8396 _updateDatepicker: function(inst) {
8397 var dims = {width: inst.dpDiv.width() + 4,
8398 height: inst.dpDiv.height() + 4};
8399 var self = this;
8400 inst.dpDiv.empty().append(this._generateHTML(inst))
8401 .find('iframe.ui-datepicker-cover').
8402 css({width: dims.width, height: dims.height})
8403 .end()
8404 .find('button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a')
8405 .bind('mouseout', function(){
8406 $(this).removeClass('ui-state-hover');
8407 if(this.className.indexOf('ui-datepicker-prev') != -1) $(this).removeClass('ui-datepicker-prev-hover');
8408 if(this.className.indexOf('ui-datepicker-next') != -1) $(this).removeClass('ui-datepicker-next-hover');
8409 })
8410 .bind('mouseover', function(){
8411 if (!self._isDisabledDatepicker( inst.inline ? inst.dpDiv.parent()[0] : inst.input[0])) {
8412 $(this).parents('.ui-datepicker-calendar').find('a').removeClass('ui-state-hover');
8413 $(this).addClass('ui-state-hover');
8414 if(this.className.indexOf('ui-datepicker-prev') != -1) $(this).addClass('ui-datepicker-prev-hover');
8415 if(this.className.indexOf('ui-datepicker-next') != -1) $(this).addClass('ui-datepicker-next-hover');
8416 }
8417 })
8418 .end()
8419 .find('.' + this._dayOverClass + ' a')
8420 .trigger('mouseover')
8421 .end();
8422 var numMonths = this._getNumberOfMonths(inst);
8423 var cols = numMonths[1];
8424 var width = 17;
8425 if (cols > 1) {
8426 inst.dpDiv.addClass('ui-datepicker-multi-' + cols).css('width', (width * cols) + 'em');
8427 } else {
8428 inst.dpDiv.removeClass('ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4').width('');
8429 }
8430 inst.dpDiv[(numMonths[0] != 1 || numMonths[1] != 1 ? 'add' : 'remove') +
8431 'Class']('ui-datepicker-multi');
8432 inst.dpDiv[(this._get(inst, 'isRTL') ? 'add' : 'remove') +
8433 'Class']('ui-datepicker-rtl');
8434 if (inst.input && inst.input[0].type != 'hidden' && inst == $.datepicker._curInst)
8435 $(inst.input[0]).focus();
8436 },
8437
8438 /* Check positioning to remain on screen. */
8439 _checkOffset: function(inst, offset, isFixed) {
8440 var dpWidth = inst.dpDiv.outerWidth();
8441 var dpHeight = inst.dpDiv.outerHeight();
8442 var inputWidth = inst.input ? inst.input.outerWidth() : 0;
8443 var inputHeight = inst.input ? inst.input.outerHeight() : 0;
8444 var viewWidth = (window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth) + $(document).scrollLeft();
8445 var viewHeight = (window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight) + $(document).scrollTop();
8446
8447 offset.left -= (this._get(inst, 'isRTL') ? (dpWidth - inputWidth) : 0);
8448 offset.left -= (isFixed && offset.left == inst.input.offset().left) ? $(document).scrollLeft() : 0;
8449 offset.top -= (isFixed && offset.top == (inst.input.offset().top + inputHeight)) ? $(document).scrollTop() : 0;
8450
8451 // now check if datepicker is showing outside window viewport - move to a better place if so.
8452 offset.left -= (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ? Math.abs(offset.left + dpWidth - viewWidth) : 0;
8453 offset.top -= (offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ? Math.abs(offset.top + dpHeight + inputHeight*2 - viewHeight) : 0;
8454
8455 return offset;
8456 },
8457
8458 /* Find an object's position on the screen. */
8459 _findPos: function(obj) {
8460 while (obj && (obj.type == 'hidden' || obj.nodeType != 1)) {
8461 obj = obj.nextSibling;
8462 }
8463 var position = $(obj).offset();
8464 return [position.left, position.top];
8465 },
8466
8467 /* Hide the date picker from view.
8468 @param input element - the input field attached to the date picker
8469 @param duration string - the duration over which to close the date picker */
8470 _hideDatepicker: function(input, duration) {
8471 var inst = this._curInst;
8472 if (!inst || (input && inst != $.data(input, PROP_NAME)))
8473 return;
8474 if (inst.stayOpen)
8475 this._selectDate('#' + inst.id, this._formatDate(inst,
8476 inst.currentDay, inst.currentMonth, inst.currentYear));
8477 inst.stayOpen = false;
8478 if (this._datepickerShowing) {
8479 duration = (duration != null ? duration : this._get(inst, 'duration'));
8480 var showAnim = this._get(inst, 'showAnim');
8481 var postProcess = function() {
8482 $.datepicker._tidyDialog(inst);
8483 };
8484 if (duration != '' && $.effects && $.effects[showAnim])
8485 inst.dpDiv.hide(showAnim, $.datepicker._get(inst, 'showOptions'),
8486 duration, postProcess);
8487 else
8488 inst.dpDiv[(duration == '' ? 'hide' : (showAnim == 'slideDown' ? 'slideUp' :
8489 (showAnim == 'fadeIn' ? 'fadeOut' : 'hide')))](duration, postProcess);
8490 if (duration == '')
8491 this._tidyDialog(inst);
8492 var onClose = this._get(inst, 'onClose');
8493 if (onClose)
8494 onClose.apply((inst.input ? inst.input[0] : null),
8495 [(inst.input ? inst.input.val() : ''), inst]); // trigger custom callback
8496 this._datepickerShowing = false;
8497 this._lastInput = null;
8498 if (this._inDialog) {
8499 this._dialogInput.css({ position: 'absolute', left: '0', top: '-100px' });
8500 if ($.blockUI) {
8501 $.unblockUI();
8502 $('body').append(this.dpDiv);
8503 }
8504 }
8505 this._inDialog = false;
8506 }
8507 this._curInst = null;
8508 },
8509
8510 /* Tidy up after a dialog display. */
8511 _tidyDialog: function(inst) {
8512 inst.dpDiv.removeClass(this._dialogClass).unbind('.ui-datepicker-calendar');
8513 },
8514
8515 /* Close date picker if clicked elsewhere. */
8516 _checkExternalClick: function(event) {
8517 if (!$.datepicker._curInst)
8518 return;
8519 var $target = $(event.target);
8520 if (($target.parents('#' + $.datepicker._mainDivId).length == 0) &&
8521 !$target.hasClass($.datepicker.markerClassName) &&
8522 !$target.hasClass($.datepicker._triggerClass) &&
8523 $.datepicker._datepickerShowing && !($.datepicker._inDialog && $.blockUI))
8524 $.datepicker._hideDatepicker(null, '');
8525 },
8526
8527 /* Adjust one of the date sub-fields. */
8528 _adjustDate: function(id, offset, period) {
8529 var target = $(id);
8530 var inst = this._getInst(target[0]);
8531 if (this._isDisabledDatepicker(target[0])) {
8532 return;
8533 }
8534 this._adjustInstDate(inst, offset +
8535 (period == 'M' ? this._get(inst, 'showCurrentAtPos') : 0), // undo positioning
8536 period);
8537 this._updateDatepicker(inst);
8538 },
8539
8540 /* Action for current link. */
8541 _gotoToday: function(id) {
8542 var target = $(id);
8543 var inst = this._getInst(target[0]);
8544 if (this._get(inst, 'gotoCurrent') && inst.currentDay) {
8545 inst.selectedDay = inst.currentDay;
8546 inst.drawMonth = inst.selectedMonth = inst.currentMonth;
8547 inst.drawYear = inst.selectedYear = inst.currentYear;
8548 }
8549 else {
8550 var date = new Date();
8551 inst.selectedDay = date.getDate();
8552 inst.drawMonth = inst.selectedMonth = date.getMonth();
8553 inst.drawYear = inst.selectedYear = date.getFullYear();
8554 }
8555 this._notifyChange(inst);
8556 this._adjustDate(target);
8557 },
8558
8559 /* Action for selecting a new month/year. */
8560 _selectMonthYear: function(id, select, period) {
8561 var target = $(id);
8562 var inst = this._getInst(target[0]);
8563 inst._selectingMonthYear = false;
8564 inst['selected' + (period == 'M' ? 'Month' : 'Year')] =
8565 inst['draw' + (period == 'M' ? 'Month' : 'Year')] =
8566 parseInt(select.options[select.selectedIndex].value,10);
8567 this._notifyChange(inst);
8568 this._adjustDate(target);
8569 },
8570
8571 /* Restore input focus after not changing month/year. */
8572 _clickMonthYear: function(id) {
8573 var target = $(id);
8574 var inst = this._getInst(target[0]);
8575 if (inst.input && inst._selectingMonthYear && !$.browser.msie)
8576 inst.input[0].focus();
8577 inst._selectingMonthYear = !inst._selectingMonthYear;
8578 },
8579
8580 /* Action for selecting a day. */
8581 _selectDay: function(id, month, year, td) {
8582 var target = $(id);
8583 if ($(td).hasClass(this._unselectableClass) || this._isDisabledDatepicker(target[0])) {
8584 return;
8585 }
8586 var inst = this._getInst(target[0]);
8587 inst.selectedDay = inst.currentDay = $('a', td).html();
8588 inst.selectedMonth = inst.currentMonth = month;
8589 inst.selectedYear = inst.currentYear = year;
8590 if (inst.stayOpen) {
8591 inst.endDay = inst.endMonth = inst.endYear = null;
8592 }
8593 this._selectDate(id, this._formatDate(inst,
8594 inst.currentDay, inst.currentMonth, inst.currentYear));
8595 if (inst.stayOpen) {
8596 inst.rangeStart = this._daylightSavingAdjust(
8597 new Date(inst.currentYear, inst.currentMonth, inst.currentDay));
8598 this._updateDatepicker(inst);
8599 }
8600 },
8601
8602 /* Erase the input field and hide the date picker. */
8603 _clearDate: function(id) {
8604 var target = $(id);
8605 var inst = this._getInst(target[0]);
8606 inst.stayOpen = false;
8607 inst.endDay = inst.endMonth = inst.endYear = inst.rangeStart = null;
8608 this._selectDate(target, '');
8609 },
8610
8611 /* Update the input field with the selected date. */
8612 _selectDate: function(id, dateStr) {
8613 var target = $(id);
8614 var inst = this._getInst(target[0]);
8615 dateStr = (dateStr != null ? dateStr : this._formatDate(inst));
8616 if (inst.input)
8617 inst.input.val(dateStr);
8618 this._updateAlternate(inst);
8619 var onSelect = this._get(inst, 'onSelect');
8620 if (onSelect)
8621 onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); // trigger custom callback
8622 else if (inst.input)
8623 inst.input.trigger('change'); // fire the change event
8624 if (inst.inline)
8625 this._updateDatepicker(inst);
8626 else if (!inst.stayOpen) {
8627 this._hideDatepicker(null, this._get(inst, 'duration'));
8628 this._lastInput = inst.input[0];
8629 if (typeof(inst.input[0]) != 'object')
8630 inst.input[0].focus(); // restore focus
8631 this._lastInput = null;
8632 }
8633 },
8634
8635 /* Update any alternate field to synchronise with the main field. */
8636 _updateAlternate: function(inst) {
8637 var altField = this._get(inst, 'altField');
8638 if (altField) { // update alternate field too
8639 var altFormat = this._get(inst, 'altFormat') || this._get(inst, 'dateFormat');
8640 var date = this._getDate(inst);
8641 dateStr = this.formatDate(altFormat, date, this._getFormatConfig(inst));
8642 $(altField).each(function() { $(this).val(dateStr); });
8643 }
8644 },
8645
8646 /* Set as beforeShowDay function to prevent selection of weekends.
8647 @param date Date - the date to customise
8648 @return [boolean, string] - is this date selectable?, what is its CSS class? */
8649 noWeekends: function(date) {
8650 var day = date.getDay();
8651 return [(day > 0 && day < 6), ''];
8652 },
8653
8654 /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.
8655 @param date Date - the date to get the week for
8656 @return number - the number of the week within the year that contains this date */
8657 iso8601Week: function(date) {
8658 var checkDate = new Date(date.getFullYear(), date.getMonth(), date.getDate());
8659 var firstMon = new Date(checkDate.getFullYear(), 1 - 1, 4); // First week always contains 4 Jan
8660 var firstDay = firstMon.getDay() || 7; // Day of week: Mon = 1, ..., Sun = 7
8661 firstMon.setDate(firstMon.getDate() + 1 - firstDay); // Preceding Monday
8662 if (firstDay < 4 && checkDate < firstMon) { // Adjust first three days in year if necessary
8663 checkDate.setDate(checkDate.getDate() - 3); // Generate for previous year
8664 return $.datepicker.iso8601Week(checkDate);
8665 } else if (checkDate > new Date(checkDate.getFullYear(), 12 - 1, 28)) { // Check last three days in year
8666 firstDay = new Date(checkDate.getFullYear() + 1, 1 - 1, 4).getDay() || 7;
8667 if (firstDay > 4 && (checkDate.getDay() || 7) < firstDay - 3) { // Adjust if necessary
8668 return 1;
8669 }
8670 }
8671 return Math.floor(((checkDate - firstMon) / 86400000) / 7) + 1; // Weeks to given date
8672 },
8673
8674 /* Parse a string value into a date object.
8675 See formatDate below for the possible formats.
8676
8677 @param format string - the expected format of the date
8678 @param value string - the date in the above format
8679 @param settings Object - attributes include:
8680 shortYearCutoff number - the cutoff year for determining the century (optional)
8681 dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
8682 dayNames string[7] - names of the days from Sunday (optional)
8683 monthNamesShort string[12] - abbreviated names of the months (optional)
8684 monthNames string[12] - names of the months (optional)
8685 @return Date - the extracted date value or null if value is blank */
8686 parseDate: function (format, value, settings) {
8687 if (format == null || value == null)
8688 throw 'Invalid arguments';
8689 value = (typeof value == 'object' ? value.toString() : value + '');
8690 if (value == '')
8691 return null;
8692 var shortYearCutoff = (settings ? settings.shortYearCutoff : null) || this._defaults.shortYearCutoff;
8693 var dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort;
8694 var dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames;
8695 var monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort;
8696 var monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames;
8697 var year = -1;
8698 var month = -1;
8699 var day = -1;
8700 var doy = -1;
8701 var literal = false;
8702 // Check whether a format character is doubled
8703 var lookAhead = function(match) {
8704 var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match);
8705 if (matches)
8706 iFormat++;
8707 return matches;
8708 };
8709 // Extract a number from the string value
8710 var getNumber = function(match) {
8711 lookAhead(match);
8712 var origSize = (match == '@' ? 14 : (match == 'y' ? 4 : (match == 'o' ? 3 : 2)));
8713 var size = origSize;
8714 var num = 0;
8715 while (size > 0 && iValue < value.length &&
8716 value.charAt(iValue) >= '0' && value.charAt(iValue) <= '9') {
8717 num = num * 10 + parseInt(value.charAt(iValue++),10);
8718 size--;
8719 }
8720 if (size == origSize)
8721 throw 'Missing number at position ' + iValue;
8722 return num;
8723 };
8724 // Extract a name from the string value and convert to an index
8725 var getName = function(match, shortNames, longNames) {
8726 var names = (lookAhead(match) ? longNames : shortNames);
8727 var size = 0;
8728 for (var j = 0; j < names.length; j++)
8729 size = Math.max(size, names[j].length);
8730 var name = '';
8731 var iInit = iValue;
8732 while (size > 0 && iValue < value.length) {
8733 name += value.charAt(iValue++);
8734 for (var i = 0; i < names.length; i++)
8735 if (name == names[i])
8736 return i + 1;
8737 size--;
8738 }
8739 throw 'Unknown name at position ' + iInit;
8740 };
8741 // Confirm that a literal character matches the string value
8742 var checkLiteral = function() {
8743 if (value.charAt(iValue) != format.charAt(iFormat))
8744 throw 'Unexpected literal at position ' + iValue;
8745 iValue++;
8746 };
8747 var iValue = 0;
8748 for (var iFormat = 0; iFormat < format.length; iFormat++) {
8749 if (literal)
8750 if (format.charAt(iFormat) == "'" && !lookAhead("'"))
8751 literal = false;
8752 else
8753 checkLiteral();
8754 else
8755 switch (format.charAt(iFormat)) {
8756 case 'd':
8757 day = getNumber('d');
8758 break;
8759 case 'D':
8760 getName('D', dayNamesShort, dayNames);
8761 break;
8762 case 'o':
8763 doy = getNumber('o');
8764 break;
8765 case 'm':
8766 month = getNumber('m');
8767 break;
8768 case 'M':
8769 month = getName('M', monthNamesShort, monthNames);
8770 break;
8771 case 'y':
8772 year = getNumber('y');
8773 break;
8774 case '@':
8775 var date = new Date(getNumber('@'));
8776 year = date.getFullYear();
8777 month = date.getMonth() + 1;
8778 day = date.getDate();
8779 break;
8780 case "'":
8781 if (lookAhead("'"))
8782 checkLiteral();
8783 else
8784 literal = true;
8785 break;
8786 default:
8787 checkLiteral();
8788 }
8789 }
8790 if (year == -1)
8791 year = new Date().getFullYear();
8792 else if (year < 100)
8793 year += new Date().getFullYear() - new Date().getFullYear() % 100 +
8794 (year <= shortYearCutoff ? 0 : -100);
8795 if (doy > -1) {
8796 month = 1;
8797 day = doy;
8798 do {
8799 var dim = this._getDaysInMonth(year, month - 1);
8800 if (day <= dim)
8801 break;
8802 month++;
8803 day -= dim;
8804 } while (true);
8805 }
8806 var date = this._daylightSavingAdjust(new Date(year, month - 1, day));
8807 if (date.getFullYear() != year || date.getMonth() + 1 != month || date.getDate() != day)
8808 throw 'Invalid date'; // E.g. 31/02/*
8809 return date;
8810 },
8811
8812 /* Standard date formats. */
8813 ATOM: 'yy-mm-dd', // RFC 3339 (ISO 8601)
8814 COOKIE: 'D, dd M yy',
8815 ISO_8601: 'yy-mm-dd',
8816 RFC_822: 'D, d M y',
8817 RFC_850: 'DD, dd-M-y',
8818 RFC_1036: 'D, d M y',
8819 RFC_1123: 'D, d M yy',
8820 RFC_2822: 'D, d M yy',
8821 RSS: 'D, d M y', // RFC 822
8822 TIMESTAMP: '@',
8823 W3C: 'yy-mm-dd', // ISO 8601
8824
8825 /* Format a date object into a string value.
8826 The format can be combinations of the following:
8827 d - day of month (no leading zero)
8828 dd - day of month (two digit)
8829 o - day of year (no leading zeros)
8830 oo - day of year (three digit)
8831 D - day name short
8832 DD - day name long
8833 m - month of year (no leading zero)
8834 mm - month of year (two digit)
8835 M - month name short
8836 MM - month name long
8837 y - year (two digit)
8838 yy - year (four digit)
8839 @ - Unix timestamp (ms since 01/01/1970)
8840 '...' - literal text
8841 '' - single quote
8842
8843 @param format string - the desired format of the date
8844 @param date Date - the date value to format
8845 @param settings Object - attributes include:
8846 dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
8847 dayNames string[7] - names of the days from Sunday (optional)
8848 monthNamesShort string[12] - abbreviated names of the months (optional)
8849 monthNames string[12] - names of the months (optional)
8850 @return string - the date in the above format */
8851 formatDate: function (format, date, settings) {
8852 if (!date)
8853 return '';
8854 var dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort;
8855 var dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames;
8856 var monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort;
8857 var monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames;
8858 // Check whether a format character is doubled
8859 var lookAhead = function(match) {
8860 var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match);
8861 if (matches)
8862 iFormat++;
8863 return matches;
8864 };
8865 // Format a number, with leading zero if necessary
8866 var formatNumber = function(match, value, len) {
8867 var num = '' + value;
8868 if (lookAhead(match))
8869 while (num.length < len)
8870 num = '0' + num;
8871 return num;
8872 };
8873 // Format a name, short or long as requested
8874 var formatName = function(match, value, shortNames, longNames) {
8875 return (lookAhead(match) ? longNames[value] : shortNames[value]);
8876 };
8877 var output = '';
8878 var literal = false;
8879 if (date)
8880 for (var iFormat = 0; iFormat < format.length; iFormat++) {
8881 if (literal)
8882 if (format.charAt(iFormat) == "'" && !lookAhead("'"))
8883 literal = false;
8884 else
8885 output += format.charAt(iFormat);
8886 else
8887 switch (format.charAt(iFormat)) {
8888 case 'd':
8889 output += formatNumber('d', date.getDate(), 2);
8890 break;
8891 case 'D':
8892 output += formatName('D', date.getDay(), dayNamesShort, dayNames);
8893 break;
8894 case 'o':
8895 var doy = date.getDate();
8896 for (var m = date.getMonth() - 1; m >= 0; m--)
8897 doy += this._getDaysInMonth(date.getFullYear(), m);
8898 output += formatNumber('o', doy, 3);
8899 break;
8900 case 'm':
8901 output += formatNumber('m', date.getMonth() + 1, 2);
8902 break;
8903 case 'M':
8904 output += formatName('M', date.getMonth(), monthNamesShort, monthNames);
8905 break;
8906 case 'y':
8907 output += (lookAhead('y') ? date.getFullYear() :
8908 (date.getYear() % 100 < 10 ? '0' : '') + date.getYear() % 100);
8909 break;
8910 case '@':
8911 output += date.getTime();
8912 break;
8913 case "'":
8914 if (lookAhead("'"))
8915 output += "'";
8916 else
8917 literal = true;
8918 break;
8919 default:
8920 output += format.charAt(iFormat);
8921 }
8922 }
8923 return output;
8924 },
8925
8926 /* Extract all possible characters from the date format. */
8927 _possibleChars: function (format) {
8928 var chars = '';
8929 var literal = false;
8930 for (var iFormat = 0; iFormat < format.length; iFormat++)
8931 if (literal)
8932 if (format.charAt(iFormat) == "'" && !lookAhead("'"))
8933 literal = false;
8934 else
8935 chars += format.charAt(iFormat);
8936 else
8937 switch (format.charAt(iFormat)) {
8938 case 'd': case 'm': case 'y': case '@':
8939 chars += '0123456789';
8940 break;
8941 case 'D': case 'M':
8942 return null; // Accept anything
8943 case "'":
8944 if (lookAhead("'"))
8945 chars += "'";
8946 else
8947 literal = true;
8948 break;
8949 default:
8950 chars += format.charAt(iFormat);
8951 }
8952 return chars;
8953 },
8954
8955 /* Get a setting value, defaulting if necessary. */
8956 _get: function(inst, name) {
8957 return inst.settings[name] !== undefined ?
8958 inst.settings[name] : this._defaults[name];
8959 },
8960
8961 /* Parse existing date and initialise date picker. */
8962 _setDateFromField: function(inst) {
8963 var dateFormat = this._get(inst, 'dateFormat');
8964 var dates = inst.input ? inst.input.val() : null;
8965 inst.endDay = inst.endMonth = inst.endYear = null;
8966 var date = defaultDate = this._getDefaultDate(inst);
8967 var settings = this._getFormatConfig(inst);
8968 try {
8969 date = this.parseDate(dateFormat, dates, settings) || defaultDate;
8970 } catch (event) {
8971 this.log(event);
8972 date = defaultDate;
8973 }
8974 inst.selectedDay = date.getDate();
8975 inst.drawMonth = inst.selectedMonth = date.getMonth();
8976 inst.drawYear = inst.selectedYear = date.getFullYear();
8977 inst.currentDay = (dates ? date.getDate() : 0);
8978 inst.currentMonth = (dates ? date.getMonth() : 0);
8979 inst.currentYear = (dates ? date.getFullYear() : 0);
8980 this._adjustInstDate(inst);
8981 },
8982
8983 /* Retrieve the default date shown on opening. */
8984 _getDefaultDate: function(inst) {
8985 var date = this._determineDate(this._get(inst, 'defaultDate'), new Date());
8986 var minDate = this._getMinMaxDate(inst, 'min', true);
8987 var maxDate = this._getMinMaxDate(inst, 'max');
8988 date = (minDate && date < minDate ? minDate : date);
8989 date = (maxDate && date > maxDate ? maxDate : date);
8990 return date;
8991 },
8992
8993 /* A date may be specified as an exact value or a relative one. */
8994 _determineDate: function(date, defaultDate) {
8995 var offsetNumeric = function(offset) {
8996 var date = new Date();
8997 date.setDate(date.getDate() + offset);
8998 return date;
8999 };
9000 var offsetString = function(offset, getDaysInMonth) {
9001 var date = new Date();
9002 var year = date.getFullYear();
9003 var month = date.getMonth();
9004 var day = date.getDate();
9005 var pattern = /([+-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g;
9006 var matches = pattern.exec(offset);
9007 while (matches) {
9008 switch (matches[2] || 'd') {
9009 case 'd' : case 'D' :
9010 day += parseInt(matches[1],10); break;
9011 case 'w' : case 'W' :
9012 day += parseInt(matches[1],10) * 7; break;
9013 case 'm' : case 'M' :
9014 month += parseInt(matches[1],10);
9015 day = Math.min(day, getDaysInMonth(year, month));
9016 break;
9017 case 'y': case 'Y' :
9018 year += parseInt(matches[1],10);
9019 day = Math.min(day, getDaysInMonth(year, month));
9020 break;
9021 }
9022 matches = pattern.exec(offset);
9023 }
9024 return new Date(year, month, day);
9025 };
9026 date = (date == null ? defaultDate :
9027 (typeof date == 'string' ? offsetString(date, this._getDaysInMonth) :
9028 (typeof date == 'number' ? (isNaN(date) ? defaultDate : offsetNumeric(date)) : date)));
9029 date = (date && date.toString() == 'Invalid Date' ? defaultDate : date);
9030 if (date) {
9031 date.setHours(0);
9032 date.setMinutes(0);
9033 date.setSeconds(0);
9034 date.setMilliseconds(0);
9035 }
9036 return this._daylightSavingAdjust(date);
9037 },
9038
9039 /* Handle switch to/from daylight saving.
9040 Hours may be non-zero on daylight saving cut-over:
9041 > 12 when midnight changeover, but then cannot generate
9042 midnight datetime, so jump to 1AM, otherwise reset.
9043 @param date (Date) the date to check
9044 @return (Date) the corrected date */
9045 _daylightSavingAdjust: function(date) {
9046 if (!date) return null;
9047 date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0);
9048 return date;
9049 },
9050
9051 /* Set the date(s) directly. */
9052 _setDate: function(inst, date, endDate) {
9053 var clear = !(date);
9054 var origMonth = inst.selectedMonth;
9055 var origYear = inst.selectedYear;
9056 date = this._determineDate(date, new Date());
9057 inst.selectedDay = inst.currentDay = date.getDate();
9058 inst.drawMonth = inst.selectedMonth = inst.currentMonth = date.getMonth();
9059 inst.drawYear = inst.selectedYear = inst.currentYear = date.getFullYear();
9060 if (origMonth != inst.selectedMonth || origYear != inst.selectedYear)
9061 this._notifyChange(inst);
9062 this._adjustInstDate(inst);
9063 if (inst.input) {
9064 inst.input.val(clear ? '' : this._formatDate(inst));
9065 }
9066 },
9067
9068 /* Retrieve the date(s) directly. */
9069 _getDate: function(inst) {
9070 var startDate = (!inst.currentYear || (inst.input && inst.input.val() == '') ? null :
9071 this._daylightSavingAdjust(new Date(
9072 inst.currentYear, inst.currentMonth, inst.currentDay)));
9073 return startDate;
9074 },
9075
9076 /* Generate the HTML for the current state of the date picker. */
9077 _generateHTML: function(inst) {
9078 var today = new Date();
9079 today = this._daylightSavingAdjust(
9080 new Date(today.getFullYear(), today.getMonth(), today.getDate())); // clear time
9081 var isRTL = this._get(inst, 'isRTL');
9082 var showButtonPanel = this._get(inst, 'showButtonPanel');
9083 var hideIfNoPrevNext = this._get(inst, 'hideIfNoPrevNext');
9084 var navigationAsDateFormat = this._get(inst, 'navigationAsDateFormat');
9085 var numMonths = this._getNumberOfMonths(inst);
9086 var showCurrentAtPos = this._get(inst, 'showCurrentAtPos');
9087 var stepMonths = this._get(inst, 'stepMonths');
9088 var stepBigMonths = this._get(inst, 'stepBigMonths');
9089 var isMultiMonth = (numMonths[0] != 1 || numMonths[1] != 1);
9090 var currentDate = this._daylightSavingAdjust((!inst.currentDay ? new Date(9999, 9, 9) :
9091 new Date(inst.currentYear, inst.currentMonth, inst.currentDay)));
9092 var minDate = this._getMinMaxDate(inst, 'min', true);
9093 var maxDate = this._getMinMaxDate(inst, 'max');
9094 var drawMonth = inst.drawMonth - showCurrentAtPos;
9095 var drawYear = inst.drawYear;
9096 if (drawMonth < 0) {
9097 drawMonth += 12;
9098 drawYear--;
9099 }
9100 if (maxDate) {
9101 var maxDraw = this._daylightSavingAdjust(new Date(maxDate.getFullYear(),
9102 maxDate.getMonth() - numMonths[1] + 1, maxDate.getDate()));
9103 maxDraw = (minDate && maxDraw < minDate ? minDate : maxDraw);
9104 while (this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1)) > maxDraw) {
9105 drawMonth--;
9106 if (drawMonth < 0) {
9107 drawMonth = 11;
9108 drawYear--;
9109 }
9110 }
9111 }
9112 inst.drawMonth = drawMonth;
9113 inst.drawYear = drawYear;
9114 var prevText = this._get(inst, 'prevText');
9115 prevText = (!navigationAsDateFormat ? prevText : this.formatDate(prevText,
9116 this._daylightSavingAdjust(new Date(drawYear, drawMonth - stepMonths, 1)),
9117 this._getFormatConfig(inst)));
9118 var prev = (this._canAdjustMonth(inst, -1, drawYear, drawMonth) ?
9119 '<a class="ui-datepicker-prev ui-corner-all" onclick="DP_jQuery.datepicker._adjustDate(\'#' + inst.id + '\', -' + stepMonths + ', \'M\');"' +
9120 ' title="' + prevText + '"><span class="ui-icon ui-icon-circle-triangle-' + ( isRTL ? 'e' : 'w') + '">' + prevText + '</span></a>' :
9121 (hideIfNoPrevNext ? '' : '<a class="ui-datepicker-prev ui-corner-all ui-state-disabled" title="'+ prevText +'"><span class="ui-icon ui-icon-circle-triangle-' + ( isRTL ? 'e' : 'w') + '">' + prevText + '</span></a>'));
9122 var nextText = this._get(inst, 'nextText');
9123 nextText = (!navigationAsDateFormat ? nextText : this.formatDate(nextText,
9124 this._daylightSavingAdjust(new Date(drawYear, drawMonth + stepMonths, 1)),
9125 this._getFormatConfig(inst)));
9126 var next = (this._canAdjustMonth(inst, +1, drawYear, drawMonth) ?
9127 '<a class="ui-datepicker-next ui-corner-all" onclick="DP_jQuery.datepicker._adjustDate(\'#' + inst.id + '\', +' + stepMonths + ', \'M\');"' +
9128 ' title="' + nextText + '"><span class="ui-icon ui-icon-circle-triangle-' + ( isRTL ? 'w' : 'e') + '">' + nextText + '</span></a>' :
9129 (hideIfNoPrevNext ? '' : '<a class="ui-datepicker-next ui-corner-all ui-state-disabled" title="'+ nextText + '"><span class="ui-icon ui-icon-circle-triangle-' + ( isRTL ? 'w' : 'e') + '">' + nextText + '</span></a>'));
9130 var currentText = this._get(inst, 'currentText');
9131 var gotoDate = (this._get(inst, 'gotoCurrent') && inst.currentDay ? currentDate : today);
9132 currentText = (!navigationAsDateFormat ? currentText :
9133 this.formatDate(currentText, gotoDate, this._getFormatConfig(inst)));
9134 var controls = (!inst.inline ? '<button type="button" class="ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all" onclick="DP_jQuery.datepicker._hideDatepicker();">' + this._get(inst, 'closeText') + '</button>' : '');
9135 var buttonPanel = (showButtonPanel) ? '<div class="ui-datepicker-buttonpane ui-widget-content">' + (isRTL ? controls : '') +
9136 (this._isInRange(inst, gotoDate) ? '<button type="button" class="ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all" onclick="DP_jQuery.datepicker._gotoToday(\'#' + inst.id + '\');"' +
9137 '>' + currentText + '</button>' : '') + (isRTL ? '' : controls) + '</div>' : '';
9138 var firstDay = parseInt(this._get(inst, 'firstDay'),10);
9139 firstDay = (isNaN(firstDay) ? 0 : firstDay);
9140 var dayNames = this._get(inst, 'dayNames');
9141 var dayNamesShort = this._get(inst, 'dayNamesShort');
9142 var dayNamesMin = this._get(inst, 'dayNamesMin');
9143 var monthNames = this._get(inst, 'monthNames');
9144 var monthNamesShort = this._get(inst, 'monthNamesShort');
9145 var beforeShowDay = this._get(inst, 'beforeShowDay');
9146 var showOtherMonths = this._get(inst, 'showOtherMonths');
9147 var calculateWeek = this._get(inst, 'calculateWeek') || this.iso8601Week;
9148 var endDate = inst.endDay ? this._daylightSavingAdjust(
9149 new Date(inst.endYear, inst.endMonth, inst.endDay)) : currentDate;
9150 var defaultDate = this._getDefaultDate(inst);
9151 var html = '';
9152 for (var row = 0; row < numMonths[0]; row++) {
9153 var group = '';
9154 for (var col = 0; col < numMonths[1]; col++) {
9155 var selectedDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, inst.selectedDay));
9156 var cornerClass = ' ui-corner-all';
9157 var calender = '';
9158 if (isMultiMonth) {
9159 calender += '<div class="ui-datepicker-group ui-datepicker-group-';
9160 switch (col) {
9161 case 0: calender += 'first'; cornerClass = ' ui-corner-' + (isRTL ? 'right' : 'left'); break;
9162 case numMonths[1]-1: calender += 'last'; cornerClass = ' ui-corner-' + (isRTL ? 'left' : 'right'); break;
9163 default: calender += 'middle'; cornerClass = ''; break;
9164 }
9165 calender += '">';
9166 }
9167 calender += '<div class="ui-datepicker-header ui-widget-header ui-helper-clearfix' + cornerClass + '">' +
9168 (/all|left/.test(cornerClass) && row == 0 ? (isRTL ? next : prev) : '') +
9169 (/all|right/.test(cornerClass) && row == 0 ? (isRTL ? prev : next) : '') +
9170 this._generateMonthYearHeader(inst, drawMonth, drawYear, minDate, maxDate,
9171 selectedDate, row > 0 || col > 0, monthNames, monthNamesShort) + // draw month headers
9172 '</div><table class="ui-datepicker-calendar"><thead>' +
9173 '<tr>';
9174 var thead = '';
9175 for (var dow = 0; dow < 7; dow++) { // days of the week
9176 var day = (dow + firstDay) % 7;
9177 thead += '<th' + ((dow + firstDay + 6) % 7 >= 5 ? ' class="ui-datepicker-week-end"' : '') + '>' +
9178 '<span title="' + dayNames[day] + '">' + dayNamesMin[day] + '</span></th>';
9179 }
9180 calender += thead + '</tr></thead><tbody>';
9181 var daysInMonth = this._getDaysInMonth(drawYear, drawMonth);
9182 if (drawYear == inst.selectedYear && drawMonth == inst.selectedMonth)
9183 inst.selectedDay = Math.min(inst.selectedDay, daysInMonth);
9184 var leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7;
9185 var numRows = (isMultiMonth ? 6 : Math.ceil((leadDays + daysInMonth) / 7)); // calculate the number of rows to generate
9186 var printDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1 - leadDays));
9187 for (var dRow = 0; dRow < numRows; dRow++) { // create date picker rows
9188 calender += '<tr>';
9189 var tbody = '';
9190 for (var dow = 0; dow < 7; dow++) { // create date picker days
9191 var daySettings = (beforeShowDay ?
9192 beforeShowDay.apply((inst.input ? inst.input[0] : null), [printDate]) : [true, '']);
9193 var otherMonth = (printDate.getMonth() != drawMonth);
9194 var unselectable = otherMonth || !daySettings[0] ||
9195 (minDate && printDate < minDate) || (maxDate && printDate > maxDate);
9196 tbody += '<td class="' +
9197 ((dow + firstDay + 6) % 7 >= 5 ? ' ui-datepicker-week-end' : '') + // highlight weekends
9198 (otherMonth ? ' ui-datepicker-other-month' : '') + // highlight days from other months
9199 ((printDate.getTime() == selectedDate.getTime() && drawMonth == inst.selectedMonth && inst._keyEvent) || // user pressed key
9200 (defaultDate.getTime() == printDate.getTime() && defaultDate.getTime() == selectedDate.getTime()) ?
9201 // or defaultDate is current printedDate and defaultDate is selectedDate
9202 ' ' + this._dayOverClass : '') + // highlight selected day
9203 (unselectable ? ' ' + this._unselectableClass + ' ui-state-disabled': '') + // highlight unselectable days
9204 (otherMonth && !showOtherMonths ? '' : ' ' + daySettings[1] + // highlight custom dates
9205 (printDate.getTime() >= currentDate.getTime() && printDate.getTime() <= endDate.getTime() ? // in current range
9206 ' ' + this._currentClass : '') + // highlight selected day
9207 (printDate.getTime() == today.getTime() ? ' ui-datepicker-today' : '')) + '"' + // highlight today (if different)
9208 ((!otherMonth || showOtherMonths) && daySettings[2] ? ' title="' + daySettings[2] + '"' : '') + // cell title
9209 (unselectable ? '' : ' onclick="DP_jQuery.datepicker._selectDay(\'#' +
9210 inst.id + '\',' + drawMonth + ',' + drawYear + ', this);return false;"') + '>' + // actions
9211 (otherMonth ? (showOtherMonths ? printDate.getDate() : '&#xa0;') : // display for other months
9212 (unselectable ? '<span class="ui-state-default">' + printDate.getDate() + '</span>' : '<a class="ui-state-default' +
9213 (printDate.getTime() == today.getTime() ? ' ui-state-highlight' : '') +
9214 (printDate.getTime() >= currentDate.getTime() && printDate.getTime() <= endDate.getTime() ? // in current range
9215 ' ui-state-active' : '') + // highlight selected day
9216 '" href="#">' + printDate.getDate() + '</a>')) + '</td>'; // display for this month
9217 printDate.setDate(printDate.getDate() + 1);
9218 printDate = this._daylightSavingAdjust(printDate);
9219 }
9220 calender += tbody + '</tr>';
9221 }
9222 drawMonth++;
9223 if (drawMonth > 11) {
9224 drawMonth = 0;
9225 drawYear++;
9226 }
9227 calender += '</tbody></table>' + (isMultiMonth ? '</div>' +
9228 ((numMonths[0] > 0 && col == numMonths[1]-1) ? '<div class="ui-datepicker-row-break"></div>' : '') : '');
9229 group += calender;
9230 }
9231 html += group;
9232 }
9233 html += buttonPanel + ($.browser.msie && parseInt($.browser.version,10) < 7 && !inst.inline ?
9234 '<iframe src="javascript:false;" class="ui-datepicker-cover" frameborder="0"></iframe>' : '');
9235 inst._keyEvent = false;
9236 return html;
9237 },
9238
9239 /* Generate the month and year header. */
9240 _generateMonthYearHeader: function(inst, drawMonth, drawYear, minDate, maxDate,
9241 selectedDate, secondary, monthNames, monthNamesShort) {
9242 minDate = (inst.rangeStart && minDate && selectedDate < minDate ? selectedDate : minDate);
9243 var changeMonth = this._get(inst, 'changeMonth');
9244 var changeYear = this._get(inst, 'changeYear');
9245 var showMonthAfterYear = this._get(inst, 'showMonthAfterYear');
9246 var html = '<div class="ui-datepicker-title">';
9247 var monthHtml = '';
9248 // month selection
9249 if (secondary || !changeMonth)
9250 monthHtml += '<span class="ui-datepicker-month">' + monthNames[drawMonth] + '</span> ';
9251 else {
9252 var inMinYear = (minDate && minDate.getFullYear() == drawYear);
9253 var inMaxYear = (maxDate && maxDate.getFullYear() == drawYear);
9254 monthHtml += '<select class="ui-datepicker-month" ' +
9255 'onchange="DP_jQuery.datepicker._selectMonthYear(\'#' + inst.id + '\', this, \'M\');" ' +
9256 'onclick="DP_jQuery.datepicker._clickMonthYear(\'#' + inst.id + '\');"' +
9257 '>';
9258 for (var month = 0; month < 12; month++) {
9259 if ((!inMinYear || month >= minDate.getMonth()) &&
9260 (!inMaxYear || month <= maxDate.getMonth()))
9261 monthHtml += '<option value="' + month + '"' +
9262 (month == drawMonth ? ' selected="selected"' : '') +
9263 '>' + monthNamesShort[month] + '</option>';
9264 }
9265 monthHtml += '</select>';
9266 }
9267 if (!showMonthAfterYear)
9268 html += monthHtml + ((secondary || changeMonth || changeYear) && (!(changeMonth && changeYear)) ? '&#xa0;' : '');
9269 // year selection
9270 if (secondary || !changeYear)
9271 html += '<span class="ui-datepicker-year">' + drawYear + '</span>';
9272 else {
9273 // determine range of years to display
9274 var years = this._get(inst, 'yearRange').split(':');
9275 var year = 0;
9276 var endYear = 0;
9277 if (years.length != 2) {
9278 year = drawYear - 10;
9279 endYear = drawYear + 10;
9280 } else if (years[0].charAt(0) == '+' || years[0].charAt(0) == '-') {
9281 year = drawYear + parseInt(years[0], 10);
9282 endYear = drawYear + parseInt(years[1], 10);
9283 } else {
9284 year = parseInt(years[0], 10);
9285 endYear = parseInt(years[1], 10);
9286 }
9287 year = (minDate ? Math.max(year, minDate.getFullYear()) : year);
9288 endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear);
9289 html += '<select class="ui-datepicker-year" ' +
9290 'onchange="DP_jQuery.datepicker._selectMonthYear(\'#' + inst.id + '\', this, \'Y\');" ' +
9291 'onclick="DP_jQuery.datepicker._clickMonthYear(\'#' + inst.id + '\');"' +
9292 '>';
9293 for (; year <= endYear; year++) {
9294 html += '<option value="' + year + '"' +
9295 (year == drawYear ? ' selected="selected"' : '') +
9296 '>' + year + '</option>';
9297 }
9298 html += '</select>';
9299 }
9300 if (showMonthAfterYear)
9301 html += (secondary || changeMonth || changeYear ? '&#xa0;' : '') + monthHtml;
9302 html += '</div>'; // Close datepicker_header
9303 return html;
9304 },
9305
9306 /* Adjust one of the date sub-fields. */
9307 _adjustInstDate: function(inst, offset, period) {
9308 var year = inst.drawYear + (period == 'Y' ? offset : 0);
9309 var month = inst.drawMonth + (period == 'M' ? offset : 0);
9310 var day = Math.min(inst.selectedDay, this._getDaysInMonth(year, month)) +
9311 (period == 'D' ? offset : 0);
9312 var date = this._daylightSavingAdjust(new Date(year, month, day));
9313 // ensure it is within the bounds set
9314 var minDate = this._getMinMaxDate(inst, 'min', true);
9315 var maxDate = this._getMinMaxDate(inst, 'max');
9316 date = (minDate && date < minDate ? minDate : date);
9317 date = (maxDate && date > maxDate ? maxDate : date);
9318 inst.selectedDay = date.getDate();
9319 inst.drawMonth = inst.selectedMonth = date.getMonth();
9320 inst.drawYear = inst.selectedYear = date.getFullYear();
9321 if (period == 'M' || period == 'Y')
9322 this._notifyChange(inst);
9323 },
9324
9325 /* Notify change of month/year. */
9326 _notifyChange: function(inst) {
9327 var onChange = this._get(inst, 'onChangeMonthYear');
9328 if (onChange)
9329 onChange.apply((inst.input ? inst.input[0] : null),
9330 [inst.selectedYear, inst.selectedMonth + 1, inst]);
9331 },
9332
9333 /* Determine the number of months to show. */
9334 _getNumberOfMonths: function(inst) {
9335 var numMonths = this._get(inst, 'numberOfMonths');
9336 return (numMonths == null ? [1, 1] : (typeof numMonths == 'number' ? [1, numMonths] : numMonths));
9337 },
9338
9339 /* Determine the current maximum date - ensure no time components are set - may be overridden for a range. */
9340 _getMinMaxDate: function(inst, minMax, checkRange) {
9341 var date = this._determineDate(this._get(inst, minMax + 'Date'), null);
9342 return (!checkRange || !inst.rangeStart ? date :
9343 (!date || inst.rangeStart > date ? inst.rangeStart : date));
9344 },
9345
9346 /* Find the number of days in a given month. */
9347 _getDaysInMonth: function(year, month) {
9348 return 32 - new Date(year, month, 32).getDate();
9349 },
9350
9351 /* Find the day of the week of the first of a month. */
9352 _getFirstDayOfMonth: function(year, month) {
9353 return new Date(year, month, 1).getDay();
9354 },
9355
9356 /* Determines if we should allow a "next/prev" month display change. */
9357 _canAdjustMonth: function(inst, offset, curYear, curMonth) {
9358 var numMonths = this._getNumberOfMonths(inst);
9359 var date = this._daylightSavingAdjust(new Date(
9360 curYear, curMonth + (offset < 0 ? offset : numMonths[1]), 1));
9361 if (offset < 0)
9362 date.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth()));
9363 return this._isInRange(inst, date);
9364 },
9365
9366 /* Is the given date in the accepted range? */
9367 _isInRange: function(inst, date) {
9368 // during range selection, use minimum of selected date and range start
9369 var newMinDate = (!inst.rangeStart ? null : this._daylightSavingAdjust(
9370 new Date(inst.selectedYear, inst.selectedMonth, inst.selectedDay)));
9371 newMinDate = (newMinDate && inst.rangeStart < newMinDate ? inst.rangeStart : newMinDate);
9372 var minDate = newMinDate || this._getMinMaxDate(inst, 'min');
9373 var maxDate = this._getMinMaxDate(inst, 'max');
9374 return ((!minDate || date >= minDate) && (!maxDate || date <= maxDate));
9375 },
9376
9377 /* Provide the configuration settings for formatting/parsing. */
9378 _getFormatConfig: function(inst) {
9379 var shortYearCutoff = this._get(inst, 'shortYearCutoff');
9380 shortYearCutoff = (typeof shortYearCutoff != 'string' ? shortYearCutoff :
9381 new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10));
9382 return {shortYearCutoff: shortYearCutoff,
9383 dayNamesShort: this._get(inst, 'dayNamesShort'), dayNames: this._get(inst, 'dayNames'),
9384 monthNamesShort: this._get(inst, 'monthNamesShort'), monthNames: this._get(inst, 'monthNames')};
9385 },
9386
9387 /* Format the given date for display. */
9388 _formatDate: function(inst, day, month, year) {
9389 if (!day) {
9390 inst.currentDay = inst.selectedDay;
9391 inst.currentMonth = inst.selectedMonth;
9392 inst.currentYear = inst.selectedYear;
9393 }
9394 var date = (day ? (typeof day == 'object' ? day :
9395 this._daylightSavingAdjust(new Date(year, month, day))) :
9396 this._daylightSavingAdjust(new Date(inst.currentYear, inst.currentMonth, inst.currentDay)));
9397 return this.formatDate(this._get(inst, 'dateFormat'), date, this._getFormatConfig(inst));
9398 }
9399 });
9400
9401 /* jQuery extend now ignores nulls! */
9402 function extendRemove(target, props) {
9403 $.extend(target, props);
9404 for (var name in props)
9405 if (props[name] == null || props[name] == undefined)
9406 target[name] = props[name];
9407 return target;
9408 };
9409
9410 /* Determine whether an object is an array. */
9411 function isArray(a) {
9412 return (a && (($.browser.safari && typeof a == 'object' && a.length) ||
9413 (a.constructor && a.constructor.toString().match(/\Array\(\)/))));
9414 };
9415
9416 /* Invoke the datepicker functionality.
9417 @param options string - a command, optionally followed by additional parameters or
9418 Object - settings for attaching new datepicker functionality
9419 @return jQuery object */
9420 $.fn.datepicker = function(options){
9421
9422 /* Initialise the date picker. */
9423 if (!$.datepicker.initialized) {
9424 $(document).mousedown($.datepicker._checkExternalClick).
9425 find('body').append($.datepicker.dpDiv);
9426 $.datepicker.initialized = true;
9427 }
9428
9429 var otherArgs = Array.prototype.slice.call(arguments, 1);
9430 if (typeof options == 'string' && (options == 'isDisabled' || options == 'getDate'))
9431 return $.datepicker['_' + options + 'Datepicker'].
9432 apply($.datepicker, [this[0]].concat(otherArgs));
9433 if (options == 'option' && arguments.length == 2 && typeof arguments[1] == 'string')
9434 return $.datepicker['_' + options + 'Datepicker'].
9435 apply($.datepicker, [this[0]].concat(otherArgs));
9436 return this.each(function() {
9437 typeof options == 'string' ?
9438 $.datepicker['_' + options + 'Datepicker'].
9439 apply($.datepicker, [this].concat(otherArgs)) :
9440 $.datepicker._attachDatepicker(this, options);
9441 });
9442 };
9443
9444 $.datepicker = new Datepicker(); // singleton instance
9445 $.datepicker.initialized = false;
9446 $.datepicker.uuid = new Date().getTime();
9447 $.datepicker.version = "1.7.2";
9448
9449 // Workaround for #4055
9450 // Add another global to avoid noConflict issues with inline event handlers
9451 window.DP_jQuery = $;
9452
9453 })(jQuery);
9454 /* JavaScript for MediaWIki JS2 */
9455
9456 /**
9457 * This is designed to be directly compatible with (and is essentially taken
9458 * directly from) the mv_embed code for bringing internationalized messages into
9459 * the JavaScript space. As such, if we get to the point of merging that stuff
9460 * into the main branch this code will be uneeded and probably cause issues.
9461 */
9462 // Creates global message object if not already in existence
9463 if ( !gMsg ) var gMsg = {};
9464 /**
9465 * Caches a list of messages for later retrieval
9466 * @param {Object} msgSet Hash of key:value pairs of messages to cache
9467 */
9468 function loadGM( msgSet ){
9469 for ( var i in msgSet ){
9470 gMsg[ i ] = msgSet[i];
9471 }
9472 }
9473 /**
9474 * Retieves a message from the global message cache, performing on-the-fly
9475 * replacements using MediaWiki message syntax ($1, $2, etc.)
9476 * @param {String} key Name of message as it is in MediaWiki
9477 * @param {Array} args Array of replacement arguments
9478 */
9479 function gM( key, args ) {
9480 var ms = '';
9481 if ( key in gMsg ) {
9482 ms = gMsg[ key ];
9483 if ( typeof args == 'object' || typeof args == 'array' ) {
9484 for ( var v in args ){
9485 var rep = '\$'+ ( parseInt(v) + 1 );
9486 ms = ms.replace( rep, args[v]);
9487 }
9488 } else if ( typeof args =='string' || typeof args =='number' ) {
9489 ms = ms.replace( /\$1/, args );
9490 }
9491 return ms;
9492 } else {
9493 return '[' + key + ']';
9494 }
9495 }
9496 /**
9497 * Mimics the no-conflict method used by the js2 stuff
9498 */
9499 $j = jQuery.noConflict();
9500 /**
9501 * Provides js2 compatible onload hook
9502 * @param func Function to call when ready
9503 */
9504 function js2AddOnloadHook( func ) {
9505 $j(document).ready( func );
9506 }
9507
9508 // Define a dummy mvJsLoader.doLoad() function
9509 mvJsLoader = { doLoad: function( deps, callback ) { callback(); } };