· 5 years ago · Feb 12, 2020, 02:00 PM
1(function( originalWindow, undefined ) {
2
3var window = originalWindow;
4
5// Use the correct document accordingly with window argument (sandbox)
6var document = window.document;
7
8// This value is computed at build time.
9var buildMetadata = {"date": "Wed Feb 12 08:54:26 2020", "commit": "eb49e3dcd3623ab7d8296d971ede9e740fae3499"};
10
11// We might be monkeypatching JSON later; if we do, ensure it's
12// our own private copy of JSON rather than the page's global one.
13var JSON = {
14 stringify: window.JSON && window.JSON.stringify,
15 parse: window.JSON && window.JSON.parse
16};
17/*
18 http://www.JSON.org/json2.js
19 2011-10-19
20
21 Public Domain.
22
23 NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
24
25 See http://www.JSON.org/js.html
26
27
28 This code should be minified before deployment.
29 See http://javascript.crockford.com/jsmin.html
30
31 USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
32 NOT CONTROL.
33
34
35 This file creates a global JSON object containing two methods: stringify
36 and parse.
37
38 JSON.stringify(value, replacer, space)
39 value any JavaScript value, usually an object or array.
40
41 replacer an optional parameter that determines how object
42 values are stringified for objects. It can be a
43 function or an array of strings.
44
45 space an optional parameter that specifies the indentation
46 of nested structures. If it is omitted, the text will
47 be packed without extra whitespace. If it is a number,
48 it will specify the number of spaces to indent at each
49 level. If it is a string (such as '\t' or ' '),
50 it contains the characters used to indent at each level.
51
52 This method produces a JSON text from a JavaScript value.
53
54 When an object value is found, if the object contains a toJSON
55 method, its toJSON method will be called and the result will be
56 stringified. A toJSON method does not serialize: it returns the
57 value represented by the name/value pair that should be serialized,
58 or undefined if nothing should be serialized. The toJSON method
59 will be passed the key associated with the value, and this will be
60 bound to the value
61
62 For example, this would serialize Dates as ISO strings.
63
64 Date.prototype.toJSON = function (key) {
65 function f(n) {
66 // Format integers to have at least two digits.
67 return n < 10 ? '0' + n : n;
68 }
69
70 return this.getUTCFullYear() + '-' +
71 f(this.getUTCMonth() + 1) + '-' +
72 f(this.getUTCDate()) + 'T' +
73 f(this.getUTCHours()) + ':' +
74 f(this.getUTCMinutes()) + ':' +
75 f(this.getUTCSeconds()) + 'Z';
76 };
77
78 You can provide an optional replacer method. It will be passed the
79 key and value of each member, with this bound to the containing
80 object. The value that is returned from your method will be
81 serialized. If your method returns undefined, then the member will
82 be excluded from the serialization.
83
84 If the replacer parameter is an array of strings, then it will be
85 used to select the members to be serialized. It filters the results
86 such that only members with keys listed in the replacer array are
87 stringified.
88
89 Values that do not have JSON representations, such as undefined or
90 functions, will not be serialized. Such values in objects will be
91 dropped; in arrays they will be replaced with null. You can use
92 a replacer function to replace those with JSON values.
93 JSON.stringify(undefined) returns undefined.
94
95 The optional space parameter produces a stringification of the
96 value that is filled with line breaks and indentation to make it
97 easier to read.
98
99 If the space parameter is a non-empty string, then that string will
100 be used for indentation. If the space parameter is a number, then
101 the indentation will be that many spaces.
102
103 Example:
104
105 text = JSON.stringify(['e', {pluribus: 'unum'}]);
106 // text is '["e",{"pluribus":"unum"}]'
107
108
109 text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
110 // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
111
112 text = JSON.stringify([new Date()], function (key, value) {
113 return this[key] instanceof Date ?
114 'Date(' + this[key] + ')' : value;
115 });
116 // text is '["Date(---current time---)"]'
117
118
119 JSON.parse(text, reviver)
120 This method parses a JSON text to produce an object or array.
121 It can throw a SyntaxError exception.
122
123 The optional reviver parameter is a function that can filter and
124 transform the results. It receives each of the keys and values,
125 and its return value is used instead of the original value.
126 If it returns what it received, then the structure is not modified.
127 If it returns undefined then the member is deleted.
128
129 Example:
130
131 // Parse the text. Values that look like ISO date strings will
132 // be converted to Date objects.
133
134 myData = JSON.parse(text, function (key, value) {
135 var a;
136 if (typeof value === 'string') {
137 a =
138/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
139 if (a) {
140 return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
141 +a[5], +a[6]));
142 }
143 }
144 return value;
145 });
146
147 myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
148 var d;
149 if (typeof value === 'string' &&
150 value.slice(0, 5) === 'Date(' &&
151 value.slice(-1) === ')') {
152 d = new Date(value.slice(5, -1));
153 if (d) {
154 return d;
155 }
156 }
157 return value;
158 });
159
160
161 This is a reference implementation. You are free to copy, modify, or
162 redistribute.
163*/
164
165/*jslint evil: true, regexp: true */
166
167/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
168 call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
169 getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
170 lastIndex, length, parse, prototype, push, replace, slice, stringify,
171 test, toJSON, toString, valueOf
172*/
173
174
175// Create a JSON object only if one does not already exist. We create the
176// methods in a closure to avoid creating global variables.
177
178var JSON;
179if (!JSON) {
180 JSON = {};
181}
182
183(function () {
184 'use strict';
185
186 function f(n) {
187 // Format integers to have at least two digits.
188 return n < 10 ? '0' + n : n;
189 }
190
191 if (typeof Date.prototype.toJSON !== 'function') {
192
193 Date.prototype.toJSON = function (key) {
194
195 return isFinite(this.valueOf())
196 ? this.getUTCFullYear() + '-' +
197 f(this.getUTCMonth() + 1) + '-' +
198 f(this.getUTCDate()) + 'T' +
199 f(this.getUTCHours()) + ':' +
200 f(this.getUTCMinutes()) + ':' +
201 f(this.getUTCSeconds()) + 'Z'
202 : null;
203 };
204
205 String.prototype.toJSON =
206 Number.prototype.toJSON =
207 Boolean.prototype.toJSON = function (key) {
208 return this.valueOf();
209 };
210 }
211
212 var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
213 escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
214 gap,
215 indent,
216 meta = { // table of character substitutions
217 '\b': '\\b',
218 '\t': '\\t',
219 '\n': '\\n',
220 '\f': '\\f',
221 '\r': '\\r',
222 '"' : '\\"',
223 '\\': '\\\\'
224 },
225 rep;
226
227
228 function quote(string) {
229
230// If the string contains no control characters, no quote characters, and no
231// backslash characters, then we can safely slap some quotes around it.
232// Otherwise we must also replace the offending characters with safe escape
233// sequences.
234
235 escapable.lastIndex = 0;
236 return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
237 var c = meta[a];
238 return typeof c === 'string'
239 ? c
240 : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
241 }) + '"' : '"' + string + '"';
242 }
243
244
245 function str(key, holder) {
246
247// Produce a string from holder[key].
248
249 var i, // The loop counter.
250 k, // The member key.
251 v, // The member value.
252 length,
253 mind = gap,
254 partial,
255 value = holder[key];
256
257// If the value has a toJSON method, call it to obtain a replacement value.
258
259 if (value && typeof value === 'object' &&
260 typeof value.toJSON === 'function') {
261 value = value.toJSON(key);
262 }
263
264// If we were called with a replacer function, then call the replacer to
265// obtain a replacement value.
266
267 if (typeof rep === 'function') {
268 value = rep.call(holder, key, value);
269 }
270
271// What happens next depends on the value's type.
272
273 switch (typeof value) {
274 case 'string':
275 return quote(value);
276
277 case 'number':
278
279// JSON numbers must be finite. Encode non-finite numbers as null.
280
281 return isFinite(value) ? String(value) : 'null';
282
283 case 'boolean':
284 case 'null':
285
286// If the value is a boolean or null, convert it to a string. Note:
287// typeof null does not produce 'null'. The case is included here in
288// the remote chance that this gets fixed someday.
289
290 return String(value);
291
292// If the type is 'object', we might be dealing with an object or an array or
293// null.
294
295 case 'object':
296
297// Due to a specification blunder in ECMAScript, typeof null is 'object',
298// so watch out for that case.
299
300 if (!value) {
301 return 'null';
302 }
303
304// Make an array to hold the partial results of stringifying this object value.
305
306 gap += indent;
307 partial = [];
308
309// Is the value an array?
310
311 if (Object.prototype.toString.apply(value) === '[object Array]') {
312
313// The value is an array. Stringify every element. Use null as a placeholder
314// for non-JSON values.
315
316 length = value.length;
317 for (i = 0; i < length; i += 1) {
318 partial[i] = str(i, value) || 'null';
319 }
320
321// Join all of the elements together, separated with commas, and wrap them in
322// brackets.
323
324 v = partial.length === 0
325 ? '[]'
326 : gap
327 ? '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']'
328 : '[' + partial.join(',') + ']';
329 gap = mind;
330 return v;
331 }
332
333// If the replacer is an array, use it to select the members to be stringified.
334
335 if (rep && typeof rep === 'object') {
336 length = rep.length;
337 for (i = 0; i < length; i += 1) {
338 if (typeof rep[i] === 'string') {
339 k = rep[i];
340 v = str(k, value);
341 if (v) {
342 partial.push(quote(k) + (gap ? ': ' : ':') + v);
343 }
344 }
345 }
346 } else {
347
348// Otherwise, iterate through all of the keys in the object.
349
350 for (k in value) {
351 if (Object.prototype.hasOwnProperty.call(value, k)) {
352 v = str(k, value);
353 if (v) {
354 partial.push(quote(k) + (gap ? ': ' : ':') + v);
355 }
356 }
357 }
358 }
359
360// Join all of the member texts together, separated with commas,
361// and wrap them in braces.
362
363 v = partial.length === 0
364 ? '{}'
365 : gap
366 ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}'
367 : '{' + partial.join(',') + '}';
368 gap = mind;
369 return v;
370 }
371 }
372
373// If the JSON object does not yet have a stringify method, give it one.
374
375 if (typeof JSON.stringify !== 'function') {
376 JSON.stringify = function (value, replacer, space) {
377
378// The stringify method takes a value and an optional replacer, and an optional
379// space parameter, and returns a JSON text. The replacer can be a function
380// that can replace values, or an array of strings that will select the keys.
381// A default replacer method can be provided. Use of the space parameter can
382// produce text that is more easily readable.
383
384 var i;
385 gap = '';
386 indent = '';
387
388// If the space parameter is a number, make an indent string containing that
389// many spaces.
390
391 if (typeof space === 'number') {
392 for (i = 0; i < space; i += 1) {
393 indent += ' ';
394 }
395
396// If the space parameter is a string, it will be used as the indent string.
397
398 } else if (typeof space === 'string') {
399 indent = space;
400 }
401
402// If there is a replacer, it must be a function or an array.
403// Otherwise, throw an error.
404
405 rep = replacer;
406 if (replacer && typeof replacer !== 'function' &&
407 (typeof replacer !== 'object' ||
408 typeof replacer.length !== 'number')) {
409 throw new Error('JSON.stringify');
410 }
411
412// Make a fake root object containing our value under the key of ''.
413// Return the result of stringifying the value.
414
415 return str('', {'': value});
416 };
417 }
418
419
420// If the JSON object does not yet have a parse method, give it one.
421
422 if (typeof JSON.parse !== 'function') {
423 JSON.parse = function (text, reviver) {
424
425// The parse method takes a text and an optional reviver function, and returns
426// a JavaScript value if the text is a valid JSON text.
427
428 var j;
429
430 function walk(holder, key) {
431
432// The walk method is used to recursively walk the resulting structure so
433// that modifications can be made.
434
435 var k, v, value = holder[key];
436 if (value && typeof value === 'object') {
437 for (k in value) {
438 if (Object.prototype.hasOwnProperty.call(value, k)) {
439 v = walk(value, k);
440 if (v !== undefined) {
441 value[k] = v;
442 } else {
443 delete value[k];
444 }
445 }
446 }
447 }
448 return reviver.call(holder, key, value);
449 }
450
451
452// Parsing happens in four stages. In the first stage, we replace certain
453// Unicode characters with escape sequences. JavaScript handles many characters
454// incorrectly, either silently deleting them, or treating them as line endings.
455
456 text = String(text);
457 cx.lastIndex = 0;
458 if (cx.test(text)) {
459 text = text.replace(cx, function (a) {
460 return '\\u' +
461 ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
462 });
463 }
464
465// In the second stage, we run the text against regular expressions that look
466// for non-JSON patterns. We are especially concerned with '()' and 'new'
467// because they can cause invocation, and '=' because it can cause mutation.
468// But just to be safe, we want to reject all unexpected forms.
469
470// We split the second stage into 4 regexp operations in order to work around
471// crippling inefficiencies in IE's and Safari's regexp engines. First we
472// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
473// replace all simple value tokens with ']' characters. Third, we delete all
474// open brackets that follow a colon or comma or that begin the text. Finally,
475// we look to see that the remaining characters are only whitespace or ']' or
476// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
477
478 if (/^[\],:{}\s]*$/
479 .test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
480 .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
481 .replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
482
483// In the third stage we use the eval function to compile the text into a
484// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
485// in JavaScript: it can begin a block or an object literal. We wrap the text
486// in parens to eliminate the ambiguity.
487
488 j = eval('(' + text + ')');
489
490// In the optional fourth stage, we recursively walk the new structure, passing
491// each name/value pair to a reviver function for possible transformation.
492
493 return typeof reviver === 'function'
494 ? walk({'': j}, '')
495 : j;
496 }
497
498// If the text is not JSON parseable, then a SyntaxError is thrown.
499
500 throw new SyntaxError('JSON.parse');
501 };
502 }
503}());
504
505// Override JSON.stringify with our safe version within the
506// goggles to avoid Array.prototype.toJSON getting in the way.
507// See http://stackoverflow.com/questions/710586/json-stringify-bizarreness
508JSON._unsafeStringify = JSON.stringify;
509JSON.stringify = function(value){
510 var restore = Array.prototype.toJSON;
511 try {
512 delete Array.prototype.toJSON;
513 var stringified = this._unsafeStringify(value);
514 } finally {
515 Array.prototype.toJSON = restore;
516 }
517 return stringified;
518};
519var jQuery = (function() {
520
521// Define a local copy of jQuery
522var jQuery = function( selector, context ) {
523 // The jQuery object is actually just the init constructor 'enhanced'
524 return new jQuery.fn.init( selector, context, rootjQuery );
525 },
526
527 // Map over jQuery in case of overwrite
528 _jQuery = window.jQuery,
529
530 // Map over the $ in case of overwrite
531 _$ = window.$,
532
533 // A central reference to the root jQuery(document)
534 rootjQuery,
535
536 // A simple way to check for HTML strings or ID strings
537 // Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
538 quickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,
539
540 // Check if a string has a non-whitespace character in it
541 rnotwhite = /\S/,
542
543 // Used for trimming whitespace
544 trimLeft = /^\s+/,
545 trimRight = /\s+$/,
546
547 // Check for digits
548 rdigit = /\d/,
549
550 // Match a standalone tag
551 rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/,
552
553 // JSON RegExp
554 rvalidchars = /^[\],:{}\s]*$/,
555 rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,
556 rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,
557 rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g,
558
559 // Useragent RegExp
560 rwebkit = /(webkit)[ \/]([\w.]+)/,
561 ropera = /(opera)(?:.*version)?[ \/]([\w.]+)/,
562 rmsie = /(msie) ([\w.]+)/,
563 rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/,
564
565 // Matches dashed string for camelizing
566 rdashAlpha = /-([a-z]|[0-9])/ig,
567 rmsPrefix = /^-ms-/,
568
569 // Used by jQuery.camelCase as callback to replace()
570 fcamelCase = function( all, letter ) {
571 return ( letter + "" ).toUpperCase();
572 },
573
574 // Keep a UserAgent string for use with jQuery.browser
575 userAgent = navigator.userAgent,
576
577 // For matching the engine and version of the browser
578 browserMatch,
579
580 // The deferred used on DOM ready
581 readyList,
582
583 // The ready event handler
584 DOMContentLoaded,
585
586 // Save a reference to some core methods
587 toString = Object.prototype.toString,
588 hasOwn = Object.prototype.hasOwnProperty,
589 push = Array.prototype.push,
590 slice = Array.prototype.slice,
591 trim = String.prototype.trim,
592 indexOf = Array.prototype.indexOf,
593
594 // [[Class]] -> type pairs
595 class2type = {};
596
597jQuery.fn = jQuery.prototype = {
598 constructor: jQuery,
599 init: function( selector, context, rootjQuery ) {
600 var match, elem, ret, doc;
601
602 // Handle $(""), $(null), or $(undefined)
603 if ( !selector ) {
604 return this;
605 }
606
607 // Handle $(DOMElement)
608 if ( selector.nodeType ) {
609 this.context = this[0] = selector;
610 this.length = 1;
611 return this;
612 }
613
614 // The body element only exists once, optimize finding it
615 if ( selector === "body" && !context && document.body ) {
616 this.context = document;
617 this[0] = document.body;
618 this.selector = selector;
619 this.length = 1;
620 return this;
621 }
622
623 // Handle HTML strings
624 if ( typeof selector === "string" ) {
625 // Are we dealing with HTML string or an ID?
626 if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
627 // Assume that strings that start and end with <> are HTML and skip the regex check
628 match = [ null, selector, null ];
629
630 } else {
631 match = quickExpr.exec( selector );
632 }
633
634 // Verify a match, and that no context was specified for #id
635 if ( match && (match[1] || !context) ) {
636
637 // HANDLE: $(html) -> $(array)
638 if ( match[1] ) {
639 context = context instanceof jQuery ? context[0] : context;
640 doc = ( context ? context.ownerDocument || context : document );
641
642 // If a single string is passed in and it's a single tag
643 // just do a createElement and skip the rest
644 ret = rsingleTag.exec( selector );
645
646 if ( ret ) {
647 if ( jQuery.isPlainObject( context ) ) {
648 selector = [ document.createElement( ret[1] ) ];
649 jQuery.fn.attr.call( selector, context, true );
650
651 } else {
652 selector = [ doc.createElement( ret[1] ) ];
653 }
654
655 } else {
656 ret = jQuery.buildFragment( [ match[1] ], [ doc ] );
657 selector = ( ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment ).childNodes;
658 }
659
660 return jQuery.merge( this, selector );
661
662 // HANDLE: $("#id")
663 } else {
664 elem = document.getElementById( match[2] );
665
666 // Check parentNode to catch when Blackberry 4.6 returns
667 // nodes that are no longer in the document #6963
668 if ( elem && elem.parentNode ) {
669 // Handle the case where IE and Opera return items
670 // by name instead of ID
671 if ( elem.id !== match[2] ) {
672 return rootjQuery.find( selector );
673 }
674
675 // Otherwise, we inject the element directly into the jQuery object
676 this.length = 1;
677 this[0] = elem;
678 }
679
680 this.context = document;
681 this.selector = selector;
682 return this;
683 }
684
685 // HANDLE: $(expr, $(...))
686 } else if ( !context || context.jquery ) {
687 return ( context || rootjQuery ).find( selector );
688
689 // HANDLE: $(expr, context)
690 // (which is just equivalent to: $(context).find(expr)
691 } else {
692 return this.constructor( context ).find( selector );
693 }
694
695 // HANDLE: $(function)
696 // Shortcut for document ready
697 } else if ( jQuery.isFunction( selector ) ) {
698 return rootjQuery.ready( selector );
699 }
700
701 if ( selector.selector !== undefined ) {
702 this.selector = selector.selector;
703 this.context = selector.context;
704 }
705
706 return jQuery.makeArray( selector, this );
707 },
708
709 // Start with an empty selector
710 selector: "",
711
712 // The current version of jQuery being used
713 jquery: "@VERSION",
714
715 // The default length of a jQuery object is 0
716 length: 0,
717
718 // The number of elements contained in the matched element set
719 size: function() {
720 return this.length;
721 },
722
723 toArray: function() {
724 return slice.call( this, 0 );
725 },
726
727 // Get the Nth element in the matched element set OR
728 // Get the whole matched element set as a clean array
729 get: function( num ) {
730 return num == null ?
731
732 // Return a 'clean' array
733 this.toArray() :
734
735 // Return just the object
736 ( num < 0 ? this[ this.length + num ] : this[ num ] );
737 },
738
739 // Take an array of elements and push it onto the stack
740 // (returning the new matched element set)
741 pushStack: function( elems, name, selector ) {
742 // Build a new jQuery matched element set
743 var ret = this.constructor();
744
745 if ( jQuery.isArray( elems ) ) {
746 push.apply( ret, elems );
747
748 } else {
749 jQuery.merge( ret, elems );
750 }
751
752 // Add the old object onto the stack (as a reference)
753 ret.prevObject = this;
754
755 ret.context = this.context;
756
757 if ( name === "find" ) {
758 ret.selector = this.selector + ( this.selector ? " " : "" ) + selector;
759 } else if ( name ) {
760 ret.selector = this.selector + "." + name + "(" + selector + ")";
761 }
762
763 // Return the newly-formed element set
764 return ret;
765 },
766
767 // Execute a callback for every element in the matched set.
768 // (You can seed the arguments with an array of args, but this is
769 // only used internally.)
770 each: function( callback, args ) {
771 return jQuery.each( this, callback, args );
772 },
773
774 ready: function( fn ) {
775 // Attach the listeners
776 jQuery.bindReady();
777
778 // Add the callback
779 readyList.add( fn );
780
781 return this;
782 },
783
784 eq: function( i ) {
785 return i === -1 ?
786 this.slice( i ) :
787 this.slice( i, +i + 1 );
788 },
789
790 first: function() {
791 return this.eq( 0 );
792 },
793
794 last: function() {
795 return this.eq( -1 );
796 },
797
798 slice: function() {
799 return this.pushStack( slice.apply( this, arguments ),
800 "slice", slice.call(arguments).join(",") );
801 },
802
803 map: function( callback ) {
804 return this.pushStack( jQuery.map(this, function( elem, i ) {
805 return callback.call( elem, i, elem );
806 }));
807 },
808
809 end: function() {
810 return this.prevObject || this.constructor(null);
811 },
812
813 // For internal use only.
814 // Behaves like an Array's method, not like a jQuery method.
815 push: push,
816 sort: [].sort,
817 splice: [].splice
818};
819
820// Give the init function the jQuery prototype for later instantiation
821jQuery.fn.init.prototype = jQuery.fn;
822
823jQuery.extend = jQuery.fn.extend = function() {
824 var options, name, src, copy, copyIsArray, clone,
825 target = arguments[0] || {},
826 i = 1,
827 length = arguments.length,
828 deep = false;
829
830 // Handle a deep copy situation
831 if ( typeof target === "boolean" ) {
832 deep = target;
833 target = arguments[1] || {};
834 // skip the boolean and the target
835 i = 2;
836 }
837
838 // Handle case when target is a string or something (possible in deep copy)
839 if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
840 target = {};
841 }
842
843 // extend jQuery itself if only one argument is passed
844 if ( length === i ) {
845 target = this;
846 --i;
847 }
848
849 for ( ; i < length; i++ ) {
850 // Only deal with non-null/undefined values
851 if ( (options = arguments[ i ]) != null ) {
852 // Extend the base object
853 for ( name in options ) {
854 src = target[ name ];
855 copy = options[ name ];
856
857 // Prevent never-ending loop
858 if ( target === copy ) {
859 continue;
860 }
861
862 // Recurse if we're merging plain objects or arrays
863 if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
864 if ( copyIsArray ) {
865 copyIsArray = false;
866 clone = src && jQuery.isArray(src) ? src : [];
867
868 } else {
869 clone = src && jQuery.isPlainObject(src) ? src : {};
870 }
871
872 // Never move original objects, clone them
873 target[ name ] = jQuery.extend( deep, clone, copy );
874
875 // Don't bring in undefined values
876 } else if ( copy !== undefined ) {
877 target[ name ] = copy;
878 }
879 }
880 }
881 }
882
883 // Return the modified object
884 return target;
885};
886
887jQuery.extend({
888 noConflict: function( deep ) {
889 if ( window.$ === jQuery ) {
890 window.$ = _$;
891 }
892
893 if ( deep && window.jQuery === jQuery ) {
894 window.jQuery = _jQuery;
895 }
896
897 return jQuery;
898 },
899
900 // Is the DOM ready to be used? Set to true once it occurs.
901 isReady: false,
902
903 // A counter to track how many items to wait for before
904 // the ready event fires. See #6781
905 readyWait: 1,
906
907 // Hold (or release) the ready event
908 holdReady: function( hold ) {
909 if ( hold ) {
910 jQuery.readyWait++;
911 } else {
912 jQuery.ready( true );
913 }
914 },
915
916 // Handle when the DOM is ready
917 ready: function( wait ) {
918 // Either a released hold or an DOMready/load event and not yet ready
919 if ( (wait === true && !--jQuery.readyWait) || (wait !== true && !jQuery.isReady) ) {
920 // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
921 if ( !document.body ) {
922 return setTimeout( jQuery.ready, 1 );
923 }
924
925 // Remember that the DOM is ready
926 jQuery.isReady = true;
927
928 // If a normal DOM Ready event fired, decrement, and wait if need be
929 if ( wait !== true && --jQuery.readyWait > 0 ) {
930 return;
931 }
932
933 // If there are functions bound, to execute
934 readyList.fireWith( document, [ jQuery ] );
935
936 // Trigger any bound ready events
937 if ( jQuery.fn.trigger ) {
938 jQuery( document ).trigger( "ready" ).unbind( "ready" );
939 }
940 }
941 },
942
943 bindReady: function() {
944 if ( readyList ) {
945 return;
946 }
947
948 readyList = jQuery.Callbacks( "once memory" );
949
950 // Catch cases where $(document).ready() is called after the
951 // browser event has already occurred.
952 if ( document.readyState === "complete" ) {
953 // Handle it asynchronously to allow scripts the opportunity to delay ready
954 return setTimeout( jQuery.ready, 1 );
955 }
956
957 // Mozilla, Opera and webkit nightlies currently support this event
958 if ( document.addEventListener ) {
959 // Use the handy event callback
960 document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
961
962 // A fallback to window.onload, that will always work
963 window.addEventListener( "load", jQuery.ready, false );
964
965 // If IE event model is used
966 } else if ( document.attachEvent ) {
967 // ensure firing before onload,
968 // maybe late but safe also for iframes
969 document.attachEvent( "onreadystatechange", DOMContentLoaded );
970
971 // A fallback to window.onload, that will always work
972 window.attachEvent( "onload", jQuery.ready );
973
974 // If IE and not a frame
975 // continually check to see if the document is ready
976 var toplevel = false;
977
978 try {
979 toplevel = window.frameElement == null;
980 } catch(e) {}
981
982 if ( document.documentElement.doScroll && toplevel ) {
983 doScrollCheck();
984 }
985 }
986 },
987
988 // See test/unit/core.js for details concerning isFunction.
989 // Since version 1.3, DOM methods and functions like alert
990 // aren't supported. They return false on IE (#2968).
991 isFunction: function( obj ) {
992 return jQuery.type(obj) === "function";
993 },
994
995 isArray: Array.isArray || function( obj ) {
996 return jQuery.type(obj) === "array";
997 },
998
999 // A crude way of determining if an object is a window
1000 isWindow: function( obj ) {
1001 return obj && typeof obj === "object" && "setInterval" in obj;
1002 },
1003
1004 isNumeric: function( obj ) {
1005 return obj != null && rdigit.test( obj ) && !isNaN( obj );
1006 },
1007
1008 type: function( obj ) {
1009 return obj == null ?
1010 String( obj ) :
1011 class2type[ toString.call(obj) ] || "object";
1012 },
1013
1014 isPlainObject: function( obj ) {
1015 // Must be an Object.
1016 // Because of IE, we also have to check the presence of the constructor property.
1017 // Make sure that DOM nodes and window objects don't pass through, as well
1018 if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
1019 return false;
1020 }
1021
1022 try {
1023 // Not own constructor property must be Object
1024 if ( obj.constructor &&
1025 !hasOwn.call(obj, "constructor") &&
1026 !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
1027 return false;
1028 }
1029 } catch ( e ) {
1030 // IE8,9 Will throw exceptions on certain host objects #9897
1031 return false;
1032 }
1033
1034 // Own properties are enumerated firstly, so to speed up,
1035 // if last one is own, then all properties are own.
1036
1037 var key;
1038 for ( key in obj ) {}
1039
1040 return key === undefined || hasOwn.call( obj, key );
1041 },
1042
1043 isEmptyObject: function( obj ) {
1044 for ( var name in obj ) {
1045 return false;
1046 }
1047 return true;
1048 },
1049
1050 error: function( msg ) {
1051 throw msg;
1052 },
1053
1054 parseJSON: function( data ) {
1055 if ( typeof data !== "string" || !data ) {
1056 return null;
1057 }
1058
1059 // Make sure leading/trailing whitespace is removed (IE can't handle it)
1060 data = jQuery.trim( data );
1061
1062 // Attempt to parse using the native JSON parser first
1063 if ( window.JSON && window.JSON.parse ) {
1064 return window.JSON.parse( data );
1065 }
1066
1067 // Make sure the incoming data is actual JSON
1068 // Logic borrowed from http://json.org/json2.js
1069 if ( rvalidchars.test( data.replace( rvalidescape, "@" )
1070 .replace( rvalidtokens, "]" )
1071 .replace( rvalidbraces, "")) ) {
1072
1073 return ( new Function( "return " + data ) )();
1074
1075 }
1076 jQuery.error( "Invalid JSON: " + data );
1077 },
1078
1079 // Cross-browser xml parsing
1080 parseXML: function( data ) {
1081 var xml, tmp;
1082 try {
1083 if ( window.DOMParser ) { // Standard
1084 tmp = new DOMParser();
1085 xml = tmp.parseFromString( data , "text/xml" );
1086 } else { // IE
1087 xml = new ActiveXObject( "Microsoft.XMLDOM" );
1088 xml.async = "false";
1089 xml.loadXML( data );
1090 }
1091 } catch( e ) {
1092 xml = undefined;
1093 }
1094 if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) {
1095 jQuery.error( "Invalid XML: " + data );
1096 }
1097 return xml;
1098 },
1099
1100 noop: function() {},
1101
1102 // Evaluates a script in a global context
1103 // Workarounds based on findings by Jim Driscoll
1104 // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context
1105 globalEval: function( data ) {
1106 if ( data && rnotwhite.test( data ) ) {
1107 // We use execScript on Internet Explorer
1108 // We use an anonymous function so that context is window
1109 // rather than jQuery in Firefox
1110 ( window.execScript || function( data ) {
1111 window[ "eval" ].call( window, data );
1112 } )( data );
1113 }
1114 },
1115
1116 // Convert dashed to camelCase; used by the css and data modules
1117 // Microsoft forgot to hump their vendor prefix (#9572)
1118 camelCase: function( string ) {
1119 return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
1120 },
1121
1122 nodeName: function( elem, name ) {
1123 return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase();
1124 },
1125
1126 // args is for internal usage only
1127 each: function( object, callback, args ) {
1128 var name, i = 0,
1129 length = object.length,
1130 isObj = length === undefined || jQuery.isFunction( object );
1131
1132 if ( args ) {
1133 if ( isObj ) {
1134 for ( name in object ) {
1135 if ( callback.apply( object[ name ], args ) === false ) {
1136 break;
1137 }
1138 }
1139 } else {
1140 for ( ; i < length; ) {
1141 if ( callback.apply( object[ i++ ], args ) === false ) {
1142 break;
1143 }
1144 }
1145 }
1146
1147 // A special, fast, case for the most common use of each
1148 } else {
1149 if ( isObj ) {
1150 for ( name in object ) {
1151 if ( callback.call( object[ name ], name, object[ name ] ) === false ) {
1152 break;
1153 }
1154 }
1155 } else {
1156 for ( ; i < length; ) {
1157 if ( callback.call( object[ i ], i, object[ i++ ] ) === false ) {
1158 break;
1159 }
1160 }
1161 }
1162 }
1163
1164 return object;
1165 },
1166
1167 // Use native String.trim function wherever possible
1168 trim: trim ?
1169 function( text ) {
1170 return text == null ?
1171 "" :
1172 trim.call( text );
1173 } :
1174
1175 // Otherwise use our own trimming functionality
1176 function( text ) {
1177 return text == null ?
1178 "" :
1179 text.toString().replace( trimLeft, "" ).replace( trimRight, "" );
1180 },
1181
1182 // results is for internal usage only
1183 makeArray: function( array, results ) {
1184 var ret = results || [];
1185
1186 if ( array != null ) {
1187 // The window, strings (and functions) also have 'length'
1188 // The extra typeof function check is to prevent crashes
1189 // in Safari 2 (See: #3039)
1190 // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930
1191 var type = jQuery.type( array );
1192
1193 if ( array.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( array ) ) {
1194 push.call( ret, array );
1195 } else {
1196 jQuery.merge( ret, array );
1197 }
1198 }
1199
1200 return ret;
1201 },
1202
1203 inArray: function( elem, array, i ) {
1204 var len;
1205
1206 if ( array ) {
1207 if ( indexOf ) {
1208 return indexOf.call( array, elem, i );
1209 }
1210
1211 len = array.length;
1212 i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0;
1213
1214 for ( ; i < len; i++ ) {
1215 // Skip accessing in sparse arrays
1216 if ( i in array && array[ i ] === elem ) {
1217 return i;
1218 }
1219 }
1220 }
1221
1222 return -1;
1223 },
1224
1225 merge: function( first, second ) {
1226 var i = first.length,
1227 j = 0;
1228
1229 if ( typeof second.length === "number" ) {
1230 for ( var l = second.length; j < l; j++ ) {
1231 first[ i++ ] = second[ j ];
1232 }
1233
1234 } else {
1235 while ( second[j] !== undefined ) {
1236 first[ i++ ] = second[ j++ ];
1237 }
1238 }
1239
1240 first.length = i;
1241
1242 return first;
1243 },
1244
1245 grep: function( elems, callback, inv ) {
1246 var ret = [], retVal;
1247 inv = !!inv;
1248
1249 // Go through the array, only saving the items
1250 // that pass the validator function
1251 for ( var i = 0, length = elems.length; i < length; i++ ) {
1252 retVal = !!callback( elems[ i ], i );
1253 if ( inv !== retVal ) {
1254 ret.push( elems[ i ] );
1255 }
1256 }
1257
1258 return ret;
1259 },
1260
1261 // arg is for internal usage only
1262 map: function( elems, callback, arg ) {
1263 var value, key, ret = [],
1264 i = 0,
1265 length = elems.length,
1266 // jquery objects are treated as arrays
1267 isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ;
1268
1269 // Go through the array, translating each of the items to their
1270 if ( isArray ) {
1271 for ( ; i < length; i++ ) {
1272 value = callback( elems[ i ], i, arg );
1273
1274 if ( value != null ) {
1275 ret[ ret.length ] = value;
1276 }
1277 }
1278
1279 // Go through every key on the object,
1280 } else {
1281 for ( key in elems ) {
1282 value = callback( elems[ key ], key, arg );
1283
1284 if ( value != null ) {
1285 ret[ ret.length ] = value;
1286 }
1287 }
1288 }
1289
1290 // Flatten any nested arrays
1291 return ret.concat.apply( [], ret );
1292 },
1293
1294 // A global GUID counter for objects
1295 guid: 1,
1296
1297 // Bind a function to a context, optionally partially applying any
1298 // arguments.
1299 proxy: function( fn, context ) {
1300 if ( typeof context === "string" ) {
1301 var tmp = fn[ context ];
1302 context = fn;
1303 fn = tmp;
1304 }
1305
1306 // Quick check to determine if target is callable, in the spec
1307 // this throws a TypeError, but we will just return undefined.
1308 if ( !jQuery.isFunction( fn ) ) {
1309 return undefined;
1310 }
1311
1312 // Simulated bind
1313 var args = slice.call( arguments, 2 ),
1314 proxy = function() {
1315 return fn.apply( context, args.concat( slice.call( arguments ) ) );
1316 };
1317
1318 // Set the guid of unique handler to the same of original handler, so it can be removed
1319 proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++;
1320
1321 return proxy;
1322 },
1323
1324 // Mutifunctional method to get and set values to a collection
1325 // The value/s can optionally be executed if it's a function
1326 access: function( elems, key, value, exec, fn, pass ) {
1327 var length = elems.length;
1328
1329 // Setting many attributes
1330 if ( typeof key === "object" ) {
1331 for ( var k in key ) {
1332 jQuery.access( elems, k, key[k], exec, fn, value );
1333 }
1334 return elems;
1335 }
1336
1337 // Setting one attribute
1338 if ( value !== undefined ) {
1339 // Optionally, function values get executed if exec is true
1340 exec = !pass && exec && jQuery.isFunction(value);
1341
1342 for ( var i = 0; i < length; i++ ) {
1343 fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass );
1344 }
1345
1346 return elems;
1347 }
1348
1349 // Getting an attribute
1350 return length ? fn( elems[0], key ) : undefined;
1351 },
1352
1353 now: function() {
1354 return ( new Date() ).getTime();
1355 },
1356
1357 // Use of jQuery.browser is frowned upon.
1358 // More details: http://docs.jquery.com/Utilities/jQuery.browser
1359 uaMatch: function( ua ) {
1360 ua = ua.toLowerCase();
1361
1362 var match = rwebkit.exec( ua ) ||
1363 ropera.exec( ua ) ||
1364 rmsie.exec( ua ) ||
1365 ua.indexOf("compatible") < 0 && rmozilla.exec( ua ) ||
1366 [];
1367
1368 return { browser: match[1] || "", version: match[2] || "0" };
1369 },
1370
1371 sub: function() {
1372 function jQuerySub( selector, context ) {
1373 return new jQuerySub.fn.init( selector, context );
1374 }
1375 jQuery.extend( true, jQuerySub, this );
1376 jQuerySub.superclass = this;
1377 jQuerySub.fn = jQuerySub.prototype = this();
1378 jQuerySub.fn.constructor = jQuerySub;
1379 jQuerySub.sub = this.sub;
1380 jQuerySub.fn.init = function init( selector, context ) {
1381 if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) {
1382 context = jQuerySub( context );
1383 }
1384
1385 return jQuery.fn.init.call( this, selector, context, rootjQuerySub );
1386 };
1387 jQuerySub.fn.init.prototype = jQuerySub.fn;
1388 var rootjQuerySub = jQuerySub(document);
1389 return jQuerySub;
1390 },
1391
1392 browser: {}
1393});
1394
1395// Populate the class2type map
1396jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) {
1397 class2type[ "[object " + name + "]" ] = name.toLowerCase();
1398});
1399
1400browserMatch = jQuery.uaMatch( userAgent );
1401if ( browserMatch.browser ) {
1402 jQuery.browser[ browserMatch.browser ] = true;
1403 jQuery.browser.version = browserMatch.version;
1404}
1405
1406// Deprecated, use jQuery.browser.webkit instead
1407if ( jQuery.browser.webkit ) {
1408 jQuery.browser.safari = true;
1409}
1410
1411// IE doesn't match non-breaking spaces with \s
1412if ( rnotwhite.test( "\xA0" ) ) {
1413 trimLeft = /^[\s\xA0]+/;
1414 trimRight = /[\s\xA0]+$/;
1415}
1416
1417// All jQuery objects should point back to these
1418rootjQuery = jQuery(document);
1419
1420// Cleanup functions for the document ready method
1421if ( document.addEventListener ) {
1422 DOMContentLoaded = function() {
1423 document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false );
1424 jQuery.ready();
1425 };
1426
1427} else if ( document.attachEvent ) {
1428 DOMContentLoaded = function() {
1429 // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
1430 if ( document.readyState === "complete" ) {
1431 document.detachEvent( "onreadystatechange", DOMContentLoaded );
1432 jQuery.ready();
1433 }
1434 };
1435}
1436
1437// The DOM ready check for Internet Explorer
1438function doScrollCheck() {
1439 if ( jQuery.isReady ) {
1440 return;
1441 }
1442
1443 try {
1444 // If IE is used, use the trick by Diego Perini
1445 // http://javascript.nwbox.com/IEContentLoaded/
1446 document.documentElement.doScroll("left");
1447 } catch(e) {
1448 setTimeout( doScrollCheck, 1 );
1449 return;
1450 }
1451
1452 // and execute any waiting functions
1453 jQuery.ready();
1454}
1455
1456// Expose jQuery as an AMD module, but only for AMD loaders that
1457// understand the issues with loading multiple versions of jQuery
1458// in a page that all might call define(). The loader will indicate
1459// they have special allowances for multiple jQuery versions by
1460// specifying define.amd.jQuery = true. Register as a named module,
1461// since jQuery can be concatenated with other files that may use define,
1462// but not use a proper concatenation script that understands anonymous
1463// AMD modules. A named AMD is safest and most robust way to register.
1464// Lowercase jquery is used because AMD module names are derived from
1465// file names, and jQuery is normally delivered in a lowercase file name.
1466if ( typeof define === "function" && define.amd && define.amd.jQuery ) {
1467 define( "jquery", [], function () { return jQuery; } );
1468}
1469
1470return jQuery;
1471
1472})();
1473(function( jQuery ) {
1474
1475// String to Object flags format cache
1476var flagsCache = {};
1477
1478// Convert String-formatted flags into Object-formatted ones and store in cache
1479function createFlags( flags ) {
1480 var object = flagsCache[ flags ] = {},
1481 i, length;
1482 flags = flags.split( /\s+/ );
1483 for ( i = 0, length = flags.length; i < length; i++ ) {
1484 object[ flags[i] ] = true;
1485 }
1486 return object;
1487}
1488
1489/*
1490 * Create a callback list using the following parameters:
1491 *
1492 * flags: an optional list of space-separated flags that will change how
1493 * the callback list behaves
1494 *
1495 * By default a callback list will act like an event callback list and can be
1496 * "fired" multiple times.
1497 *
1498 * Possible flags:
1499 *
1500 * once: will ensure the callback list can only be fired once (like a Deferred)
1501 *
1502 * memory: will keep track of previous values and will call any callback added
1503 * after the list has been fired right away with the latest "memorized"
1504 * values (like a Deferred)
1505 *
1506 * unique: will ensure a callback can only be added once (no duplicate in the list)
1507 *
1508 * stopOnFalse: interrupt callings when a callback returns false
1509 *
1510 */
1511jQuery.Callbacks = function( flags ) {
1512
1513 // Convert flags from String-formatted to Object-formatted
1514 // (we check in cache first)
1515 flags = flags ? ( flagsCache[ flags ] || createFlags( flags ) ) : {};
1516
1517 var // Actual callback list
1518 list = [],
1519 // Stack of fire calls for repeatable lists
1520 stack = [],
1521 // Last fire value (for non-forgettable lists)
1522 memory,
1523 // Flag to know if list is currently firing
1524 firing,
1525 // First callback to fire (used internally by add and fireWith)
1526 firingStart,
1527 // End of the loop when firing
1528 firingLength,
1529 // Index of currently firing callback (modified by remove if needed)
1530 firingIndex,
1531 // Add one or several callbacks to the list
1532 add = function( args ) {
1533 var i,
1534 length,
1535 elem,
1536 type,
1537 actual;
1538 for ( i = 0, length = args.length; i < length; i++ ) {
1539 elem = args[ i ];
1540 type = jQuery.type( elem );
1541 if ( type === "array" ) {
1542 // Inspect recursively
1543 add( elem );
1544 } else if ( type === "function" ) {
1545 // Add if not in unique mode and callback is not in
1546 if ( !flags.unique || !self.has( elem ) ) {
1547 list.push( elem );
1548 }
1549 }
1550 }
1551 },
1552 // Fire callbacks
1553 fire = function( context, args ) {
1554 args = args || [];
1555 memory = !flags.memory || [ context, args ];
1556 firing = true;
1557 firingIndex = firingStart || 0;
1558 firingStart = 0;
1559 firingLength = list.length;
1560 for ( ; list && firingIndex < firingLength; firingIndex++ ) {
1561 if ( list[ firingIndex ].apply( context, args ) === false && flags.stopOnFalse ) {
1562 memory = true; // Mark as halted
1563 break;
1564 }
1565 }
1566 firing = false;
1567 if ( list ) {
1568 if ( !flags.once ) {
1569 if ( stack && stack.length ) {
1570 memory = stack.shift();
1571 self.fireWith( memory[ 0 ], memory[ 1 ] );
1572 }
1573 } else if ( memory === true ) {
1574 self.disable();
1575 } else {
1576 list = [];
1577 }
1578 }
1579 },
1580 // Actual Callbacks object
1581 self = {
1582 // Add a callback or a collection of callbacks to the list
1583 add: function() {
1584 if ( list ) {
1585 var length = list.length;
1586 add( arguments );
1587 // Do we need to add the callbacks to the
1588 // current firing batch?
1589 if ( firing ) {
1590 firingLength = list.length;
1591 // With memory, if we're not firing then
1592 // we should call right away, unless previous
1593 // firing was halted (stopOnFalse)
1594 } else if ( memory && memory !== true ) {
1595 firingStart = length;
1596 fire( memory[ 0 ], memory[ 1 ] );
1597 }
1598 }
1599 return this;
1600 },
1601 // Remove a callback from the list
1602 remove: function() {
1603 if ( list ) {
1604 var args = arguments,
1605 argIndex = 0,
1606 argLength = args.length;
1607 for ( ; argIndex < argLength ; argIndex++ ) {
1608 for ( var i = 0; i < list.length; i++ ) {
1609 if ( args[ argIndex ] === list[ i ] ) {
1610 // Handle firingIndex and firingLength
1611 if ( firing ) {
1612 if ( i <= firingLength ) {
1613 firingLength--;
1614 if ( i <= firingIndex ) {
1615 firingIndex--;
1616 }
1617 }
1618 }
1619 // Remove the element
1620 list.splice( i--, 1 );
1621 // If we have some unicity property then
1622 // we only need to do this once
1623 if ( flags.unique ) {
1624 break;
1625 }
1626 }
1627 }
1628 }
1629 }
1630 return this;
1631 },
1632 // Control if a given callback is in the list
1633 has: function( fn ) {
1634 if ( list ) {
1635 var i = 0,
1636 length = list.length;
1637 for ( ; i < length; i++ ) {
1638 if ( fn === list[ i ] ) {
1639 return true;
1640 }
1641 }
1642 }
1643 return false;
1644 },
1645 // Remove all callbacks from the list
1646 empty: function() {
1647 list = [];
1648 return this;
1649 },
1650 // Have the list do nothing anymore
1651 disable: function() {
1652 list = stack = memory = undefined;
1653 return this;
1654 },
1655 // Is it disabled?
1656 disabled: function() {
1657 return !list;
1658 },
1659 // Lock the list in its current state
1660 lock: function() {
1661 stack = undefined;
1662 if ( !memory || memory === true ) {
1663 self.disable();
1664 }
1665 return this;
1666 },
1667 // Is it locked?
1668 locked: function() {
1669 return !stack;
1670 },
1671 // Call all callbacks with the given context and arguments
1672 fireWith: function( context, args ) {
1673 if ( stack ) {
1674 if ( firing ) {
1675 if ( !flags.once ) {
1676 stack.push( [ context, args ] );
1677 }
1678 } else if ( !( flags.once && memory ) ) {
1679 fire( context, args );
1680 }
1681 }
1682 return this;
1683 },
1684 // Call all the callbacks with the given arguments
1685 fire: function() {
1686 self.fireWith( this, arguments );
1687 return this;
1688 },
1689 // To know if the callbacks have already been called at least once
1690 fired: function() {
1691 return !!memory;
1692 }
1693 };
1694
1695 return self;
1696};
1697
1698})( jQuery );
1699(function( jQuery ) {
1700
1701var // Static reference to slice
1702 sliceDeferred = [].slice;
1703
1704jQuery.extend({
1705
1706 Deferred: function( func ) {
1707 var doneList = jQuery.Callbacks( "once memory" ),
1708 failList = jQuery.Callbacks( "once memory" ),
1709 progressList = jQuery.Callbacks( "memory" ),
1710 state = "pending",
1711 lists = {
1712 resolve: doneList,
1713 reject: failList,
1714 notify: progressList
1715 },
1716 promise = {
1717 done: doneList.add,
1718 fail: failList.add,
1719 progress: progressList.add,
1720
1721 state: function() {
1722 return state;
1723 },
1724
1725 // Deprecated
1726 isResolved: doneList.fired,
1727 isRejected: failList.fired,
1728
1729 then: function( doneCallbacks, failCallbacks, progressCallbacks ) {
1730 deferred.done( doneCallbacks ).fail( failCallbacks ).progress( progressCallbacks );
1731 return this;
1732 },
1733 always: function() {
1734 return deferred.done.apply( deferred, arguments ).fail.apply( deferred, arguments );
1735 },
1736 pipe: function( fnDone, fnFail, fnProgress ) {
1737 return jQuery.Deferred(function( newDefer ) {
1738 jQuery.each( {
1739 done: [ fnDone, "resolve" ],
1740 fail: [ fnFail, "reject" ],
1741 progress: [ fnProgress, "notify" ]
1742 }, function( handler, data ) {
1743 var fn = data[ 0 ],
1744 action = data[ 1 ],
1745 returned;
1746 if ( jQuery.isFunction( fn ) ) {
1747 deferred[ handler ](function() {
1748 returned = fn.apply( this, arguments );
1749 if ( returned && jQuery.isFunction( returned.promise ) ) {
1750 returned.promise().then( newDefer.resolve, newDefer.reject, newDefer.notify );
1751 } else {
1752 newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] );
1753 }
1754 });
1755 } else {
1756 deferred[ handler ]( newDefer[ action ] );
1757 }
1758 });
1759 }).promise();
1760 },
1761 // Get a promise for this deferred
1762 // If obj is provided, the promise aspect is added to the object
1763 promise: function( obj ) {
1764 if ( obj == null ) {
1765 obj = promise;
1766 } else {
1767 for ( var key in promise ) {
1768 obj[ key ] = promise[ key ];
1769 }
1770 }
1771 return obj;
1772 }
1773 },
1774 deferred = promise.promise({}),
1775 key;
1776
1777 for ( key in lists ) {
1778 deferred[ key ] = lists[ key ].fire;
1779 deferred[ key + "With" ] = lists[ key ].fireWith;
1780 }
1781
1782 // Handle state
1783 deferred.done( function() {
1784 state = "resolved";
1785 }, failList.disable, progressList.lock ).fail( function() {
1786 state = "rejected";
1787 }, doneList.disable, progressList.lock );
1788
1789 // Call given func if any
1790 if ( func ) {
1791 func.call( deferred, deferred );
1792 }
1793
1794 // All done!
1795 return deferred;
1796 },
1797
1798 // Deferred helper
1799 when: function( firstParam ) {
1800 var args = sliceDeferred.call( arguments, 0 ),
1801 i = 0,
1802 length = args.length,
1803 pValues = new Array( length ),
1804 count = length,
1805 pCount = length,
1806 deferred = length <= 1 && firstParam && jQuery.isFunction( firstParam.promise ) ?
1807 firstParam :
1808 jQuery.Deferred(),
1809 promise = deferred.promise();
1810 function resolveFunc( i ) {
1811 return function( value ) {
1812 args[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value;
1813 if ( !( --count ) ) {
1814 deferred.resolveWith( deferred, args );
1815 }
1816 };
1817 }
1818 function progressFunc( i ) {
1819 return function( value ) {
1820 pValues[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value;
1821 deferred.notifyWith( promise, pValues );
1822 };
1823 }
1824 if ( length > 1 ) {
1825 for ( ; i < length; i++ ) {
1826 if ( args[ i ] && args[ i ].promise && jQuery.isFunction( args[ i ].promise ) ) {
1827 args[ i ].promise().then( resolveFunc(i), deferred.reject, progressFunc(i) );
1828 } else {
1829 --count;
1830 }
1831 }
1832 if ( !count ) {
1833 deferred.resolveWith( deferred, args );
1834 }
1835 } else if ( deferred !== firstParam ) {
1836 deferred.resolveWith( deferred, length ? [ firstParam ] : [] );
1837 }
1838 return promise;
1839 }
1840});
1841
1842})( jQuery );
1843(function( jQuery ) {
1844
1845jQuery.support = (function() {
1846
1847 var div = document.createElement( "div" ),
1848 documentElement = document.documentElement,
1849 all,
1850 a,
1851 select,
1852 opt,
1853 input,
1854 marginDiv,
1855 support,
1856 fragment,
1857 body,
1858 testElementParent,
1859 testElement,
1860 testElementStyle,
1861 tds,
1862 events,
1863 eventName,
1864 i,
1865 isSupported;
1866
1867 // Preliminary tests
1868 div.setAttribute("className", "t");
1869 div.innerHTML = " <link/><table></table><a href='/a' style='top:1px;float:left;opacity:.55;'>a</a><input type='checkbox'/><nav></nav>";
1870
1871
1872 all = div.getElementsByTagName( "*" );
1873 a = div.getElementsByTagName( "a" )[ 0 ];
1874
1875 // Can't get basic test support
1876 if ( !all || !all.length || !a ) {
1877 return {};
1878 }
1879
1880 // First batch of supports tests
1881 select = document.createElement( "select" );
1882 opt = select.appendChild( document.createElement("option") );
1883 input = div.getElementsByTagName( "input" )[ 0 ];
1884
1885 support = {
1886 // IE strips leading whitespace when .innerHTML is used
1887 leadingWhitespace: ( div.firstChild.nodeType === 3 ),
1888
1889 // Make sure that tbody elements aren't automatically inserted
1890 // IE will insert them into empty tables
1891 tbody: !div.getElementsByTagName( "tbody" ).length,
1892
1893 // Make sure that link elements get serialized correctly by innerHTML
1894 // This requires a wrapper element in IE
1895 htmlSerialize: !!div.getElementsByTagName( "link" ).length,
1896
1897 // Get the style information from getAttribute
1898 // (IE uses .cssText instead)
1899 style: /top/.test( a.getAttribute("style") ),
1900
1901 // Make sure that URLs aren't manipulated
1902 // (IE normalizes it by default)
1903 hrefNormalized: ( a.getAttribute( "href" ) === "/a" ),
1904
1905 // Make sure that element opacity exists
1906 // (IE uses filter instead)
1907 // Use a regex to work around a WebKit issue. See #5145
1908 opacity: /^0.55/.test( a.style.opacity ),
1909
1910 // Verify style float existence
1911 // (IE uses styleFloat instead of cssFloat)
1912 cssFloat: !!a.style.cssFloat,
1913
1914 // Make sure unknown elements (like HTML5 elems) are handled appropriately
1915 unknownElems: !!div.getElementsByTagName( "nav" ).length,
1916
1917 // Make sure that if no value is specified for a checkbox
1918 // that it defaults to "on".
1919 // (WebKit defaults to "" instead)
1920 checkOn: ( input.value === "on" ),
1921
1922 // Make sure that a selected-by-default option has a working selected property.
1923 // (WebKit defaults to false instead of true, IE too, if it's in an optgroup)
1924 optSelected: opt.selected,
1925
1926 // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7)
1927 getSetAttribute: div.className !== "t",
1928
1929 // Tests for enctype support on a form(#6743)
1930 enctype: !!document.createElement("form").enctype,
1931
1932 // Will be defined later
1933 submitBubbles: true,
1934 changeBubbles: true,
1935 focusinBubbles: false,
1936 deleteExpando: true,
1937 noCloneEvent: true,
1938 inlineBlockNeedsLayout: false,
1939 shrinkWrapBlocks: false,
1940 reliableMarginRight: true
1941 };
1942
1943 // Make sure checked status is properly cloned
1944 input.checked = true;
1945 support.noCloneChecked = input.cloneNode( true ).checked;
1946
1947 // Make sure that the options inside disabled selects aren't marked as disabled
1948 // (WebKit marks them as disabled)
1949 select.disabled = true;
1950 support.optDisabled = !opt.disabled;
1951
1952 // Test to see if it's possible to delete an expando from an element
1953 // Fails in Internet Explorer
1954 try {
1955 delete div.test;
1956 } catch( e ) {
1957 support.deleteExpando = false;
1958 }
1959
1960 if ( !div.addEventListener && div.attachEvent && div.fireEvent ) {
1961 div.attachEvent( "onclick", function() {
1962 // Cloning a node shouldn't copy over any
1963 // bound event handlers (IE does this)
1964 support.noCloneEvent = false;
1965 });
1966 div.cloneNode( true ).fireEvent( "onclick" );
1967 }
1968
1969 // Check if a radio maintains its value
1970 // after being appended to the DOM
1971 input = document.createElement("input");
1972 input.value = "t";
1973 input.setAttribute("type", "radio");
1974 support.radioValue = input.value === "t";
1975
1976 input.setAttribute("checked", "checked");
1977 div.appendChild( input );
1978 fragment = document.createDocumentFragment();
1979 fragment.appendChild( div.lastChild );
1980
1981 // WebKit doesn't clone checked state correctly in fragments
1982 support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked;
1983
1984 div.innerHTML = "";
1985
1986 // Figure out if the W3C box model works as expected
1987 div.style.width = div.style.paddingLeft = "1px";
1988
1989 // We don't want to do body-related feature tests on frameset
1990 // documents, which lack a body. So we use
1991 // document.getElementsByTagName("body")[0], which is undefined in
1992 // frameset documents, while document.body isn’t. (7398)
1993 body = document.getElementsByTagName("body")[ 0 ];
1994 // We use our own, invisible, body unless the body is already present
1995 // in which case we use a div (#9239)
1996 testElement = document.createElement( body ? "div" : "body" );
1997 testElementStyle = {
1998 visibility: "hidden",
1999 width: 0,
2000 height: 0,
2001 border: 0,
2002 margin: 0,
2003 background: "none"
2004 };
2005 if ( body ) {
2006 jQuery.extend( testElementStyle, {
2007 position: "absolute",
2008 left: "-999px",
2009 top: "-999px"
2010 });
2011 }
2012 for ( i in testElementStyle ) {
2013 testElement.style[ i ] = testElementStyle[ i ];
2014 }
2015 testElement.appendChild( div );
2016 testElementParent = body || documentElement;
2017 testElementParent.insertBefore( testElement, testElementParent.firstChild );
2018
2019 // Check if a disconnected checkbox will retain its checked
2020 // value of true after appended to the DOM (IE6/7)
2021 support.appendChecked = input.checked;
2022
2023 support.boxModel = div.offsetWidth === 2;
2024
2025 if ( "zoom" in div.style ) {
2026 // Check if natively block-level elements act like inline-block
2027 // elements when setting their display to 'inline' and giving
2028 // them layout
2029 // (IE < 8 does this)
2030 div.style.display = "inline";
2031 div.style.zoom = 1;
2032 support.inlineBlockNeedsLayout = ( div.offsetWidth === 2 );
2033
2034 // Check if elements with layout shrink-wrap their children
2035 // (IE 6 does this)
2036 div.style.display = "";
2037 div.innerHTML = "<div style='width:4px;'></div>";
2038 support.shrinkWrapBlocks = ( div.offsetWidth !== 2 );
2039 }
2040
2041 div.innerHTML = "<table><tr><td style='padding:0;border:0;display:none'></td><td>t</td></tr></table>";
2042 tds = div.getElementsByTagName( "td" );
2043
2044 // Check if table cells still have offsetWidth/Height when they are set
2045 // to display:none and there are still other visible table cells in a
2046 // table row; if so, offsetWidth/Height are not reliable for use when
2047 // determining if an element has been hidden directly using
2048 // display:none (it is still safe to use offsets if a parent element is
2049 // hidden; don safety goggles and see bug #4512 for more information).
2050 // (only IE 8 fails this test)
2051 isSupported = ( tds[ 0 ].offsetHeight === 0 );
2052
2053 tds[ 0 ].style.display = "";
2054 tds[ 1 ].style.display = "none";
2055
2056 // Check if empty table cells still have offsetWidth/Height
2057 // (IE < 8 fail this test)
2058 support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 );
2059 div.innerHTML = "";
2060
2061 // Check if div with explicit width and no margin-right incorrectly
2062 // gets computed margin-right based on width of container. For more
2063 // info see bug #3333
2064 // Fails in WebKit before Feb 2011 nightlies
2065 // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
2066 if ( document.defaultView && document.defaultView.getComputedStyle ) {
2067 marginDiv = document.createElement( "div" );
2068 marginDiv.style.width = "0";
2069 marginDiv.style.marginRight = "0";
2070 div.appendChild( marginDiv );
2071 support.reliableMarginRight =
2072 ( parseInt( ( document.defaultView.getComputedStyle( marginDiv, null ) || { marginRight: 0 } ).marginRight, 10 ) || 0 ) === 0;
2073 }
2074
2075 // Technique from Juriy Zaytsev
2076 // http://perfectionkills.com/detecting-event-support-without-browser-sniffing/
2077 // We only care about the case where non-standard event systems
2078 // are used, namely in IE. Short-circuiting here helps us to
2079 // avoid an eval call (in setAttribute) which can cause CSP
2080 // to go haywire. See: https://developer.mozilla.org/en/Security/CSP
2081 if ( div.attachEvent ) {
2082 for( i in {
2083 submit: 1,
2084 change: 1,
2085 focusin: 1
2086 } ) {
2087 eventName = "on" + i;
2088 isSupported = ( eventName in div );
2089 if ( !isSupported ) {
2090 div.setAttribute( eventName, "return;" );
2091 isSupported = ( typeof div[ eventName ] === "function" );
2092 }
2093 support[ i + "Bubbles" ] = isSupported;
2094 }
2095 }
2096
2097 // Run fixed position tests at doc ready to avoid a crash
2098 // related to the invisible body in IE8
2099 jQuery(function() {
2100 var container, outer, inner, table, td, offsetSupport,
2101 conMarginTop = 1,
2102 ptlm = "position:absolute;top:0;left:0;width:1px;height:1px;margin:0;",
2103 vb = "visibility:hidden;border:0;",
2104 style = "style='" + ptlm + "border:5px solid #000;padding:0;'",
2105 html = "<div " + style + "><div></div></div>" +
2106 "<table " + style + " cellpadding='0' cellspacing='0'>" +
2107 "<tr><td></td></tr></table>";
2108
2109 // Reconstruct a container
2110 body = document.getElementsByTagName("body")[0];
2111 if ( !body ) {
2112 // Return for frameset docs that don't have a body
2113 // These tests cannot be done
2114 return;
2115 }
2116
2117 container = document.createElement("div");
2118 container.style.cssText = vb + "width:0;height:0;position:static;top:0;margin-top:" + conMarginTop + "px";
2119 body.insertBefore( container, body.firstChild );
2120
2121 // Construct a test element
2122 testElement = document.createElement("div");
2123 testElement.style.cssText = ptlm + vb;
2124
2125 testElement.innerHTML = html;
2126 container.appendChild( testElement );
2127 outer = testElement.firstChild;
2128 inner = outer.firstChild;
2129 td = outer.nextSibling.firstChild.firstChild;
2130
2131 offsetSupport = {
2132 doesNotAddBorder: ( inner.offsetTop !== 5 ),
2133 doesAddBorderForTableAndCells: ( td.offsetTop === 5 )
2134 };
2135
2136 inner.style.position = "fixed";
2137 inner.style.top = "20px";
2138
2139 // safari subtracts parent border width here which is 5px
2140 offsetSupport.fixedPosition = ( inner.offsetTop === 20 || inner.offsetTop === 15 );
2141 inner.style.position = inner.style.top = "";
2142
2143 outer.style.overflow = "hidden";
2144 outer.style.position = "relative";
2145
2146 offsetSupport.subtractsBorderForOverflowNotVisible = ( inner.offsetTop === -5 );
2147 offsetSupport.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== conMarginTop );
2148
2149 body.removeChild( container );
2150 testElement = container = null;
2151
2152 jQuery.extend( support, offsetSupport );
2153 });
2154
2155 testElement.innerHTML = "";
2156 testElementParent.removeChild( testElement );
2157
2158 // Null connected elements to avoid leaks in IE
2159 testElement = fragment = select = opt = body = marginDiv = div = input = null;
2160
2161 return support;
2162})();
2163
2164// Keep track of boxModel
2165jQuery.boxModel = jQuery.support.boxModel;
2166
2167})( jQuery );
2168(function( jQuery ) {
2169
2170var rbrace = /^(?:\{.*\}|\[.*\])$/,
2171 rmultiDash = /([A-Z])/g;
2172
2173jQuery.extend({
2174 cache: {},
2175
2176 // Please use with caution
2177 uuid: 0,
2178
2179 // Unique for each copy of jQuery on the page
2180 // Non-digits removed to match rinlinejQuery
2181 expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ),
2182
2183 // The following elements throw uncatchable exceptions if you
2184 // attempt to add expando properties to them.
2185 noData: {
2186 "embed": true,
2187 // Ban all objects except for Flash (which handle expandos)
2188 "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",
2189 "applet": true
2190 },
2191
2192 hasData: function( elem ) {
2193 elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];
2194 return !!elem && !isEmptyDataObject( elem );
2195 },
2196
2197 data: function( elem, name, data, pvt /* Internal Use Only */ ) {
2198 if ( !jQuery.acceptData( elem ) ) {
2199 return;
2200 }
2201
2202 var privateCache, thisCache, ret,
2203 internalKey = jQuery.expando,
2204 getByName = typeof name === "string",
2205
2206 // We have to handle DOM nodes and JS objects differently because IE6-7
2207 // can't GC object references properly across the DOM-JS boundary
2208 isNode = elem.nodeType,
2209
2210 // Only DOM nodes need the global jQuery cache; JS object data is
2211 // attached directly to the object so GC can occur automatically
2212 cache = isNode ? jQuery.cache : elem,
2213
2214 // Only defining an ID for JS objects if its cache already exists allows
2215 // the code to shortcut on the same path as a DOM node with no cache
2216 id = isNode ? elem[ jQuery.expando ] : elem[ jQuery.expando ] && jQuery.expando,
2217 isEvents = name === "events";
2218
2219 // Avoid doing any more work than we need to when trying to get data on an
2220 // object that has no data at all
2221 if ( (!id || !cache[id] || (!isEvents && !pvt && !cache[id].data)) && getByName && data === undefined ) {
2222 return;
2223 }
2224
2225 if ( !id ) {
2226 // Only DOM nodes need a new unique ID for each element since their data
2227 // ends up in the global cache
2228 if ( isNode ) {
2229 elem[ jQuery.expando ] = id = ++jQuery.uuid;
2230 } else {
2231 id = jQuery.expando;
2232 }
2233 }
2234
2235 if ( !cache[ id ] ) {
2236 cache[ id ] = {};
2237
2238 // Avoids exposing jQuery metadata on plain JS objects when the object
2239 // is serialized using JSON.stringify
2240 if ( !isNode ) {
2241 cache[ id ].toJSON = jQuery.noop;
2242 }
2243 }
2244
2245 // An object can be passed to jQuery.data instead of a key/value pair; this gets
2246 // shallow copied over onto the existing cache
2247 if ( typeof name === "object" || typeof name === "function" ) {
2248 if ( pvt ) {
2249 cache[ id ] = jQuery.extend( cache[ id ], name );
2250 } else {
2251 cache[ id ].data = jQuery.extend( cache[ id ].data, name );
2252 }
2253 }
2254
2255 privateCache = thisCache = cache[ id ];
2256
2257 // jQuery data() is stored in a separate object inside the object's internal data
2258 // cache in order to avoid key collisions between internal data and user-defined
2259 // data.
2260 if ( !pvt ) {
2261 if ( !thisCache.data ) {
2262 thisCache.data = {};
2263 }
2264
2265 thisCache = thisCache.data;
2266 }
2267
2268 if ( data !== undefined ) {
2269 thisCache[ jQuery.camelCase( name ) ] = data;
2270 }
2271
2272 // Users should not attempt to inspect the internal events object using jQuery.data,
2273 // it is undocumented and subject to change. But does anyone listen? No.
2274 if ( isEvents && !thisCache[ name ] ) {
2275 return privateCache.events;
2276 }
2277
2278 // Check for both converted-to-camel and non-converted data property names
2279 // If a data property was specified
2280 if ( getByName ) {
2281
2282 // First Try to find as-is property data
2283 ret = thisCache[ name ];
2284
2285 // Test for null|undefined property data
2286 if ( ret == null ) {
2287
2288 // Try to find the camelCased property
2289 ret = thisCache[ jQuery.camelCase( name ) ];
2290 }
2291 } else {
2292 ret = thisCache;
2293 }
2294
2295 return ret;
2296 },
2297
2298 removeData: function( elem, name, pvt /* Internal Use Only */ ) {
2299 if ( !jQuery.acceptData( elem ) ) {
2300 return;
2301 }
2302
2303 var thisCache, i, l,
2304
2305 // Reference to internal data cache key
2306 internalKey = jQuery.expando,
2307
2308 isNode = elem.nodeType,
2309
2310 // See jQuery.data for more information
2311 cache = isNode ? jQuery.cache : elem,
2312
2313 // See jQuery.data for more information
2314 id = isNode ? elem[ jQuery.expando ] : jQuery.expando;
2315
2316 // If there is already no cache entry for this object, there is no
2317 // purpose in continuing
2318 if ( !cache[ id ] ) {
2319 return;
2320 }
2321
2322 if ( name ) {
2323
2324 thisCache = pvt ? cache[ id ] : cache[ id ].data;
2325
2326 if ( thisCache ) {
2327
2328 // Support space separated names
2329 if ( jQuery.isArray( name ) ) {
2330 name = name;
2331 } else if ( name in thisCache ) {
2332 name = [ name ];
2333 } else {
2334
2335 // split the camel cased version by spaces
2336 name = jQuery.camelCase( name );
2337 if ( name in thisCache ) {
2338 name = [ name ];
2339 } else {
2340 name = name.split( " " );
2341 }
2342 }
2343
2344 for ( i = 0, l = name.length; i < l; i++ ) {
2345 delete thisCache[ name[i] ];
2346 }
2347
2348 // If there is no data left in the cache, we want to continue
2349 // and let the cache object itself get destroyed
2350 if ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) {
2351 return;
2352 }
2353 }
2354 }
2355
2356 // See jQuery.data for more information
2357 if ( !pvt ) {
2358 delete cache[ id ].data;
2359
2360 // Don't destroy the parent cache unless the internal data object
2361 // had been the only thing left in it
2362 if ( !isEmptyDataObject(cache[ id ]) ) {
2363 return;
2364 }
2365 }
2366
2367 // Browsers that fail expando deletion also refuse to delete expandos on
2368 // the window, but it will allow it on all other JS objects; other browsers
2369 // don't care
2370 // Ensure that `cache` is not a window object #10080
2371 if ( jQuery.support.deleteExpando || !cache.setInterval ) {
2372 delete cache[ id ];
2373 } else {
2374 cache[ id ] = null;
2375 }
2376
2377 // We destroyed the cache and need to eliminate the expando on the node to avoid
2378 // false lookups in the cache for entries that no longer exist
2379 if ( isNode ) {
2380 // IE does not allow us to delete expando properties from nodes,
2381 // nor does it have a removeAttribute function on Document nodes;
2382 // we must handle all of these cases
2383 if ( jQuery.support.deleteExpando ) {
2384 delete elem[ jQuery.expando ];
2385 } else if ( elem.removeAttribute ) {
2386 elem.removeAttribute( jQuery.expando );
2387 } else {
2388 elem[ jQuery.expando ] = null;
2389 }
2390 }
2391 },
2392
2393 // For internal use only.
2394 _data: function( elem, name, data ) {
2395 return jQuery.data( elem, name, data, true );
2396 },
2397
2398 // A method for determining if a DOM node can handle the data expando
2399 acceptData: function( elem ) {
2400 if ( elem.nodeName ) {
2401 var match = jQuery.noData[ elem.nodeName.toLowerCase() ];
2402
2403 if ( match ) {
2404 return !(match === true || elem.getAttribute("classid") !== match);
2405 }
2406 }
2407
2408 return true;
2409 }
2410});
2411
2412jQuery.fn.extend({
2413 data: function( key, value ) {
2414 var parts, attr, name,
2415 data = null;
2416
2417 if ( typeof key === "undefined" ) {
2418 if ( this.length ) {
2419 data = jQuery.data( this[0] );
2420
2421 if ( this[0].nodeType === 1 && !jQuery._data( this[0], "parsedAttrs" ) ) {
2422 attr = this[0].attributes;
2423 for ( var i = 0, l = attr.length; i < l; i++ ) {
2424 name = attr[i].name;
2425
2426 if ( name.indexOf( "data-" ) === 0 ) {
2427 name = jQuery.camelCase( name.substring(5) );
2428
2429 dataAttr( this[0], name, data[ name ] );
2430 }
2431 }
2432 jQuery._data( this[0], "parsedAttrs", true );
2433 }
2434 }
2435
2436 return data;
2437
2438 } else if ( typeof key === "object" ) {
2439 return this.each(function() {
2440 jQuery.data( this, key );
2441 });
2442 }
2443
2444 parts = key.split(".");
2445 parts[1] = parts[1] ? "." + parts[1] : "";
2446
2447 if ( value === undefined ) {
2448 data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]);
2449
2450 // Try to fetch any internally stored data first
2451 if ( data === undefined && this.length ) {
2452 data = jQuery.data( this[0], key );
2453 data = dataAttr( this[0], key, data );
2454 }
2455
2456 return data === undefined && parts[1] ?
2457 this.data( parts[0] ) :
2458 data;
2459
2460 } else {
2461 return this.each(function() {
2462 var $this = jQuery( this ),
2463 args = [ parts[0], value ];
2464
2465 $this.triggerHandler( "setData" + parts[1] + "!", args );
2466 jQuery.data( this, key, value );
2467 $this.triggerHandler( "changeData" + parts[1] + "!", args );
2468 });
2469 }
2470 },
2471
2472 removeData: function( key ) {
2473 return this.each(function() {
2474 jQuery.removeData( this, key );
2475 });
2476 }
2477});
2478
2479function dataAttr( elem, key, data ) {
2480 // If nothing was found internally, try to fetch any
2481 // data from the HTML5 data-* attribute
2482 if ( data === undefined && elem.nodeType === 1 ) {
2483
2484 var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase();
2485
2486 data = elem.getAttribute( name );
2487
2488 if ( typeof data === "string" ) {
2489 try {
2490 data = data === "true" ? true :
2491 data === "false" ? false :
2492 data === "null" ? null :
2493 jQuery.isNumeric( data ) ? parseFloat( data ) :
2494 rbrace.test( data ) ? jQuery.parseJSON( data ) :
2495 data;
2496 } catch( e ) {}
2497
2498 // Make sure we set the data so it isn't changed later
2499 jQuery.data( elem, key, data );
2500
2501 } else {
2502 data = undefined;
2503 }
2504 }
2505
2506 return data;
2507}
2508
2509// checks a cache object for emptiness
2510function isEmptyDataObject( obj ) {
2511 for ( var name in obj ) {
2512
2513 // if the public data object is empty, the private is still empty
2514 if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) {
2515 continue;
2516 }
2517 if ( name !== "toJSON" ) {
2518 return false;
2519 }
2520 }
2521
2522 return true;
2523}
2524
2525})( jQuery );
2526(function( jQuery ) {
2527
2528function handleQueueMarkDefer( elem, type, src ) {
2529 var deferDataKey = type + "defer",
2530 queueDataKey = type + "queue",
2531 markDataKey = type + "mark",
2532 defer = jQuery._data( elem, deferDataKey );
2533 if ( defer &&
2534 ( src === "queue" || !jQuery._data(elem, queueDataKey) ) &&
2535 ( src === "mark" || !jQuery._data(elem, markDataKey) ) ) {
2536 // Give room for hard-coded callbacks to fire first
2537 // and eventually mark/queue something else on the element
2538 setTimeout( function() {
2539 if ( !jQuery._data( elem, queueDataKey ) &&
2540 !jQuery._data( elem, markDataKey ) ) {
2541 jQuery.removeData( elem, deferDataKey, true );
2542 defer.fire();
2543 }
2544 }, 0 );
2545 }
2546}
2547
2548jQuery.extend({
2549
2550 _mark: function( elem, type ) {
2551 if ( elem ) {
2552 type = ( type || "fx" ) + "mark";
2553 jQuery._data( elem, type, (jQuery._data( elem, type ) || 0) + 1 );
2554 }
2555 },
2556
2557 _unmark: function( force, elem, type ) {
2558 if ( force !== true ) {
2559 type = elem;
2560 elem = force;
2561 force = false;
2562 }
2563 if ( elem ) {
2564 type = type || "fx";
2565 var key = type + "mark",
2566 count = force ? 0 : ( (jQuery._data( elem, key ) || 1) - 1 );
2567 if ( count ) {
2568 jQuery._data( elem, key, count );
2569 } else {
2570 jQuery.removeData( elem, key, true );
2571 handleQueueMarkDefer( elem, type, "mark" );
2572 }
2573 }
2574 },
2575
2576 queue: function( elem, type, data ) {
2577 var q;
2578 if ( elem ) {
2579 type = ( type || "fx" ) + "queue";
2580 q = jQuery._data( elem, type );
2581
2582 // Speed up dequeue by getting out quickly if this is just a lookup
2583 if ( data ) {
2584 if ( !q || jQuery.isArray(data) ) {
2585 q = jQuery._data( elem, type, jQuery.makeArray(data) );
2586 } else {
2587 q.push( data );
2588 }
2589 }
2590 return q || [];
2591 }
2592 },
2593
2594 dequeue: function( elem, type ) {
2595 type = type || "fx";
2596
2597 var queue = jQuery.queue( elem, type ),
2598 fn = queue.shift(),
2599 hooks = {};
2600
2601 // If the fx queue is dequeued, always remove the progress sentinel
2602 if ( fn === "inprogress" ) {
2603 fn = queue.shift();
2604 }
2605
2606 if ( fn ) {
2607 // Add a progress sentinel to prevent the fx queue from being
2608 // automatically dequeued
2609 if ( type === "fx" ) {
2610 queue.unshift( "inprogress" );
2611 }
2612
2613 jQuery._data( elem, type + ".run", hooks );
2614 fn.call( elem, function() {
2615 jQuery.dequeue( elem, type );
2616 }, hooks );
2617 }
2618
2619 if ( !queue.length ) {
2620 jQuery.removeData( elem, type + "queue " + type + ".run", true );
2621 handleQueueMarkDefer( elem, type, "queue" );
2622 }
2623 }
2624});
2625
2626jQuery.fn.extend({
2627 queue: function( type, data ) {
2628 if ( typeof type !== "string" ) {
2629 data = type;
2630 type = "fx";
2631 }
2632
2633 if ( data === undefined ) {
2634 return jQuery.queue( this[0], type );
2635 }
2636 return this.each(function() {
2637 var queue = jQuery.queue( this, type, data );
2638
2639 if ( type === "fx" && queue[0] !== "inprogress" ) {
2640 jQuery.dequeue( this, type );
2641 }
2642 });
2643 },
2644 dequeue: function( type ) {
2645 return this.each(function() {
2646 jQuery.dequeue( this, type );
2647 });
2648 },
2649 // Based off of the plugin by Clint Helfers, with permission.
2650 // http://blindsignals.com/index.php/2009/07/jquery-delay/
2651 delay: function( time, type ) {
2652 time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
2653 type = type || "fx";
2654
2655 return this.queue( type, function( next, hooks ) {
2656 var timeout = setTimeout( next, time );
2657 hooks.stop = function() {
2658 clearTimeout( timeout );
2659 };
2660 });
2661 },
2662 clearQueue: function( type ) {
2663 return this.queue( type || "fx", [] );
2664 },
2665 // Get a promise resolved when queues of a certain type
2666 // are emptied (fx is the type by default)
2667 promise: function( type, object ) {
2668 if ( typeof type !== "string" ) {
2669 object = type;
2670 type = undefined;
2671 }
2672 type = type || "fx";
2673 var defer = jQuery.Deferred(),
2674 elements = this,
2675 i = elements.length,
2676 count = 1,
2677 deferDataKey = type + "defer",
2678 queueDataKey = type + "queue",
2679 markDataKey = type + "mark",
2680 tmp;
2681 function resolve() {
2682 if ( !( --count ) ) {
2683 defer.resolveWith( elements, [ elements ] );
2684 }
2685 }
2686 while( i-- ) {
2687 if (( tmp = jQuery.data( elements[ i ], deferDataKey, undefined, true ) ||
2688 ( jQuery.data( elements[ i ], queueDataKey, undefined, true ) ||
2689 jQuery.data( elements[ i ], markDataKey, undefined, true ) ) &&
2690 jQuery.data( elements[ i ], deferDataKey, jQuery.Callbacks( "once memory" ), true ) )) {
2691 count++;
2692 tmp.add( resolve );
2693 }
2694 }
2695 resolve();
2696 return defer.promise();
2697 }
2698});
2699
2700})( jQuery );
2701(function( jQuery ) {
2702
2703var rclass = /[\n\t\r]/g,
2704 rspace = /\s+/,
2705 rreturn = /\r/g,
2706 rtype = /^(?:button|input)$/i,
2707 rfocusable = /^(?:button|input|object|select|textarea)$/i,
2708 rclickable = /^a(?:rea)?$/i,
2709 rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,
2710 getSetAttribute = jQuery.support.getSetAttribute,
2711 nodeHook, boolHook, fixSpecified;
2712
2713jQuery.fn.extend({
2714 attr: function( name, value ) {
2715 return jQuery.access( this, name, value, true, jQuery.attr );
2716 },
2717
2718 removeAttr: function( name ) {
2719 return this.each(function() {
2720 jQuery.removeAttr( this, name );
2721 });
2722 },
2723
2724 prop: function( name, value ) {
2725 return jQuery.access( this, name, value, true, jQuery.prop );
2726 },
2727
2728 removeProp: function( name ) {
2729 name = jQuery.propFix[ name ] || name;
2730 return this.each(function() {
2731 // try/catch handles cases where IE balks (such as removing a property on window)
2732 try {
2733 this[ name ] = undefined;
2734 delete this[ name ];
2735 } catch( e ) {}
2736 });
2737 },
2738
2739 addClass: function( value ) {
2740 var classNames, i, l, elem,
2741 setClass, c, cl;
2742
2743 if ( jQuery.isFunction( value ) ) {
2744 return this.each(function( j ) {
2745 jQuery( this ).addClass( value.call(this, j, this.className) );
2746 });
2747 }
2748
2749 if ( value && typeof value === "string" ) {
2750 classNames = value.split( rspace );
2751
2752 for ( i = 0, l = this.length; i < l; i++ ) {
2753 elem = this[ i ];
2754
2755 if ( elem.nodeType === 1 ) {
2756 if ( !elem.className && classNames.length === 1 ) {
2757 elem.className = value;
2758
2759 } else {
2760 setClass = " " + elem.className + " ";
2761
2762 for ( c = 0, cl = classNames.length; c < cl; c++ ) {
2763 if ( !~setClass.indexOf( " " + classNames[ c ] + " " ) ) {
2764 setClass += classNames[ c ] + " ";
2765 }
2766 }
2767 elem.className = jQuery.trim( setClass );
2768 }
2769 }
2770 }
2771 }
2772
2773 return this;
2774 },
2775
2776 removeClass: function( value ) {
2777 var classNames, i, l, elem, className, c, cl;
2778
2779 if ( jQuery.isFunction( value ) ) {
2780 return this.each(function( j ) {
2781 jQuery( this ).removeClass( value.call(this, j, this.className) );
2782 });
2783 }
2784
2785 if ( (value && typeof value === "string") || value === undefined ) {
2786 classNames = ( value || "" ).split( rspace );
2787
2788 for ( i = 0, l = this.length; i < l; i++ ) {
2789 elem = this[ i ];
2790
2791 if ( elem.nodeType === 1 && elem.className ) {
2792 if ( value ) {
2793 className = (" " + elem.className + " ").replace( rclass, " " );
2794 for ( c = 0, cl = classNames.length; c < cl; c++ ) {
2795 className = className.replace(" " + classNames[ c ] + " ", " ");
2796 }
2797 elem.className = jQuery.trim( className );
2798
2799 } else {
2800 elem.className = "";
2801 }
2802 }
2803 }
2804 }
2805
2806 return this;
2807 },
2808
2809 toggleClass: function( value, stateVal ) {
2810 var type = typeof value,
2811 isBool = typeof stateVal === "boolean";
2812
2813 if ( jQuery.isFunction( value ) ) {
2814 return this.each(function( i ) {
2815 jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );
2816 });
2817 }
2818
2819 return this.each(function() {
2820 if ( type === "string" ) {
2821 // toggle individual class names
2822 var className,
2823 i = 0,
2824 self = jQuery( this ),
2825 state = stateVal,
2826 classNames = value.split( rspace );
2827
2828 while ( (className = classNames[ i++ ]) ) {
2829 // check each className given, space seperated list
2830 state = isBool ? state : !self.hasClass( className );
2831 self[ state ? "addClass" : "removeClass" ]( className );
2832 }
2833
2834 } else if ( type === "undefined" || type === "boolean" ) {
2835 if ( this.className ) {
2836 // store className if set
2837 jQuery._data( this, "__className__", this.className );
2838 }
2839
2840 // toggle whole className
2841 this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || "";
2842 }
2843 });
2844 },
2845
2846 hasClass: function( selector ) {
2847 var className = " " + selector + " ",
2848 i = 0,
2849 l = this.length;
2850 for ( ; i < l; i++ ) {
2851 if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) {
2852 return true;
2853 }
2854 }
2855
2856 return false;
2857 },
2858
2859 val: function( value ) {
2860 var hooks, ret, isFunction,
2861 elem = this[0];
2862
2863 if ( !arguments.length ) {
2864 if ( elem ) {
2865 hooks = jQuery.valHooks[ elem.nodeName.toLowerCase() ] || jQuery.valHooks[ elem.type ];
2866
2867 if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) {
2868 return ret;
2869 }
2870
2871 ret = elem.value;
2872
2873 return typeof ret === "string" ?
2874 // handle most common string cases
2875 ret.replace(rreturn, "") :
2876 // handle cases where value is null/undef or number
2877 ret == null ? "" : ret;
2878 }
2879
2880 return undefined;
2881 }
2882
2883 isFunction = jQuery.isFunction( value );
2884
2885 return this.each(function( i ) {
2886 var self = jQuery(this), val;
2887
2888 if ( this.nodeType !== 1 ) {
2889 return;
2890 }
2891
2892 if ( isFunction ) {
2893 val = value.call( this, i, self.val() );
2894 } else {
2895 val = value;
2896 }
2897
2898 // Treat null/undefined as ""; convert numbers to string
2899 if ( val == null ) {
2900 val = "";
2901 } else if ( typeof val === "number" ) {
2902 val += "";
2903 } else if ( jQuery.isArray( val ) ) {
2904 val = jQuery.map(val, function ( value ) {
2905 return value == null ? "" : value + "";
2906 });
2907 }
2908
2909 hooks = jQuery.valHooks[ this.nodeName.toLowerCase() ] || jQuery.valHooks[ this.type ];
2910
2911 // If set returns undefined, fall back to normal setting
2912 if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) {
2913 this.value = val;
2914 }
2915 });
2916 }
2917});
2918
2919jQuery.extend({
2920 valHooks: {
2921 option: {
2922 get: function( elem ) {
2923 // attributes.value is undefined in Blackberry 4.7 but
2924 // uses .value. See #6932
2925 var val = elem.attributes.value;
2926 return !val || val.specified ? elem.value : elem.text;
2927 }
2928 },
2929 select: {
2930 get: function( elem ) {
2931 var value, i, max, option,
2932 index = elem.selectedIndex,
2933 values = [],
2934 options = elem.options,
2935 one = elem.type === "select-one";
2936
2937 // Nothing was selected
2938 if ( index < 0 ) {
2939 return null;
2940 }
2941
2942 // Loop through all the selected options
2943 i = one ? index : 0;
2944 max = one ? index + 1 : options.length;
2945 for ( ; i < max; i++ ) {
2946 option = options[ i ];
2947
2948 // Don't return options that are disabled or in a disabled optgroup
2949 if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) &&
2950 (!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) {
2951
2952 // Get the specific value for the option
2953 value = jQuery( option ).val();
2954
2955 // We don't need an array for one selects
2956 if ( one ) {
2957 return value;
2958 }
2959
2960 // Multi-Selects return an array
2961 values.push( value );
2962 }
2963 }
2964
2965 // Fixes Bug #2551 -- select.val() broken in IE after form.reset()
2966 if ( one && !values.length && options.length ) {
2967 return jQuery( options[ index ] ).val();
2968 }
2969
2970 return values;
2971 },
2972
2973 set: function( elem, value ) {
2974 var values = jQuery.makeArray( value );
2975
2976 jQuery(elem).find("option").each(function() {
2977 this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0;
2978 });
2979
2980 if ( !values.length ) {
2981 elem.selectedIndex = -1;
2982 }
2983 return values;
2984 }
2985 }
2986 },
2987
2988 attrFn: {
2989 val: true,
2990 css: true,
2991 html: true,
2992 text: true,
2993 data: true,
2994 width: true,
2995 height: true,
2996 offset: true
2997 },
2998
2999 attr: function( elem, name, value, pass ) {
3000 var ret, hooks, notxml,
3001 nType = elem.nodeType;
3002
3003 // don't get/set attributes on text, comment and attribute nodes
3004 if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
3005 return undefined;
3006 }
3007
3008 if ( pass && name in jQuery.attrFn ) {
3009 return jQuery( elem )[ name ]( value );
3010 }
3011
3012 // Fallback to prop when attributes are not supported
3013 if ( !("getAttribute" in elem) ) {
3014 return jQuery.prop( elem, name, value );
3015 }
3016
3017 notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
3018
3019 // All attributes are lowercase
3020 // Grab necessary hook if one is defined
3021 if ( notxml ) {
3022 name = name.toLowerCase();
3023 hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook );
3024 }
3025
3026 if ( value !== undefined ) {
3027
3028 if ( value === null ) {
3029 jQuery.removeAttr( elem, name );
3030 return undefined;
3031
3032 } else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) {
3033 return ret;
3034
3035 } else {
3036 elem.setAttribute( name, "" + value );
3037 return value;
3038 }
3039
3040 } else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) {
3041 return ret;
3042
3043 } else {
3044
3045 ret = elem.getAttribute( name );
3046
3047 // Non-existent attributes return null, we normalize to undefined
3048 return ret === null ?
3049 undefined :
3050 ret;
3051 }
3052 },
3053
3054 removeAttr: function( elem, value ) {
3055 var propName, attrNames, name, l,
3056 i = 0;
3057
3058 if ( elem.nodeType === 1 ) {
3059 attrNames = ( value || "" ).split( rspace );
3060 l = attrNames.length;
3061
3062 for ( ; i < l; i++ ) {
3063 name = attrNames[ i ].toLowerCase();
3064 propName = jQuery.propFix[ name ] || name;
3065
3066 // See #9699 for explanation of this approach (setting first, then removal)
3067 jQuery.attr( elem, name, "" );
3068 elem.removeAttribute( getSetAttribute ? name : propName );
3069
3070 // Set corresponding property to false for boolean attributes
3071 if ( rboolean.test( name ) && propName in elem ) {
3072 elem[ propName ] = false;
3073 }
3074 }
3075 }
3076 },
3077
3078 attrHooks: {
3079 type: {
3080 set: function( elem, value ) {
3081 // We can't allow the type property to be changed (since it causes problems in IE)
3082 if ( rtype.test( elem.nodeName ) && elem.parentNode ) {
3083 jQuery.error( "type property can't be changed" );
3084 } else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) {
3085 // Setting the type on a radio button after the value resets the value in IE6-9
3086 // Reset value to it's default in case type is set after value
3087 // This is for element creation
3088 var val = elem.value;
3089 elem.setAttribute( "type", value );
3090 if ( val ) {
3091 elem.value = val;
3092 }
3093 return value;
3094 }
3095 }
3096 },
3097 // Use the value property for back compat
3098 // Use the nodeHook for button elements in IE6/7 (#1954)
3099 value: {
3100 get: function( elem, name ) {
3101 if ( nodeHook && jQuery.nodeName( elem, "button" ) ) {
3102 return nodeHook.get( elem, name );
3103 }
3104 return name in elem ?
3105 elem.value :
3106 null;
3107 },
3108 set: function( elem, value, name ) {
3109 if ( nodeHook && jQuery.nodeName( elem, "button" ) ) {
3110 return nodeHook.set( elem, value, name );
3111 }
3112 // Does not return so that setAttribute is also used
3113 elem.value = value;
3114 }
3115 }
3116 },
3117
3118 propFix: {
3119 tabindex: "tabIndex",
3120 readonly: "readOnly",
3121 "for": "htmlFor",
3122 "class": "className",
3123 maxlength: "maxLength",
3124 cellspacing: "cellSpacing",
3125 cellpadding: "cellPadding",
3126 rowspan: "rowSpan",
3127 colspan: "colSpan",
3128 usemap: "useMap",
3129 frameborder: "frameBorder",
3130 contenteditable: "contentEditable"
3131 },
3132
3133 prop: function( elem, name, value ) {
3134 var ret, hooks, notxml,
3135 nType = elem.nodeType;
3136
3137 // don't get/set properties on text, comment and attribute nodes
3138 if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
3139 return undefined;
3140 }
3141
3142 notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
3143
3144 if ( notxml ) {
3145 // Fix name and attach hooks
3146 name = jQuery.propFix[ name ] || name;
3147 hooks = jQuery.propHooks[ name ];
3148 }
3149
3150 if ( value !== undefined ) {
3151 if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
3152 return ret;
3153
3154 } else {
3155 return ( elem[ name ] = value );
3156 }
3157
3158 } else {
3159 if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
3160 return ret;
3161
3162 } else {
3163 return elem[ name ];
3164 }
3165 }
3166 },
3167
3168 propHooks: {
3169 tabIndex: {
3170 get: function( elem ) {
3171 // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set
3172 // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
3173 var attributeNode = elem.getAttributeNode("tabindex");
3174
3175 return attributeNode && attributeNode.specified ?
3176 parseInt( attributeNode.value, 10 ) :
3177 rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?
3178 0 :
3179 undefined;
3180 }
3181 }
3182 }
3183});
3184
3185// Add the tabIndex propHook to attrHooks for back-compat (different case is intentional)
3186jQuery.attrHooks.tabindex = jQuery.propHooks.tabIndex;
3187
3188// Hook for boolean attributes
3189boolHook = {
3190 get: function( elem, name ) {
3191 // Align boolean attributes with corresponding properties
3192 // Fall back to attribute presence where some booleans are not supported
3193 var attrNode,
3194 property = jQuery.prop( elem, name );
3195 return property === true || typeof property !== "boolean" && ( attrNode = elem.getAttributeNode(name) ) && attrNode.nodeValue !== false ?
3196 name.toLowerCase() :
3197 undefined;
3198 },
3199 set: function( elem, value, name ) {
3200 var propName;
3201 if ( value === false ) {
3202 // Remove boolean attributes when set to false
3203 jQuery.removeAttr( elem, name );
3204 } else {
3205 // value is true since we know at this point it's type boolean and not false
3206 // Set boolean attributes to the same name and set the DOM property
3207 propName = jQuery.propFix[ name ] || name;
3208 if ( propName in elem ) {
3209 // Only set the IDL specifically if it already exists on the element
3210 elem[ propName ] = true;
3211 }
3212
3213 elem.setAttribute( name, name.toLowerCase() );
3214 }
3215 return name;
3216 }
3217};
3218
3219// IE6/7 do not support getting/setting some attributes with get/setAttribute
3220if ( !getSetAttribute ) {
3221
3222 fixSpecified = {
3223 name: true,
3224 id: true
3225 };
3226
3227 // Use this for any attribute in IE6/7
3228 // This fixes almost every IE6/7 issue
3229 nodeHook = jQuery.valHooks.button = {
3230 get: function( elem, name ) {
3231 var ret;
3232 ret = elem.getAttributeNode( name );
3233 return ret && ( fixSpecified[ name ] ? ret.nodeValue !== "" : ret.specified ) ?
3234 ret.nodeValue :
3235 undefined;
3236 },
3237 set: function( elem, value, name ) {
3238 // Set the existing or create a new attribute node
3239 var ret = elem.getAttributeNode( name );
3240 if ( !ret ) {
3241 ret = document.createAttribute( name );
3242 elem.setAttributeNode( ret );
3243 }
3244 return ( ret.nodeValue = value + "" );
3245 }
3246 };
3247
3248 // Apply the nodeHook to tabindex
3249 jQuery.attrHooks.tabindex.set = nodeHook.set;
3250
3251 // Set width and height to auto instead of 0 on empty string( Bug #8150 )
3252 // This is for removals
3253 jQuery.each([ "width", "height" ], function( i, name ) {
3254 jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {
3255 set: function( elem, value ) {
3256 if ( value === "" ) {
3257 elem.setAttribute( name, "auto" );
3258 return value;
3259 }
3260 }
3261 });
3262 });
3263
3264 // Set contenteditable to false on removals(#10429)
3265 // Setting to empty string throws an error as an invalid value
3266 jQuery.attrHooks.contenteditable = {
3267 get: nodeHook.get,
3268 set: function( elem, value, name ) {
3269 if ( value === "" ) {
3270 value = "false";
3271 }
3272 nodeHook.set( elem, value, name );
3273 }
3274 };
3275}
3276
3277
3278// Some attributes require a special call on IE
3279if ( !jQuery.support.hrefNormalized ) {
3280 jQuery.each([ "href", "src", "width", "height" ], function( i, name ) {
3281 jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {
3282 get: function( elem ) {
3283 var ret = elem.getAttribute( name, 2 );
3284 return ret === null ? undefined : ret;
3285 }
3286 });
3287 });
3288}
3289
3290if ( !jQuery.support.style ) {
3291 jQuery.attrHooks.style = {
3292 get: function( elem ) {
3293 // Return undefined in the case of empty string
3294 // Normalize to lowercase since IE uppercases css property names
3295 return elem.style.cssText.toLowerCase() || undefined;
3296 },
3297 set: function( elem, value ) {
3298 return ( elem.style.cssText = "" + value );
3299 }
3300 };
3301}
3302
3303// Safari mis-reports the default selected property of an option
3304// Accessing the parent's selectedIndex property fixes it
3305if ( !jQuery.support.optSelected ) {
3306 jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, {
3307 get: function( elem ) {
3308 var parent = elem.parentNode;
3309
3310 if ( parent ) {
3311 parent.selectedIndex;
3312
3313 // Make sure that it also works with optgroups, see #5701
3314 if ( parent.parentNode ) {
3315 parent.parentNode.selectedIndex;
3316 }
3317 }
3318 return null;
3319 }
3320 });
3321}
3322
3323// IE6/7 call enctype encoding
3324if ( !jQuery.support.enctype ) {
3325 jQuery.propFix.enctype = "encoding";
3326}
3327
3328// Radios and checkboxes getter/setter
3329if ( !jQuery.support.checkOn ) {
3330 jQuery.each([ "radio", "checkbox" ], function() {
3331 jQuery.valHooks[ this ] = {
3332 get: function( elem ) {
3333 // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified
3334 return elem.getAttribute("value") === null ? "on" : elem.value;
3335 }
3336 };
3337 });
3338}
3339jQuery.each([ "radio", "checkbox" ], function() {
3340 jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], {
3341 set: function( elem, value ) {
3342 if ( jQuery.isArray( value ) ) {
3343 return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 );
3344 }
3345 }
3346 });
3347});
3348
3349})( jQuery );
3350(function( jQuery ) {
3351
3352var rnamespaces = /\.(.*)$/,
3353 rformElems = /^(?:textarea|input|select)$/i,
3354 rperiod = /\./g,
3355 rspaces = / /g,
3356 rescape = /[^\w\s.|`]/g,
3357 rtypenamespace = /^([^\.]*)?(?:\.(.+))?$/,
3358 rhoverHack = /\bhover(\.\S+)?/,
3359 rkeyEvent = /^key/,
3360 rmouseEvent = /^(?:mouse|contextmenu)|click/,
3361 rquickIs = /^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/,
3362 quickParse = function( selector ) {
3363 var quick = rquickIs.exec( selector );
3364 if ( quick ) {
3365 // 0 1 2 3
3366 // [ _, tag, id, class ]
3367 quick[1] = ( quick[1] || "" ).toLowerCase();
3368 quick[3] = quick[3] && new RegExp( "(?:^|\\s)" + quick[3] + "(?:\\s|$)" );
3369 }
3370 return quick;
3371 },
3372 quickIs = function( elem, m ) {
3373 return (
3374 (!m[1] || elem.nodeName.toLowerCase() === m[1]) &&
3375 (!m[2] || elem.id === m[2]) &&
3376 (!m[3] || m[3].test( elem.className ))
3377 );
3378 },
3379 hoverHack = function( events ) {
3380 return jQuery.event.special.hover ? events : events.replace( rhoverHack, "mouseenter$1 mouseleave$1" );
3381 };
3382
3383/*
3384 * Helper functions for managing events -- not part of the public interface.
3385 * Props to Dean Edwards' addEvent library for many of the ideas.
3386 */
3387jQuery.event = {
3388
3389 add: function( elem, types, handler, data, selector ) {
3390
3391 var elemData, eventHandle, events,
3392 t, tns, type, namespaces, handleObj,
3393 handleObjIn, quick, handlers, special;
3394
3395 // Don't attach events to noData or text/comment nodes (allow plain objects tho)
3396 if ( elem.nodeType === 3 || elem.nodeType === 8 || !types || !handler || !(elemData = jQuery._data( elem )) ) {
3397 return;
3398 }
3399
3400 // Caller can pass in an object of custom data in lieu of the handler
3401 if ( handler.handler ) {
3402 handleObjIn = handler;
3403 handler = handleObjIn.handler;
3404 }
3405
3406 // Make sure that the handler has a unique ID, used to find/remove it later
3407 if ( !handler.guid ) {
3408 handler.guid = jQuery.guid++;
3409 }
3410
3411 // Init the element's event structure and main handler, if this is the first
3412 events = elemData.events;
3413 if ( !events ) {
3414 elemData.events = events = {};
3415 }
3416 eventHandle = elemData.handle;
3417 if ( !eventHandle ) {
3418 elemData.handle = eventHandle = function( e ) {
3419 // Discard the second event of a jQuery.event.trigger() and
3420 // when an event is called after a page has unloaded
3421 return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ?
3422 jQuery.event.dispatch.apply( eventHandle.elem, arguments ) :
3423 undefined;
3424 };
3425 // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events
3426 eventHandle.elem = elem;
3427 }
3428
3429 // Handle multiple events separated by a space
3430 // jQuery(...).bind("mouseover mouseout", fn);
3431 types = hoverHack(types).split( " " );
3432 for ( t = 0; t < types.length; t++ ) {
3433
3434 tns = rtypenamespace.exec( types[t] ) || [];
3435 type = tns[1];
3436 namespaces = ( tns[2] || "" ).split( "." ).sort();
3437
3438 // If event changes its type, use the special event handlers for the changed type
3439 special = jQuery.event.special[ type ] || {};
3440
3441 // If selector defined, determine special event api type, otherwise given type
3442 type = ( selector ? special.delegateType : special.bindType ) || type;
3443
3444 // Update special based on newly reset type
3445 special = jQuery.event.special[ type ] || {};
3446
3447 // handleObj is passed to all event handlers
3448 handleObj = jQuery.extend({
3449 type: type,
3450 origType: tns[1],
3451 data: data,
3452 handler: handler,
3453 guid: handler.guid,
3454 selector: selector,
3455 namespace: namespaces.join(".")
3456 }, handleObjIn );
3457
3458 // Delegated event; pre-analyze selector so it's processed quickly on event dispatch
3459 if ( selector ) {
3460 handleObj.quick = quickParse( selector );
3461 if ( !handleObj.quick && jQuery.expr.match.POS.test( selector ) ) {
3462 handleObj.isPositional = true;
3463 }
3464 }
3465
3466 // Init the event handler queue if we're the first
3467 handlers = events[ type ];
3468 if ( !handlers ) {
3469 handlers = events[ type ] = [];
3470 handlers.delegateCount = 0;
3471
3472 // Only use addEventListener/attachEvent if the special events handler returns false
3473 if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
3474 // Bind the global event handler to the element
3475 if ( elem.addEventListener ) {
3476 elem.addEventListener( type, eventHandle, false );
3477
3478 } else if ( elem.attachEvent ) {
3479 elem.attachEvent( "on" + type, eventHandle );
3480 }
3481 }
3482 }
3483
3484 if ( special.add ) {
3485 special.add.call( elem, handleObj );
3486
3487 if ( !handleObj.handler.guid ) {
3488 handleObj.handler.guid = handler.guid;
3489 }
3490 }
3491
3492 // Add to the element's handler list, delegates in front
3493 if ( selector ) {
3494 handlers.splice( handlers.delegateCount++, 0, handleObj );
3495 } else {
3496 handlers.push( handleObj );
3497 }
3498
3499 // Keep track of which events have ever been used, for event optimization
3500 jQuery.event.global[ type ] = true;
3501 }
3502
3503 // Nullify elem to prevent memory leaks in IE
3504 elem = null;
3505 },
3506
3507 global: {},
3508
3509 // Detach an event or set of events from an element
3510 remove: function( elem, types, handler, selector ) {
3511
3512 var elemData = jQuery.hasData( elem ) && jQuery._data( elem ),
3513 t, tns, type, namespaces, origCount,
3514 j, events, special, handle, eventType, handleObj;
3515
3516 if ( !elemData || !(events = elemData.events) ) {
3517 return;
3518 }
3519
3520 // Once for each type.namespace in types; type may be omitted
3521 types = hoverHack( types || "" ).split(" ");
3522 for ( t = 0; t < types.length; t++ ) {
3523 tns = rtypenamespace.exec( types[t] ) || [];
3524 type = tns[1];
3525 namespaces = tns[2];
3526
3527 // Unbind all events (on this namespace, if provided) for the element
3528 if ( !type ) {
3529 namespaces = namespaces? "." + namespaces : "";
3530 for ( j in events ) {
3531 jQuery.event.remove( elem, j + namespaces, handler, selector );
3532 }
3533 return;
3534 }
3535
3536 special = jQuery.event.special[ type ] || {};
3537 type = ( selector? special.delegateType : special.bindType ) || type;
3538 eventType = events[ type ] || [];
3539 origCount = eventType.length;
3540 namespaces = namespaces ? new RegExp("(^|\\.)" + namespaces.split(".").sort().join("\\.(?:.*\\.)?") + "(\\.|$)") : null;
3541
3542 // Only need to loop for special events or selective removal
3543 if ( handler || namespaces || selector || special.remove ) {
3544 for ( j = 0; j < eventType.length; j++ ) {
3545 handleObj = eventType[ j ];
3546
3547 if ( !handler || handler.guid === handleObj.guid ) {
3548 if ( !namespaces || namespaces.test( handleObj.namespace ) ) {
3549 if ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) {
3550 eventType.splice( j--, 1 );
3551
3552 if ( handleObj.selector ) {
3553 eventType.delegateCount--;
3554 }
3555 if ( special.remove ) {
3556 special.remove.call( elem, handleObj );
3557 }
3558 }
3559 }
3560 }
3561 }
3562 } else {
3563 // Removing all events
3564 eventType.length = 0;
3565 }
3566
3567 // Remove generic event handler if we removed something and no more handlers exist
3568 // (avoids potential for endless recursion during removal of special event handlers)
3569 if ( eventType.length === 0 && origCount !== eventType.length ) {
3570 if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) {
3571 jQuery.removeEvent( elem, type, elemData.handle );
3572 }
3573
3574 delete events[ type ];
3575 }
3576 }
3577
3578 // Remove the expando if it's no longer used
3579 if ( jQuery.isEmptyObject( events ) ) {
3580 handle = elemData.handle;
3581 if ( handle ) {
3582 handle.elem = null;
3583 }
3584
3585 // removeData also checks for emptiness and clears the expando if empty
3586 // so use it instead of delete
3587 jQuery.removeData( elem, [ "events", "handle" ], true );
3588 }
3589 },
3590
3591 // Events that are safe to short-circuit if no handlers are attached.
3592 // Native DOM events should not be added, they may have inline handlers.
3593 customEvent: {
3594 "getData": true,
3595 "setData": true,
3596 "changeData": true
3597 },
3598
3599 trigger: function( event, data, elem, onlyHandlers ) {
3600 // Don't do events on text and comment nodes
3601 if ( elem && (elem.nodeType === 3 || elem.nodeType === 8) ) {
3602 return;
3603 }
3604
3605 // Event object or event type
3606 var type = event.type || event,
3607 namespaces = [],
3608 cache, exclusive, i, cur, old, ontype, special, handle, eventPath, bubbleType;
3609
3610 if ( type.indexOf( "!" ) >= 0 ) {
3611 // Exclusive events trigger only for the exact event (no namespaces)
3612 type = type.slice(0, -1);
3613 exclusive = true;
3614 }
3615
3616 if ( type.indexOf( "." ) >= 0 ) {
3617 // Namespaced trigger; create a regexp to match event type in handle()
3618 namespaces = type.split(".");
3619 type = namespaces.shift();
3620 namespaces.sort();
3621 }
3622
3623 if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) {
3624 // No jQuery handlers for this event type, and it can't have inline handlers
3625 return;
3626 }
3627
3628 // Caller can pass in an Event, Object, or just an event type string
3629 event = typeof event === "object" ?
3630 // jQuery.Event object
3631 event[ jQuery.expando ] ? event :
3632 // Object literal
3633 new jQuery.Event( type, event ) :
3634 // Just the event type (string)
3635 new jQuery.Event( type );
3636
3637 event.type = type;
3638 event.isTrigger = true;
3639 event.exclusive = exclusive;
3640 event.namespace = namespaces.join( "." );
3641 event.namespace_re = event.namespace? new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.)?") + "(\\.|$)") : null;
3642 ontype = type.indexOf( ":" ) < 0 ? "on" + type : "";
3643
3644 // triggerHandler() and global events don't bubble or run the default action
3645 if ( onlyHandlers || !elem ) {
3646 event.preventDefault();
3647 }
3648
3649 // Handle a global trigger
3650 if ( !elem ) {
3651
3652 // TODO: Stop taunting the data cache; remove global events and always attach to document
3653 cache = jQuery.cache;
3654 for ( i in cache ) {
3655 if ( cache[ i ].events && cache[ i ].events[ type ] ) {
3656 jQuery.event.trigger( event, data, cache[ i ].handle.elem, true );
3657 }
3658 }
3659 return;
3660 }
3661
3662 // Clean up the event in case it is being reused
3663 event.result = undefined;
3664 if ( !event.target ) {
3665 event.target = elem;
3666 }
3667
3668 // Clone any incoming data and prepend the event, creating the handler arg list
3669 data = data != null ? jQuery.makeArray( data ) : [];
3670 data.unshift( event );
3671
3672 // Allow special events to draw outside the lines
3673 special = jQuery.event.special[ type ] || {};
3674 if ( special.trigger && special.trigger.apply( elem, data ) === false ) {
3675 return;
3676 }
3677
3678 // Determine event propagation path in advance, per W3C events spec (#9951)
3679 // Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
3680 eventPath = [[ elem, special.bindType || type ]];
3681 if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {
3682
3683 bubbleType = special.delegateType || type;
3684 old = null;
3685 for ( cur = elem.parentNode; cur; cur = cur.parentNode ) {
3686 eventPath.push([ cur, bubbleType ]);
3687 old = cur;
3688 }
3689
3690 // Only add window if we got to document (e.g., not plain obj or detached DOM)
3691 if ( old && old === elem.ownerDocument ) {
3692 eventPath.push([ old.defaultView || old.parentWindow || window, bubbleType ]);
3693 }
3694 }
3695
3696 // Fire handlers on the event path
3697 for ( i = 0; i < eventPath.length; i++ ) {
3698
3699 cur = eventPath[i][0];
3700 event.type = eventPath[i][1];
3701
3702 handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" );
3703 if ( handle ) {
3704 handle.apply( cur, data );
3705 }
3706 handle = ontype && cur[ ontype ];
3707 if ( handle && jQuery.acceptData( cur ) ) {
3708 handle.apply( cur, data );
3709 }
3710
3711 if ( event.isPropagationStopped() ) {
3712 break;
3713 }
3714 }
3715 event.type = type;
3716
3717 // If nobody prevented the default action, do it now
3718 if ( !event.isDefaultPrevented() ) {
3719
3720 if ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) &&
3721 !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) {
3722
3723 // Call a native DOM method on the target with the same name name as the event.
3724 // Can't use an .isFunction() check here because IE6/7 fails that test.
3725 // Don't do default actions on window, that's where global variables be (#6170)
3726 // IE<9 dies on focus/blur to hidden element (#1486)
3727 if ( ontype && elem[ type ] && ((type !== "focus" && type !== "blur") || event.target.offsetWidth !== 0) && !jQuery.isWindow( elem ) ) {
3728
3729 // Don't re-trigger an onFOO event when we call its FOO() method
3730 old = elem[ ontype ];
3731
3732 if ( old ) {
3733 elem[ ontype ] = null;
3734 }
3735
3736 // Prevent re-triggering of the same event, since we already bubbled it above
3737 jQuery.event.triggered = type;
3738 elem[ type ]();
3739 jQuery.event.triggered = undefined;
3740
3741 if ( old ) {
3742 elem[ ontype ] = old;
3743 }
3744 }
3745 }
3746 }
3747
3748 return event.result;
3749 },
3750
3751 dispatch: function( event ) {
3752
3753 // Make a writable jQuery.Event from the native event object
3754 event = jQuery.event.fix( event || window.event );
3755
3756 var handlers = ( (jQuery._data( this, "events" ) || {} )[ event.type ] || []),
3757 delegateCount = handlers.delegateCount,
3758 args = [].slice.call( arguments, 0 ),
3759 run_all = !event.exclusive && !event.namespace,
3760 specialHandle = ( jQuery.event.special[ event.type ] || {} ).handle,
3761 handlerQueue = [],
3762 i, j, cur, ret, selMatch, matched, matches, handleObj, sel, hit, related;
3763
3764 // Use the fix-ed jQuery.Event rather than the (read-only) native event
3765 args[0] = event;
3766 event.delegateTarget = this;
3767
3768 // Determine handlers that should run if there are delegated events
3769 // Avoid disabled elements in IE (#6911) and non-left-click bubbling in Firefox (#3861)
3770 if ( delegateCount && !event.target.disabled && !(event.button && event.type === "click") ) {
3771
3772 for ( cur = event.target; cur != this; cur = cur.parentNode || this ) {
3773 selMatch = {};
3774 matches = [];
3775 for ( i = 0; i < delegateCount; i++ ) {
3776 handleObj = handlers[ i ];
3777 sel = handleObj.selector;
3778 hit = selMatch[ sel ];
3779
3780 if ( handleObj.isPositional ) {
3781 // Since .is() does not work for positionals; see http://jsfiddle.net/eJ4yd/3/
3782 hit = ( hit || (selMatch[ sel ] = jQuery( sel )) ).index( cur ) >= 0;
3783 } else if ( hit === undefined ) {
3784 hit = selMatch[ sel ] = ( handleObj.quick ? quickIs( cur, handleObj.quick ) : jQuery( cur ).is( sel ) );
3785 }
3786 if ( hit ) {
3787 matches.push( handleObj );
3788 }
3789 }
3790 if ( matches.length ) {
3791 handlerQueue.push({ elem: cur, matches: matches });
3792 }
3793 }
3794 }
3795
3796 // Add the remaining (directly-bound) handlers
3797 if ( handlers.length > delegateCount ) {
3798 handlerQueue.push({ elem: this, matches: handlers.slice( delegateCount ) });
3799 }
3800
3801 // Run delegates first; they may want to stop propagation beneath us
3802 for ( i = 0; i < handlerQueue.length && !event.isPropagationStopped(); i++ ) {
3803 matched = handlerQueue[ i ];
3804 event.currentTarget = matched.elem;
3805
3806 for ( j = 0; j < matched.matches.length && !event.isImmediatePropagationStopped(); j++ ) {
3807 handleObj = matched.matches[ j ];
3808
3809 // Triggered event must either 1) be non-exclusive and have no namespace, or
3810 // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace).
3811 if ( run_all || (!event.namespace && !handleObj.namespace) || event.namespace_re && event.namespace_re.test( handleObj.namespace ) ) {
3812
3813 event.data = handleObj.data;
3814 event.handleObj = handleObj;
3815
3816 ret = ( specialHandle || handleObj.handler ).apply( matched.elem, args );
3817
3818 if ( ret !== undefined ) {
3819 event.result = ret;
3820 if ( ret === false ) {
3821 event.preventDefault();
3822 event.stopPropagation();
3823 }
3824 }
3825 }
3826 }
3827 }
3828
3829 return event.result;
3830 },
3831
3832 // Includes some event props shared by KeyEvent and MouseEvent
3833 // *** attrChange attrName relatedNode srcElement are not normalized, non-W3C, deprecated, will be removed in 1.8 ***
3834 props: "attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),
3835
3836 fixHooks: {},
3837
3838 keyHooks: {
3839 props: "char charCode key keyCode".split(" "),
3840 filter: function( event, original ) {
3841
3842 // Add which for key events
3843 if ( event.which == null ) {
3844 event.which = original.charCode != null ? original.charCode : original.keyCode;
3845 }
3846
3847 return event;
3848 }
3849 },
3850
3851 mouseHooks: {
3852 props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement wheelDelta".split(" "),
3853 filter: function( event, original ) {
3854 var eventDoc, doc, body,
3855 button = original.button,
3856 fromElement = original.fromElement;
3857
3858 // Calculate pageX/Y if missing and clientX/Y available
3859 if ( event.pageX == null && original.clientX != null ) {
3860 eventDoc = event.target.ownerDocument || document;
3861 doc = eventDoc.documentElement;
3862 body = eventDoc.body;
3863
3864 event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 );
3865 event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 );
3866 }
3867
3868 // Add relatedTarget, if necessary
3869 if ( !event.relatedTarget && fromElement ) {
3870 event.relatedTarget = fromElement === event.target ? original.toElement : fromElement;
3871 }
3872
3873 // Add which for click: 1 === left; 2 === middle; 3 === right
3874 // Note: button is not normalized, so don't use it
3875 if ( !event.which && button !== undefined ) {
3876 event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );
3877 }
3878
3879 return event;
3880 }
3881 },
3882
3883 fix: function( event ) {
3884 if ( event[ jQuery.expando ] ) {
3885 return event;
3886 }
3887
3888 // Create a writable copy of the event object and normalize some properties
3889 var i, prop,
3890 originalEvent = event,
3891 fixHook = jQuery.event.fixHooks[ event.type ] || {},
3892 copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props;
3893
3894 event = jQuery.Event( originalEvent );
3895
3896 for ( i = copy.length; i; ) {
3897 prop = copy[ --i ];
3898 event[ prop ] = originalEvent[ prop ];
3899 }
3900
3901 // Fix target property, if necessary (#1925, IE 6/7/8 & Safari2)
3902 if ( !event.target ) {
3903 event.target = originalEvent.srcElement || document;
3904 }
3905
3906 // Target should not be a text node (#504, Safari)
3907 if ( event.target.nodeType === 3 ) {
3908 event.target = event.target.parentNode;
3909 }
3910
3911 // For mouse/key events; add metaKey if it's not there (#3368, IE6/7/8)
3912 if ( event.metaKey === undefined ) {
3913 event.metaKey = event.ctrlKey;
3914 }
3915
3916 return fixHook.filter? fixHook.filter( event, originalEvent ) : event;
3917 },
3918
3919 special: {
3920 ready: {
3921 // Make sure the ready event is setup
3922 setup: jQuery.bindReady
3923 },
3924
3925 focus: {
3926 delegateType: "focusin",
3927 noBubble: true
3928 },
3929 blur: {
3930 delegateType: "focusout",
3931 noBubble: true
3932 },
3933
3934 beforeunload: {
3935 setup: function( data, namespaces, eventHandle ) {
3936 // We only want to do this special case on windows
3937 if ( jQuery.isWindow( this ) ) {
3938 this.onbeforeunload = eventHandle;
3939 }
3940 },
3941
3942 teardown: function( namespaces, eventHandle ) {
3943 if ( this.onbeforeunload === eventHandle ) {
3944 this.onbeforeunload = null;
3945 }
3946 }
3947 }
3948 },
3949
3950 simulate: function( type, elem, event, bubble ) {
3951 // Piggyback on a donor event to simulate a different one.
3952 // Fake originalEvent to avoid donor's stopPropagation, but if the
3953 // simulated event prevents default then we do the same on the donor.
3954 var e = jQuery.extend(
3955 new jQuery.Event(),
3956 event,
3957 { type: type,
3958 isSimulated: true,
3959 originalEvent: {}
3960 }
3961 );
3962 if ( bubble ) {
3963 jQuery.event.trigger( e, null, elem );
3964 } else {
3965 jQuery.event.dispatch.call( elem, e );
3966 }
3967 if ( e.isDefaultPrevented() ) {
3968 event.preventDefault();
3969 }
3970 }
3971};
3972
3973// Some plugins are using, but it's undocumented/deprecated and will be removed.
3974// The 1.7 special event interface should provide all the hooks needed now.
3975jQuery.event.handle = jQuery.event.dispatch;
3976
3977jQuery.removeEvent = document.removeEventListener ?
3978 function( elem, type, handle ) {
3979 if ( elem.removeEventListener ) {
3980 elem.removeEventListener( type, handle, false );
3981 }
3982 } :
3983 function( elem, type, handle ) {
3984 if ( elem.detachEvent ) {
3985 elem.detachEvent( "on" + type, handle );
3986 }
3987 };
3988
3989jQuery.Event = function( src, props ) {
3990 // Allow instantiation without the 'new' keyword
3991 if ( !(this instanceof jQuery.Event) ) {
3992 return new jQuery.Event( src, props );
3993 }
3994
3995 // Event object
3996 if ( src && src.type ) {
3997 this.originalEvent = src;
3998 this.type = src.type;
3999
4000 // Events bubbling up the document may have been marked as prevented
4001 // by a handler lower down the tree; reflect the correct value.
4002 this.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false ||
4003 src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse;
4004
4005 // Event type
4006 } else {
4007 this.type = src;
4008 }
4009
4010 // Put explicitly provided properties onto the event object
4011 if ( props ) {
4012 jQuery.extend( this, props );
4013 }
4014
4015 // Create a timestamp if incoming event doesn't have one
4016 this.timeStamp = src && src.timeStamp || jQuery.now();
4017
4018 // Mark it as fixed
4019 this[ jQuery.expando ] = true;
4020};
4021
4022function returnFalse() {
4023 return false;
4024}
4025function returnTrue() {
4026 return true;
4027}
4028
4029// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
4030// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
4031jQuery.Event.prototype = {
4032 preventDefault: function() {
4033 this.isDefaultPrevented = returnTrue;
4034
4035 var e = this.originalEvent;
4036 if ( !e ) {
4037 return;
4038 }
4039
4040 // if preventDefault exists run it on the original event
4041 if ( e.preventDefault ) {
4042 e.preventDefault();
4043
4044 // otherwise set the returnValue property of the original event to false (IE)
4045 } else {
4046 e.returnValue = false;
4047 }
4048 },
4049 stopPropagation: function() {
4050 this.isPropagationStopped = returnTrue;
4051
4052 var e = this.originalEvent;
4053 if ( !e ) {
4054 return;
4055 }
4056 // if stopPropagation exists run it on the original event
4057 if ( e.stopPropagation ) {
4058 e.stopPropagation();
4059 }
4060 // otherwise set the cancelBubble property of the original event to true (IE)
4061 e.cancelBubble = true;
4062 },
4063 stopImmediatePropagation: function() {
4064 this.isImmediatePropagationStopped = returnTrue;
4065 this.stopPropagation();
4066 },
4067 isDefaultPrevented: returnFalse,
4068 isPropagationStopped: returnFalse,
4069 isImmediatePropagationStopped: returnFalse
4070};
4071
4072// Create mouseenter/leave events using mouseover/out and event-time checks
4073jQuery.each({
4074 mouseenter: "mouseover",
4075 mouseleave: "mouseout"
4076}, function( orig, fix ) {
4077 jQuery.event.special[ orig ] = jQuery.event.special[ fix ] = {
4078 delegateType: fix,
4079 bindType: fix,
4080
4081 handle: function( event ) {
4082 var target = this,
4083 related = event.relatedTarget,
4084 handleObj = event.handleObj,
4085 selector = handleObj.selector,
4086 oldType, ret;
4087
4088 // For a real mouseover/out, always call the handler; for
4089 // mousenter/leave call the handler if related is outside the target.
4090 // NB: No relatedTarget if the mouse left/entered the browser window
4091 if ( !related || handleObj.origType === event.type || (related !== target && !jQuery.contains( target, related )) ) {
4092 oldType = event.type;
4093 event.type = handleObj.origType;
4094 ret = handleObj.handler.apply( this, arguments );
4095 event.type = oldType;
4096 }
4097 return ret;
4098 }
4099 };
4100});
4101
4102// IE submit delegation
4103if ( !jQuery.support.submitBubbles ) {
4104
4105 jQuery.event.special.submit = {
4106 setup: function() {
4107 // Only need this for delegated form submit events
4108 if ( jQuery.nodeName( this, "form" ) ) {
4109 return false;
4110 }
4111
4112 // Lazy-add a submit handler when a descendant form may potentially be submitted
4113 jQuery.event.add( this, "click._submit keypress._submit", function( e ) {
4114 // Node name check avoids a VML-related crash in IE (#9807)
4115 var elem = e.target,
4116 form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined;
4117 if ( form && !form._submit_attached ) {
4118 jQuery.event.add( form, "submit._submit", function( event ) {
4119 // Form was submitted, bubble the event up the tree
4120 if ( this.parentNode ) {
4121 jQuery.event.simulate( "submit", this.parentNode, event, true );
4122 }
4123 });
4124 form._submit_attached = true;
4125 }
4126 });
4127 // return undefined since we don't need an event listener
4128 },
4129
4130 teardown: function() {
4131 // Only need this for delegated form submit events
4132 if ( jQuery.nodeName( this, "form" ) ) {
4133 return false;
4134 }
4135
4136 // Remove delegated handlers; cleanData eventually reaps submit handlers attached above
4137 jQuery.event.remove( this, "._submit" );
4138 }
4139 };
4140}
4141
4142// IE change delegation and checkbox/radio fix
4143if ( !jQuery.support.changeBubbles ) {
4144
4145 jQuery.event.special.change = {
4146
4147 setup: function() {
4148
4149 if ( rformElems.test( this.nodeName ) ) {
4150 // IE doesn't fire change on a check/radio until blur; trigger it on click
4151 // after a propertychange. Eat the blur-change in special.change.handle.
4152 // This still fires onchange a second time for check/radio after blur.
4153 if ( this.type === "checkbox" || this.type === "radio" ) {
4154 jQuery.event.add( this, "propertychange._change", function( event ) {
4155 if ( event.originalEvent.propertyName === "checked" ) {
4156 this._just_changed = true;
4157 }
4158 });
4159 jQuery.event.add( this, "click._change", function( event ) {
4160 if ( this._just_changed ) {
4161 this._just_changed = false;
4162 jQuery.event.simulate( "change", this, event, true );
4163 }
4164 });
4165 }
4166 return false;
4167 }
4168 // Delegated event; lazy-add a change handler on descendant inputs
4169 jQuery.event.add( this, "beforeactivate._change", function( e ) {
4170 var elem = e.target;
4171
4172 if ( rformElems.test( elem.nodeName ) && !elem._change_attached ) {
4173 jQuery.event.add( elem, "change._change", function( event ) {
4174 if ( this.parentNode && !event.isSimulated ) {
4175 jQuery.event.simulate( "change", this.parentNode, event, true );
4176 }
4177 });
4178 elem._change_attached = true;
4179 }
4180 });
4181 },
4182
4183 handle: function( event ) {
4184 var elem = event.target;
4185
4186 // Swallow native change events from checkbox/radio, we already triggered them above
4187 if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) {
4188 return event.handleObj.handler.apply( this, arguments );
4189 }
4190 },
4191
4192 teardown: function() {
4193 jQuery.event.remove( this, "._change" );
4194
4195 return rformElems.test( this.nodeName );
4196 }
4197 };
4198}
4199
4200// Create "bubbling" focus and blur events
4201if ( !jQuery.support.focusinBubbles ) {
4202 jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
4203
4204 // Attach a single capturing handler while someone wants focusin/focusout
4205 var attaches = 0,
4206 handler = function( event ) {
4207 jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true );
4208 };
4209
4210 jQuery.event.special[ fix ] = {
4211 setup: function() {
4212 if ( attaches++ === 0 ) {
4213 document.addEventListener( orig, handler, true );
4214 }
4215 },
4216 teardown: function() {
4217 if ( --attaches === 0 ) {
4218 document.removeEventListener( orig, handler, true );
4219 }
4220 }
4221 };
4222 });
4223}
4224
4225jQuery.fn.extend({
4226
4227 on: function( types, selector, data, fn, /*INTERNAL*/ one ) {
4228 var origFn, type;
4229
4230 // Types can be a map of types/handlers
4231 if ( typeof types === "object" ) {
4232 // ( types-Object, selector, data )
4233 if ( typeof selector !== "string" ) {
4234 // ( types-Object, data )
4235 data = selector;
4236 selector = undefined;
4237 }
4238 for ( type in types ) {
4239 this.on( type, selector, data, types[ type ], one );
4240 }
4241 return this;
4242 }
4243
4244 if ( data == null && fn == null ) {
4245 // ( types, fn )
4246 fn = selector;
4247 data = selector = undefined;
4248 } else if ( fn == null ) {
4249 if ( typeof selector === "string" ) {
4250 // ( types, selector, fn )
4251 fn = data;
4252 data = undefined;
4253 } else {
4254 // ( types, data, fn )
4255 fn = data;
4256 data = selector;
4257 selector = undefined;
4258 }
4259 }
4260 if ( fn === false ) {
4261 fn = returnFalse;
4262 } else if ( !fn ) {
4263 return this;
4264 }
4265
4266 if ( one === 1 ) {
4267 origFn = fn;
4268 fn = function( event ) {
4269 // Can use an empty set, since event contains the info
4270 jQuery().off( event );
4271 return origFn.apply( this, arguments );
4272 };
4273 // Use same guid so caller can remove using origFn
4274 fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
4275 }
4276 return this.each( function() {
4277 jQuery.event.add( this, types, fn, data, selector );
4278 });
4279 },
4280 one: function( types, selector, data, fn ) {
4281 return this.on.call( this, types, selector, data, fn, 1 );
4282 },
4283 off: function( types, selector, fn ) {
4284 if ( types && types.preventDefault && types.handleObj ) {
4285 // ( event ) dispatched jQuery.Event
4286 var handleObj = types.handleObj;
4287 jQuery( types.delegateTarget ).off(
4288 handleObj.namespace? handleObj.type + "." + handleObj.namespace : handleObj.type,
4289 handleObj.selector,
4290 handleObj.handler
4291 );
4292 return this;
4293 }
4294 if ( typeof types === "object" ) {
4295 // ( types-object [, selector] )
4296 for ( var type in types ) {
4297 this.off( type, selector, types[ type ] );
4298 }
4299 return this;
4300 }
4301 if ( selector === false || typeof selector === "function" ) {
4302 // ( types [, fn] )
4303 fn = selector;
4304 selector = undefined;
4305 }
4306 if ( fn === false ) {
4307 fn = returnFalse;
4308 }
4309 return this.each(function() {
4310 jQuery.event.remove( this, types, fn, selector );
4311 });
4312 },
4313
4314 bind: function( types, data, fn ) {
4315 return this.on( types, null, data, fn );
4316 },
4317 unbind: function( types, fn ) {
4318 return this.off( types, null, fn );
4319 },
4320
4321 live: function( types, data, fn ) {
4322 jQuery( this.context ).on( types, this.selector, data, fn );
4323 return this;
4324 },
4325 die: function( types, fn ) {
4326 jQuery( this.context ).off( types, this.selector || "**", fn );
4327 return this;
4328 },
4329
4330 delegate: function( selector, types, data, fn ) {
4331 return this.on( types, selector, data, fn );
4332 },
4333 undelegate: function( selector, types, fn ) {
4334 // ( namespace ) or ( selector, types [, fn] )
4335 return arguments.length == 1? this.off( selector, "**" ) : this.off( types, selector, fn );
4336 },
4337
4338 trigger: function( type, data ) {
4339 return this.each(function() {
4340 jQuery.event.trigger( type, data, this );
4341 });
4342 },
4343 triggerHandler: function( type, data ) {
4344 if ( this[0] ) {
4345 return jQuery.event.trigger( type, data, this[0], true );
4346 }
4347 },
4348
4349 toggle: function( fn ) {
4350 // Save reference to arguments for access in closure
4351 var args = arguments,
4352 guid = fn.guid || jQuery.guid++,
4353 i = 0,
4354 toggler = function( event ) {
4355 // Figure out which function to execute
4356 var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i;
4357 jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 );
4358
4359 // Make sure that clicks stop
4360 event.preventDefault();
4361
4362 // and execute the function
4363 return args[ lastToggle ].apply( this, arguments ) || false;
4364 };
4365
4366 // link all the functions, so any of them can unbind this click handler
4367 toggler.guid = guid;
4368 while ( i < args.length ) {
4369 args[ i++ ].guid = guid;
4370 }
4371
4372 return this.click( toggler );
4373 },
4374
4375 hover: function( fnOver, fnOut ) {
4376 return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
4377 }
4378});
4379
4380jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
4381 "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
4382 "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) {
4383
4384 // Handle event binding
4385 jQuery.fn[ name ] = function( data, fn ) {
4386 if ( fn == null ) {
4387 fn = data;
4388 data = null;
4389 }
4390
4391 return arguments.length > 0 ?
4392 this.bind( name, data, fn ) :
4393 this.trigger( name );
4394 };
4395
4396 if ( jQuery.attrFn ) {
4397 jQuery.attrFn[ name ] = true;
4398 }
4399
4400 if ( rkeyEvent.test( name ) ) {
4401 jQuery.event.fixHooks[ name ] = jQuery.event.keyHooks;
4402 }
4403
4404 if ( rmouseEvent.test( name ) ) {
4405 jQuery.event.fixHooks[ name ] = jQuery.event.mouseHooks;
4406 }
4407});
4408
4409})( jQuery );
4410
4411/*!
4412 * Sizzle CSS Selector Engine
4413 * Copyright 2011, The Dojo Foundation
4414 * Released under the MIT, BSD, and GPL Licenses.
4415 * More information: http://sizzlejs.com/
4416 */
4417(function(){
4418
4419var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
4420 expando = "sizcache" + (Math.random() + '').replace('.', ''),
4421 done = 0,
4422 toString = Object.prototype.toString,
4423 hasDuplicate = false,
4424 baseHasDuplicate = true,
4425 rBackslash = /\\/g,
4426 rReturn = /\r\n/g,
4427 rNonWord = /\W/;
4428
4429// Here we check if the JavaScript engine is using some sort of
4430// optimization where it does not always call our comparision
4431// function. If that is the case, discard the hasDuplicate value.
4432// Thus far that includes Google Chrome.
4433[0, 0].sort(function() {
4434 baseHasDuplicate = false;
4435 return 0;
4436});
4437
4438var Sizzle = function( selector, context, results, seed ) {
4439 results = results || [];
4440 context = context || document;
4441
4442 var origContext = context;
4443
4444 if ( context.nodeType !== 1 && context.nodeType !== 9 ) {
4445 return [];
4446 }
4447
4448 if ( !selector || typeof selector !== "string" ) {
4449 return results;
4450 }
4451
4452 var m, set, checkSet, extra, ret, cur, pop, i,
4453 prune = true,
4454 contextXML = Sizzle.isXML( context ),
4455 parts = [],
4456 soFar = selector;
4457
4458 // Reset the position of the chunker regexp (start from head)
4459 do {
4460 chunker.exec( "" );
4461 m = chunker.exec( soFar );
4462
4463 if ( m ) {
4464 soFar = m[3];
4465
4466 parts.push( m[1] );
4467
4468 if ( m[2] ) {
4469 extra = m[3];
4470 break;
4471 }
4472 }
4473 } while ( m );
4474
4475 if ( parts.length > 1 && origPOS.exec( selector ) ) {
4476
4477 if ( parts.length === 2 && Expr.relative[ parts[0] ] ) {
4478 set = posProcess( parts[0] + parts[1], context, seed );
4479
4480 } else {
4481 set = Expr.relative[ parts[0] ] ?
4482 [ context ] :
4483 Sizzle( parts.shift(), context );
4484
4485 while ( parts.length ) {
4486 selector = parts.shift();
4487
4488 if ( Expr.relative[ selector ] ) {
4489 selector += parts.shift();
4490 }
4491
4492 set = posProcess( selector, set, seed );
4493 }
4494 }
4495
4496 } else {
4497 // Take a shortcut and set the context if the root selector is an ID
4498 // (but not if it'll be faster if the inner selector is an ID)
4499 if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML &&
4500 Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) {
4501
4502 ret = Sizzle.find( parts.shift(), context, contextXML );
4503 context = ret.expr ?
4504 Sizzle.filter( ret.expr, ret.set )[0] :
4505 ret.set[0];
4506 }
4507
4508 if ( context ) {
4509 ret = seed ?
4510 { expr: parts.pop(), set: makeArray(seed) } :
4511 Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML );
4512
4513 set = ret.expr ?
4514 Sizzle.filter( ret.expr, ret.set ) :
4515 ret.set;
4516
4517 if ( parts.length > 0 ) {
4518 checkSet = makeArray( set );
4519
4520 } else {
4521 prune = false;
4522 }
4523
4524 while ( parts.length ) {
4525 cur = parts.pop();
4526 pop = cur;
4527
4528 if ( !Expr.relative[ cur ] ) {
4529 cur = "";
4530 } else {
4531 pop = parts.pop();
4532 }
4533
4534 if ( pop == null ) {
4535 pop = context;
4536 }
4537
4538 Expr.relative[ cur ]( checkSet, pop, contextXML );
4539 }
4540
4541 } else {
4542 checkSet = parts = [];
4543 }
4544 }
4545
4546 if ( !checkSet ) {
4547 checkSet = set;
4548 }
4549
4550 if ( !checkSet ) {
4551 Sizzle.error( cur || selector );
4552 }
4553
4554 if ( toString.call(checkSet) === "[object Array]" ) {
4555 if ( !prune ) {
4556 results.push.apply( results, checkSet );
4557
4558 } else if ( context && context.nodeType === 1 ) {
4559 for ( i = 0; checkSet[i] != null; i++ ) {
4560 if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && Sizzle.contains(context, checkSet[i])) ) {
4561 results.push( set[i] );
4562 }
4563 }
4564
4565 } else {
4566 for ( i = 0; checkSet[i] != null; i++ ) {
4567 if ( checkSet[i] && checkSet[i].nodeType === 1 ) {
4568 results.push( set[i] );
4569 }
4570 }
4571 }
4572
4573 } else {
4574 makeArray( checkSet, results );
4575 }
4576
4577 if ( extra ) {
4578 Sizzle( extra, origContext, results, seed );
4579 Sizzle.uniqueSort( results );
4580 }
4581
4582 return results;
4583};
4584
4585Sizzle.uniqueSort = function( results ) {
4586 if ( sortOrder ) {
4587 hasDuplicate = baseHasDuplicate;
4588 results.sort( sortOrder );
4589
4590 if ( hasDuplicate ) {
4591 for ( var i = 1; i < results.length; i++ ) {
4592 if ( results[i] === results[ i - 1 ] ) {
4593 results.splice( i--, 1 );
4594 }
4595 }
4596 }
4597 }
4598
4599 return results;
4600};
4601
4602Sizzle.matches = function( expr, set ) {
4603 return Sizzle( expr, null, null, set );
4604};
4605
4606Sizzle.matchesSelector = function( node, expr ) {
4607 return Sizzle( expr, null, null, [node] ).length > 0;
4608};
4609
4610Sizzle.find = function( expr, context, isXML ) {
4611 var set, i, len, match, type, left;
4612
4613 if ( !expr ) {
4614 return [];
4615 }
4616
4617 for ( i = 0, len = Expr.order.length; i < len; i++ ) {
4618 type = Expr.order[i];
4619
4620 if ( (match = Expr.leftMatch[ type ].exec( expr )) ) {
4621 left = match[1];
4622 match.splice( 1, 1 );
4623
4624 if ( left.substr( left.length - 1 ) !== "\\" ) {
4625 match[1] = (match[1] || "").replace( rBackslash, "" );
4626 set = Expr.find[ type ]( match, context, isXML );
4627
4628 if ( set != null ) {
4629 expr = expr.replace( Expr.match[ type ], "" );
4630 break;
4631 }
4632 }
4633 }
4634 }
4635
4636 if ( !set ) {
4637 set = typeof context.getElementsByTagName !== "undefined" ?
4638 context.getElementsByTagName( "*" ) :
4639 [];
4640 }
4641
4642 return { set: set, expr: expr };
4643};
4644
4645Sizzle.filter = function( expr, set, inplace, not ) {
4646 var match, anyFound,
4647 type, found, item, filter, left,
4648 i, pass,
4649 old = expr,
4650 result = [],
4651 curLoop = set,
4652 isXMLFilter = set && set[0] && Sizzle.isXML( set[0] );
4653
4654 while ( expr && set.length ) {
4655 for ( type in Expr.filter ) {
4656 if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) {
4657 filter = Expr.filter[ type ];
4658 left = match[1];
4659
4660 anyFound = false;
4661
4662 match.splice(1,1);
4663
4664 if ( left.substr( left.length - 1 ) === "\\" ) {
4665 continue;
4666 }
4667
4668 if ( curLoop === result ) {
4669 result = [];
4670 }
4671
4672 if ( Expr.preFilter[ type ] ) {
4673 match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter );
4674
4675 if ( !match ) {
4676 anyFound = found = true;
4677
4678 } else if ( match === true ) {
4679 continue;
4680 }
4681 }
4682
4683 if ( match ) {
4684 for ( i = 0; (item = curLoop[i]) != null; i++ ) {
4685 if ( item ) {
4686 found = filter( item, match, i, curLoop );
4687 pass = not ^ found;
4688
4689 if ( inplace && found != null ) {
4690 if ( pass ) {
4691 anyFound = true;
4692
4693 } else {
4694 curLoop[i] = false;
4695 }
4696
4697 } else if ( pass ) {
4698 result.push( item );
4699 anyFound = true;
4700 }
4701 }
4702 }
4703 }
4704
4705 if ( found !== undefined ) {
4706 if ( !inplace ) {
4707 curLoop = result;
4708 }
4709
4710 expr = expr.replace( Expr.match[ type ], "" );
4711
4712 if ( !anyFound ) {
4713 return [];
4714 }
4715
4716 break;
4717 }
4718 }
4719 }
4720
4721 // Improper expression
4722 if ( expr === old ) {
4723 if ( anyFound == null ) {
4724 Sizzle.error( expr );
4725
4726 } else {
4727 break;
4728 }
4729 }
4730
4731 old = expr;
4732 }
4733
4734 return curLoop;
4735};
4736
4737Sizzle.error = function( msg ) {
4738 throw "Syntax error, unrecognized expression: " + msg;
4739};
4740
4741/**
4742 * Utility function for retreiving the text value of an array of DOM nodes
4743 * @param {Array|Element} elem
4744 */
4745var getText = Sizzle.getText = function( elem ) {
4746 var i, node,
4747 nodeType = elem.nodeType,
4748 ret = "";
4749
4750 if ( nodeType ) {
4751 if ( nodeType === 1 ) {
4752 // Use textContent || innerText for elements
4753 if ( typeof elem.textContent === 'string' ) {
4754 return elem.textContent;
4755 } else if ( typeof elem.innerText === 'string' ) {
4756 // Replace IE's carriage returns
4757 return elem.innerText.replace( rReturn, '' );
4758 } else {
4759 // Traverse it's children
4760 for ( elem = elem.firstChild; elem; elem = elem.nextSibling) {
4761 ret += getText( elem );
4762 }
4763 }
4764 } else if ( nodeType === 3 || nodeType === 4 ) {
4765 return elem.nodeValue;
4766 }
4767 } else {
4768
4769 // If no nodeType, this is expected to be an array
4770 for ( i = 0; (node = elem[i]); i++ ) {
4771 // Do not traverse comment nodes
4772 if ( node.nodeType !== 8 ) {
4773 ret += getText( node );
4774 }
4775 }
4776 }
4777 return ret;
4778};
4779
4780var Expr = Sizzle.selectors = {
4781 order: [ "ID", "NAME", "TAG" ],
4782
4783 match: {
4784 ID: /#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,
4785 CLASS: /\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,
4786 NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,
4787 ATTR: /\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/,
4788 TAG: /^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,
4789 CHILD: /:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/,
4790 POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,
4791 PSEUDO: /:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/
4792 },
4793
4794 leftMatch: {},
4795
4796 attrMap: {
4797 "class": "className",
4798 "for": "htmlFor"
4799 },
4800
4801 attrHandle: {
4802 href: function( elem ) {
4803 return elem.getAttribute( "href" );
4804 },
4805 type: function( elem ) {
4806 return elem.getAttribute( "type" );
4807 }
4808 },
4809
4810 relative: {
4811 "+": function(checkSet, part){
4812 var isPartStr = typeof part === "string",
4813 isTag = isPartStr && !rNonWord.test( part ),
4814 isPartStrNotTag = isPartStr && !isTag;
4815
4816 if ( isTag ) {
4817 part = part.toLowerCase();
4818 }
4819
4820 for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) {
4821 if ( (elem = checkSet[i]) ) {
4822 while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {}
4823
4824 checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ?
4825 elem || false :
4826 elem === part;
4827 }
4828 }
4829
4830 if ( isPartStrNotTag ) {
4831 Sizzle.filter( part, checkSet, true );
4832 }
4833 },
4834
4835 ">": function( checkSet, part ) {
4836 var elem,
4837 isPartStr = typeof part === "string",
4838 i = 0,
4839 l = checkSet.length;
4840
4841 if ( isPartStr && !rNonWord.test( part ) ) {
4842 part = part.toLowerCase();
4843
4844 for ( ; i < l; i++ ) {
4845 elem = checkSet[i];
4846
4847 if ( elem ) {
4848 var parent = elem.parentNode;
4849 checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false;
4850 }
4851 }
4852
4853 } else {
4854 for ( ; i < l; i++ ) {
4855 elem = checkSet[i];
4856
4857 if ( elem ) {
4858 checkSet[i] = isPartStr ?
4859 elem.parentNode :
4860 elem.parentNode === part;
4861 }
4862 }
4863
4864 if ( isPartStr ) {
4865 Sizzle.filter( part, checkSet, true );
4866 }
4867 }
4868 },
4869
4870 "": function(checkSet, part, isXML){
4871 var nodeCheck,
4872 doneName = done++,
4873 checkFn = dirCheck;
4874
4875 if ( typeof part === "string" && !rNonWord.test( part ) ) {
4876 part = part.toLowerCase();
4877 nodeCheck = part;
4878 checkFn = dirNodeCheck;
4879 }
4880
4881 checkFn( "parentNode", part, doneName, checkSet, nodeCheck, isXML );
4882 },
4883
4884 "~": function( checkSet, part, isXML ) {
4885 var nodeCheck,
4886 doneName = done++,
4887 checkFn = dirCheck;
4888
4889 if ( typeof part === "string" && !rNonWord.test( part ) ) {
4890 part = part.toLowerCase();
4891 nodeCheck = part;
4892 checkFn = dirNodeCheck;
4893 }
4894
4895 checkFn( "previousSibling", part, doneName, checkSet, nodeCheck, isXML );
4896 }
4897 },
4898
4899 find: {
4900 ID: function( match, context, isXML ) {
4901 if ( typeof context.getElementById !== "undefined" && !isXML ) {
4902 var m = context.getElementById(match[1]);
4903 // Check parentNode to catch when Blackberry 4.6 returns
4904 // nodes that are no longer in the document #6963
4905 return m && m.parentNode ? [m] : [];
4906 }
4907 },
4908
4909 NAME: function( match, context ) {
4910 if ( typeof context.getElementsByName !== "undefined" ) {
4911 var ret = [],
4912 results = context.getElementsByName( match[1] );
4913
4914 for ( var i = 0, l = results.length; i < l; i++ ) {
4915 if ( results[i].getAttribute("name") === match[1] ) {
4916 ret.push( results[i] );
4917 }
4918 }
4919
4920 return ret.length === 0 ? null : ret;
4921 }
4922 },
4923
4924 TAG: function( match, context ) {
4925 if ( typeof context.getElementsByTagName !== "undefined" ) {
4926 return context.getElementsByTagName( match[1] );
4927 }
4928 }
4929 },
4930 preFilter: {
4931 CLASS: function( match, curLoop, inplace, result, not, isXML ) {
4932 match = " " + match[1].replace( rBackslash, "" ) + " ";
4933
4934 if ( isXML ) {
4935 return match;
4936 }
4937
4938 for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) {
4939 if ( elem ) {
4940 if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n\r]/g, " ").indexOf(match) >= 0) ) {
4941 if ( !inplace ) {
4942 result.push( elem );
4943 }
4944
4945 } else if ( inplace ) {
4946 curLoop[i] = false;
4947 }
4948 }
4949 }
4950
4951 return false;
4952 },
4953
4954 ID: function( match ) {
4955 return match[1].replace( rBackslash, "" );
4956 },
4957
4958 TAG: function( match, curLoop ) {
4959 return match[1].replace( rBackslash, "" ).toLowerCase();
4960 },
4961
4962 CHILD: function( match ) {
4963 if ( match[1] === "nth" ) {
4964 if ( !match[2] ) {
4965 Sizzle.error( match[0] );
4966 }
4967
4968 match[2] = match[2].replace(/^\+|\s*/g, '');
4969
4970 // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'
4971 var test = /(-?)(\d*)(?:n([+\-]?\d*))?/.exec(
4972 match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" ||
4973 !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]);
4974
4975 // calculate the numbers (first)n+(last) including if they are negative
4976 match[2] = (test[1] + (test[2] || 1)) - 0;
4977 match[3] = test[3] - 0;
4978 }
4979 else if ( match[2] ) {
4980 Sizzle.error( match[0] );
4981 }
4982
4983 // TODO: Move to normal caching system
4984 match[0] = done++;
4985
4986 return match;
4987 },
4988
4989 ATTR: function( match, curLoop, inplace, result, not, isXML ) {
4990 var name = match[1] = match[1].replace( rBackslash, "" );
4991
4992 if ( !isXML && Expr.attrMap[name] ) {
4993 match[1] = Expr.attrMap[name];
4994 }
4995
4996 // Handle if an un-quoted value was used
4997 match[4] = ( match[4] || match[5] || "" ).replace( rBackslash, "" );
4998
4999 if ( match[2] === "~=" ) {
5000 match[4] = " " + match[4] + " ";
5001 }
5002
5003 return match;
5004 },
5005
5006 PSEUDO: function( match, curLoop, inplace, result, not ) {
5007 if ( match[1] === "not" ) {
5008 // If we're dealing with a complex expression, or a simple one
5009 if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) {
5010 match[3] = Sizzle(match[3], null, null, curLoop);
5011
5012 } else {
5013 var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not);
5014
5015 if ( !inplace ) {
5016 result.push.apply( result, ret );
5017 }
5018
5019 return false;
5020 }
5021
5022 } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) {
5023 return true;
5024 }
5025
5026 return match;
5027 },
5028
5029 POS: function( match ) {
5030 match.unshift( true );
5031
5032 return match;
5033 }
5034 },
5035
5036 filters: {
5037 enabled: function( elem ) {
5038 return elem.disabled === false && elem.type !== "hidden";
5039 },
5040
5041 disabled: function( elem ) {
5042 return elem.disabled === true;
5043 },
5044
5045 checked: function( elem ) {
5046 return elem.checked === true;
5047 },
5048
5049 selected: function( elem ) {
5050 // Accessing this property makes selected-by-default
5051 // options in Safari work properly
5052 if ( elem.parentNode ) {
5053 elem.parentNode.selectedIndex;
5054 }
5055
5056 return elem.selected === true;
5057 },
5058
5059 parent: function( elem ) {
5060 return !!elem.firstChild;
5061 },
5062
5063 empty: function( elem ) {
5064 return !elem.firstChild;
5065 },
5066
5067 has: function( elem, i, match ) {
5068 return !!Sizzle( match[3], elem ).length;
5069 },
5070
5071 header: function( elem ) {
5072 return (/h\d/i).test( elem.nodeName );
5073 },
5074
5075 text: function( elem ) {
5076 var attr = elem.getAttribute( "type" ), type = elem.type;
5077 // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc)
5078 // use getAttribute instead to test this case
5079 return elem.nodeName.toLowerCase() === "input" && "text" === type && ( attr === type || attr === null );
5080 },
5081
5082 radio: function( elem ) {
5083 return elem.nodeName.toLowerCase() === "input" && "radio" === elem.type;
5084 },
5085
5086 checkbox: function( elem ) {
5087 return elem.nodeName.toLowerCase() === "input" && "checkbox" === elem.type;
5088 },
5089
5090 file: function( elem ) {
5091 return elem.nodeName.toLowerCase() === "input" && "file" === elem.type;
5092 },
5093
5094 password: function( elem ) {
5095 return elem.nodeName.toLowerCase() === "input" && "password" === elem.type;
5096 },
5097
5098 submit: function( elem ) {
5099 var name = elem.nodeName.toLowerCase();
5100 return (name === "input" || name === "button") && "submit" === elem.type;
5101 },
5102
5103 image: function( elem ) {
5104 return elem.nodeName.toLowerCase() === "input" && "image" === elem.type;
5105 },
5106
5107 reset: function( elem ) {
5108 var name = elem.nodeName.toLowerCase();
5109 return (name === "input" || name === "button") && "reset" === elem.type;
5110 },
5111
5112 button: function( elem ) {
5113 var name = elem.nodeName.toLowerCase();
5114 return name === "input" && "button" === elem.type || name === "button";
5115 },
5116
5117 input: function( elem ) {
5118 return (/input|select|textarea|button/i).test( elem.nodeName );
5119 },
5120
5121 focus: function( elem ) {
5122 return elem === elem.ownerDocument.activeElement;
5123 }
5124 },
5125 setFilters: {
5126 first: function( elem, i ) {
5127 return i === 0;
5128 },
5129
5130 last: function( elem, i, match, array ) {
5131 return i === array.length - 1;
5132 },
5133
5134 even: function( elem, i ) {
5135 return i % 2 === 0;
5136 },
5137
5138 odd: function( elem, i ) {
5139 return i % 2 === 1;
5140 },
5141
5142 lt: function( elem, i, match ) {
5143 return i < match[3] - 0;
5144 },
5145
5146 gt: function( elem, i, match ) {
5147 return i > match[3] - 0;
5148 },
5149
5150 nth: function( elem, i, match ) {
5151 return match[3] - 0 === i;
5152 },
5153
5154 eq: function( elem, i, match ) {
5155 return match[3] - 0 === i;
5156 }
5157 },
5158 filter: {
5159 PSEUDO: function( elem, match, i, array ) {
5160 var name = match[1],
5161 filter = Expr.filters[ name ];
5162
5163 if ( filter ) {
5164 return filter( elem, i, match, array );
5165
5166 } else if ( name === "contains" ) {
5167 return (elem.textContent || elem.innerText || getText([ elem ]) || "").indexOf(match[3]) >= 0;
5168
5169 } else if ( name === "not" ) {
5170 var not = match[3];
5171
5172 for ( var j = 0, l = not.length; j < l; j++ ) {
5173 if ( not[j] === elem ) {
5174 return false;
5175 }
5176 }
5177
5178 return true;
5179
5180 } else {
5181 Sizzle.error( name );
5182 }
5183 },
5184
5185 CHILD: function( elem, match ) {
5186 var first, last,
5187 doneName, parent, cache,
5188 count, diff,
5189 type = match[1],
5190 node = elem;
5191
5192 switch ( type ) {
5193 case "only":
5194 case "first":
5195 while ( (node = node.previousSibling) ) {
5196 if ( node.nodeType === 1 ) {
5197 return false;
5198 }
5199 }
5200
5201 if ( type === "first" ) {
5202 return true;
5203 }
5204
5205 node = elem;
5206
5207 case "last":
5208 while ( (node = node.nextSibling) ) {
5209 if ( node.nodeType === 1 ) {
5210 return false;
5211 }
5212 }
5213
5214 return true;
5215
5216 case "nth":
5217 first = match[2];
5218 last = match[3];
5219
5220 if ( first === 1 && last === 0 ) {
5221 return true;
5222 }
5223
5224 doneName = match[0];
5225 parent = elem.parentNode;
5226
5227 if ( parent && (parent[ expando ] !== doneName || !elem.nodeIndex) ) {
5228 count = 0;
5229
5230 for ( node = parent.firstChild; node; node = node.nextSibling ) {
5231 if ( node.nodeType === 1 ) {
5232 node.nodeIndex = ++count;
5233 }
5234 }
5235
5236 parent[ expando ] = doneName;
5237 }
5238
5239 diff = elem.nodeIndex - last;
5240
5241 if ( first === 0 ) {
5242 return diff === 0;
5243
5244 } else {
5245 return ( diff % first === 0 && diff / first >= 0 );
5246 }
5247 }
5248 },
5249
5250 ID: function( elem, match ) {
5251 return elem.nodeType === 1 && elem.getAttribute("id") === match;
5252 },
5253
5254 TAG: function( elem, match ) {
5255 return (match === "*" && elem.nodeType === 1) || !!elem.nodeName && elem.nodeName.toLowerCase() === match;
5256 },
5257
5258 CLASS: function( elem, match ) {
5259 return (" " + (elem.className || elem.getAttribute("class")) + " ")
5260 .indexOf( match ) > -1;
5261 },
5262
5263 ATTR: function( elem, match ) {
5264 var name = match[1],
5265 result = Sizzle.attr ?
5266 Sizzle.attr( elem, name ) :
5267 Expr.attrHandle[ name ] ?
5268 Expr.attrHandle[ name ]( elem ) :
5269 elem[ name ] != null ?
5270 elem[ name ] :
5271 elem.getAttribute( name ),
5272 value = result + "",
5273 type = match[2],
5274 check = match[4];
5275
5276 return result == null ?
5277 type === "!=" :
5278 !type && Sizzle.attr ?
5279 result != null :
5280 type === "=" ?
5281 value === check :
5282 type === "*=" ?
5283 value.indexOf(check) >= 0 :
5284 type === "~=" ?
5285 (" " + value + " ").indexOf(check) >= 0 :
5286 !check ?
5287 value && result !== false :
5288 type === "!=" ?
5289 value !== check :
5290 type === "^=" ?
5291 value.indexOf(check) === 0 :
5292 type === "$=" ?
5293 value.substr(value.length - check.length) === check :
5294 type === "|=" ?
5295 value === check || value.substr(0, check.length + 1) === check + "-" :
5296 false;
5297 },
5298
5299 POS: function( elem, match, i, array ) {
5300 var name = match[2],
5301 filter = Expr.setFilters[ name ];
5302
5303 if ( filter ) {
5304 return filter( elem, i, match, array );
5305 }
5306 }
5307 }
5308};
5309
5310var origPOS = Expr.match.POS,
5311 fescape = function(all, num){
5312 return "\\" + (num - 0 + 1);
5313 };
5314
5315for ( var type in Expr.match ) {
5316 Expr.match[ type ] = new RegExp( Expr.match[ type ].source + (/(?![^\[]*\])(?![^\(]*\))/.source) );
5317 Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, fescape) );
5318}
5319
5320var makeArray = function( array, results ) {
5321 array = Array.prototype.slice.call( array, 0 );
5322
5323 if ( results ) {
5324 results.push.apply( results, array );
5325 return results;
5326 }
5327
5328 return array;
5329};
5330
5331// Perform a simple check to determine if the browser is capable of
5332// converting a NodeList to an array using builtin methods.
5333// Also verifies that the returned array holds DOM nodes
5334// (which is not the case in the Blackberry browser)
5335try {
5336 Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType;
5337
5338// Provide a fallback method if it does not work
5339} catch( e ) {
5340 makeArray = function( array, results ) {
5341 var i = 0,
5342 ret = results || [];
5343
5344 if ( toString.call(array) === "[object Array]" ) {
5345 Array.prototype.push.apply( ret, array );
5346
5347 } else {
5348 if ( typeof array.length === "number" ) {
5349 for ( var l = array.length; i < l; i++ ) {
5350 ret.push( array[i] );
5351 }
5352
5353 } else {
5354 for ( ; array[i]; i++ ) {
5355 ret.push( array[i] );
5356 }
5357 }
5358 }
5359
5360 return ret;
5361 };
5362}
5363
5364var sortOrder, siblingCheck;
5365
5366if ( document.documentElement.compareDocumentPosition ) {
5367 sortOrder = function( a, b ) {
5368 if ( a === b ) {
5369 hasDuplicate = true;
5370 return 0;
5371 }
5372
5373 if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) {
5374 return a.compareDocumentPosition ? -1 : 1;
5375 }
5376
5377 return a.compareDocumentPosition(b) & 4 ? -1 : 1;
5378 };
5379
5380} else {
5381 sortOrder = function( a, b ) {
5382 // The nodes are identical, we can exit early
5383 if ( a === b ) {
5384 hasDuplicate = true;
5385 return 0;
5386
5387 // Fallback to using sourceIndex (in IE) if it's available on both nodes
5388 } else if ( a.sourceIndex && b.sourceIndex ) {
5389 return a.sourceIndex - b.sourceIndex;
5390 }
5391
5392 var al, bl,
5393 ap = [],
5394 bp = [],
5395 aup = a.parentNode,
5396 bup = b.parentNode,
5397 cur = aup;
5398
5399 // If the nodes are siblings (or identical) we can do a quick check
5400 if ( aup === bup ) {
5401 return siblingCheck( a, b );
5402
5403 // If no parents were found then the nodes are disconnected
5404 } else if ( !aup ) {
5405 return -1;
5406
5407 } else if ( !bup ) {
5408 return 1;
5409 }
5410
5411 // Otherwise they're somewhere else in the tree so we need
5412 // to build up a full list of the parentNodes for comparison
5413 while ( cur ) {
5414 ap.unshift( cur );
5415 cur = cur.parentNode;
5416 }
5417
5418 cur = bup;
5419
5420 while ( cur ) {
5421 bp.unshift( cur );
5422 cur = cur.parentNode;
5423 }
5424
5425 al = ap.length;
5426 bl = bp.length;
5427
5428 // Start walking down the tree looking for a discrepancy
5429 for ( var i = 0; i < al && i < bl; i++ ) {
5430 if ( ap[i] !== bp[i] ) {
5431 return siblingCheck( ap[i], bp[i] );
5432 }
5433 }
5434
5435 // We ended someplace up the tree so do a sibling check
5436 return i === al ?
5437 siblingCheck( a, bp[i], -1 ) :
5438 siblingCheck( ap[i], b, 1 );
5439 };
5440
5441 siblingCheck = function( a, b, ret ) {
5442 if ( a === b ) {
5443 return ret;
5444 }
5445
5446 var cur = a.nextSibling;
5447
5448 while ( cur ) {
5449 if ( cur === b ) {
5450 return -1;
5451 }
5452
5453 cur = cur.nextSibling;
5454 }
5455
5456 return 1;
5457 };
5458}
5459
5460// Check to see if the browser returns elements by name when
5461// querying by getElementById (and provide a workaround)
5462(function(){
5463 // We're going to inject a fake input element with a specified name
5464 var form = document.createElement("div"),
5465 id = "script" + (new Date()).getTime(),
5466 root = document.documentElement;
5467
5468 form.innerHTML = "<a name='" + id + "'/>";
5469
5470 // Inject it into the root element, check its status, and remove it quickly
5471 root.insertBefore( form, root.firstChild );
5472
5473 // The workaround has to do additional checks after a getElementById
5474 // Which slows things down for other browsers (hence the branching)
5475 if ( document.getElementById( id ) ) {
5476 Expr.find.ID = function( match, context, isXML ) {
5477 if ( typeof context.getElementById !== "undefined" && !isXML ) {
5478 var m = context.getElementById(match[1]);
5479
5480 return m ?
5481 m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ?
5482 [m] :
5483 undefined :
5484 [];
5485 }
5486 };
5487
5488 Expr.filter.ID = function( elem, match ) {
5489 var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id");
5490
5491 return elem.nodeType === 1 && node && node.nodeValue === match;
5492 };
5493 }
5494
5495 root.removeChild( form );
5496
5497 // release memory in IE
5498 root = form = null;
5499})();
5500
5501(function(){
5502 // Check to see if the browser returns only elements
5503 // when doing getElementsByTagName("*")
5504
5505 // Create a fake element
5506 var div = document.createElement("div");
5507 div.appendChild( document.createComment("") );
5508
5509 // Make sure no comments are found
5510 if ( div.getElementsByTagName("*").length > 0 ) {
5511 Expr.find.TAG = function( match, context ) {
5512 var results = context.getElementsByTagName( match[1] );
5513
5514 // Filter out possible comments
5515 if ( match[1] === "*" ) {
5516 var tmp = [];
5517
5518 for ( var i = 0; results[i]; i++ ) {
5519 if ( results[i].nodeType === 1 ) {
5520 tmp.push( results[i] );
5521 }
5522 }
5523
5524 results = tmp;
5525 }
5526
5527 return results;
5528 };
5529 }
5530
5531 // Check to see if an attribute returns normalized href attributes
5532 div.innerHTML = "<a href='#'></a>";
5533
5534 if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" &&
5535 div.firstChild.getAttribute("href") !== "#" ) {
5536
5537 Expr.attrHandle.href = function( elem ) {
5538 return elem.getAttribute( "href", 2 );
5539 };
5540 }
5541
5542 // release memory in IE
5543 div = null;
5544})();
5545
5546if ( document.querySelectorAll ) {
5547 (function(){
5548 var oldSizzle = Sizzle,
5549 div = document.createElement("div"),
5550 id = "__sizzle__";
5551
5552 div.innerHTML = "<p class='TEST'></p>";
5553
5554 // Safari can't handle uppercase or unicode characters when
5555 // in quirks mode.
5556 if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) {
5557 return;
5558 }
5559
5560 Sizzle = function( query, context, extra, seed ) {
5561 context = context || document;
5562
5563 // Only use querySelectorAll on non-XML documents
5564 // (ID selectors don't work in non-HTML documents)
5565 if ( !seed && !Sizzle.isXML(context) ) {
5566 // See if we find a selector to speed up
5567 var match = /^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec( query );
5568
5569 if ( match && (context.nodeType === 1 || context.nodeType === 9) ) {
5570 // Speed-up: Sizzle("TAG")
5571 if ( match[1] ) {
5572 return makeArray( context.getElementsByTagName( query ), extra );
5573
5574 // Speed-up: Sizzle(".CLASS")
5575 } else if ( match[2] && Expr.find.CLASS && context.getElementsByClassName ) {
5576 return makeArray( context.getElementsByClassName( match[2] ), extra );
5577 }
5578 }
5579
5580 if ( context.nodeType === 9 ) {
5581 // Speed-up: Sizzle("body")
5582 // The body element only exists once, optimize finding it
5583 if ( query === "body" && context.body ) {
5584 return makeArray( [ context.body ], extra );
5585
5586 // Speed-up: Sizzle("#ID")
5587 } else if ( match && match[3] ) {
5588 var elem = context.getElementById( match[3] );
5589
5590 // Check parentNode to catch when Blackberry 4.6 returns
5591 // nodes that are no longer in the document #6963
5592 if ( elem && elem.parentNode ) {
5593 // Handle the case where IE and Opera return items
5594 // by name instead of ID
5595 if ( elem.id === match[3] ) {
5596 return makeArray( [ elem ], extra );
5597 }
5598
5599 } else {
5600 return makeArray( [], extra );
5601 }
5602 }
5603
5604 try {
5605 return makeArray( context.querySelectorAll(query), extra );
5606 } catch(qsaError) {}
5607
5608 // qSA works strangely on Element-rooted queries
5609 // We can work around this by specifying an extra ID on the root
5610 // and working up from there (Thanks to Andrew Dupont for the technique)
5611 // IE 8 doesn't work on object elements
5612 } else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
5613 var oldContext = context,
5614 old = context.getAttribute( "id" ),
5615 nid = old || id,
5616 hasParent = context.parentNode,
5617 relativeHierarchySelector = /^\s*[+~]/.test( query );
5618
5619 if ( !old ) {
5620 context.setAttribute( "id", nid );
5621 } else {
5622 nid = nid.replace( /'/g, "\\$&" );
5623 }
5624 if ( relativeHierarchySelector && hasParent ) {
5625 context = context.parentNode;
5626 }
5627
5628 try {
5629 if ( !relativeHierarchySelector || hasParent ) {
5630 return makeArray( context.querySelectorAll( "[id='" + nid + "'] " + query ), extra );
5631 }
5632
5633 } catch(pseudoError) {
5634 } finally {
5635 if ( !old ) {
5636 oldContext.removeAttribute( "id" );
5637 }
5638 }
5639 }
5640 }
5641
5642 return oldSizzle(query, context, extra, seed);
5643 };
5644
5645 for ( var prop in oldSizzle ) {
5646 Sizzle[ prop ] = oldSizzle[ prop ];
5647 }
5648
5649 // release memory in IE
5650 div = null;
5651 })();
5652}
5653
5654(function(){
5655 var html = document.documentElement,
5656 matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector;
5657
5658 if ( matches ) {
5659 // Check to see if it's possible to do matchesSelector
5660 // on a disconnected node (IE 9 fails this)
5661 var disconnectedMatch = !matches.call( document.createElement( "div" ), "div" ),
5662 pseudoWorks = false;
5663
5664 try {
5665 // This should fail with an exception
5666 // Gecko does not error, returns false instead
5667 matches.call( document.documentElement, "[test!='']:sizzle" );
5668
5669 } catch( pseudoError ) {
5670 pseudoWorks = true;
5671 }
5672
5673 Sizzle.matchesSelector = function( node, expr ) {
5674 // Make sure that attribute selectors are quoted
5675 expr = expr.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']");
5676
5677 if ( !Sizzle.isXML( node ) ) {
5678 try {
5679 if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) {
5680 var ret = matches.call( node, expr );
5681
5682 // IE 9's matchesSelector returns false on disconnected nodes
5683 if ( ret || !disconnectedMatch ||
5684 // As well, disconnected nodes are said to be in a document
5685 // fragment in IE 9, so check for that
5686 node.document && node.document.nodeType !== 11 ) {
5687 return ret;
5688 }
5689 }
5690 } catch(e) {}
5691 }
5692
5693 return Sizzle(expr, null, null, [node]).length > 0;
5694 };
5695 }
5696})();
5697
5698(function(){
5699 var div = document.createElement("div");
5700
5701 div.innerHTML = "<div class='test e'></div><div class='test'></div>";
5702
5703 // Opera can't find a second classname (in 9.6)
5704 // Also, make sure that getElementsByClassName actually exists
5705 if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) {
5706 return;
5707 }
5708
5709 // Safari caches class attributes, doesn't catch changes (in 3.2)
5710 div.lastChild.className = "e";
5711
5712 if ( div.getElementsByClassName("e").length === 1 ) {
5713 return;
5714 }
5715
5716 Expr.order.splice(1, 0, "CLASS");
5717 Expr.find.CLASS = function( match, context, isXML ) {
5718 if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) {
5719 return context.getElementsByClassName(match[1]);
5720 }
5721 };
5722
5723 // release memory in IE
5724 div = null;
5725})();
5726
5727function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
5728 for ( var i = 0, l = checkSet.length; i < l; i++ ) {
5729 var elem = checkSet[i];
5730
5731 if ( elem ) {
5732 var match = false;
5733
5734 elem = elem[dir];
5735
5736 while ( elem ) {
5737 if ( elem[ expando ] === doneName ) {
5738 match = checkSet[elem.sizset];
5739 break;
5740 }
5741
5742 if ( elem.nodeType === 1 && !isXML ){
5743 elem[ expando ] = doneName;
5744 elem.sizset = i;
5745 }
5746
5747 if ( elem.nodeName.toLowerCase() === cur ) {
5748 match = elem;
5749 break;
5750 }
5751
5752 elem = elem[dir];
5753 }
5754
5755 checkSet[i] = match;
5756 }
5757 }
5758}
5759
5760function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
5761 for ( var i = 0, l = checkSet.length; i < l; i++ ) {
5762 var elem = checkSet[i];
5763
5764 if ( elem ) {
5765 var match = false;
5766
5767 elem = elem[dir];
5768
5769 while ( elem ) {
5770 if ( elem[ expando ] === doneName ) {
5771 match = checkSet[elem.sizset];
5772 break;
5773 }
5774
5775 if ( elem.nodeType === 1 ) {
5776 if ( !isXML ) {
5777 elem[ expando ] = doneName;
5778 elem.sizset = i;
5779 }
5780
5781 if ( typeof cur !== "string" ) {
5782 if ( elem === cur ) {
5783 match = true;
5784 break;
5785 }
5786
5787 } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) {
5788 match = elem;
5789 break;
5790 }
5791 }
5792
5793 elem = elem[dir];
5794 }
5795
5796 checkSet[i] = match;
5797 }
5798 }
5799}
5800
5801if ( document.documentElement.contains ) {
5802 Sizzle.contains = function( a, b ) {
5803 return a !== b && (a.contains ? a.contains(b) : true);
5804 };
5805
5806} else if ( document.documentElement.compareDocumentPosition ) {
5807 Sizzle.contains = function( a, b ) {
5808 return !!(a.compareDocumentPosition(b) & 16);
5809 };
5810
5811} else {
5812 Sizzle.contains = function() {
5813 return false;
5814 };
5815}
5816
5817Sizzle.isXML = function( elem ) {
5818 // documentElement is verified for cases where it doesn't yet exist
5819 // (such as loading iframes in IE - #4833)
5820 var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement;
5821
5822 return documentElement ? documentElement.nodeName !== "HTML" : false;
5823};
5824
5825var posProcess = function( selector, context, seed ) {
5826 var match,
5827 tmpSet = [],
5828 later = "",
5829 root = context.nodeType ? [context] : context;
5830
5831 // Position selectors must be done after the filter
5832 // And so must :not(positional) so we move all PSEUDOs to the end
5833 while ( (match = Expr.match.PSEUDO.exec( selector )) ) {
5834 later += match[0];
5835 selector = selector.replace( Expr.match.PSEUDO, "" );
5836 }
5837
5838 selector = Expr.relative[selector] ? selector + "*" : selector;
5839
5840 for ( var i = 0, l = root.length; i < l; i++ ) {
5841 Sizzle( selector, root[i], tmpSet, seed );
5842 }
5843
5844 return Sizzle.filter( later, tmpSet );
5845};
5846
5847// EXPOSE
5848// Override sizzle attribute retrieval
5849Sizzle.attr = jQuery.attr;
5850Sizzle.selectors.attrMap = {};
5851jQuery.find = Sizzle;
5852jQuery.expr = Sizzle.selectors;
5853jQuery.expr[":"] = jQuery.expr.filters;
5854jQuery.unique = Sizzle.uniqueSort;
5855jQuery.text = Sizzle.getText;
5856jQuery.isXMLDoc = Sizzle.isXML;
5857jQuery.contains = Sizzle.contains;
5858
5859
5860})();
5861(function( jQuery ) {
5862
5863var runtil = /Until$/,
5864 rparentsprev = /^(?:parents|prevUntil|prevAll)/,
5865 // Note: This RegExp should be improved, or likely pulled from Sizzle
5866 rmultiselector = /,/,
5867 isSimple = /^.[^:#\[\.,]*$/,
5868 slice = Array.prototype.slice,
5869 POS = jQuery.expr.match.POS,
5870 // methods guaranteed to produce a unique set when starting from a unique set
5871 guaranteedUnique = {
5872 children: true,
5873 contents: true,
5874 next: true,
5875 prev: true
5876 };
5877
5878jQuery.fn.extend({
5879 find: function( selector ) {
5880 var self = this,
5881 i, l;
5882
5883 if ( typeof selector !== "string" ) {
5884 return jQuery( selector ).filter(function() {
5885 for ( i = 0, l = self.length; i < l; i++ ) {
5886 if ( jQuery.contains( self[ i ], this ) ) {
5887 return true;
5888 }
5889 }
5890 });
5891 }
5892
5893 var ret = this.pushStack( "", "find", selector ),
5894 length, n, r;
5895
5896 for ( i = 0, l = this.length; i < l; i++ ) {
5897 length = ret.length;
5898 jQuery.find( selector, this[i], ret );
5899
5900 if ( i > 0 ) {
5901 // Make sure that the results are unique
5902 for ( n = length; n < ret.length; n++ ) {
5903 for ( r = 0; r < length; r++ ) {
5904 if ( ret[r] === ret[n] ) {
5905 ret.splice(n--, 1);
5906 break;
5907 }
5908 }
5909 }
5910 }
5911 }
5912
5913 return ret;
5914 },
5915
5916 has: function( target ) {
5917 var targets = jQuery( target );
5918 return this.filter(function() {
5919 for ( var i = 0, l = targets.length; i < l; i++ ) {
5920 if ( jQuery.contains( this, targets[i] ) ) {
5921 return true;
5922 }
5923 }
5924 });
5925 },
5926
5927 not: function( selector ) {
5928 return this.pushStack( winnow(this, selector, false), "not", selector);
5929 },
5930
5931 filter: function( selector ) {
5932 return this.pushStack( winnow(this, selector, true), "filter", selector );
5933 },
5934
5935 is: function( selector ) {
5936 return !!selector && (
5937 typeof selector === "string" ?
5938 // If this is a positional selector, check membership in the returned set
5939 // so $("p:first").is("p:last") won't return true for a doc with two "p".
5940 POS.test( selector ) ?
5941 jQuery( selector, this.context ).index( this[0] ) >= 0 :
5942 jQuery.filter( selector, this ).length > 0 :
5943 this.filter( selector ).length > 0 );
5944 },
5945
5946 closest: function( selectors, context ) {
5947 var ret = [], i, l, cur = this[0];
5948
5949 // Array (deprecated as of jQuery 1.7)
5950 if ( jQuery.isArray( selectors ) ) {
5951 var level = 1;
5952
5953 while ( cur && cur.ownerDocument && cur !== context ) {
5954 for ( i = 0; i < selectors.length; i++ ) {
5955
5956 if ( jQuery( cur ).is( selectors[ i ] ) ) {
5957 ret.push({ selector: selectors[ i ], elem: cur, level: level });
5958 }
5959 }
5960
5961 cur = cur.parentNode;
5962 level++;
5963 }
5964
5965 return ret;
5966 }
5967
5968 // String
5969 var pos = POS.test( selectors ) || typeof selectors !== "string" ?
5970 jQuery( selectors, context || this.context ) :
5971 0;
5972
5973 for ( i = 0, l = this.length; i < l; i++ ) {
5974 cur = this[i];
5975
5976 while ( cur ) {
5977 if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) {
5978 ret.push( cur );
5979 break;
5980
5981 } else {
5982 cur = cur.parentNode;
5983 if ( !cur || !cur.ownerDocument || cur === context || cur.nodeType === 11 ) {
5984 break;
5985 }
5986 }
5987 }
5988 }
5989
5990 ret = ret.length > 1 ? jQuery.unique( ret ) : ret;
5991
5992 return this.pushStack( ret, "closest", selectors );
5993 },
5994
5995 // Determine the position of an element within
5996 // the matched set of elements
5997 index: function( elem ) {
5998
5999 // No argument, return index in parent
6000 if ( !elem ) {
6001 return ( this[0] && this[0].parentNode ) ? this.prevAll().length : -1;
6002 }
6003
6004 // index in selector
6005 if ( typeof elem === "string" ) {
6006 return jQuery.inArray( this[0], jQuery( elem ) );
6007 }
6008
6009 // Locate the position of the desired element
6010 return jQuery.inArray(
6011 // If it receives a jQuery object, the first element is used
6012 elem.jquery ? elem[0] : elem, this );
6013 },
6014
6015 add: function( selector, context ) {
6016 var set = typeof selector === "string" ?
6017 jQuery( selector, context ) :
6018 jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ),
6019 all = jQuery.merge( this.get(), set );
6020
6021 return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ?
6022 all :
6023 jQuery.unique( all ) );
6024 },
6025
6026 andSelf: function() {
6027 return this.add( this.prevObject );
6028 }
6029});
6030
6031// A painfully simple check to see if an element is disconnected
6032// from a document (should be improved, where feasible).
6033function isDisconnected( node ) {
6034 return !node || !node.parentNode || node.parentNode.nodeType === 11;
6035}
6036
6037jQuery.each({
6038 parent: function( elem ) {
6039 var parent = elem.parentNode;
6040 return parent && parent.nodeType !== 11 ? parent : null;
6041 },
6042 parents: function( elem ) {
6043 return jQuery.dir( elem, "parentNode" );
6044 },
6045 parentsUntil: function( elem, i, until ) {
6046 return jQuery.dir( elem, "parentNode", until );
6047 },
6048 next: function( elem ) {
6049 return jQuery.nth( elem, 2, "nextSibling" );
6050 },
6051 prev: function( elem ) {
6052 return jQuery.nth( elem, 2, "previousSibling" );
6053 },
6054 nextAll: function( elem ) {
6055 return jQuery.dir( elem, "nextSibling" );
6056 },
6057 prevAll: function( elem ) {
6058 return jQuery.dir( elem, "previousSibling" );
6059 },
6060 nextUntil: function( elem, i, until ) {
6061 return jQuery.dir( elem, "nextSibling", until );
6062 },
6063 prevUntil: function( elem, i, until ) {
6064 return jQuery.dir( elem, "previousSibling", until );
6065 },
6066 siblings: function( elem ) {
6067 return jQuery.sibling( elem.parentNode.firstChild, elem );
6068 },
6069 children: function( elem ) {
6070 return jQuery.sibling( elem.firstChild );
6071 },
6072 contents: function( elem ) {
6073 return jQuery.nodeName( elem, "iframe" ) ?
6074 elem.contentDocument || elem.contentWindow.document :
6075 jQuery.makeArray( elem.childNodes );
6076 }
6077}, function( name, fn ) {
6078 jQuery.fn[ name ] = function( until, selector ) {
6079 var ret = jQuery.map( this, fn, until ),
6080 // The variable 'args' was introduced in
6081 // https://github.com/jquery/jquery/commit/52a0238
6082 // to work around a bug in Chrome 10 (Dev) and should be removed when the bug is fixed.
6083 // http://code.google.com/p/v8/issues/detail?id=1050
6084 args = slice.call(arguments);
6085
6086 if ( !runtil.test( name ) ) {
6087 selector = until;
6088 }
6089
6090 if ( selector && typeof selector === "string" ) {
6091 ret = jQuery.filter( selector, ret );
6092 }
6093
6094 ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret;
6095
6096 if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) {
6097 ret = ret.reverse();
6098 }
6099
6100 return this.pushStack( ret, name, args.join(",") );
6101 };
6102});
6103
6104jQuery.extend({
6105 filter: function( expr, elems, not ) {
6106 if ( not ) {
6107 expr = ":not(" + expr + ")";
6108 }
6109
6110 return elems.length === 1 ?
6111 jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] :
6112 jQuery.find.matches(expr, elems);
6113 },
6114
6115 dir: function( elem, dir, until ) {
6116 var matched = [],
6117 cur = elem[ dir ];
6118
6119 while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {
6120 if ( cur.nodeType === 1 ) {
6121 matched.push( cur );
6122 }
6123 cur = cur[dir];
6124 }
6125 return matched;
6126 },
6127
6128 nth: function( cur, result, dir, elem ) {
6129 result = result || 1;
6130 var num = 0;
6131
6132 for ( ; cur; cur = cur[dir] ) {
6133 if ( cur.nodeType === 1 && ++num === result ) {
6134 break;
6135 }
6136 }
6137
6138 return cur;
6139 },
6140
6141 sibling: function( n, elem ) {
6142 var r = [];
6143
6144 for ( ; n; n = n.nextSibling ) {
6145 if ( n.nodeType === 1 && n !== elem ) {
6146 r.push( n );
6147 }
6148 }
6149
6150 return r;
6151 }
6152});
6153
6154// Implement the identical functionality for filter and not
6155function winnow( elements, qualifier, keep ) {
6156
6157 // Can't pass null or undefined to indexOf in Firefox 4
6158 // Set to 0 to skip string check
6159 qualifier = qualifier || 0;
6160
6161 if ( jQuery.isFunction( qualifier ) ) {
6162 return jQuery.grep(elements, function( elem, i ) {
6163 var retVal = !!qualifier.call( elem, i, elem );
6164 return retVal === keep;
6165 });
6166
6167 } else if ( qualifier.nodeType ) {
6168 return jQuery.grep(elements, function( elem, i ) {
6169 return ( elem === qualifier ) === keep;
6170 });
6171
6172 } else if ( typeof qualifier === "string" ) {
6173 var filtered = jQuery.grep(elements, function( elem ) {
6174 return elem.nodeType === 1;
6175 });
6176
6177 if ( isSimple.test( qualifier ) ) {
6178 return jQuery.filter(qualifier, filtered, !keep);
6179 } else {
6180 qualifier = jQuery.filter( qualifier, filtered );
6181 }
6182 }
6183
6184 return jQuery.grep(elements, function( elem, i ) {
6185 return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep;
6186 });
6187}
6188
6189})( jQuery );
6190(function( jQuery ) {
6191
6192function createSafeFragment( document ) {
6193 var list = nodeNames.split( " " ),
6194 safeFrag = document.createDocumentFragment();
6195
6196 if ( safeFrag.createElement ) {
6197 while ( list.length ) {
6198 safeFrag.createElement(
6199 list.pop()
6200 );
6201 }
6202 }
6203 return safeFrag;
6204}
6205
6206var nodeNames = "abbr article aside audio canvas datalist details figcaption figure footer " +
6207 "header hgroup mark meter nav output progress section summary time video",
6208 rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g,
6209 rleadingWhitespace = /^\s+/,
6210 rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,
6211 rtagName = /<([\w:]+)/,
6212 rtbody = /<tbody/i,
6213 rhtml = /<|&#?\w+;/,
6214 rnoInnerhtml = /<(?:script|style)/i,
6215 rnocache = /<(?:script|object|embed|option|style)/i,
6216 rnoshimcache = new RegExp("<(?:" + nodeNames.replace(" ", "|") + ")", "i"),
6217 // checked="checked" or checked
6218 rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
6219 rscriptType = /\/(java|ecma)script/i,
6220 rcleanScript = /^\s*<!(?:\[CDATA\[|\-\-)/,
6221 wrapMap = {
6222 option: [ 1, "<select multiple='multiple'>", "</select>" ],
6223 legend: [ 1, "<fieldset>", "</fieldset>" ],
6224 thead: [ 1, "<table>", "</table>" ],
6225 tr: [ 2, "<table><tbody>", "</tbody></table>" ],
6226 td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
6227 col: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ],
6228 area: [ 1, "<map>", "</map>" ],
6229 _default: [ 0, "", "" ]
6230 },
6231 safeFragment = createSafeFragment( document );
6232
6233wrapMap.optgroup = wrapMap.option;
6234wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
6235wrapMap.th = wrapMap.td;
6236
6237// IE can't serialize <link> and <script> tags normally
6238if ( !jQuery.support.htmlSerialize ) {
6239 wrapMap._default = [ 1, "div<div>", "</div>" ];
6240}
6241
6242jQuery.fn.extend({
6243 text: function( text ) {
6244 if ( jQuery.isFunction(text) ) {
6245 return this.each(function(i) {
6246 var self = jQuery( this );
6247
6248 self.text( text.call(this, i, self.text()) );
6249 });
6250 }
6251
6252 if ( typeof text !== "object" && text !== undefined ) {
6253 return this.empty().append( (this[0] && this[0].ownerDocument || document).createTextNode( text ) );
6254 }
6255
6256 return jQuery.text( this );
6257 },
6258
6259 wrapAll: function( html ) {
6260 if ( jQuery.isFunction( html ) ) {
6261 return this.each(function(i) {
6262 jQuery(this).wrapAll( html.call(this, i) );
6263 });
6264 }
6265
6266 if ( this[0] ) {
6267 // The elements to wrap the target around
6268 var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true);
6269
6270 if ( this[0].parentNode ) {
6271 wrap.insertBefore( this[0] );
6272 }
6273
6274 wrap.map(function() {
6275 var elem = this;
6276
6277 while ( elem.firstChild && elem.firstChild.nodeType === 1 ) {
6278 elem = elem.firstChild;
6279 }
6280
6281 return elem;
6282 }).append( this );
6283 }
6284
6285 return this;
6286 },
6287
6288 wrapInner: function( html ) {
6289 if ( jQuery.isFunction( html ) ) {
6290 return this.each(function(i) {
6291 jQuery(this).wrapInner( html.call(this, i) );
6292 });
6293 }
6294
6295 return this.each(function() {
6296 var self = jQuery( this ),
6297 contents = self.contents();
6298
6299 if ( contents.length ) {
6300 contents.wrapAll( html );
6301
6302 } else {
6303 self.append( html );
6304 }
6305 });
6306 },
6307
6308 wrap: function( html ) {
6309 return this.each(function() {
6310 jQuery( this ).wrapAll( html );
6311 });
6312 },
6313
6314 unwrap: function() {
6315 return this.parent().each(function() {
6316 if ( !jQuery.nodeName( this, "body" ) ) {
6317 jQuery( this ).replaceWith( this.childNodes );
6318 }
6319 }).end();
6320 },
6321
6322 append: function() {
6323 return this.domManip(arguments, true, function( elem ) {
6324 if ( this.nodeType === 1 ) {
6325 this.appendChild( elem );
6326 }
6327 });
6328 },
6329
6330 prepend: function() {
6331 return this.domManip(arguments, true, function( elem ) {
6332 if ( this.nodeType === 1 ) {
6333 this.insertBefore( elem, this.firstChild );
6334 }
6335 });
6336 },
6337
6338 before: function() {
6339 if ( this[0] && this[0].parentNode ) {
6340 return this.domManip(arguments, false, function( elem ) {
6341 this.parentNode.insertBefore( elem, this );
6342 });
6343 } else if ( arguments.length ) {
6344 var set = jQuery(arguments[0]);
6345 set.push.apply( set, this.toArray() );
6346 return this.pushStack( set, "before", arguments );
6347 }
6348 },
6349
6350 after: function() {
6351 if ( this[0] && this[0].parentNode ) {
6352 return this.domManip(arguments, false, function( elem ) {
6353 this.parentNode.insertBefore( elem, this.nextSibling );
6354 });
6355 } else if ( arguments.length ) {
6356 var set = this.pushStack( this, "after", arguments );
6357 set.push.apply( set, jQuery(arguments[0]).toArray() );
6358 return set;
6359 }
6360 },
6361
6362 // keepData is for internal use only--do not document
6363 remove: function( selector, keepData ) {
6364 for ( var i = 0, elem; (elem = this[i]) != null; i++ ) {
6365 if ( !selector || jQuery.filter( selector, [ elem ] ).length ) {
6366 if ( !keepData && elem.nodeType === 1 ) {
6367 jQuery.cleanData( elem.getElementsByTagName("*") );
6368 jQuery.cleanData( [ elem ] );
6369 }
6370
6371 if ( elem.parentNode ) {
6372 elem.parentNode.removeChild( elem );
6373 }
6374 }
6375 }
6376
6377 return this;
6378 },
6379
6380 empty: function() {
6381 for ( var i = 0, elem; (elem = this[i]) != null; i++ ) {
6382 // Remove element nodes and prevent memory leaks
6383 if ( elem.nodeType === 1 ) {
6384 jQuery.cleanData( elem.getElementsByTagName("*") );
6385 }
6386
6387 // Remove any remaining nodes
6388 while ( elem.firstChild ) {
6389 elem.removeChild( elem.firstChild );
6390 }
6391 }
6392
6393 return this;
6394 },
6395
6396 clone: function( dataAndEvents, deepDataAndEvents ) {
6397 dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
6398 deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
6399
6400 return this.map( function () {
6401 return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
6402 });
6403 },
6404
6405 html: function( value ) {
6406 if ( value === undefined ) {
6407 return this[0] && this[0].nodeType === 1 ?
6408 this[0].innerHTML.replace(rinlinejQuery, "") :
6409 null;
6410
6411 // See if we can take a shortcut and just use innerHTML
6412 } else if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
6413 (jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value )) &&
6414 !wrapMap[ (rtagName.exec( value ) || ["", ""])[1].toLowerCase() ] ) {
6415
6416 value = value.replace(rxhtmlTag, "<$1></$2>");
6417
6418 try {
6419 for ( var i = 0, l = this.length; i < l; i++ ) {
6420 // Remove element nodes and prevent memory leaks
6421 if ( this[i].nodeType === 1 ) {
6422 jQuery.cleanData( this[i].getElementsByTagName("*") );
6423 this[i].innerHTML = value;
6424 }
6425 }
6426
6427 // If using innerHTML throws an exception, use the fallback method
6428 } catch(e) {
6429 this.empty().append( value );
6430 }
6431
6432 } else if ( jQuery.isFunction( value ) ) {
6433 this.each(function(i){
6434 var self = jQuery( this );
6435
6436 self.html( value.call(this, i, self.html()) );
6437 });
6438
6439 } else {
6440 this.empty().append( value );
6441 }
6442
6443 return this;
6444 },
6445
6446 replaceWith: function( value ) {
6447 if ( this[0] && this[0].parentNode ) {
6448 // Make sure that the elements are removed from the DOM before they are inserted
6449 // this can help fix replacing a parent with child elements
6450 if ( jQuery.isFunction( value ) ) {
6451 return this.each(function(i) {
6452 var self = jQuery(this), old = self.html();
6453 self.replaceWith( value.call( this, i, old ) );
6454 });
6455 }
6456
6457 if ( typeof value !== "string" ) {
6458 value = jQuery( value ).detach();
6459 }
6460
6461 return this.each(function() {
6462 var next = this.nextSibling,
6463 parent = this.parentNode;
6464
6465 jQuery( this ).remove();
6466
6467 if ( next ) {
6468 jQuery(next).before( value );
6469 } else {
6470 jQuery(parent).append( value );
6471 }
6472 });
6473 } else {
6474 return this.length ?
6475 this.pushStack( jQuery(jQuery.isFunction(value) ? value() : value), "replaceWith", value ) :
6476 this;
6477 }
6478 },
6479
6480 detach: function( selector ) {
6481 return this.remove( selector, true );
6482 },
6483
6484 domManip: function( args, table, callback ) {
6485 var results, first, fragment, parent,
6486 value = args[0],
6487 scripts = [];
6488
6489 // We can't cloneNode fragments that contain checked, in WebKit
6490 if ( !jQuery.support.checkClone && arguments.length === 3 && typeof value === "string" && rchecked.test( value ) ) {
6491 return this.each(function() {
6492 jQuery(this).domManip( args, table, callback, true );
6493 });
6494 }
6495
6496 if ( jQuery.isFunction(value) ) {
6497 return this.each(function(i) {
6498 var self = jQuery(this);
6499 args[0] = value.call(this, i, table ? self.html() : undefined);
6500 self.domManip( args, table, callback );
6501 });
6502 }
6503
6504 if ( this[0] ) {
6505 parent = value && value.parentNode;
6506
6507 // If we're in a fragment, just use that instead of building a new one
6508 if ( jQuery.support.parentNode && parent && parent.nodeType === 11 && parent.childNodes.length === this.length ) {
6509 results = { fragment: parent };
6510
6511 } else {
6512 results = jQuery.buildFragment( args, this, scripts );
6513 }
6514
6515 fragment = results.fragment;
6516
6517 if ( fragment.childNodes.length === 1 ) {
6518 first = fragment = fragment.firstChild;
6519 } else {
6520 first = fragment.firstChild;
6521 }
6522
6523 if ( first ) {
6524 table = table && jQuery.nodeName( first, "tr" );
6525
6526 for ( var i = 0, l = this.length, lastIndex = l - 1; i < l; i++ ) {
6527 callback.call(
6528 table ?
6529 root(this[i], first) :
6530 this[i],
6531 // Make sure that we do not leak memory by inadvertently discarding
6532 // the original fragment (which might have attached data) instead of
6533 // using it; in addition, use the original fragment object for the last
6534 // item instead of first because it can end up being emptied incorrectly
6535 // in certain situations (Bug #8070).
6536 // Fragments from the fragment cache must always be cloned and never used
6537 // in place.
6538 results.cacheable || ( l > 1 && i < lastIndex ) ?
6539 jQuery.clone( fragment, true, true ) :
6540 fragment
6541 );
6542 }
6543 }
6544
6545 if ( scripts.length ) {
6546 jQuery.each( scripts, evalScript );
6547 }
6548 }
6549
6550 return this;
6551 }
6552});
6553
6554function root( elem, cur ) {
6555 return jQuery.nodeName(elem, "table") ?
6556 (elem.getElementsByTagName("tbody")[0] ||
6557 elem.appendChild(elem.ownerDocument.createElement("tbody"))) :
6558 elem;
6559}
6560
6561function cloneCopyEvent( src, dest ) {
6562
6563 if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) {
6564 return;
6565 }
6566
6567 var type, i, l,
6568 oldData = jQuery._data( src ),
6569 curData = jQuery._data( dest, oldData ),
6570 events = oldData.events;
6571
6572 if ( events ) {
6573 delete curData.handle;
6574 curData.events = {};
6575
6576 for ( type in events ) {
6577 for ( i = 0, l = events[ type ].length; i < l; i++ ) {
6578 jQuery.event.add( dest, type + ( events[ type ][ i ].namespace ? "." : "" ) + events[ type ][ i ].namespace, events[ type ][ i ], events[ type ][ i ].data );
6579 }
6580 }
6581 }
6582
6583 // make the cloned public data object a copy from the original
6584 if ( curData.data ) {
6585 curData.data = jQuery.extend( {}, curData.data );
6586 }
6587}
6588
6589function cloneFixAttributes( src, dest ) {
6590 var nodeName;
6591
6592 // We do not need to do anything for non-Elements
6593 if ( dest.nodeType !== 1 ) {
6594 return;
6595 }
6596
6597 // clearAttributes removes the attributes, which we don't want,
6598 // but also removes the attachEvent events, which we *do* want
6599 if ( dest.clearAttributes ) {
6600 dest.clearAttributes();
6601 }
6602
6603 // mergeAttributes, in contrast, only merges back on the
6604 // original attributes, not the events
6605 if ( dest.mergeAttributes ) {
6606 dest.mergeAttributes( src );
6607 }
6608
6609 nodeName = dest.nodeName.toLowerCase();
6610
6611 // IE6-8 fail to clone children inside object elements that use
6612 // the proprietary classid attribute value (rather than the type
6613 // attribute) to identify the type of content to display
6614 if ( nodeName === "object" ) {
6615 dest.outerHTML = src.outerHTML;
6616
6617 } else if ( nodeName === "input" && (src.type === "checkbox" || src.type === "radio") ) {
6618 // IE6-8 fails to persist the checked state of a cloned checkbox
6619 // or radio button. Worse, IE6-7 fail to give the cloned element
6620 // a checked appearance if the defaultChecked value isn't also set
6621 if ( src.checked ) {
6622 dest.defaultChecked = dest.checked = src.checked;
6623 }
6624
6625 // IE6-7 get confused and end up setting the value of a cloned
6626 // checkbox/radio button to an empty string instead of "on"
6627 if ( dest.value !== src.value ) {
6628 dest.value = src.value;
6629 }
6630
6631 // IE6-8 fails to return the selected option to the default selected
6632 // state when cloning options
6633 } else if ( nodeName === "option" ) {
6634 dest.selected = src.defaultSelected;
6635
6636 // IE6-8 fails to set the defaultValue to the correct value when
6637 // cloning other types of input fields
6638 } else if ( nodeName === "input" || nodeName === "textarea" ) {
6639 dest.defaultValue = src.defaultValue;
6640 }
6641
6642 // Event data gets referenced instead of copied if the expando
6643 // gets copied too
6644 dest.removeAttribute( jQuery.expando );
6645}
6646
6647jQuery.buildFragment = function( args, nodes, scripts ) {
6648 var fragment, cacheable, cacheresults, doc,
6649 first = args[ 0 ];
6650
6651 // nodes may contain either an explicit document object,
6652 // a jQuery collection or context object.
6653 // If nodes[0] contains a valid object to assign to doc
6654 if ( nodes && nodes[0] ) {
6655 doc = nodes[0].ownerDocument || nodes[0];
6656 }
6657
6658 // Ensure that an attr object doesn't incorrectly stand in as a document object
6659 // Chrome and Firefox seem to allow this to occur and will throw exception
6660 // Fixes #8950
6661 if ( !doc.createDocumentFragment ) {
6662 doc = document;
6663 }
6664
6665 // Only cache "small" (1/2 KB) HTML strings that are associated with the main document
6666 // Cloning options loses the selected state, so don't cache them
6667 // IE 6 doesn't like it when you put <object> or <embed> elements in a fragment
6668 // Also, WebKit does not clone 'checked' attributes on cloneNode, so don't cache
6669 // Lastly, IE6,7,8 will not correctly reuse cached fragments that were created from unknown elems #10501
6670 if ( args.length === 1 && typeof first === "string" && first.length < 512 && doc === document &&
6671 first.charAt(0) === "<" && !rnocache.test( first ) &&
6672 (jQuery.support.checkClone || !rchecked.test( first )) &&
6673 (!jQuery.support.unknownElems && rnoshimcache.test( first )) ) {
6674
6675 cacheable = true;
6676
6677 cacheresults = jQuery.fragments[ first ];
6678 if ( cacheresults && cacheresults !== 1 ) {
6679 fragment = cacheresults;
6680 }
6681 }
6682
6683 if ( !fragment ) {
6684 fragment = doc.createDocumentFragment();
6685 jQuery.clean( args, doc, fragment, scripts );
6686 }
6687
6688 if ( cacheable ) {
6689 jQuery.fragments[ first ] = cacheresults ? fragment : 1;
6690 }
6691
6692 return { fragment: fragment, cacheable: cacheable };
6693};
6694
6695jQuery.fragments = {};
6696
6697jQuery.each({
6698 appendTo: "append",
6699 prependTo: "prepend",
6700 insertBefore: "before",
6701 insertAfter: "after",
6702 replaceAll: "replaceWith"
6703}, function( name, original ) {
6704 jQuery.fn[ name ] = function( selector ) {
6705 var ret = [],
6706 insert = jQuery( selector ),
6707 parent = this.length === 1 && this[0].parentNode;
6708
6709 if ( parent && parent.nodeType === 11 && parent.childNodes.length === 1 && insert.length === 1 ) {
6710 insert[ original ]( this[0] );
6711 return this;
6712
6713 } else {
6714 for ( var i = 0, l = insert.length; i < l; i++ ) {
6715 var elems = ( i > 0 ? this.clone(true) : this ).get();
6716 jQuery( insert[i] )[ original ]( elems );
6717 ret = ret.concat( elems );
6718 }
6719
6720 return this.pushStack( ret, name, insert.selector );
6721 }
6722 };
6723});
6724
6725function getAll( elem ) {
6726 if ( typeof elem.getElementsByTagName !== "undefined" ) {
6727 return elem.getElementsByTagName( "*" );
6728
6729 } else if ( typeof elem.querySelectorAll !== "undefined" ) {
6730 return elem.querySelectorAll( "*" );
6731
6732 } else {
6733 return [];
6734 }
6735}
6736
6737// Used in clean, fixes the defaultChecked property
6738function fixDefaultChecked( elem ) {
6739 if ( elem.type === "checkbox" || elem.type === "radio" ) {
6740 elem.defaultChecked = elem.checked;
6741 }
6742}
6743// Finds all inputs and passes them to fixDefaultChecked
6744function findInputs( elem ) {
6745 var nodeName = ( elem.nodeName || "" ).toLowerCase();
6746 if ( nodeName === "input" ) {
6747 fixDefaultChecked( elem );
6748 // Skip scripts, get other children
6749 } else if ( nodeName !== "script" && typeof elem.getElementsByTagName !== "undefined" ) {
6750 jQuery.grep( elem.getElementsByTagName("input"), fixDefaultChecked );
6751 }
6752}
6753
6754jQuery.extend({
6755 clone: function( elem, dataAndEvents, deepDataAndEvents ) {
6756 var clone = elem.cloneNode(true),
6757 srcElements,
6758 destElements,
6759 i;
6760
6761 if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) &&
6762 (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) {
6763 // IE copies events bound via attachEvent when using cloneNode.
6764 // Calling detachEvent on the clone will also remove the events
6765 // from the original. In order to get around this, we use some
6766 // proprietary methods to clear the events. Thanks to MooTools
6767 // guys for this hotness.
6768
6769 cloneFixAttributes( elem, clone );
6770
6771 // Using Sizzle here is crazy slow, so we use getElementsByTagName
6772 // instead
6773 srcElements = getAll( elem );
6774 destElements = getAll( clone );
6775
6776 // Weird iteration because IE will replace the length property
6777 // with an element if you are cloning the body and one of the
6778 // elements on the page has a name or id of "length"
6779 for ( i = 0; srcElements[i]; ++i ) {
6780 // Ensure that the destination node is not null; Fixes #9587
6781 if ( destElements[i] ) {
6782 cloneFixAttributes( srcElements[i], destElements[i] );
6783 }
6784 }
6785 }
6786
6787 // Copy the events from the original to the clone
6788 if ( dataAndEvents ) {
6789 cloneCopyEvent( elem, clone );
6790
6791 if ( deepDataAndEvents ) {
6792 srcElements = getAll( elem );
6793 destElements = getAll( clone );
6794
6795 for ( i = 0; srcElements[i]; ++i ) {
6796 cloneCopyEvent( srcElements[i], destElements[i] );
6797 }
6798 }
6799 }
6800
6801 srcElements = destElements = null;
6802
6803 // Return the cloned set
6804 return clone;
6805 },
6806
6807 clean: function( elems, context, fragment, scripts ) {
6808 var checkScriptType;
6809
6810 context = context || document;
6811
6812 // !context.createElement fails in IE with an error but returns typeof 'object'
6813 if ( typeof context.createElement === "undefined" ) {
6814 context = context.ownerDocument || context[0] && context[0].ownerDocument || document;
6815 }
6816
6817 var ret = [], j;
6818
6819 for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
6820 if ( typeof elem === "number" ) {
6821 elem += "";
6822 }
6823
6824 if ( !elem ) {
6825 continue;
6826 }
6827
6828 // Convert html string into DOM nodes
6829 if ( typeof elem === "string" ) {
6830 if ( !rhtml.test( elem ) ) {
6831 elem = context.createTextNode( elem );
6832 } else {
6833 // Fix "XHTML"-style tags in all browsers
6834 elem = elem.replace(rxhtmlTag, "<$1></$2>");
6835
6836 // Trim whitespace, otherwise indexOf won't work as expected
6837 var tag = ( rtagName.exec( elem ) || ["", ""] )[1].toLowerCase(),
6838 wrap = wrapMap[ tag ] || wrapMap._default,
6839 depth = wrap[0],
6840 div = context.createElement("div");
6841
6842 // Append wrapper element to unknown element safe doc fragment
6843 if ( context === document ) {
6844 // Use the fragment we've already created for this document
6845 safeFragment.appendChild( div );
6846 } else {
6847 // Use a fragment created with the owner document
6848 createSafeFragment( context ).appendChild( div );
6849 }
6850
6851 // Go to html and back, then peel off extra wrappers
6852 div.innerHTML = wrap[1] + elem + wrap[2];
6853
6854 // Move to the right depth
6855 while ( depth-- ) {
6856 div = div.lastChild;
6857 }
6858
6859 // Remove IE's autoinserted <tbody> from table fragments
6860 if ( !jQuery.support.tbody ) {
6861
6862 // String was a <table>, *may* have spurious <tbody>
6863 var hasBody = rtbody.test(elem),
6864 tbody = tag === "table" && !hasBody ?
6865 div.firstChild && div.firstChild.childNodes :
6866
6867 // String was a bare <thead> or <tfoot>
6868 wrap[1] === "<table>" && !hasBody ?
6869 div.childNodes :
6870 [];
6871
6872 for ( j = tbody.length - 1; j >= 0 ; --j ) {
6873 if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length ) {
6874 tbody[ j ].parentNode.removeChild( tbody[ j ] );
6875 }
6876 }
6877 }
6878
6879 // IE completely kills leading whitespace when innerHTML is used
6880 if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {
6881 div.insertBefore( context.createTextNode( rleadingWhitespace.exec(elem)[0] ), div.firstChild );
6882 }
6883
6884 elem = div.childNodes;
6885 }
6886 }
6887
6888 // Resets defaultChecked for any radios and checkboxes
6889 // about to be appended to the DOM in IE 6/7 (#8060)
6890 var len;
6891 if ( !jQuery.support.appendChecked ) {
6892 if ( elem[0] && typeof (len = elem.length) === "number" ) {
6893 for ( j = 0; j < len; j++ ) {
6894 findInputs( elem[j] );
6895 }
6896 } else {
6897 findInputs( elem );
6898 }
6899 }
6900
6901 if ( elem.nodeType ) {
6902 ret.push( elem );
6903 } else {
6904 ret = jQuery.merge( ret, elem );
6905 }
6906 }
6907
6908 if ( fragment ) {
6909 checkScriptType = function( elem ) {
6910 return !elem.type || rscriptType.test( elem.type );
6911 };
6912 for ( i = 0; ret[i]; i++ ) {
6913 if ( scripts && jQuery.nodeName( ret[i], "script" ) && (!ret[i].type || ret[i].type.toLowerCase() === "text/javascript") ) {
6914 scripts.push( ret[i].parentNode ? ret[i].parentNode.removeChild( ret[i] ) : ret[i] );
6915
6916 } else {
6917 if ( ret[i].nodeType === 1 ) {
6918 var jsTags = jQuery.grep( ret[i].getElementsByTagName( "script" ), checkScriptType );
6919
6920 ret.splice.apply( ret, [i + 1, 0].concat( jsTags ) );
6921 }
6922 fragment.appendChild( ret[i] );
6923 }
6924 }
6925 }
6926
6927 return ret;
6928 },
6929
6930 cleanData: function( elems ) {
6931 var data, id,
6932 cache = jQuery.cache,
6933 special = jQuery.event.special,
6934 deleteExpando = jQuery.support.deleteExpando;
6935
6936 for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
6937 if ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) {
6938 continue;
6939 }
6940
6941 id = elem[ jQuery.expando ];
6942
6943 if ( id ) {
6944 data = cache[ id ];
6945
6946 if ( data && data.events ) {
6947 for ( var type in data.events ) {
6948 if ( special[ type ] ) {
6949 jQuery.event.remove( elem, type );
6950
6951 // This is a shortcut to avoid jQuery.event.remove's overhead
6952 } else {
6953 jQuery.removeEvent( elem, type, data.handle );
6954 }
6955 }
6956
6957 // Null the DOM reference to avoid IE6/7/8 leak (#7054)
6958 if ( data.handle ) {
6959 data.handle.elem = null;
6960 }
6961 }
6962
6963 if ( deleteExpando ) {
6964 delete elem[ jQuery.expando ];
6965
6966 } else if ( elem.removeAttribute ) {
6967 elem.removeAttribute( jQuery.expando );
6968 }
6969
6970 delete cache[ id ];
6971 }
6972 }
6973 }
6974});
6975
6976function evalScript( i, elem ) {
6977 if ( elem.src ) {
6978 jQuery.ajax({
6979 url: elem.src,
6980 async: false,
6981 dataType: "script"
6982 });
6983 } else {
6984 jQuery.globalEval( ( elem.text || elem.textContent || elem.innerHTML || "" ).replace( rcleanScript, "/*$0*/" ) );
6985 }
6986
6987 if ( elem.parentNode ) {
6988 elem.parentNode.removeChild( elem );
6989 }
6990}
6991
6992})( jQuery );
6993(function( jQuery ) {
6994
6995var ralpha = /alpha\([^)]*\)/i,
6996 ropacity = /opacity=([^)]*)/,
6997 // fixed for IE9, see #8346
6998 rupper = /([A-Z]|^ms)/g,
6999 rnumpx = /^-?\d+(?:px)?$/i,
7000 rnum = /^-?\d/,
7001 rrelNum = /^([\-+])=([\-+.\de]+)/,
7002
7003 cssShow = { position: "absolute", visibility: "hidden", display: "block" },
7004 cssWidth = [ "Left", "Right" ],
7005 cssHeight = [ "Top", "Bottom" ],
7006 curCSS,
7007
7008 getComputedStyle,
7009 currentStyle;
7010
7011jQuery.fn.css = function( name, value ) {
7012 // Setting 'undefined' is a no-op
7013 if ( arguments.length === 2 && value === undefined ) {
7014 return this;
7015 }
7016
7017 return jQuery.access( this, name, value, true, function( elem, name, value ) {
7018 return value !== undefined ?
7019 jQuery.style( elem, name, value ) :
7020 jQuery.css( elem, name );
7021 });
7022};
7023
7024jQuery.extend({
7025 // Add in style property hooks for overriding the default
7026 // behavior of getting and setting a style property
7027 cssHooks: {
7028 opacity: {
7029 get: function( elem, computed ) {
7030 if ( computed ) {
7031 // We should always get a number back from opacity
7032 var ret = curCSS( elem, "opacity", "opacity" );
7033 return ret === "" ? "1" : ret;
7034
7035 } else {
7036 return elem.style.opacity;
7037 }
7038 }
7039 }
7040 },
7041
7042 // Exclude the following css properties to add px
7043 cssNumber: {
7044 "fillOpacity": true,
7045 "fontWeight": true,
7046 "lineHeight": true,
7047 "opacity": true,
7048 "orphans": true,
7049 "widows": true,
7050 "zIndex": true,
7051 "zoom": true
7052 },
7053
7054 // Add in properties whose names you wish to fix before
7055 // setting or getting the value
7056 cssProps: {
7057 // normalize float css property
7058 "float": jQuery.support.cssFloat ? "cssFloat" : "styleFloat"
7059 },
7060
7061 // Get and set the style property on a DOM Node
7062 style: function( elem, name, value, extra ) {
7063 // Don't set styles on text and comment nodes
7064 if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
7065 return;
7066 }
7067
7068 // Make sure that we're working with the right name
7069 var ret, type, origName = jQuery.camelCase( name ),
7070 style = elem.style, hooks = jQuery.cssHooks[ origName ];
7071
7072 name = jQuery.cssProps[ origName ] || origName;
7073
7074 // Check if we're setting a value
7075 if ( value !== undefined ) {
7076 type = typeof value;
7077
7078 // convert relative number strings (+= or -=) to relative numbers. #7345
7079 if ( type === "string" && (ret = rrelNum.exec( value )) ) {
7080 value = ( +( ret[1] + 1) * +ret[2] ) + parseFloat( jQuery.css( elem, name ) );
7081 // Fixes bug #9237
7082 type = "number";
7083 }
7084
7085 // Make sure that NaN and null values aren't set. See: #7116
7086 if ( value == null || type === "number" && isNaN( value ) ) {
7087 return;
7088 }
7089
7090 // If a number was passed in, add 'px' to the (except for certain CSS properties)
7091 if ( type === "number" && !jQuery.cssNumber[ origName ] ) {
7092 value += "px";
7093 }
7094
7095 // If a hook was provided, use that value, otherwise just set the specified value
7096 if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value )) !== undefined ) {
7097 // Wrapped to prevent IE from throwing errors when 'invalid' values are provided
7098 // Fixes bug #5509
7099 try {
7100 style[ name ] = value;
7101 } catch(e) {}
7102 }
7103
7104 } else {
7105 // If a hook was provided get the non-computed value from there
7106 if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {
7107 return ret;
7108 }
7109
7110 // Otherwise just get the value from the style object
7111 return style[ name ];
7112 }
7113 },
7114
7115 css: function( elem, name, extra ) {
7116 var ret, hooks;
7117
7118 // Make sure that we're working with the right name
7119 name = jQuery.camelCase( name );
7120 hooks = jQuery.cssHooks[ name ];
7121 name = jQuery.cssProps[ name ] || name;
7122
7123 // cssFloat needs a special treatment
7124 if ( name === "cssFloat" ) {
7125 name = "float";
7126 }
7127
7128 // If a hook was provided get the computed value from there
7129 if ( hooks && "get" in hooks && (ret = hooks.get( elem, true, extra )) !== undefined ) {
7130 return ret;
7131
7132 // Otherwise, if a way to get the computed value exists, use that
7133 } else if ( curCSS ) {
7134 return curCSS( elem, name );
7135 }
7136 },
7137
7138 // A method for quickly swapping in/out CSS properties to get correct calculations
7139 swap: function( elem, options, callback ) {
7140 var old = {};
7141
7142 // Remember the old values, and insert the new ones
7143 for ( var name in options ) {
7144 old[ name ] = elem.style[ name ];
7145 elem.style[ name ] = options[ name ];
7146 }
7147
7148 callback.call( elem );
7149
7150 // Revert the old values
7151 for ( name in options ) {
7152 elem.style[ name ] = old[ name ];
7153 }
7154 }
7155});
7156
7157// DEPRECATED, Use jQuery.css() instead
7158jQuery.curCSS = jQuery.css;
7159
7160jQuery.each(["height", "width"], function( i, name ) {
7161 jQuery.cssHooks[ name ] = {
7162 get: function( elem, computed, extra ) {
7163 var val;
7164
7165 if ( computed ) {
7166 if ( elem.offsetWidth !== 0 ) {
7167 return getWH( elem, name, extra );
7168 } else {
7169 jQuery.swap( elem, cssShow, function() {
7170 val = getWH( elem, name, extra );
7171 });
7172 }
7173
7174 return val;
7175 }
7176 },
7177
7178 set: function( elem, value ) {
7179 if ( rnumpx.test( value ) ) {
7180 // ignore negative width and height values #1599
7181 value = parseFloat( value );
7182
7183 if ( value >= 0 ) {
7184 return value + "px";
7185 }
7186
7187 } else {
7188 return value;
7189 }
7190 }
7191 };
7192});
7193
7194if ( !jQuery.support.opacity ) {
7195 jQuery.cssHooks.opacity = {
7196 get: function( elem, computed ) {
7197 // IE uses filters for opacity
7198 return ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "" ) ?
7199 ( parseFloat( RegExp.$1 ) / 100 ) + "" :
7200 computed ? "1" : "";
7201 },
7202
7203 set: function( elem, value ) {
7204 var style = elem.style,
7205 currentStyle = elem.currentStyle,
7206 opacity = jQuery.isNumeric( value ) ? "alpha(opacity=" + value * 100 + ")" : "",
7207 filter = currentStyle && currentStyle.filter || style.filter || "";
7208
7209 // IE has trouble with opacity if it does not have layout
7210 // Force it by setting the zoom level
7211 style.zoom = 1;
7212
7213 // if setting opacity to 1, and no other filters exist - attempt to remove filter attribute #6652
7214 if ( value >= 1 && jQuery.trim( filter.replace( ralpha, "" ) ) === "" ) {
7215
7216 // Setting style.filter to null, "" & " " still leave "filter:" in the cssText
7217 // if "filter:" is present at all, clearType is disabled, we want to avoid this
7218 // style.removeAttribute is IE Only, but so apparently is this code path...
7219 style.removeAttribute( "filter" );
7220
7221 // if there there is no filter style applied in a css rule, we are done
7222 if ( currentStyle && !currentStyle.filter ) {
7223 return;
7224 }
7225 }
7226
7227 // otherwise, set new filter values
7228 style.filter = ralpha.test( filter ) ?
7229 filter.replace( ralpha, opacity ) :
7230 filter + " " + opacity;
7231 }
7232 };
7233}
7234
7235jQuery(function() {
7236 // This hook cannot be added until DOM ready because the support test
7237 // for it is not run until after DOM ready
7238 if ( !jQuery.support.reliableMarginRight ) {
7239 jQuery.cssHooks.marginRight = {
7240 get: function( elem, computed ) {
7241 // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
7242 // Work around by temporarily setting element display to inline-block
7243 var ret;
7244 jQuery.swap( elem, { "display": "inline-block" }, function() {
7245 if ( computed ) {
7246 ret = curCSS( elem, "margin-right", "marginRight" );
7247 } else {
7248 ret = elem.style.marginRight;
7249 }
7250 });
7251 return ret;
7252 }
7253 };
7254 }
7255});
7256
7257if ( document.defaultView && document.defaultView.getComputedStyle ) {
7258 getComputedStyle = function( elem, name ) {
7259 var ret, defaultView, computedStyle;
7260
7261 name = name.replace( rupper, "-$1" ).toLowerCase();
7262
7263 if ( !(defaultView = elem.ownerDocument.defaultView) ) {
7264 return undefined;
7265 }
7266
7267 if ( (computedStyle = defaultView.getComputedStyle( elem, null )) ) {
7268 ret = computedStyle.getPropertyValue( name );
7269 if ( ret === "" && !jQuery.contains( elem.ownerDocument.documentElement, elem ) ) {
7270 ret = jQuery.style( elem, name );
7271 }
7272 }
7273
7274 return ret;
7275 };
7276}
7277
7278if ( document.documentElement.currentStyle ) {
7279 currentStyle = function( elem, name ) {
7280 var left, rsLeft, uncomputed,
7281 ret = elem.currentStyle && elem.currentStyle[ name ],
7282 style = elem.style;
7283
7284 // Avoid setting ret to empty string here
7285 // so we don't default to auto
7286 if ( ret === null && style && (uncomputed = style[ name ]) ) {
7287 ret = uncomputed;
7288 }
7289
7290 // From the awesome hack by Dean Edwards
7291 // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
7292
7293 // If we're not dealing with a regular pixel number
7294 // but a number that has a weird ending, we need to convert it to pixels
7295 if ( !rnumpx.test( ret ) && rnum.test( ret ) ) {
7296
7297 // Remember the original values
7298 left = style.left;
7299 rsLeft = elem.runtimeStyle && elem.runtimeStyle.left;
7300
7301 // Put in the new values to get a computed value out
7302 if ( rsLeft ) {
7303 elem.runtimeStyle.left = elem.currentStyle.left;
7304 }
7305 style.left = name === "fontSize" ? "1em" : ( ret || 0 );
7306 ret = style.pixelLeft + "px";
7307
7308 // Revert the changed values
7309 style.left = left;
7310 if ( rsLeft ) {
7311 elem.runtimeStyle.left = rsLeft;
7312 }
7313 }
7314
7315 return ret === "" ? "auto" : ret;
7316 };
7317}
7318
7319curCSS = getComputedStyle || currentStyle;
7320
7321function getWH( elem, name, extra ) {
7322
7323 // Start with offset property
7324 var val = name === "width" ? elem.offsetWidth : elem.offsetHeight,
7325 which = name === "width" ? cssWidth : cssHeight;
7326
7327 if ( val > 0 ) {
7328 if ( extra !== "border" ) {
7329 jQuery.each( which, function() {
7330 if ( !extra ) {
7331 val -= parseFloat( jQuery.css( elem, "padding" + this ) ) || 0;
7332 }
7333 if ( extra === "margin" ) {
7334 val += parseFloat( jQuery.css( elem, extra + this ) ) || 0;
7335 } else {
7336 val -= parseFloat( jQuery.css( elem, "border" + this + "Width" ) ) || 0;
7337 }
7338 });
7339 }
7340
7341 return val + "px";
7342 }
7343
7344 // Fall back to computed then uncomputed css if necessary
7345 val = curCSS( elem, name, name );
7346 if ( val < 0 || val == null ) {
7347 val = elem.style[ name ] || 0;
7348 }
7349 // Normalize "", auto, and prepare for extra
7350 val = parseFloat( val ) || 0;
7351
7352 // Add padding, border, margin
7353 if ( extra ) {
7354 jQuery.each( which, function() {
7355 val += parseFloat( jQuery.css( elem, "padding" + this ) ) || 0;
7356 if ( extra !== "padding" ) {
7357 val += parseFloat( jQuery.css( elem, "border" + this + "Width" ) ) || 0;
7358 }
7359 if ( extra === "margin" ) {
7360 val += parseFloat( jQuery.css( elem, extra + this ) ) || 0;
7361 }
7362 });
7363 }
7364
7365 return val + "px";
7366}
7367
7368if ( jQuery.expr && jQuery.expr.filters ) {
7369 jQuery.expr.filters.hidden = function( elem ) {
7370 var width = elem.offsetWidth,
7371 height = elem.offsetHeight;
7372
7373 return ( width === 0 && height === 0 ) || (!jQuery.support.reliableHiddenOffsets && ((elem.style && elem.style.display) || jQuery.css( elem, "display" )) === "none");
7374 };
7375
7376 jQuery.expr.filters.visible = function( elem ) {
7377 return !jQuery.expr.filters.hidden( elem );
7378 };
7379}
7380
7381})( jQuery );
7382(function( jQuery ) {
7383
7384var r20 = /%20/g,
7385 rbracket = /\[\]$/,
7386 rCRLF = /\r?\n/g,
7387 rhash = /#.*$/,
7388 rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL
7389 rinput = /^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,
7390 // #7653, #8125, #8152: local protocol detection
7391 rlocalProtocol = /^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,
7392 rnoContent = /^(?:GET|HEAD)$/,
7393 rprotocol = /^\/\//,
7394 rquery = /\?/,
7395 rscript = /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,
7396 rselectTextarea = /^(?:select|textarea)/i,
7397 rspacesAjax = /\s+/,
7398 rts = /([?&])_=[^&]*/,
7399 rurl = /^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,
7400
7401 // Keep a copy of the old load method
7402 _load = jQuery.fn.load,
7403
7404 /* Prefilters
7405 * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
7406 * 2) These are called:
7407 * - BEFORE asking for a transport
7408 * - AFTER param serialization (s.data is a string if s.processData is true)
7409 * 3) key is the dataType
7410 * 4) the catchall symbol "*" can be used
7411 * 5) execution will start with transport dataType and THEN continue down to "*" if needed
7412 */
7413 prefilters = {},
7414
7415 /* Transports bindings
7416 * 1) key is the dataType
7417 * 2) the catchall symbol "*" can be used
7418 * 3) selection will start with transport dataType and THEN go to "*" if needed
7419 */
7420 transports = {},
7421
7422 // Document location
7423 ajaxLocation,
7424
7425 // Document location segments
7426 ajaxLocParts,
7427
7428 // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
7429 allTypes = ["*/"] + ["*"];
7430
7431// #8138, IE may throw an exception when accessing
7432// a field from window.location if document.domain has been set
7433try {
7434 ajaxLocation = location.href;
7435} catch( e ) {
7436 // Use the href attribute of an A element
7437 // since IE will modify it given document.location
7438 ajaxLocation = document.createElement( "a" );
7439 ajaxLocation.href = "";
7440 ajaxLocation = ajaxLocation.href;
7441}
7442
7443// Segment location into parts
7444ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];
7445
7446// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
7447function addToPrefiltersOrTransports( structure ) {
7448
7449 // dataTypeExpression is optional and defaults to "*"
7450 return function( dataTypeExpression, func ) {
7451
7452 if ( typeof dataTypeExpression !== "string" ) {
7453 func = dataTypeExpression;
7454 dataTypeExpression = "*";
7455 }
7456
7457 if ( jQuery.isFunction( func ) ) {
7458 var dataTypes = dataTypeExpression.toLowerCase().split( rspacesAjax ),
7459 i = 0,
7460 length = dataTypes.length,
7461 dataType,
7462 list,
7463 placeBefore;
7464
7465 // For each dataType in the dataTypeExpression
7466 for ( ; i < length; i++ ) {
7467 dataType = dataTypes[ i ];
7468 // We control if we're asked to add before
7469 // any existing element
7470 placeBefore = /^\+/.test( dataType );
7471 if ( placeBefore ) {
7472 dataType = dataType.substr( 1 ) || "*";
7473 }
7474 list = structure[ dataType ] = structure[ dataType ] || [];
7475 // then we add to the structure accordingly
7476 list[ placeBefore ? "unshift" : "push" ]( func );
7477 }
7478 }
7479 };
7480}
7481
7482// Base inspection function for prefilters and transports
7483function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR,
7484 dataType /* internal */, inspected /* internal */ ) {
7485
7486 dataType = dataType || options.dataTypes[ 0 ];
7487 inspected = inspected || {};
7488
7489 inspected[ dataType ] = true;
7490
7491 var list = structure[ dataType ],
7492 i = 0,
7493 length = list ? list.length : 0,
7494 executeOnly = ( structure === prefilters ),
7495 selection;
7496
7497 for ( ; i < length && ( executeOnly || !selection ); i++ ) {
7498 selection = list[ i ]( options, originalOptions, jqXHR );
7499 // If we got redirected to another dataType
7500 // we try there if executing only and not done already
7501 if ( typeof selection === "string" ) {
7502 if ( !executeOnly || inspected[ selection ] ) {
7503 selection = undefined;
7504 } else {
7505 options.dataTypes.unshift( selection );
7506 selection = inspectPrefiltersOrTransports(
7507 structure, options, originalOptions, jqXHR, selection, inspected );
7508 }
7509 }
7510 }
7511 // If we're only executing or nothing was selected
7512 // we try the catchall dataType if not done already
7513 if ( ( executeOnly || !selection ) && !inspected[ "*" ] ) {
7514 selection = inspectPrefiltersOrTransports(
7515 structure, options, originalOptions, jqXHR, "*", inspected );
7516 }
7517 // unnecessary when only executing (prefilters)
7518 // but it'll be ignored by the caller in that case
7519 return selection;
7520}
7521
7522// A special extend for ajax options
7523// that takes "flat" options (not to be deep extended)
7524// Fixes #9887
7525function ajaxExtend( target, src ) {
7526 var key, deep,
7527 flatOptions = jQuery.ajaxSettings.flatOptions || {};
7528 for ( key in src ) {
7529 if ( src[ key ] !== undefined ) {
7530 ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ];
7531 }
7532 }
7533 if ( deep ) {
7534 jQuery.extend( true, target, deep );
7535 }
7536}
7537
7538jQuery.fn.extend({
7539 load: function( url, params, callback ) {
7540 if ( typeof url !== "string" && _load ) {
7541 return _load.apply( this, arguments );
7542
7543 // Don't do a request if no elements are being requested
7544 } else if ( !this.length ) {
7545 return this;
7546 }
7547
7548 var off = url.indexOf( " " );
7549 if ( off >= 0 ) {
7550 var selector = url.slice( off, url.length );
7551 url = url.slice( 0, off );
7552 }
7553
7554 // Default to a GET request
7555 var type = "GET";
7556
7557 // If the second parameter was provided
7558 if ( params ) {
7559 // If it's a function
7560 if ( jQuery.isFunction( params ) ) {
7561 // We assume that it's the callback
7562 callback = params;
7563 params = undefined;
7564
7565 // Otherwise, build a param string
7566 } else if ( typeof params === "object" ) {
7567 params = jQuery.param( params, jQuery.ajaxSettings.traditional );
7568 type = "POST";
7569 }
7570 }
7571
7572 var self = this;
7573
7574 // Request the remote document
7575 jQuery.ajax({
7576 url: url,
7577 type: type,
7578 dataType: "html",
7579 data: params,
7580 // Complete callback (responseText is used internally)
7581 complete: function( jqXHR, status, responseText ) {
7582 // Store the response as specified by the jqXHR object
7583 responseText = jqXHR.responseText;
7584 // If successful, inject the HTML into all the matched elements
7585 if ( jqXHR.isResolved() ) {
7586 // #4825: Get the actual response in case
7587 // a dataFilter is present in ajaxSettings
7588 jqXHR.done(function( r ) {
7589 responseText = r;
7590 });
7591 // See if a selector was specified
7592 self.html( selector ?
7593 // Create a dummy div to hold the results
7594 jQuery("<div>")
7595 // inject the contents of the document in, removing the scripts
7596 // to avoid any 'Permission Denied' errors in IE
7597 .append(responseText.replace(rscript, ""))
7598
7599 // Locate the specified elements
7600 .find(selector) :
7601
7602 // If not, just inject the full result
7603 responseText );
7604 }
7605
7606 if ( callback ) {
7607 self.each( callback, [ responseText, status, jqXHR ] );
7608 }
7609 }
7610 });
7611
7612 return this;
7613 },
7614
7615 serialize: function() {
7616 return jQuery.param( this.serializeArray() );
7617 },
7618
7619 serializeArray: function() {
7620 return this.map(function(){
7621 return this.elements ? jQuery.makeArray( this.elements ) : this;
7622 })
7623 .filter(function(){
7624 return this.name && !this.disabled &&
7625 ( this.checked || rselectTextarea.test( this.nodeName ) ||
7626 rinput.test( this.type ) );
7627 })
7628 .map(function( i, elem ){
7629 var val = jQuery( this ).val();
7630
7631 return val == null ?
7632 null :
7633 jQuery.isArray( val ) ?
7634 jQuery.map( val, function( val, i ){
7635 return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
7636 }) :
7637 { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
7638 }).get();
7639 }
7640});
7641
7642// Attach a bunch of functions for handling common AJAX events
7643jQuery.each( "ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split( " " ), function( i, o ){
7644 jQuery.fn[ o ] = function( f ){
7645 return this.bind( o, f );
7646 };
7647});
7648
7649jQuery.each( [ "get", "post" ], function( i, method ) {
7650 jQuery[ method ] = function( url, data, callback, type ) {
7651 // shift arguments if data argument was omitted
7652 if ( jQuery.isFunction( data ) ) {
7653 type = type || callback;
7654 callback = data;
7655 data = undefined;
7656 }
7657
7658 return jQuery.ajax({
7659 type: method,
7660 url: url,
7661 data: data,
7662 success: callback,
7663 dataType: type
7664 });
7665 };
7666});
7667
7668jQuery.extend({
7669
7670 getScript: function( url, callback ) {
7671 return jQuery.get( url, undefined, callback, "script" );
7672 },
7673
7674 getJSON: function( url, data, callback ) {
7675 return jQuery.get( url, data, callback, "json" );
7676 },
7677
7678 // Creates a full fledged settings object into target
7679 // with both ajaxSettings and settings fields.
7680 // If target is omitted, writes into ajaxSettings.
7681 ajaxSetup: function( target, settings ) {
7682 if ( settings ) {
7683 // Building a settings object
7684 ajaxExtend( target, jQuery.ajaxSettings );
7685 } else {
7686 // Extending ajaxSettings
7687 settings = target;
7688 target = jQuery.ajaxSettings;
7689 }
7690 ajaxExtend( target, settings );
7691 return target;
7692 },
7693
7694 ajaxSettings: {
7695 url: ajaxLocation,
7696 isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),
7697 global: true,
7698 type: "GET",
7699 contentType: "application/x-www-form-urlencoded",
7700 processData: true,
7701 async: true,
7702 /*
7703 timeout: 0,
7704 data: null,
7705 dataType: null,
7706 username: null,
7707 password: null,
7708 cache: null,
7709 traditional: false,
7710 headers: {},
7711 */
7712
7713 accepts: {
7714 xml: "application/xml, text/xml",
7715 html: "text/html",
7716 text: "text/plain",
7717 json: "application/json, text/javascript",
7718 "*": allTypes
7719 },
7720
7721 contents: {
7722 xml: /xml/,
7723 html: /html/,
7724 json: /json/
7725 },
7726
7727 responseFields: {
7728 xml: "responseXML",
7729 text: "responseText"
7730 },
7731
7732 // List of data converters
7733 // 1) key format is "source_type destination_type" (a single space in-between)
7734 // 2) the catchall symbol "*" can be used for source_type
7735 converters: {
7736
7737 // Convert anything to text
7738 "* text": window.String,
7739
7740 // Text to html (true = no transformation)
7741 "text html": true,
7742
7743 // Evaluate text as a json expression
7744 "text json": jQuery.parseJSON,
7745
7746 // Parse text as xml
7747 "text xml": jQuery.parseXML
7748 },
7749
7750 // For options that shouldn't be deep extended:
7751 // you can add your own custom options here if
7752 // and when you create one that shouldn't be
7753 // deep extended (see ajaxExtend)
7754 flatOptions: {
7755 context: true,
7756 url: true
7757 }
7758 },
7759
7760 ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
7761 ajaxTransport: addToPrefiltersOrTransports( transports ),
7762
7763 // Main method
7764 ajax: function( url, options ) {
7765
7766 // If url is an object, simulate pre-1.5 signature
7767 if ( typeof url === "object" ) {
7768 options = url;
7769 url = undefined;
7770 }
7771
7772 // Force options to be an object
7773 options = options || {};
7774
7775 var // Create the final options object
7776 s = jQuery.ajaxSetup( {}, options ),
7777 // Callbacks context
7778 callbackContext = s.context || s,
7779 // Context for global events
7780 // It's the callbackContext if one was provided in the options
7781 // and if it's a DOM node or a jQuery collection
7782 globalEventContext = callbackContext !== s &&
7783 ( callbackContext.nodeType || callbackContext instanceof jQuery ) ?
7784 jQuery( callbackContext ) : jQuery.event,
7785 // Deferreds
7786 deferred = jQuery.Deferred(),
7787 completeDeferred = jQuery.Callbacks( "once memory" ),
7788 // Status-dependent callbacks
7789 statusCode = s.statusCode || {},
7790 // ifModified key
7791 ifModifiedKey,
7792 // Headers (they are sent all at once)
7793 requestHeaders = {},
7794 requestHeadersNames = {},
7795 // Response headers
7796 responseHeadersString,
7797 responseHeaders,
7798 // transport
7799 transport,
7800 // timeout handle
7801 timeoutTimer,
7802 // Cross-domain detection vars
7803 parts,
7804 // The jqXHR state
7805 state = 0,
7806 // To know if global events are to be dispatched
7807 fireGlobals,
7808 // Loop variable
7809 i,
7810 // Fake xhr
7811 jqXHR = {
7812
7813 readyState: 0,
7814
7815 // Caches the header
7816 setRequestHeader: function( name, value ) {
7817 if ( !state ) {
7818 var lname = name.toLowerCase();
7819 name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;
7820 requestHeaders[ name ] = value;
7821 }
7822 return this;
7823 },
7824
7825 // Raw string
7826 getAllResponseHeaders: function() {
7827 return state === 2 ? responseHeadersString : null;
7828 },
7829
7830 // Builds headers hashtable if needed
7831 getResponseHeader: function( key ) {
7832 var match;
7833 if ( state === 2 ) {
7834 if ( !responseHeaders ) {
7835 responseHeaders = {};
7836 while( ( match = rheaders.exec( responseHeadersString ) ) ) {
7837 responseHeaders[ match[1].toLowerCase() ] = match[ 2 ];
7838 }
7839 }
7840 match = responseHeaders[ key.toLowerCase() ];
7841 }
7842 return match === undefined ? null : match;
7843 },
7844
7845 // Overrides response content-type header
7846 overrideMimeType: function( type ) {
7847 if ( !state ) {
7848 s.mimeType = type;
7849 }
7850 return this;
7851 },
7852
7853 // Cancel the request
7854 abort: function( statusText ) {
7855 statusText = statusText || "abort";
7856 if ( transport ) {
7857 transport.abort( statusText );
7858 }
7859 done( 0, statusText );
7860 return this;
7861 }
7862 };
7863
7864 // Callback for when everything is done
7865 // It is defined here because jslint complains if it is declared
7866 // at the end of the function (which would be more logical and readable)
7867 function done( status, nativeStatusText, responses, headers ) {
7868
7869 // Called once
7870 if ( state === 2 ) {
7871 return;
7872 }
7873
7874 // State is "done" now
7875 state = 2;
7876
7877 // Clear timeout if it exists
7878 if ( timeoutTimer ) {
7879 clearTimeout( timeoutTimer );
7880 }
7881
7882 // Dereference transport for early garbage collection
7883 // (no matter how long the jqXHR object will be used)
7884 transport = undefined;
7885
7886 // Cache response headers
7887 responseHeadersString = headers || "";
7888
7889 // Set readyState
7890 jqXHR.readyState = status > 0 ? 4 : 0;
7891
7892 var isSuccess,
7893 success,
7894 error,
7895 statusText = nativeStatusText,
7896 response = responses ? ajaxHandleResponses( s, jqXHR, responses ) : undefined,
7897 lastModified,
7898 etag;
7899
7900 // If successful, handle type chaining
7901 if ( status >= 200 && status < 300 || status === 304 ) {
7902
7903 // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
7904 if ( s.ifModified ) {
7905
7906 if ( ( lastModified = jqXHR.getResponseHeader( "Last-Modified" ) ) ) {
7907 jQuery.lastModified[ ifModifiedKey ] = lastModified;
7908 }
7909 if ( ( etag = jqXHR.getResponseHeader( "Etag" ) ) ) {
7910 jQuery.etag[ ifModifiedKey ] = etag;
7911 }
7912 }
7913
7914 // If not modified
7915 if ( status === 304 ) {
7916
7917 statusText = "notmodified";
7918 isSuccess = true;
7919
7920 // If we have data
7921 } else {
7922
7923 try {
7924 success = ajaxConvert( s, response );
7925 statusText = "success";
7926 isSuccess = true;
7927 } catch(e) {
7928 // We have a parsererror
7929 statusText = "parsererror";
7930 error = e;
7931 }
7932 }
7933 } else {
7934 // We extract error from statusText
7935 // then normalize statusText and status for non-aborts
7936 error = statusText;
7937 if ( !statusText || status ) {
7938 statusText = "error";
7939 if ( status < 0 ) {
7940 status = 0;
7941 }
7942 }
7943 }
7944
7945 // Set data for the fake xhr object
7946 jqXHR.status = status;
7947 jqXHR.statusText = "" + ( nativeStatusText || statusText );
7948
7949 // Success/Error
7950 if ( isSuccess ) {
7951 deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
7952 } else {
7953 deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
7954 }
7955
7956 // Status-dependent callbacks
7957 jqXHR.statusCode( statusCode );
7958 statusCode = undefined;
7959
7960 if ( fireGlobals ) {
7961 globalEventContext.trigger( "ajax" + ( isSuccess ? "Success" : "Error" ),
7962 [ jqXHR, s, isSuccess ? success : error ] );
7963 }
7964
7965 // Complete
7966 completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );
7967
7968 if ( fireGlobals ) {
7969 globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
7970 // Handle the global AJAX counter
7971 if ( !( --jQuery.active ) ) {
7972 jQuery.event.trigger( "ajaxStop" );
7973 }
7974 }
7975 }
7976
7977 // Attach deferreds
7978 deferred.promise( jqXHR );
7979 jqXHR.success = jqXHR.done;
7980 jqXHR.error = jqXHR.fail;
7981 jqXHR.complete = completeDeferred.add;
7982
7983 // Status-dependent callbacks
7984 jqXHR.statusCode = function( map ) {
7985 if ( map ) {
7986 var tmp;
7987 if ( state < 2 ) {
7988 for ( tmp in map ) {
7989 statusCode[ tmp ] = [ statusCode[tmp], map[tmp] ];
7990 }
7991 } else {
7992 tmp = map[ jqXHR.status ];
7993 jqXHR.then( tmp, tmp );
7994 }
7995 }
7996 return this;
7997 };
7998
7999 // Remove hash character (#7531: and string promotion)
8000 // Add protocol if not provided (#5866: IE7 issue with protocol-less urls)
8001 // We also use the url parameter if available
8002 s.url = ( ( url || s.url ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" );
8003
8004 // Extract dataTypes list
8005 s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().split( rspacesAjax );
8006
8007 // Determine if a cross-domain request is in order
8008 if ( s.crossDomain == null ) {
8009 parts = rurl.exec( s.url.toLowerCase() );
8010 s.crossDomain = !!( parts &&
8011 ( parts[ 1 ] != ajaxLocParts[ 1 ] || parts[ 2 ] != ajaxLocParts[ 2 ] ||
8012 ( parts[ 3 ] || ( parts[ 1 ] === "http:" ? 80 : 443 ) ) !=
8013 ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? 80 : 443 ) ) )
8014 );
8015 }
8016
8017 // Convert data if not already a string
8018 if ( s.data && s.processData && typeof s.data !== "string" ) {
8019 s.data = jQuery.param( s.data, s.traditional );
8020 }
8021
8022 // Apply prefilters
8023 inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
8024
8025 // If request was aborted inside a prefiler, stop there
8026 if ( state === 2 ) {
8027 return false;
8028 }
8029
8030 // We can fire global events as of now if asked to
8031 fireGlobals = s.global;
8032
8033 // Uppercase the type
8034 s.type = s.type.toUpperCase();
8035
8036 // Determine if request has content
8037 s.hasContent = !rnoContent.test( s.type );
8038
8039 // Watch for a new set of requests
8040 if ( fireGlobals && jQuery.active++ === 0 ) {
8041 jQuery.event.trigger( "ajaxStart" );
8042 }
8043
8044 // More options handling for requests with no content
8045 if ( !s.hasContent ) {
8046
8047 // If data is available, append data to url
8048 if ( s.data ) {
8049 s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.data;
8050 // #9682: remove data so that it's not used in an eventual retry
8051 delete s.data;
8052 }
8053
8054 // Get ifModifiedKey before adding the anti-cache parameter
8055 ifModifiedKey = s.url;
8056
8057 // Add anti-cache in url if needed
8058 if ( s.cache === false ) {
8059
8060 var ts = jQuery.now(),
8061 // try replacing _= if it is there
8062 ret = s.url.replace( rts, "$1_=" + ts );
8063
8064 // if nothing was replaced, add timestamp to the end
8065 s.url = ret + ( ( ret === s.url ) ? ( rquery.test( s.url ) ? "&" : "?" ) + "_=" + ts : "" );
8066 }
8067 }
8068
8069 // Set the correct header, if data is being sent
8070 if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
8071 jqXHR.setRequestHeader( "Content-Type", s.contentType );
8072 }
8073
8074 // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
8075 if ( s.ifModified ) {
8076 ifModifiedKey = ifModifiedKey || s.url;
8077 if ( jQuery.lastModified[ ifModifiedKey ] ) {
8078 jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ ifModifiedKey ] );
8079 }
8080 if ( jQuery.etag[ ifModifiedKey ] ) {
8081 jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ ifModifiedKey ] );
8082 }
8083 }
8084
8085 // Set the Accepts header for the server, depending on the dataType
8086 jqXHR.setRequestHeader(
8087 "Accept",
8088 s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?
8089 s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
8090 s.accepts[ "*" ]
8091 );
8092
8093 // Check for headers option
8094 for ( i in s.headers ) {
8095 jqXHR.setRequestHeader( i, s.headers[ i ] );
8096 }
8097
8098 // Allow custom headers/mimetypes and early abort
8099 if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {
8100 // Abort if not done already
8101 jqXHR.abort();
8102 return false;
8103
8104 }
8105
8106 // Install callbacks on deferreds
8107 for ( i in { success: 1, error: 1, complete: 1 } ) {
8108 jqXHR[ i ]( s[ i ] );
8109 }
8110
8111 // Get transport
8112 transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
8113
8114 // If no transport, we auto-abort
8115 if ( !transport ) {
8116 done( -1, "No Transport" );
8117 } else {
8118 jqXHR.readyState = 1;
8119 // Send global event
8120 if ( fireGlobals ) {
8121 globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
8122 }
8123 // Timeout
8124 if ( s.async && s.timeout > 0 ) {
8125 timeoutTimer = setTimeout( function(){
8126 jqXHR.abort( "timeout" );
8127 }, s.timeout );
8128 }
8129
8130 try {
8131 state = 1;
8132 transport.send( requestHeaders, done );
8133 } catch (e) {
8134 // Propagate exception as error if not done
8135 if ( state < 2 ) {
8136 done( -1, e );
8137 // Simply rethrow otherwise
8138 } else {
8139 jQuery.error( e );
8140 }
8141 }
8142 }
8143
8144 return jqXHR;
8145 },
8146
8147 // Serialize an array of form elements or a set of
8148 // key/values into a query string
8149 param: function( a, traditional ) {
8150 var s = [],
8151 add = function( key, value ) {
8152 // If value is a function, invoke it and return its value
8153 value = jQuery.isFunction( value ) ? value() : value;
8154 s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value );
8155 };
8156
8157 // Set traditional to true for jQuery <= 1.3.2 behavior.
8158 if ( traditional === undefined ) {
8159 traditional = jQuery.ajaxSettings.traditional;
8160 }
8161
8162 // If an array was passed in, assume that it is an array of form elements.
8163 if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
8164 // Serialize the form elements
8165 jQuery.each( a, function() {
8166 add( this.name, this.value );
8167 });
8168
8169 } else {
8170 // If traditional, encode the "old" way (the way 1.3.2 or older
8171 // did it), otherwise encode params recursively.
8172 for ( var prefix in a ) {
8173 buildParams( prefix, a[ prefix ], traditional, add );
8174 }
8175 }
8176
8177 // Return the resulting serialization
8178 return s.join( "&" ).replace( r20, "+" );
8179 }
8180});
8181
8182function buildParams( prefix, obj, traditional, add ) {
8183 if ( jQuery.isArray( obj ) ) {
8184 // Serialize array item.
8185 jQuery.each( obj, function( i, v ) {
8186 if ( traditional || rbracket.test( prefix ) ) {
8187 // Treat each array item as a scalar.
8188 add( prefix, v );
8189
8190 } else {
8191 // If array item is non-scalar (array or object), encode its
8192 // numeric index to resolve deserialization ambiguity issues.
8193 // Note that rack (as of 1.0.0) can't currently deserialize
8194 // nested arrays properly, and attempting to do so may cause
8195 // a server error. Possible fixes are to modify rack's
8196 // deserialization algorithm or to provide an option or flag
8197 // to force array serialization to be shallow.
8198 buildParams( prefix + "[" + ( typeof v === "object" || jQuery.isArray(v) ? i : "" ) + "]", v, traditional, add );
8199 }
8200 });
8201
8202 } else if ( !traditional && obj != null && typeof obj === "object" ) {
8203 // Serialize object item.
8204 for ( var name in obj ) {
8205 buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
8206 }
8207
8208 } else {
8209 // Serialize scalar item.
8210 add( prefix, obj );
8211 }
8212}
8213
8214// This is still on the jQuery object... for now
8215// Want to move this to jQuery.ajax some day
8216jQuery.extend({
8217
8218 // Counter for holding the number of active queries
8219 active: 0,
8220
8221 // Last-Modified header cache for next request
8222 lastModified: {},
8223 etag: {}
8224
8225});
8226
8227/* Handles responses to an ajax request:
8228 * - sets all responseXXX fields accordingly
8229 * - finds the right dataType (mediates between content-type and expected dataType)
8230 * - returns the corresponding response
8231 */
8232function ajaxHandleResponses( s, jqXHR, responses ) {
8233
8234 var contents = s.contents,
8235 dataTypes = s.dataTypes,
8236 responseFields = s.responseFields,
8237 ct,
8238 type,
8239 finalDataType,
8240 firstDataType;
8241
8242 // Fill responseXXX fields
8243 for ( type in responseFields ) {
8244 if ( type in responses ) {
8245 jqXHR[ responseFields[type] ] = responses[ type ];
8246 }
8247 }
8248
8249 // Remove auto dataType and get content-type in the process
8250 while( dataTypes[ 0 ] === "*" ) {
8251 dataTypes.shift();
8252 if ( ct === undefined ) {
8253 ct = s.mimeType || jqXHR.getResponseHeader( "content-type" );
8254 }
8255 }
8256
8257 // Check if we're dealing with a known content-type
8258 if ( ct ) {
8259 for ( type in contents ) {
8260 if ( contents[ type ] && contents[ type ].test( ct ) ) {
8261 dataTypes.unshift( type );
8262 break;
8263 }
8264 }
8265 }
8266
8267 // Check to see if we have a response for the expected dataType
8268 if ( dataTypes[ 0 ] in responses ) {
8269 finalDataType = dataTypes[ 0 ];
8270 } else {
8271 // Try convertible dataTypes
8272 for ( type in responses ) {
8273 if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) {
8274 finalDataType = type;
8275 break;
8276 }
8277 if ( !firstDataType ) {
8278 firstDataType = type;
8279 }
8280 }
8281 // Or just use first one
8282 finalDataType = finalDataType || firstDataType;
8283 }
8284
8285 // If we found a dataType
8286 // We add the dataType to the list if needed
8287 // and return the corresponding response
8288 if ( finalDataType ) {
8289 if ( finalDataType !== dataTypes[ 0 ] ) {
8290 dataTypes.unshift( finalDataType );
8291 }
8292 return responses[ finalDataType ];
8293 }
8294}
8295
8296// Chain conversions given the request and the original response
8297function ajaxConvert( s, response ) {
8298
8299 // Apply the dataFilter if provided
8300 if ( s.dataFilter ) {
8301 response = s.dataFilter( response, s.dataType );
8302 }
8303
8304 var dataTypes = s.dataTypes,
8305 converters = {},
8306 i,
8307 key,
8308 length = dataTypes.length,
8309 tmp,
8310 // Current and previous dataTypes
8311 current = dataTypes[ 0 ],
8312 prev,
8313 // Conversion expression
8314 conversion,
8315 // Conversion function
8316 conv,
8317 // Conversion functions (transitive conversion)
8318 conv1,
8319 conv2;
8320
8321 // For each dataType in the chain
8322 for ( i = 1; i < length; i++ ) {
8323
8324 // Create converters map
8325 // with lowercased keys
8326 if ( i === 1 ) {
8327 for ( key in s.converters ) {
8328 if ( typeof key === "string" ) {
8329 converters[ key.toLowerCase() ] = s.converters[ key ];
8330 }
8331 }
8332 }
8333
8334 // Get the dataTypes
8335 prev = current;
8336 current = dataTypes[ i ];
8337
8338 // If current is auto dataType, update it to prev
8339 if ( current === "*" ) {
8340 current = prev;
8341 // If no auto and dataTypes are actually different
8342 } else if ( prev !== "*" && prev !== current ) {
8343
8344 // Get the converter
8345 conversion = prev + " " + current;
8346 conv = converters[ conversion ] || converters[ "* " + current ];
8347
8348 // If there is no direct converter, search transitively
8349 if ( !conv ) {
8350 conv2 = undefined;
8351 for ( conv1 in converters ) {
8352 tmp = conv1.split( " " );
8353 if ( tmp[ 0 ] === prev || tmp[ 0 ] === "*" ) {
8354 conv2 = converters[ tmp[1] + " " + current ];
8355 if ( conv2 ) {
8356 conv1 = converters[ conv1 ];
8357 if ( conv1 === true ) {
8358 conv = conv2;
8359 } else if ( conv2 === true ) {
8360 conv = conv1;
8361 }
8362 break;
8363 }
8364 }
8365 }
8366 }
8367 // If we found no converter, dispatch an error
8368 if ( !( conv || conv2 ) ) {
8369 jQuery.error( "No conversion from " + conversion.replace(" "," to ") );
8370 }
8371 // If found converter is not an equivalence
8372 if ( conv !== true ) {
8373 // Convert with 1 or 2 converters accordingly
8374 response = conv ? conv( response ) : conv2( conv1(response) );
8375 }
8376 }
8377 }
8378 return response;
8379}
8380
8381})( jQuery );
8382(function( jQuery ) {
8383
8384var jsc = jQuery.now(),
8385 jsre = /(\=)\?(&|$)|\?\?/i;
8386
8387// Default jsonp settings
8388jQuery.ajaxSetup({
8389 jsonp: "callback",
8390 jsonpCallback: function() {
8391 return jQuery.expando + "_" + ( jsc++ );
8392 }
8393});
8394
8395// Detect, normalize options and install callbacks for jsonp requests
8396jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
8397
8398 var inspectData = s.contentType === "application/x-www-form-urlencoded" &&
8399 ( typeof s.data === "string" );
8400
8401 if ( s.dataTypes[ 0 ] === "jsonp" ||
8402 s.jsonp !== false && ( jsre.test( s.url ) ||
8403 inspectData && jsre.test( s.data ) ) ) {
8404
8405 var responseContainer,
8406 jsonpCallback = s.jsonpCallback =
8407 jQuery.isFunction( s.jsonpCallback ) ? s.jsonpCallback() : s.jsonpCallback,
8408 previous = window[ jsonpCallback ],
8409 url = s.url,
8410 data = s.data,
8411 replace = "$1" + jsonpCallback + "$2";
8412
8413 if ( s.jsonp !== false ) {
8414 url = url.replace( jsre, replace );
8415 if ( s.url === url ) {
8416 if ( inspectData ) {
8417 data = data.replace( jsre, replace );
8418 }
8419 if ( s.data === data ) {
8420 // Add callback manually
8421 url += (/\?/.test( url ) ? "&" : "?") + s.jsonp + "=" + jsonpCallback;
8422 }
8423 }
8424 }
8425
8426 s.url = url;
8427 s.data = data;
8428
8429 // Install callback
8430 window[ jsonpCallback ] = function( response ) {
8431 responseContainer = [ response ];
8432 };
8433
8434 // Clean-up function
8435 jqXHR.always(function() {
8436 // Set callback back to previous value
8437 window[ jsonpCallback ] = previous;
8438 // Call if it was a function and we have a response
8439 if ( responseContainer && jQuery.isFunction( previous ) ) {
8440 window[ jsonpCallback ]( responseContainer[ 0 ] );
8441 }
8442 });
8443
8444 // Use data converter to retrieve json after script execution
8445 s.converters["script json"] = function() {
8446 if ( !responseContainer ) {
8447 jQuery.error( jsonpCallback + " was not called" );
8448 }
8449 return responseContainer[ 0 ];
8450 };
8451
8452 // force json dataType
8453 s.dataTypes[ 0 ] = "json";
8454
8455 // Delegate to script
8456 return "script";
8457 }
8458});
8459
8460})( jQuery );
8461(function( jQuery ) {
8462
8463// Install script dataType
8464jQuery.ajaxSetup({
8465 accepts: {
8466 script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
8467 },
8468 contents: {
8469 script: /javascript|ecmascript/
8470 },
8471 converters: {
8472 "text script": function( text ) {
8473 jQuery.globalEval( text );
8474 return text;
8475 }
8476 }
8477});
8478
8479// Handle cache's special case and global
8480jQuery.ajaxPrefilter( "script", function( s ) {
8481 if ( s.cache === undefined ) {
8482 s.cache = false;
8483 }
8484 if ( s.crossDomain ) {
8485 s.type = "GET";
8486 s.global = false;
8487 }
8488});
8489
8490// Bind script tag hack transport
8491jQuery.ajaxTransport( "script", function(s) {
8492
8493 // This transport only deals with cross domain requests
8494 if ( s.crossDomain ) {
8495
8496 var script,
8497 head = document.head || document.getElementsByTagName( "head" )[0] || document.documentElement;
8498
8499 return {
8500
8501 send: function( _, callback ) {
8502
8503 script = document.createElement( "script" );
8504
8505 script.async = "async";
8506
8507 if ( s.scriptCharset ) {
8508 script.charset = s.scriptCharset;
8509 }
8510
8511 script.src = s.url;
8512
8513 // Attach handlers for all browsers
8514 script.onload = script.onreadystatechange = function( _, isAbort ) {
8515
8516 if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) {
8517
8518 // Handle memory leak in IE
8519 script.onload = script.onreadystatechange = null;
8520
8521 // Remove the script
8522 if ( head && script.parentNode ) {
8523 head.removeChild( script );
8524 }
8525
8526 // Dereference the script
8527 script = undefined;
8528
8529 // Callback if not abort
8530 if ( !isAbort ) {
8531 callback( 200, "success" );
8532 }
8533 }
8534 };
8535 // Use insertBefore instead of appendChild to circumvent an IE6 bug.
8536 // This arises when a base node is used (#2709 and #4378).
8537 head.insertBefore( script, head.firstChild );
8538 },
8539
8540 abort: function() {
8541 if ( script ) {
8542 script.onload( 0, 1 );
8543 }
8544 }
8545 };
8546 }
8547});
8548
8549})( jQuery );
8550(function( jQuery ) {
8551
8552var // #5280: Internet Explorer will keep connections alive if we don't abort on unload
8553 xhrOnUnloadAbort = window.ActiveXObject ? function() {
8554 // Abort all pending requests
8555 for ( var key in xhrCallbacks ) {
8556 xhrCallbacks[ key ]( 0, 1 );
8557 }
8558 } : false,
8559 xhrId = 0,
8560 xhrCallbacks;
8561
8562// Functions to create xhrs
8563function createStandardXHR() {
8564 try {
8565 return new window.XMLHttpRequest();
8566 } catch( e ) {}
8567}
8568
8569function createActiveXHR() {
8570 try {
8571 return new window.ActiveXObject( "Microsoft.XMLHTTP" );
8572 } catch( e ) {}
8573}
8574
8575// Create the request object
8576// (This is still attached to ajaxSettings for backward compatibility)
8577jQuery.ajaxSettings.xhr = window.ActiveXObject ?
8578 /* Microsoft failed to properly
8579 * implement the XMLHttpRequest in IE7 (can't request local files),
8580 * so we use the ActiveXObject when it is available
8581 * Additionally XMLHttpRequest can be disabled in IE7/IE8 so
8582 * we need a fallback.
8583 */
8584 function() {
8585 return !this.isLocal && createStandardXHR() || createActiveXHR();
8586 } :
8587 // For all other browsers, use the standard XMLHttpRequest object
8588 createStandardXHR;
8589
8590// Determine support properties
8591(function( xhr ) {
8592 jQuery.extend( jQuery.support, {
8593 ajax: !!xhr,
8594 cors: !!xhr && ( "withCredentials" in xhr )
8595 });
8596})( jQuery.ajaxSettings.xhr() );
8597
8598// Create transport if the browser can provide an xhr
8599if ( jQuery.support.ajax ) {
8600
8601 jQuery.ajaxTransport(function( s ) {
8602 // Cross domain only allowed if supported through XMLHttpRequest
8603 if ( !s.crossDomain || jQuery.support.cors ) {
8604
8605 var callback;
8606
8607 return {
8608 send: function( headers, complete ) {
8609
8610 // Get a new xhr
8611 var xhr = s.xhr(),
8612 handle,
8613 i;
8614
8615 // Open the socket
8616 // Passing null username, generates a login popup on Opera (#2865)
8617 if ( s.username ) {
8618 xhr.open( s.type, s.url, s.async, s.username, s.password );
8619 } else {
8620 xhr.open( s.type, s.url, s.async );
8621 }
8622
8623 // Apply custom fields if provided
8624 if ( s.xhrFields ) {
8625 for ( i in s.xhrFields ) {
8626 xhr[ i ] = s.xhrFields[ i ];
8627 }
8628 }
8629
8630 // Override mime type if needed
8631 if ( s.mimeType && xhr.overrideMimeType ) {
8632 xhr.overrideMimeType( s.mimeType );
8633 }
8634
8635 // X-Requested-With header
8636 // For cross-domain requests, seeing as conditions for a preflight are
8637 // akin to a jigsaw puzzle, we simply never set it to be sure.
8638 // (it can always be set on a per-request basis or even using ajaxSetup)
8639 // For same-domain requests, won't change header if already provided.
8640 if ( !s.crossDomain && !headers["X-Requested-With"] ) {
8641 headers[ "X-Requested-With" ] = "XMLHttpRequest";
8642 }
8643
8644 // Need an extra try/catch for cross domain requests in Firefox 3
8645 try {
8646 for ( i in headers ) {
8647 xhr.setRequestHeader( i, headers[ i ] );
8648 }
8649 } catch( _ ) {}
8650
8651 // Do send the request
8652 // This may raise an exception which is actually
8653 // handled in jQuery.ajax (so no try/catch here)
8654 xhr.send( ( s.hasContent && s.data ) || null );
8655
8656 // Listener
8657 callback = function( _, isAbort ) {
8658
8659 var status,
8660 statusText,
8661 responseHeaders,
8662 responses,
8663 xml;
8664
8665 // Firefox throws exceptions when accessing properties
8666 // of an xhr when a network error occured
8667 // http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_(NS_ERROR_NOT_AVAILABLE)
8668 try {
8669
8670 // Was never called and is aborted or complete
8671 if ( callback && ( isAbort || xhr.readyState === 4 ) ) {
8672
8673 // Only called once
8674 callback = undefined;
8675
8676 // Do not keep as active anymore
8677 if ( handle ) {
8678 xhr.onreadystatechange = jQuery.noop;
8679 if ( xhrOnUnloadAbort ) {
8680 delete xhrCallbacks[ handle ];
8681 }
8682 }
8683
8684 // If it's an abort
8685 if ( isAbort ) {
8686 // Abort it manually if needed
8687 if ( xhr.readyState !== 4 ) {
8688 xhr.abort();
8689 }
8690 } else {
8691 status = xhr.status;
8692 responseHeaders = xhr.getAllResponseHeaders();
8693 responses = {};
8694 xml = xhr.responseXML;
8695
8696 // Construct response list
8697 if ( xml && xml.documentElement /* #4958 */ ) {
8698 responses.xml = xml;
8699 }
8700 responses.text = xhr.responseText;
8701
8702 // Firefox throws an exception when accessing
8703 // statusText for faulty cross-domain requests
8704 try {
8705 statusText = xhr.statusText;
8706 } catch( e ) {
8707 // We normalize with Webkit giving an empty statusText
8708 statusText = "";
8709 }
8710
8711 // Filter status for non standard behaviors
8712
8713 // If the request is local and we have data: assume a success
8714 // (success with no data won't get notified, that's the best we
8715 // can do given current implementations)
8716 if ( !status && s.isLocal && !s.crossDomain ) {
8717 status = responses.text ? 200 : 404;
8718 // IE - #1450: sometimes returns 1223 when it should be 204
8719 } else if ( status === 1223 ) {
8720 status = 204;
8721 }
8722 }
8723 }
8724 } catch( firefoxAccessException ) {
8725 if ( !isAbort ) {
8726 complete( -1, firefoxAccessException );
8727 }
8728 }
8729
8730 // Call complete if needed
8731 if ( responses ) {
8732 complete( status, statusText, responses, responseHeaders );
8733 }
8734 };
8735
8736 // if we're in sync mode or it's in cache
8737 // and has been retrieved directly (IE6 & IE7)
8738 // we need to manually fire the callback
8739 if ( !s.async || xhr.readyState === 4 ) {
8740 callback();
8741 } else {
8742 handle = ++xhrId;
8743 if ( xhrOnUnloadAbort ) {
8744 // Create the active xhrs callbacks list if needed
8745 // and attach the unload handler
8746 if ( !xhrCallbacks ) {
8747 xhrCallbacks = {};
8748 jQuery( window ).unload( xhrOnUnloadAbort );
8749 }
8750 // Add to list of active xhrs callbacks
8751 xhrCallbacks[ handle ] = callback;
8752 }
8753 xhr.onreadystatechange = callback;
8754 }
8755 },
8756
8757 abort: function() {
8758 if ( callback ) {
8759 callback(0,1);
8760 }
8761 }
8762 };
8763 }
8764 });
8765}
8766
8767})( jQuery );
8768(function( jQuery ) {
8769
8770var elemdisplay = {},
8771 iframe, iframeDoc,
8772 rfxtypes = /^(?:toggle|show|hide)$/,
8773 rfxnum = /^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,
8774 timerId,
8775 fxAttrs = [
8776 // height animations
8777 [ "height", "marginTop", "marginBottom", "paddingTop", "paddingBottom" ],
8778 // width animations
8779 [ "width", "marginLeft", "marginRight", "paddingLeft", "paddingRight" ],
8780 // opacity animations
8781 [ "opacity" ]
8782 ],
8783 fxNow;
8784
8785jQuery.fn.extend({
8786 show: function( speed, easing, callback ) {
8787 var elem, display;
8788
8789 if ( speed || speed === 0 ) {
8790 return this.animate( genFx("show", 3), speed, easing, callback );
8791
8792 } else {
8793 for ( var i = 0, j = this.length; i < j; i++ ) {
8794 elem = this[ i ];
8795
8796 if ( elem.style ) {
8797 display = elem.style.display;
8798
8799 // Reset the inline display of this element to learn if it is
8800 // being hidden by cascaded rules or not
8801 if ( !jQuery._data(elem, "olddisplay") && display === "none" ) {
8802 display = elem.style.display = "";
8803 }
8804
8805 // Set elements which have been overridden with display: none
8806 // in a stylesheet to whatever the default browser style is
8807 // for such an element
8808 if ( display === "" && jQuery.css(elem, "display") === "none" ) {
8809 jQuery._data( elem, "olddisplay", defaultDisplay(elem.nodeName) );
8810 }
8811 }
8812 }
8813
8814 // Set the display of most of the elements in a second loop
8815 // to avoid the constant reflow
8816 for ( i = 0; i < j; i++ ) {
8817 elem = this[ i ];
8818
8819 if ( elem.style ) {
8820 display = elem.style.display;
8821
8822 if ( display === "" || display === "none" ) {
8823 elem.style.display = jQuery._data( elem, "olddisplay" ) || "";
8824 }
8825 }
8826 }
8827
8828 return this;
8829 }
8830 },
8831
8832 hide: function( speed, easing, callback ) {
8833 if ( speed || speed === 0 ) {
8834 return this.animate( genFx("hide", 3), speed, easing, callback);
8835
8836 } else {
8837 var elem, display,
8838 i = 0,
8839 j = this.length;
8840
8841 for ( ; i < j; i++ ) {
8842 elem = this[i];
8843 if ( elem.style ) {
8844 display = jQuery.css( elem, "display" );
8845
8846 if ( display !== "none" && !jQuery._data( elem, "olddisplay" ) ) {
8847 jQuery._data( elem, "olddisplay", display );
8848 }
8849 }
8850 }
8851
8852 // Set the display of the elements in a second loop
8853 // to avoid the constant reflow
8854 for ( i = 0; i < j; i++ ) {
8855 if ( this[i].style ) {
8856 this[i].style.display = "none";
8857 }
8858 }
8859
8860 return this;
8861 }
8862 },
8863
8864 // Save the old toggle function
8865 _toggle: jQuery.fn.toggle,
8866
8867 toggle: function( fn, fn2, callback ) {
8868 var bool = typeof fn === "boolean";
8869
8870 if ( jQuery.isFunction(fn) && jQuery.isFunction(fn2) ) {
8871 this._toggle.apply( this, arguments );
8872
8873 } else if ( fn == null || bool ) {
8874 this.each(function() {
8875 var state = bool ? fn : jQuery(this).is(":hidden");
8876 jQuery(this)[ state ? "show" : "hide" ]();
8877 });
8878
8879 } else {
8880 this.animate(genFx("toggle", 3), fn, fn2, callback);
8881 }
8882
8883 return this;
8884 },
8885
8886 fadeTo: function( speed, to, easing, callback ) {
8887 return this.filter(":hidden").css("opacity", 0).show().end()
8888 .animate({opacity: to}, speed, easing, callback);
8889 },
8890
8891 animate: function( prop, speed, easing, callback ) {
8892 var optall = jQuery.speed( speed, easing, callback );
8893
8894 if ( jQuery.isEmptyObject( prop ) ) {
8895 return this.each( optall.complete, [ false ] );
8896 }
8897
8898 // Do not change referenced properties as per-property easing will be lost
8899 prop = jQuery.extend( {}, prop );
8900
8901 function doAnimation() {
8902 // XXX 'this' does not always have a nodeName when running the
8903 // test suite
8904
8905 if ( optall.queue === false ) {
8906 jQuery._mark( this );
8907 }
8908
8909 var opt = jQuery.extend( {}, optall ),
8910 isElement = this.nodeType === 1,
8911 hidden = isElement && jQuery(this).is(":hidden"),
8912 name, val, p, e,
8913 parts, start, end, unit,
8914 method;
8915
8916 // will store per property easing and be used to determine when an animation is complete
8917 opt.animatedProperties = {};
8918
8919 for ( p in prop ) {
8920
8921 // property name normalization
8922 name = jQuery.camelCase( p );
8923 if ( p !== name ) {
8924 prop[ name ] = prop[ p ];
8925 delete prop[ p ];
8926 }
8927
8928 val = prop[ name ];
8929
8930 // easing resolution: per property > opt.specialEasing > opt.easing > 'swing' (default)
8931 if ( jQuery.isArray( val ) ) {
8932 opt.animatedProperties[ name ] = val[ 1 ];
8933 val = prop[ name ] = val[ 0 ];
8934 } else {
8935 opt.animatedProperties[ name ] = opt.specialEasing && opt.specialEasing[ name ] || opt.easing || 'swing';
8936 }
8937
8938 if ( val === "hide" && hidden || val === "show" && !hidden ) {
8939 return opt.complete.call( this );
8940 }
8941
8942 if ( isElement && ( name === "height" || name === "width" ) ) {
8943 // Make sure that nothing sneaks out
8944 // Record all 3 overflow attributes because IE does not
8945 // change the overflow attribute when overflowX and
8946 // overflowY are set to the same value
8947 opt.overflow = [ this.style.overflow, this.style.overflowX, this.style.overflowY ];
8948
8949 // Set display property to inline-block for height/width
8950 // animations on inline elements that are having width/height animated
8951 if ( jQuery.css( this, "display" ) === "inline" &&
8952 jQuery.css( this, "float" ) === "none" ) {
8953
8954 // inline-level elements accept inline-block;
8955 // block-level elements need to be inline with layout
8956 if ( !jQuery.support.inlineBlockNeedsLayout || defaultDisplay( this.nodeName ) === "inline" ) {
8957 this.style.display = "inline-block";
8958
8959 } else {
8960 this.style.zoom = 1;
8961 }
8962 }
8963 }
8964 }
8965
8966 if ( opt.overflow != null ) {
8967 this.style.overflow = "hidden";
8968 }
8969
8970 for ( p in prop ) {
8971 e = new jQuery.fx( this, opt, p );
8972 val = prop[ p ];
8973
8974 if ( rfxtypes.test( val ) ) {
8975
8976 // Tracks whether to show or hide based on private
8977 // data attached to the element
8978 method = jQuery._data( this, "toggle" + p ) || ( val === "toggle" ? hidden ? "show" : "hide" : 0 );
8979 if ( method ) {
8980 jQuery._data( this, "toggle" + p, method === "show" ? "hide" : "show" );
8981 e[ method ]();
8982 } else {
8983 e[ val ]();
8984 }
8985
8986 } else {
8987 parts = rfxnum.exec( val );
8988 start = e.cur();
8989
8990 if ( parts ) {
8991 end = parseFloat( parts[2] );
8992 unit = parts[3] || ( jQuery.cssNumber[ p ] ? "" : "px" );
8993
8994 // We need to compute starting value
8995 if ( unit !== "px" ) {
8996 jQuery.style( this, p, (end || 1) + unit);
8997 start = ( (end || 1) / e.cur() ) * start;
8998 jQuery.style( this, p, start + unit);
8999 }
9000
9001 // If a +=/-= token was provided, we're doing a relative animation
9002 if ( parts[1] ) {
9003 end = ( (parts[ 1 ] === "-=" ? -1 : 1) * end ) + start;
9004 }
9005
9006 e.custom( start, end, unit );
9007
9008 } else {
9009 e.custom( start, val, "" );
9010 }
9011 }
9012 }
9013
9014 // For JS strict compliance
9015 return true;
9016 }
9017
9018 return optall.queue === false ?
9019 this.each( doAnimation ) :
9020 this.queue( optall.queue, doAnimation );
9021 },
9022
9023 stop: function( type, clearQueue, gotoEnd ) {
9024 if ( typeof type !== "string" ) {
9025 gotoEnd = clearQueue;
9026 clearQueue = type;
9027 type = undefined;
9028 }
9029 if ( clearQueue && type !== false ) {
9030 this.queue( type || "fx", [] );
9031 }
9032
9033 return this.each(function() {
9034 var i,
9035 hadTimers = false,
9036 timers = jQuery.timers,
9037 data = jQuery._data( this );
9038
9039 // clear marker counters if we know they won't be
9040 if ( !gotoEnd ) {
9041 jQuery._unmark( true, this );
9042 }
9043
9044 function stopQueue( elem, data, i ) {
9045 var hooks = data[ i ];
9046 jQuery.removeData( elem, i, true );
9047 hooks.stop( gotoEnd );
9048 }
9049
9050 if ( type == null ) {
9051 for ( i in data ) {
9052 if ( data[ i ].stop && i.indexOf(".run") === i.length - 4 ) {
9053 stopQueue( this, data, i );
9054 }
9055 }
9056 } else if ( data[ i = type + ".run" ] && data[ i ].stop ){
9057 stopQueue( this, data, i );
9058 }
9059
9060 for ( i = timers.length; i--; ) {
9061 if ( timers[ i ].elem === this && (type == null || timers[ i ].queue === type) ) {
9062 if ( gotoEnd ) {
9063
9064 // force the next step to be the last
9065 timers[ i ]( true );
9066 } else {
9067 timers[ i ].saveState();
9068 }
9069 hadTimers = true;
9070 timers.splice( i, 1 );
9071 }
9072 }
9073
9074 // start the next in the queue if the last step wasn't forced
9075 // timers currently will call their complete callbacks, which will dequeue
9076 // but only if they were gotoEnd
9077 if ( !( gotoEnd && hadTimers ) ) {
9078 jQuery.dequeue( this, type );
9079 }
9080 });
9081 }
9082
9083});
9084
9085// Animations created synchronously will run synchronously
9086function createFxNow() {
9087 setTimeout( clearFxNow, 0 );
9088 return ( fxNow = jQuery.now() );
9089}
9090
9091function clearFxNow() {
9092 fxNow = undefined;
9093}
9094
9095// Generate parameters to create a standard animation
9096function genFx( type, num ) {
9097 var obj = {};
9098
9099 jQuery.each( fxAttrs.concat.apply([], fxAttrs.slice( 0, num )), function() {
9100 obj[ this ] = type;
9101 });
9102
9103 return obj;
9104}
9105
9106// Generate shortcuts for custom animations
9107jQuery.each({
9108 slideDown: genFx( "show", 1 ),
9109 slideUp: genFx( "hide", 1 ),
9110 slideToggle: genFx( "toggle", 1 ),
9111 fadeIn: { opacity: "show" },
9112 fadeOut: { opacity: "hide" },
9113 fadeToggle: { opacity: "toggle" }
9114}, function( name, props ) {
9115 jQuery.fn[ name ] = function( speed, easing, callback ) {
9116 return this.animate( props, speed, easing, callback );
9117 };
9118});
9119
9120jQuery.extend({
9121 speed: function( speed, easing, fn ) {
9122 var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
9123 complete: fn || !fn && easing ||
9124 jQuery.isFunction( speed ) && speed,
9125 duration: speed,
9126 easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing
9127 };
9128
9129 opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
9130 opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;
9131
9132 // normalize opt.queue - true/undefined/null -> "fx"
9133 if ( opt.queue == null || opt.queue === true ) {
9134 opt.queue = "fx";
9135 }
9136
9137 // Queueing
9138 opt.old = opt.complete;
9139
9140 opt.complete = function( noUnmark ) {
9141 if ( jQuery.isFunction( opt.old ) ) {
9142 opt.old.call( this );
9143 }
9144
9145 if ( opt.queue ) {
9146 jQuery.dequeue( this, opt.queue );
9147 } else if ( noUnmark !== false ) {
9148 jQuery._unmark( this );
9149 }
9150 };
9151
9152 return opt;
9153 },
9154
9155 easing: {
9156 linear: function( p, n, firstNum, diff ) {
9157 return firstNum + diff * p;
9158 },
9159 swing: function( p, n, firstNum, diff ) {
9160 return ( ( -Math.cos( p*Math.PI ) / 2 ) + 0.5 ) * diff + firstNum;
9161 }
9162 },
9163
9164 timers: [],
9165
9166 fx: function( elem, options, prop ) {
9167 this.options = options;
9168 this.elem = elem;
9169 this.prop = prop;
9170
9171 options.orig = options.orig || {};
9172 }
9173
9174});
9175
9176jQuery.fx.prototype = {
9177 // Simple function for setting a style value
9178 update: function() {
9179 if ( this.options.step ) {
9180 this.options.step.call( this.elem, this.now, this );
9181 }
9182
9183 ( jQuery.fx.step[ this.prop ] || jQuery.fx.step._default )( this );
9184 },
9185
9186 // Get the current size
9187 cur: function() {
9188 if ( this.elem[ this.prop ] != null && (!this.elem.style || this.elem.style[ this.prop ] == null) ) {
9189 return this.elem[ this.prop ];
9190 }
9191
9192 var parsed,
9193 r = jQuery.css( this.elem, this.prop );
9194 // Empty strings, null, undefined and "auto" are converted to 0,
9195 // complex values such as "rotate(1rad)" are returned as is,
9196 // simple values such as "10px" are parsed to Float.
9197 return isNaN( parsed = parseFloat( r ) ) ? !r || r === "auto" ? 0 : r : parsed;
9198 },
9199
9200 // Start an animation from one number to another
9201 custom: function( from, to, unit ) {
9202 var self = this,
9203 fx = jQuery.fx;
9204
9205 this.startTime = fxNow || createFxNow();
9206 this.end = to;
9207 this.now = this.start = from;
9208 this.pos = this.state = 0;
9209 this.unit = unit || this.unit || ( jQuery.cssNumber[ this.prop ] ? "" : "px" );
9210
9211 function t( gotoEnd ) {
9212 return self.step( gotoEnd );
9213 }
9214
9215 t.queue = this.options.queue;
9216 t.elem = this.elem;
9217 t.saveState = function() {
9218 if ( self.options.hide && jQuery._data( self.elem, "fxshow" + self.prop ) === undefined ) {
9219 jQuery._data( self.elem, "fxshow" + self.prop, self.start );
9220 }
9221 };
9222
9223 if ( t() && jQuery.timers.push(t) && !timerId ) {
9224 timerId = setInterval( fx.tick, fx.interval );
9225 }
9226 },
9227
9228 // Simple 'show' function
9229 show: function() {
9230 var dataShow = jQuery._data( this.elem, "fxshow" + this.prop );
9231
9232 // Remember where we started, so that we can go back to it later
9233 this.options.orig[ this.prop ] = dataShow || jQuery.style( this.elem, this.prop );
9234 this.options.show = true;
9235
9236 // Begin the animation
9237 // Make sure that we start at a small width/height to avoid any flash of content
9238 if ( dataShow !== undefined ) {
9239 // This show is picking up where a previous hide or show left off
9240 this.custom( this.cur(), dataShow );
9241 } else {
9242 this.custom( this.prop === "width" || this.prop === "height" ? 1 : 0, this.cur() );
9243 }
9244
9245 // Start by showing the element
9246 jQuery( this.elem ).show();
9247 },
9248
9249 // Simple 'hide' function
9250 hide: function() {
9251 // Remember where we started, so that we can go back to it later
9252 this.options.orig[ this.prop ] = jQuery._data( this.elem, "fxshow" + this.prop ) || jQuery.style( this.elem, this.prop );
9253 this.options.hide = true;
9254
9255 // Begin the animation
9256 this.custom( this.cur(), 0 );
9257 },
9258
9259 // Each step of an animation
9260 step: function( gotoEnd ) {
9261 var p, n, complete,
9262 t = fxNow || createFxNow(),
9263 done = true,
9264 elem = this.elem,
9265 options = this.options;
9266
9267 if ( gotoEnd || t >= options.duration + this.startTime ) {
9268 this.now = this.end;
9269 this.pos = this.state = 1;
9270 this.update();
9271
9272 options.animatedProperties[ this.prop ] = true;
9273
9274 for ( p in options.animatedProperties ) {
9275 if ( options.animatedProperties[ p ] !== true ) {
9276 done = false;
9277 }
9278 }
9279
9280 if ( done ) {
9281 // Reset the overflow
9282 if ( options.overflow != null && !jQuery.support.shrinkWrapBlocks ) {
9283
9284 jQuery.each( [ "", "X", "Y" ], function( index, value ) {
9285 elem.style[ "overflow" + value ] = options.overflow[ index ];
9286 });
9287 }
9288
9289 // Hide the element if the "hide" operation was done
9290 if ( options.hide ) {
9291 jQuery( elem ).hide();
9292 }
9293
9294 // Reset the properties, if the item has been hidden or shown
9295 if ( options.hide || options.show ) {
9296 for ( p in options.animatedProperties ) {
9297 jQuery.style( elem, p, options.orig[ p ] );
9298 jQuery.removeData( elem, "fxshow" + p, true );
9299 // Toggle data is no longer needed
9300 jQuery.removeData( elem, "toggle" + p, true );
9301 }
9302 }
9303
9304 // Execute the complete function
9305 // in the event that the complete function throws an exception
9306 // we must ensure it won't be called twice. #5684
9307
9308 complete = options.complete;
9309 if ( complete ) {
9310
9311 options.complete = false;
9312 complete.call( elem );
9313 }
9314 }
9315
9316 return false;
9317
9318 } else {
9319 // classical easing cannot be used with an Infinity duration
9320 if ( options.duration == Infinity ) {
9321 this.now = t;
9322 } else {
9323 n = t - this.startTime;
9324 this.state = n / options.duration;
9325
9326 // Perform the easing function, defaults to swing
9327 this.pos = jQuery.easing[ options.animatedProperties[this.prop] ]( this.state, n, 0, 1, options.duration );
9328 this.now = this.start + ( (this.end - this.start) * this.pos );
9329 }
9330 // Perform the next step of the animation
9331 this.update();
9332 }
9333
9334 return true;
9335 }
9336};
9337
9338jQuery.extend( jQuery.fx, {
9339 tick: function() {
9340 var timer,
9341 timers = jQuery.timers,
9342 i = 0;
9343
9344 for ( ; i < timers.length; i++ ) {
9345 timer = timers[ i ];
9346 // Checks the timer has not already been removed
9347 if ( !timer() && timers[ i ] === timer ) {
9348 timers.splice( i--, 1 );
9349 }
9350 }
9351
9352 if ( !timers.length ) {
9353 jQuery.fx.stop();
9354 }
9355 },
9356
9357 interval: 13,
9358
9359 stop: function() {
9360 clearInterval( timerId );
9361 timerId = null;
9362 },
9363
9364 speeds: {
9365 slow: 600,
9366 fast: 200,
9367 // Default speed
9368 _default: 400
9369 },
9370
9371 step: {
9372 opacity: function( fx ) {
9373 jQuery.style( fx.elem, "opacity", fx.now );
9374 },
9375
9376 _default: function( fx ) {
9377 if ( fx.elem.style && fx.elem.style[ fx.prop ] != null ) {
9378 fx.elem.style[ fx.prop ] = fx.now + fx.unit;
9379 } else {
9380 fx.elem[ fx.prop ] = fx.now;
9381 }
9382 }
9383 }
9384});
9385
9386// Adds width/height step functions
9387// Do not set anything below 0
9388jQuery.each([ "width", "height" ], function( i, prop ) {
9389 jQuery.fx.step[ prop ] = function( fx ) {
9390 jQuery.style( fx.elem, prop, Math.max(0, fx.now) );
9391 };
9392});
9393
9394if ( jQuery.expr && jQuery.expr.filters ) {
9395 jQuery.expr.filters.animated = function( elem ) {
9396 return jQuery.grep(jQuery.timers, function( fn ) {
9397 return elem === fn.elem;
9398 }).length;
9399 };
9400}
9401
9402// Try to restore the default display value of an element
9403function defaultDisplay( nodeName ) {
9404
9405 if ( !elemdisplay[ nodeName ] ) {
9406
9407 var body = document.body,
9408 elem = jQuery( "<" + nodeName + ">" ).appendTo( body ),
9409 display = elem.css( "display" );
9410 elem.remove();
9411
9412 // If the simple way fails,
9413 // get element's real default display by attaching it to a temp iframe
9414 if ( display === "none" || display === "" ) {
9415 // No iframe to use yet, so create it
9416 if ( !iframe ) {
9417 iframe = document.createElement( "iframe" );
9418 iframe.frameBorder = iframe.width = iframe.height = 0;
9419 }
9420
9421 body.appendChild( iframe );
9422
9423 // Create a cacheable copy of the iframe document on first call.
9424 // IE and Opera will allow us to reuse the iframeDoc without re-writing the fake HTML
9425 // document to it; WebKit & Firefox won't allow reusing the iframe document.
9426 if ( !iframeDoc || !iframe.createElement ) {
9427 iframeDoc = ( iframe.contentWindow || iframe.contentDocument ).document;
9428 iframeDoc.write( ( document.compatMode === "CSS1Compat" ? "<!doctype html>" : "" ) + "<html><body>" );
9429 iframeDoc.close();
9430 }
9431
9432 elem = iframeDoc.createElement( nodeName );
9433
9434 iframeDoc.body.appendChild( elem );
9435
9436 display = jQuery.css( elem, "display" );
9437 body.removeChild( iframe );
9438 }
9439
9440 // Store the correct default display
9441 elemdisplay[ nodeName ] = display;
9442 }
9443
9444 return elemdisplay[ nodeName ];
9445}
9446
9447})( jQuery );
9448(function( jQuery ) {
9449
9450var rtable = /^t(?:able|d|h)$/i,
9451 rroot = /^(?:body|html)$/i;
9452
9453if ( "getBoundingClientRect" in document.documentElement ) {
9454 jQuery.fn.offset = function( options ) {
9455 var elem = this[0], box;
9456
9457 if ( options ) {
9458 return this.each(function( i ) {
9459 jQuery.offset.setOffset( this, options, i );
9460 });
9461 }
9462
9463 if ( !elem || !elem.ownerDocument ) {
9464 return null;
9465 }
9466
9467 if ( elem === elem.ownerDocument.body ) {
9468 return jQuery.offset.bodyOffset( elem );
9469 }
9470
9471 try {
9472 box = elem.getBoundingClientRect();
9473 } catch(e) {}
9474
9475 var doc = elem.ownerDocument,
9476 docElem = doc.documentElement;
9477
9478 // Make sure we're not dealing with a disconnected DOM node
9479 if ( !box || !jQuery.contains( docElem, elem ) ) {
9480 return box ? { top: box.top, left: box.left } : { top: 0, left: 0 };
9481 }
9482
9483 var body = doc.body,
9484 win = getWindow(doc),
9485 clientTop = docElem.clientTop || body.clientTop || 0,
9486 clientLeft = docElem.clientLeft || body.clientLeft || 0,
9487 scrollTop = win.pageYOffset || jQuery.support.boxModel && docElem.scrollTop || body.scrollTop,
9488 scrollLeft = win.pageXOffset || jQuery.support.boxModel && docElem.scrollLeft || body.scrollLeft,
9489 top = box.top + scrollTop - clientTop,
9490 left = box.left + scrollLeft - clientLeft;
9491
9492 return { top: top, left: left };
9493 };
9494
9495} else {
9496 jQuery.fn.offset = function( options ) {
9497 var elem = this[0];
9498
9499 if ( options ) {
9500 return this.each(function( i ) {
9501 jQuery.offset.setOffset( this, options, i );
9502 });
9503 }
9504
9505 if ( !elem || !elem.ownerDocument ) {
9506 return null;
9507 }
9508
9509 if ( elem === elem.ownerDocument.body ) {
9510 return jQuery.offset.bodyOffset( elem );
9511 }
9512
9513 var computedStyle,
9514 offsetParent = elem.offsetParent,
9515 prevOffsetParent = elem,
9516 doc = elem.ownerDocument,
9517 docElem = doc.documentElement,
9518 body = doc.body,
9519 defaultView = doc.defaultView,
9520 prevComputedStyle = defaultView ? defaultView.getComputedStyle( elem, null ) : elem.currentStyle,
9521 top = elem.offsetTop,
9522 left = elem.offsetLeft;
9523
9524 while ( (elem = elem.parentNode) && elem !== body && elem !== docElem ) {
9525 if ( jQuery.support.fixedPosition && prevComputedStyle.position === "fixed" ) {
9526 break;
9527 }
9528
9529 computedStyle = defaultView ? defaultView.getComputedStyle(elem, null) : elem.currentStyle;
9530 top -= elem.scrollTop;
9531 left -= elem.scrollLeft;
9532
9533 if ( elem === offsetParent ) {
9534 top += elem.offsetTop;
9535 left += elem.offsetLeft;
9536
9537 if ( jQuery.support.doesNotAddBorder && !(jQuery.support.doesAddBorderForTableAndCells && rtable.test(elem.nodeName)) ) {
9538 top += parseFloat( computedStyle.borderTopWidth ) || 0;
9539 left += parseFloat( computedStyle.borderLeftWidth ) || 0;
9540 }
9541
9542 prevOffsetParent = offsetParent;
9543 offsetParent = elem.offsetParent;
9544 }
9545
9546 if ( jQuery.support.subtractsBorderForOverflowNotVisible && computedStyle.overflow !== "visible" ) {
9547 top += parseFloat( computedStyle.borderTopWidth ) || 0;
9548 left += parseFloat( computedStyle.borderLeftWidth ) || 0;
9549 }
9550
9551 prevComputedStyle = computedStyle;
9552 }
9553
9554 if ( prevComputedStyle.position === "relative" || prevComputedStyle.position === "static" ) {
9555 top += body.offsetTop;
9556 left += body.offsetLeft;
9557 }
9558
9559 if ( jQuery.support.fixedPosition && prevComputedStyle.position === "fixed" ) {
9560 top += Math.max( docElem.scrollTop, body.scrollTop );
9561 left += Math.max( docElem.scrollLeft, body.scrollLeft );
9562 }
9563
9564 return { top: top, left: left };
9565 };
9566}
9567
9568jQuery.offset = {
9569
9570 bodyOffset: function( body ) {
9571 var top = body.offsetTop,
9572 left = body.offsetLeft;
9573
9574 if ( jQuery.support.doesNotIncludeMarginInBodyOffset ) {
9575 top += parseFloat( jQuery.css(body, "marginTop") ) || 0;
9576 left += parseFloat( jQuery.css(body, "marginLeft") ) || 0;
9577 }
9578
9579 return { top: top, left: left };
9580 },
9581
9582 setOffset: function( elem, options, i ) {
9583 var position = jQuery.css( elem, "position" );
9584
9585 // set position first, in-case top/left are set even on static elem
9586 if ( position === "static" ) {
9587 elem.style.position = "relative";
9588 }
9589
9590 var curElem = jQuery( elem ),
9591 curOffset = curElem.offset(),
9592 curCSSTop = jQuery.css( elem, "top" ),
9593 curCSSLeft = jQuery.css( elem, "left" ),
9594 calculatePosition = ( position === "absolute" || position === "fixed" ) && jQuery.inArray("auto", [curCSSTop, curCSSLeft]) > -1,
9595 props = {}, curPosition = {}, curTop, curLeft;
9596
9597 // need to be able to calculate position if either top or left is auto and position is either absolute or fixed
9598 if ( calculatePosition ) {
9599 curPosition = curElem.position();
9600 curTop = curPosition.top;
9601 curLeft = curPosition.left;
9602 } else {
9603 curTop = parseFloat( curCSSTop ) || 0;
9604 curLeft = parseFloat( curCSSLeft ) || 0;
9605 }
9606
9607 if ( jQuery.isFunction( options ) ) {
9608 options = options.call( elem, i, curOffset );
9609 }
9610
9611 if ( options.top != null ) {
9612 props.top = ( options.top - curOffset.top ) + curTop;
9613 }
9614 if ( options.left != null ) {
9615 props.left = ( options.left - curOffset.left ) + curLeft;
9616 }
9617
9618 if ( "using" in options ) {
9619 options.using.call( elem, props );
9620 } else {
9621 curElem.css( props );
9622 }
9623 }
9624};
9625
9626
9627jQuery.fn.extend({
9628
9629 position: function() {
9630 if ( !this[0] ) {
9631 return null;
9632 }
9633
9634 var elem = this[0],
9635
9636 // Get *real* offsetParent
9637 offsetParent = this.offsetParent(),
9638
9639 // Get correct offsets
9640 offset = this.offset(),
9641 parentOffset = rroot.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset();
9642
9643 // Subtract element margins
9644 // note: when an element has margin: auto the offsetLeft and marginLeft
9645 // are the same in Safari causing offset.left to incorrectly be 0
9646 offset.top -= parseFloat( jQuery.css(elem, "marginTop") ) || 0;
9647 offset.left -= parseFloat( jQuery.css(elem, "marginLeft") ) || 0;
9648
9649 // Add offsetParent borders
9650 parentOffset.top += parseFloat( jQuery.css(offsetParent[0], "borderTopWidth") ) || 0;
9651 parentOffset.left += parseFloat( jQuery.css(offsetParent[0], "borderLeftWidth") ) || 0;
9652
9653 // Subtract the two offsets
9654 return {
9655 top: offset.top - parentOffset.top,
9656 left: offset.left - parentOffset.left
9657 };
9658 },
9659
9660 offsetParent: function() {
9661 return this.map(function() {
9662 var offsetParent = this.offsetParent || document.body;
9663 while ( offsetParent && (!rroot.test(offsetParent.nodeName) && jQuery.css(offsetParent, "position") === "static") ) {
9664 offsetParent = offsetParent.offsetParent;
9665 }
9666 return offsetParent;
9667 });
9668 }
9669});
9670
9671
9672// Create scrollLeft and scrollTop methods
9673jQuery.each( ["Left", "Top"], function( i, name ) {
9674 var method = "scroll" + name;
9675
9676 jQuery.fn[ method ] = function( val ) {
9677 var elem, win;
9678
9679 if ( val === undefined ) {
9680 elem = this[ 0 ];
9681
9682 if ( !elem ) {
9683 return null;
9684 }
9685
9686 win = getWindow( elem );
9687
9688 // Return the scroll offset
9689 return win ? ("pageXOffset" in win) ? win[ i ? "pageYOffset" : "pageXOffset" ] :
9690 jQuery.support.boxModel && win.document.documentElement[ method ] ||
9691 win.document.body[ method ] :
9692 elem[ method ];
9693 }
9694
9695 // Set the scroll offset
9696 return this.each(function() {
9697 win = getWindow( this );
9698
9699 if ( win ) {
9700 win.scrollTo(
9701 !i ? val : jQuery( win ).scrollLeft(),
9702 i ? val : jQuery( win ).scrollTop()
9703 );
9704
9705 } else {
9706 this[ method ] = val;
9707 }
9708 });
9709 };
9710});
9711
9712function getWindow( elem ) {
9713 return jQuery.isWindow( elem ) ?
9714 elem :
9715 elem.nodeType === 9 ?
9716 elem.defaultView || elem.parentWindow :
9717 false;
9718}
9719
9720})( jQuery );
9721(function( jQuery ) {
9722
9723// Create width, height, innerHeight, innerWidth, outerHeight and outerWidth methods
9724jQuery.each([ "Height", "Width" ], function( i, name ) {
9725
9726 var type = name.toLowerCase();
9727
9728 // innerHeight and innerWidth
9729 jQuery.fn[ "inner" + name ] = function() {
9730 var elem = this[0];
9731 return elem ?
9732 elem.style ?
9733 parseFloat( jQuery.css( elem, type, "padding" ) ) :
9734 this[ type ]() :
9735 null;
9736 };
9737
9738 // outerHeight and outerWidth
9739 jQuery.fn[ "outer" + name ] = function( margin ) {
9740 var elem = this[0];
9741 return elem ?
9742 elem.style ?
9743 parseFloat( jQuery.css( elem, type, margin ? "margin" : "border" ) ) :
9744 this[ type ]() :
9745 null;
9746 };
9747
9748 jQuery.fn[ type ] = function( size ) {
9749 // Get window width or height
9750 var elem = this[0];
9751 if ( !elem ) {
9752 return size == null ? null : this;
9753 }
9754
9755 if ( jQuery.isFunction( size ) ) {
9756 return this.each(function( i ) {
9757 var self = jQuery( this );
9758 self[ type ]( size.call( this, i, self[ type ]() ) );
9759 });
9760 }
9761
9762 if ( jQuery.isWindow( elem ) ) {
9763 // Everyone else use document.documentElement or document.body depending on Quirks vs Standards mode
9764 // 3rd condition allows Nokia support, as it supports the docElem prop but not CSS1Compat
9765 var docElemProp = elem.document.documentElement[ "client" + name ],
9766 body = elem.document.body;
9767 return elem.document.compatMode === "CSS1Compat" && docElemProp ||
9768 body && body[ "client" + name ] || docElemProp;
9769
9770 // Get document width or height
9771 } else if ( elem.nodeType === 9 ) {
9772 // Either scroll[Width/Height] or offset[Width/Height], whichever is greater
9773 return Math.max(
9774 elem.documentElement["client" + name],
9775 elem.body["scroll" + name], elem.documentElement["scroll" + name],
9776 elem.body["offset" + name], elem.documentElement["offset" + name]
9777 );
9778
9779 // Get or set width or height on the element
9780 } else if ( size === undefined ) {
9781 var orig = jQuery.css( elem, type ),
9782 ret = parseFloat( orig );
9783
9784 return jQuery.isNumeric( ret ) ? ret : orig;
9785
9786 // Set the width or height on the element (default to pixels if value is unitless)
9787 } else {
9788 return this.css( type, typeof size === "string" ? size : size + "px" );
9789 }
9790 };
9791
9792});
9793
9794})( jQuery );
9795(function(jQuery) {
9796 if (typeof(Array.prototype.indexOf) == "undefined")
9797 Array.prototype.indexOf = function(value) {
9798 return jQuery.inArray(value, this);
9799 };
9800
9801 if (typeof(Array.prototype.map) == "undefined")
9802 Array.prototype.map = function(callback) {
9803 return jQuery.map(this, callback);
9804 };
9805
9806 if (typeof(Array.prototype.forEach) == "undefined")
9807 Array.prototype.forEach = function(callback) {
9808 jQuery.each(this, function() {
9809 callback(this);
9810 });
9811 };
9812})(jQuery);
9813var Webxray = (function() {
9814 "use strict";
9815
9816 var GLOBAL_GOGGLES_LOAD_CB = 'webxrayWhenGogglesLoad';
9817
9818 return {
9819 _getBaseURI: function() {
9820 // We would use document.baseURI, but it's not supported on IE9.
9821 var a = document.createElement("a");
9822 a.setAttribute("href", "./");
9823 return a.href;
9824 },
9825 getBookmarkletURL: function getBookmarkletURL(baseURI) {
9826 baseURI = baseURI || this._getBaseURI();
9827
9828 var baseCode = "(function(){var script=document.createElement('script');script.src='http://localhost:8000/webxray.js';script.className='webxray';document.body.appendChild(script);})();";
9829 var code = baseCode.replace('http://localhost:8000/', baseURI);
9830
9831 return 'javascript:' + code;
9832 },
9833 whenLoaded: function whenLoaded(cb, global) {
9834 global = global || window;
9835 global[GLOBAL_GOGGLES_LOAD_CB] = cb;
9836 },
9837 triggerWhenLoaded: function triggerWhenLoaded(ui, global) {
9838 global = global || window;
9839 if (GLOBAL_GOGGLES_LOAD_CB in global &&
9840 typeof(global[GLOBAL_GOGGLES_LOAD_CB]) == 'function')
9841 global[GLOBAL_GOGGLES_LOAD_CB](ui);
9842 }
9843 };
9844})();
9845(function(jQuery) {
9846 "use strict";
9847
9848 var $ = jQuery;
9849
9850 function parseLanguage(language) {
9851 var match = language.match(/([a-z]+)-([A-Z]+)/);
9852 if (match)
9853 return { language: match[1], region: match[2] }
9854 else
9855 return { language: language, region: null }
9856 }
9857
9858 function normalizeLanguage(language) {
9859 var match = language.match(/([A-Za-z]+)-([A-Za-z]+)/);
9860 if (match)
9861 return match[1].toLowerCase() + "-" + match[2].toUpperCase();
9862 return language.toLowerCase();
9863 }
9864
9865 jQuery.fn.extend({
9866 localize: function localize(locale, defaultScope) {
9867 locale = locale || jQuery.locale;
9868
9869 this.find("[data-l10n]").each(function() {
9870 var scopedName = $(this).attr("data-l10n");
9871 if (scopedName.indexOf(':') == -1)
9872 scopedName = defaultScope + ':' + scopedName;
9873 $(this).text(locale.get(scopedName));
9874 });
9875 }
9876 });
9877
9878 jQuery.localization = {
9879 extend: function extend(language, scope, obj) {
9880 language = normalizeLanguage(language);
9881 if (!(language in this))
9882 this[language] = {};
9883 for (var name in obj)
9884 this[language][scope + ":" + name] = obj[name];
9885 },
9886 createLocale: function createLocale(languages) {
9887 // We especially want to do this in the case where the client
9888 // is just passing in navigator.language, which is all lowercase
9889 // in Safari.
9890 languages = languages.map(normalizeLanguage);
9891
9892 var locale = {
9893 languages: languages,
9894 has: function has(scopedName) {
9895 return (scopedName in locale);
9896 },
9897 get: function get(scopedName) {
9898 return locale[scopedName] || "unable to find locale string " +
9899 scopedName;
9900 },
9901 scope: function scopeLocale(scope) {
9902 return function(name) {
9903 return locale.get(scope + ":" + name);
9904 }
9905 }
9906 };
9907
9908 languages.forEach(function(language) {
9909 var parsed = parseLanguage(language);
9910 if (parsed.language != language &&
9911 parsed.language in jQuery.localization)
9912 jQuery.extend.call(locale, jQuery.localization[parsed.language]);
9913 if (language in jQuery.localization)
9914 jQuery.extend.call(locale, jQuery.localization[language]);
9915 });
9916
9917 return locale;
9918 },
9919 loadLocale: function(options) {
9920 var deferreds = [];
9921 var languages = options.languages.map(normalizeLanguage);
9922
9923 languages.forEach(function(language) {
9924 var deferred = jQuery.Deferred();
9925 jQuery.ajax({
9926 url: options.path + language + ".js",
9927 dataType: "script",
9928 complete: function(jqXHR, textStatus) {
9929 deferred.resolve(language, textStatus);
9930 }
9931 });
9932 deferreds.push(deferred);
9933 });
9934 jQuery.when.apply(jQuery, deferreds).done(function() {
9935 var locale = jQuery.localization.createLocale(languages);
9936 options.complete(locale, arguments);
9937 });
9938 },
9939 init: function init(languages) {
9940 jQuery.locale = this.createLocale(languages);
9941 }
9942 };
9943
9944 jQuery.localization.init([]);
9945})(jQuery);
9946jQuery.localization.extend("en", "style-info", {"more-info": "Shift-click for more information.", "tap-space-html": "Tap <div class=\"webxray-kbd\">space bar</div> to edit this style.", "style-change": "style change"});
9947jQuery.localization.extend("en", "mix-master", {"too-big-to-change": "That element is too big to remix. Try selecting a smaller one!", "too-big-to-remix-html": "<div>That <code><${tagName}></code> element is too big to remix. Try selecting a smaller one!</div>", "deletion": "deletion", "replacement": "replacement"});
9948jQuery.localization.extend("en", "mix-master-dialog", {"rendering-header": "What You See", "html-header": "HTML Source Code", "title": "Remixer", "advanced-source-tab": "Advanced", "skeleton-header": "What Your Browser Sees", "basic-source-tab": "Basic"});
9949jQuery.localization.extend("en", "uproot-dialog", {"view-html": "View HTML Source", "html-source": "Here's the HTML source code of your remix.", "publishing": "Publishing...", "success": "Here is the URL for your remix that anyone can view.", "to-internet": "Publish To Internet", "header": "Publish Your Remix", "intro": "There are two ways you can publish your remix and share it with others.", "error": "Sorry, an error occurred. Please try again later.", "view-html-desc": "Grab the HTML source of your remix and publish it yourself.", "to-internet-desc": "Instantly publish your remix to a URL that anyone can view."});
9950jQuery.localization.extend("en", "command-manager", {"executed": "Executed", "cannot-undo-html": "<span>Nothing left to undo!</span>", "redid": "Redid", "cannot-redo-html": "<span>Nothing left to redo!</span>", "undid": "Undid"});
9951jQuery.localization.extend("en", "key-names", {"RIGHT": "\u2192", "UP": "\u2191", "DOWN": "\u2193", "DELETE-MacIntel": "delete", "ESC": "esc", "DELETE": "backspace", "LEFT": "\u2190"});
9952jQuery.localization.extend("en", "short-command-descriptions", {"quit": "quit", "remix": "remix", "help": "help", "css-quasimode": "css", "undo": "undo", "dom-descend": "descend", "bug-report": "report bug", "remove": "remove", "dom-ascend": "ascend", "uproot": "publish", "redo": "redo"});
9953jQuery.localization.extend("en", "short-element-descriptions", {"bgsound": "background sound", "code": "code fragment", "meter": "scalar gauge", "aside": "tangential content", "spacer": "layout space", "noscript": "script fallback content", "style": "CSS style sheet", "img": "image", "title": "document title", "menu": "list of commands", "tt": "teletype text", "tr": "table row", "param": "object parameter", "li": "list item", "source": "embedded media source", "tfoot": "table footer", "th": "table header cell", "input": "input form control", "td": "table data cell", "dl": "definition list", "blockquote": "block quotation", "fieldset": "set of form controls", "dd": "definition description", "nobr": "no breaks", "kbd": "keyboard input", "optgroup": "option grouping", "dt": "definition term", "wbr": "word break opportunity", "button": "interactive button", "summary": "summary of details", "p": "paragraph", "small": "small text", "output": "calculated result", "div": "document division", "em": "emphasis", "datalist": "list of predefined options", "hgroup": "heading group", "meta": "metadata", "video": "embedded video stream", "canvas": "dynamic graphics drawing area", "sub": "subscript", "bdo": "bi-directional override", "bdi": "bi-directional text formatting", "label": "form control label", "sup": "superscript", "progress": "progress indicator", "body": "document body", "base": "base URL", "br": "line break", "article": "independent article", "strong": "strong emphasis", "legend": "field set legend", "ol": "ordered list", "script": "embedded script", "caption": "table caption", "col": "table column", "h2": "heading", "h3": "heading", "h1": "heading", "h6": "heading", "h4": "heading", "h5": "heading", "table": "tabular data", "select": "selection list", "span": "text span", "area": "image-map hyperlink", "mark": "marked text", "dfn": "definition", "var": "variable", "cite": "work title", "thead": "table header", "head": "document metadata container", "option": "option item", "form": "user-submittable form", "hr": "horizontal rule", "link": "metadata for inter-document relationships", "b": "bold", "colgroup": "table column group", "keygen": "key-pair generator", "ul": "unordered list", "del": "deleted text", "iframe": "inline frame", "pre": "preformatted text", "ins": "inserted text", "tbody": "table body", "html": "document root", "nav": "navigation", "details": "on-demand control", "command": "user action control", "samp": "sample text", "map": "image map", "object": "embedded object", "figcaption": "figure caption", "a": "anchor or hyperlink", "textarea": "multi-line text input", "i": "italics", "q": "quotation", "u": "underline", "time": "date or time", "audio": "embedded audio stream", "section": "document outline section", "abbr": "abbreviation"});
9954jQuery.localization.extend("en", "dialog-common", {"close": "Close", "nevermind": "Nevermind", "ok": "Commit changes", "product-name": "X-Ray Goggles"});
9955jQuery.localization.extend("en", "command-descriptions", {"quit": "Deactivate goggles", "remix": "Replace/remix selected element", "help": "This help reference", "css-quasimode": "View/edit computed style of selected element", "undo": "Undo", "dom-descend": "Descend to child element", "bug-report": "Report a bug", "remove": "Remove selected element", "dom-ascend": "Ascend to parent element", "uproot": "Publish your remix", "redo": "Redo"});
9956jQuery.localization.extend("en", "css-property-docs", {"letter-spacing": "The<code> letter-spacing </code>CSS property specifies spacing behavior between text characters.", "right": "The <code>right</code> <a title=\"CSS\" rel=\"internal\" href=\"https://developer.mozilla.org/en/CSS\">CSS</a> property specifies part of the position of positioned elements.", "vertical-align": "The <code>vertical-align</code> <a title=\"CSS\" rel=\"internal\" href=\"https://developer.mozilla.org/en/CSS\">CSS</a> property specifies the vertical alignment of an inline or table-cell element.", "color": "The <code>color</code> CSS property sets the foreground color of an element's text content", "float": "The <code>float</code> CSS property specifies that an element should be taken from the normal flow and placed along the left or right side of its container, where text and inline elements will wrap around it.", "font-size": "The <code>font-size</code> <a title=\"CSS\" rel=\"internal\" href=\"https://developer.mozilla.org/en/CSS\">CSS</a> property specifies the size of the font. The font size may, in turn, change the size of other items, since it is used to compute the value of <code>em</code> and <code>ex</code> length units.", "min-height": "The<code> min-height </code>CSS property is used to set the minimum height of a given element. It prevents the used value of the <code><a rel=\"custom\" href=\"https://developer.mozilla.org/en/CSS/height\">height</a></code>\n property from becoming smaller than the value specified for<code> min-height</code>.", "height": "The<code> height </code>CSS property specifies the height of the content area of an element. The <a title=\"en/CSS/Box_model#content\" rel=\"internal\" href=\"https://developer.mozilla.org/en/CSS/box_model#content\">content area</a> is <em>inside</em> the padding, border, and margin of the element.", "word-spacing": "The<code> word-spacing </code>CSS property specifies spacing behavior between tags and words.", "text-rendering": "The <code>text-rendering</code> CSS property provides information to the rendering engine about what to optimize for when rendering text. The browser makes trade-offs among speed, legibility, and geometric precision. The text-rendering property is an SVG property that is not defined in any CSS standard. However, Gecko and WebKit browsers let you apply this property to HTML and XML content on Windows, Mac OS X and Linux. ", "font-style": "The<code> font-style </code>CSS property allows<code> italic </code>or<code> oblique </code>faces to be selected within a <code><a rel=\"custom\" href=\"https://developer.mozilla.org/en/CSS/font-family\">font-family</a></code>\n.<br> ", "background-clip": "The<code> background-clip </code>CSS property specifies whether an element's background, either the color or image, extends underneath its border.", "background-size": "The<code> background-size </code>CSS property specifies the size of the background images.", "line-height": "On inline elements, the<code> line-height </code>CSS property specifies the height that is used in the calculation of the line box height.<br>\nOn block level elements,<code> line-height </code>specifies the minimal height of line boxes within the element.", "list-style-image": "The<code> list-style-image </code>CSS property sets the image that will be used as the list item marker. It is often more convenient to use the shortcut <code><a rel=\"custom\" href=\"https://developer.mozilla.org/en/CSS/list-style\">list-style</a></code>\n.", "background-repeat": "The <code>background-repeat</code> <a title=\"CSS\" rel=\"internal\" href=\"https://developer.mozilla.org/en/CSS\">CSS</a> property defines how background images are repeated. A background image can be repeated along the horizontal axis, the vertical axis, both, or not repeated at all. When the repetition of the image tiles doesn't let them exactly cover the background, the way adjustments are done can be controlled by the author: by default, the last image is clipped, but the different tiles can instead be re-sized, or space can be inserted between the tiles.", "background-origin": "The<code> background-origin </code>CSS property determines the background positioning area, that is the position of the origin of an image specified using the <code><a rel=\"custom\" href=\"https://developer.mozilla.org/en/CSS/background-image\">background-image</a></code>\n CSS property.", "bottom": "The <code>bottom</code> <a title=\"CSS\" rel=\"internal\" href=\"https://developer.mozilla.org/en/CSS\">CSS</a> property participates in specifying the position of <em>positioned elements</em>.", "text-overflow": "The <code>text-overflow</code> <a title=\"CSS\" rel=\"internal\" href=\"https://developer.mozilla.org/en/CSS\">CSS</a> property determines how overflowed content that is not displayed is signaled to the users. It can be clipped, display an ellipsis ('<code>\u2026</code>', <code style=\"text-transform: uppercase;\">U+2026 Horizontal Ellipsis</code>) or a Web author-defined string.", "top": "The <code>top</code> CSS property specifies part of the position of positioned elements. It has no effect on non-positioned elements.", "min-width": "The<code> min-width </code>CSS property is used to set the minimum width of a given element. It prevents the used value of the <code><a rel=\"custom\" href=\"https://developer.mozilla.org/en/CSS/width\">width</a></code>\n property from becoming smaller than the value specified for<code> min-width</code>.", "width": "The<code> width </code>CSS property specifies the width of the content area of an element. The <a title=\"en/CSS/box_model#content\" rel=\"internal\" href=\"https://developer.mozilla.org/en/CSS/box_model#content\">content area</a> is <em>inside</em> the padding, border, and margin of the element.", "font-variant": "The<code> font-variant </code>CSS property selects a<code> normal</code>, or<code> small-caps </code>face from a font family. Setting<code> font-variant </code>is also possible by using the <code><a rel=\"custom\" href=\"https://developer.mozilla.org/en/CSS/font\">font</a></code>\n shorthand.", "font-weight": "The <code><a rel=\"custom\" href=\"https://developer.mozilla.org/en/CSS/font-weight\">font-weight</a></code>\n <a title=\"CSS\" rel=\"internal\" href=\"https://developer.mozilla.org/en/CSS\">CSS</a> property specifies the weight or boldness of the font. However, some fonts are not available in all weights; some are available only on <code>normal</code> and <code>bold</code>.", "background-color": "The <code>background-color</code> <a title=\"CSS\" rel=\"internal\" href=\"https://developer.mozilla.org/en/CSS\">CSS</a> property sets the background color of an element, either through a color value or the keyword <code>transparent</code>.", "opacity": "The <code>opacity</code> CSS property specifies the transparency of an element, that is, the degree to which the background behind the element is overlaid.", "direction": "The <code>direction</code> CSS property should be set to match the direction of the text: <code>rtl</code> for Hebrew or Arabic text and <code>ltr</code> for other scripts. This should normally be done as part of the document (e.g., using the <code>dir</code> attribute in HTML) rather than through direct use of CSS.", "word-wrap": "The <code>word-wrap</code> <a title=\"CSS\" rel=\"internal\" href=\"https://developer.mozilla.org/en/CSS\">CSS</a> property is used to to specify whether or not the browser is allowed to break lines within words in order to prevent overflow when an otherwise unbreakable string is too long to fit.", "visibility": "The<code> visibility </code>CSS property is used for two things:", "text-indent": "The<code> text-indent </code>CSS property specifies how much horizontal space should be left before beginning of the first line of the text content of an element. Horizontal spacing is with respect to the left (or right, for right-to-left layout) edge of the containing block element's box.", "text-shadow": "The<code> text-shadow </code>CSS property adds shadows to text. It accepts a comma-separated list of shadows to be applied to the text and <code><a rel=\"custom\" href=\"https://developer.mozilla.org/en/CSS/text-decoration\">text-decorations</a></code>\n of the element.", "z-index": "The<code> z-index </code>CSS property specifies the z-order of an element and its descendants. When elements overlap, z-order determines which one covers the other. An element with a larger z-index generally covers an element with a lower one.", "background-attachment": "If a <code><a rel=\"custom\" href=\"https://developer.mozilla.org/en/CSS/background-image\">background-image</a></code>\n is specified, the <code>background-attachment</code> <a title=\"CSS\" rel=\"internal\" href=\"https://developer.mozilla.org/en/CSS\">CSS</a> property determines whether that image's position is fixed within the viewport, or scrolls along with its containing block.", "white-space": "The<code> white-space </code>CSS property is used to to describe how whitespace inside the element is handled.", "list-style-type": "The<code> list-style-type </code>CSS property specifies appearance of a list item element. As it is the only one who defaults to <code>display:list-item</code>, this is usually a <code><a rel=\"custom\" href=\"https://developer.mozilla.org/en/HTML/Element/li\"><li></a></code>\n element, but can be any element with this <code><a rel=\"custom\" href=\"https://developer.mozilla.org/en/CSS/display\">display</a></code>\n value.", "font-family": "The<code> font-family </code>CSS property allows for a prioritized list of font family names and/or generic family names to be specified for the selected element. Unlike most other CSS properties, values are separated by a comma to indicate that they are alternatives. The browser will select the first font on the list that is installed on the computer, or that can be downloaded using the information provided by a <code><a rel=\"custom\" href=\"https://developer.mozilla.org/en/CSS/@font-face\">@font-face</a></code>\n at-rule.", "text-align": "The<code> text-align </code>CSS property describes how inline content like text is aligned in its parent block element.<code> text-align </code>does not control the alignment of block elements itself, only their inline content.", "background-image": "The<code> background-image </code>CSS property sets the background images for an element. The images are drawn on successive stacking context layers, with the first specified being drawn as if it is the closest to the user. The <a title=\"border\" rel=\"internal\" href=\"https://developer.mozilla.org/cn/CSS/border\">borders</a> of the element are then drawn on top of them, and the <code><a rel=\"custom\" href=\"https://developer.mozilla.org/en/CSS/background-color\">background-color</a></code>\n is drawn beneath them.", "background-position": "The<code> background-position </code>CSS property sets the initial position, relative to the background position layer defined by <code><a rel=\"custom\" href=\"https://developer.mozilla.org/en/CSS/background-origin\">background-origin</a></code>\n for each defined background image.", "clear": "The <code>clear</code> <a title=\"CSS\" rel=\"internal\" href=\"https://developer.mozilla.org/en/CSS\">CSS</a> property specifies whether an element can be next to <a title=\"en/CSS/float\" rel=\"internal\" href=\"https://developer.mozilla.org/en/CSS/float\">floating</a> elements that precede it or must be moved down (cleared) below them.", "text-decoration": "The<code> text-decoration </code>CSS property is used to set the text formattings <code>underline, overline, line-through</code> and <code>blink</code>.", "cursor": "The<code> cursor </code>CSS property specifies the mouse cursor displayed when the mouse pointer is over an element.", "position": "The<code> position </code>CSS property chooses alternative rules for positioning elements, designed to be useful for scripted animation effects.", "list-style-position": "The<code> list-style-position </code>CSS property specifies the position of the marker box in the principal block box. It is often more convenient to use the shortcut <span class=\"lang lang-en\"><code><a rel=\"custom\" href=\"https://developer.mozilla.org/en/CSS/list-style\">list-style</a></code>\n</span>.", "text-transform": "The <code>text-transform</code> CSS property specifies how to capitalize an element's text. It can be used to make text appear in all-uppercase or all-lowercase, or with each word capitalized.", "display": "The <code>display</code> CSS property specifies the type of rendering box used for an element. In HTML, default <code>display</code> property values are taken from behaviors described in the HTML specifications or from the browser/user default stylesheet. The default value in XML is <code>inline</code>.", "left": "The <code>left</code> CSS property specifies part of the position of positioned elements."});
9957jQuery.localization.extend("en", "bug-report-dialog", {"publishing": "Publishing...", "success": "Here is the URL for your bug that anyone can view.", "to-internet": "Publish To Internet", "header": "Report A Bug", "intro": "Enter a description for the bug you're experiencing below. Note that your description, as well as the current page you're using the goggles on, will be made public, as Hackasaurus is an open-source project.", "error": "Sorry, an error occurred. Please try again later.", "to-internet-desc": "Instantly publish your bug to a URL that anyone can view."});
9958jQuery.localization.extend("en", "input", {"unload-blocked": "You have made unsaved changes to this page."});
9959jQuery.localization.extend("en", "hud-overlay", {"and": "and", "pointing-at": "pointing at", "class": "class", "element": "element", "ancestor-intro": "It is inside a", "focused-intro": "You are on a", "default-html": "<span>Web X-Ray Goggles activated! Press ESC to deactivate.</span>", "with": "with", "id": "id"});(function(jQuery) {
9960 "use strict";
9961
9962 function makeAbsoluteURL(baseURI, url) {
9963 if (url.match(/^https?:/))
9964 return url;
9965 return baseURI + url;
9966 }
9967
9968 jQuery.webxraySettings = {
9969 extend: jQuery.extend,
9970 url: function(name) {
9971 if (jQuery.isArray(this[name])) {
9972 var self = this;
9973 return jQuery.map(this[name], function(url) {
9974 return makeAbsoluteURL(self.baseURI, url);
9975 });
9976 }
9977 return makeAbsoluteURL(this.baseURI, this[name]);
9978 },
9979 language: navigator.language || navigator.userLanguage,
9980 baseURI: "",
9981 cssURL: "webxray.css",
9982 preferencesURL: "preferences.html",
9983 easyRemixDialogURL: "easy-remix-dialog/index.html",
9984 uprootDialogURL: "uproot-dialog.html",
9985 bugReportDialogURL: "bug-report-dialog.html",
9986 hackpubURL: "http://hackpub.hackasaurus.org/",
9987 bugReportHackpubURL: "http://hackpub.hackasaurus.org/buckets/webxray-bugs/",
9988 hackpubInjectionURL: "published-hack/injector.js",
9989 pluginURLs: []
9990 };
9991})(jQuery);
9992(function(jQuery) {
9993 "use strict";
9994
9995 var $ = jQuery;
9996
9997 function createLocalizedHelp(keys, locale, platform) {
9998 locale = locale || jQuery.locale;
9999 platform = platform || navigator.platform;
10000
10001 var descriptions = locale.scope('command-descriptions');
10002 var localizedKeys = [];
10003 keys.forEach(function(info) {
10004 var localizedInfo = {key: null, desc: null};
10005 localizedInfo.key = jQuery.nameForKey(info.key, locale, platform);
10006 localizedInfo.desc = descriptions(info.cmd);
10007 localizedKeys.push(localizedInfo);
10008 });
10009 return localizedKeys;
10010 }
10011
10012 jQuery.extend({
10013 nameForKey: function(key, locale, platform) {
10014 locale = locale || jQuery.locale;
10015 platform = platform || navigator.platform;
10016
10017 var normalKey = "key-names:" + key;
10018 var osKey = normalKey + "-" + platform;
10019
10020 return locale[osKey] ||
10021 locale[normalKey] ||
10022 key;
10023 },
10024 createKeyboardHelpReference: function(keyboardHelp, locale, platform) {
10025 var keys = createLocalizedHelp(keyboardHelp, locale, platform);
10026 var table = $('<div class="webxray-help-box"></div>');
10027 keys.forEach(function(info) {
10028 var row = $('<div class="webxray-help-row"></div>');
10029 var keyCell = $('<div class="webxray-help-key"></div>');
10030 var keyValue = $('<div class="webxray-help-desc"></div>');
10031
10032 keyCell.append($('<div class="webxray-kbd"></div>').text(info.key));
10033 keyValue.text(info.desc);
10034 row.append(keyCell).append(keyValue);
10035 table.append(row);
10036 });
10037 return table;
10038 }
10039 });
10040})(jQuery);
10041(function(jQuery) {
10042 "use strict";
10043
10044 var $ = jQuery;
10045 var HEX_REGEXP = /#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})/i;
10046 var RGB_REGEXP = /rgb\((\d+),\s*(\d+),\s*(\d+)\)/;
10047
10048 jQuery.extend({
10049 // Load the given script. Returns a jQuery deferred that resolves
10050 // when the script is loaded. Nothing happens if the
10051 // script fails to load.
10052 loadScript: function loadScript(url) {
10053 var script = document.createElement('script');
10054 var deferred = jQuery.Deferred();
10055 script.setAttribute('src', url);
10056 script.addEventListener("load", function() {
10057 document.head.removeChild(script);
10058 deferred.resolve();
10059 }, false);
10060 document.head.appendChild(script);
10061 return deferred;
10062 },
10063 // Return a string that is shortened to be the given maximum
10064 // length, with a trailing ellipsis at the end. If the string
10065 // isn't longer than the maximum length, the string is returned
10066 // unaltered.
10067 shortenText: function shortenText(text, maxLength) {
10068 if (text.length > maxLength)
10069 return text.substring(0, maxLength) + '\u2026';
10070 return text;
10071 },
10072 // Return an rgba()-style CSS color string given a color and an
10073 // alpha value.
10074 makeRGBA: function makeRGBA(color, alpha) {
10075 // WebKit and Gecko use this.
10076 var match = color.match(RGB_REGEXP);
10077 if (!match) {
10078 // This is what Opera uses.
10079 var hexMatch = color.match(HEX_REGEXP);
10080 if (hexMatch) {
10081 match = [null];
10082 for (var i = 1; i <= 3; i++)
10083 match.push(parseInt(hexMatch[i], 16));
10084 } else
10085 throw new Error("Couldn't parse " + color);
10086 }
10087 return "rgba(" +
10088 match[1] + ", " +
10089 match[2] + ", " +
10090 match[3] + ", " +
10091 alpha + ")";
10092 },
10093 // Like console.warn(), but only does anything if console exists.
10094 warn: function warn() {
10095 if (window.console && window.console.warn) {
10096 if (window.console.warn.apply)
10097 window.console.warn.apply(window.console, arguments);
10098 else
10099 // IE9's console.warn doesn't have an apply method...
10100 window.console.warn(arguments[0] + " " + arguments[1]);
10101 }
10102 }
10103 });
10104
10105 jQuery.fn.extend({
10106 // Turns all URLs in src and href attributes into absolute URLs
10107 // if they're not already.
10108 absolutifyURLs: function() {
10109 var URL_PROPS = ['href', 'src'];
10110 this.find('*').andSelf().each(function() {
10111 var self = this;
10112 URL_PROPS.forEach(function(name) {
10113 if (name in self && self[name]) {
10114 $(self).attr(name, self[name]);
10115 }
10116 });
10117 });
10118 return this;
10119 },
10120 // returns whether at least one of the matched elements is a
10121 // void element (i.e., has no closing tag).
10122 isVoidElement: function() {
10123 // Taken from:
10124 // http://www.w3.org/TR/html-markup/syntax.html#syntax-elements
10125 return this.is("area, base, br, col, command, embed, hr, img, " +
10126 "input, keygen, link, meta, param, source, " +
10127 "track, wbr");
10128 },
10129 // works much like jQuery's html() with no arguments, but
10130 // includes HTML code for the matched elements themselves.
10131 // unlike jQuery, this will include all matched elements.
10132 outerHtml: function outerHtml() {
10133 var clonedElement = this.clone();
10134 var trivialParent = $('<div></div>').append(clonedElement);
10135 return trivialParent.html();
10136 },
10137 // Given a descendant on the first matched element, returns a CSS
10138 // selector that uniquely selects only the descendant from the
10139 // first matched element.
10140 pathTo: function pathTo(descendant) {
10141 var root = this[0];
10142 var target = $(descendant).get(0);
10143 var parts = [];
10144
10145 for (var node = target; node && node != root; node = node.parentNode) {
10146 var n = $(node).prevAll(node.nodeName.toLowerCase()).length + 1;
10147 var id = $(node).attr("id");
10148 var className = $(node).attr("class");
10149 var classNames = [];
10150 var selector = node.nodeName.toLowerCase();
10151
10152 // Class and id parts are based on jQuery-GetPath code.
10153 if (typeof(id) != "undefined" && id.length)
10154 selector += "#" + id;
10155
10156 if (typeof(className) != "undefined" && className.length)
10157 jQuery.each(jQuery.trim(className).split(/[\s\n]+/), function() {
10158 // Only keep the sane-looking class names. The CSS standard
10159 // does prescribe escape patterns for odd characters in
10160 // selectors, but jQuery's selector parser isn't completely
10161 // standards-compliant, so we'll stick with the safe ones.
10162 if (/^[A-Za-z0-9_\-]+$/.test(this))
10163 classNames.push(this);
10164 });
10165
10166 if (classNames.length)
10167 selector += "." + classNames.join('.');
10168
10169 selector += ':nth-of-type(' + n + ')';
10170 parts.push(selector);
10171 }
10172
10173 parts.reverse();
10174 return ' > ' + parts.join(' > ');
10175 },
10176
10177 // Temporarily remove the set of matched elements,
10178 // returning a removal object with one method,
10179 // undo(), that can be used to undo the removal.
10180 temporarilyRemove: function temporarilyRemove() {
10181 var undoers = [];
10182 jQuery.each(this, function(i, element) {
10183 var document = element.ownerDocument;
10184 var replacer = document.createTextNode('');
10185 element.parentNode.replaceChild(replacer, element);
10186 undoers.push(function() {
10187 replacer.parentNode.replaceChild(element, replacer);
10188 });
10189 });
10190 return {
10191 undo: function undo() {
10192 jQuery.each(undoers, function(i, undoer) {
10193 undoer();
10194 });
10195 undoers = null;
10196 }
10197 };
10198 },
10199
10200 // Return the nth ancestor of the first matched element.
10201 ancestor: function ancestor(generation) {
10202 var ancestor = this[0];
10203
10204 for (var i = 0; i < generation; i++)
10205 if (ancestor.parentNode)
10206 ancestor = ancestor.parentNode;
10207 else
10208 return null;
10209
10210 return $(ancestor);
10211 },
10212 // Return the bounding client rectangle of the first element
10213 // in the selection, taking CSS transforms into account if
10214 // possible.
10215 //
10216 // The returned object has top/left/height/width properties.
10217 bounds: function bounds() {
10218 try {
10219 var rect = this.get(0).getBoundingClientRect();
10220 var window = this.get(0).ownerDocument.defaultView;
10221 return {
10222 top: rect.top + window.pageYOffset,
10223 left: rect.left + window.pageXOffset,
10224 height: rect.height,
10225 width: rect.width
10226 };
10227 } catch (e) {
10228 // Not sure if this will ever get called, but there's code in
10229 // Tilt that deals with this kind of situation, and we'd like to
10230 // gracefully fallback to code that we know works if the above
10231 // fails. For more discussion, see bug #98:
10232 //
10233 // http://hackasaurus.lighthouseapp.com/projects/81472/tickets/98
10234
10235 var pos = this.offset();
10236 return {
10237 top: pos.top,
10238 left: pos.left,
10239 height: this.outerHeight(),
10240 width: this.outerWidth()
10241 };
10242 }
10243 },
10244 // Create and return a div that floats above the first
10245 // matched element.
10246 overlay: function overlay() {
10247 var html = this.get(0).ownerDocument.documentElement;
10248 var overlay = $('<div class="webxray-base webxray-overlay">' +
10249 ' </div>');
10250
10251 overlay.css(this.bounds());
10252 $(html).append(overlay);
10253 return overlay;
10254 },
10255 // Like jQuery.append(), but accepts an arbitrary number of arguments,
10256 // and automatically converts string arguments into text nodes.
10257 emit: function emit() {
10258 for (var i = 0; i < arguments.length; i++) {
10259 var arg = arguments[i];
10260 if (typeof(arg) == "string")
10261 arg = document.createTextNode(arg);
10262 this.append(arg);
10263 }
10264 },
10265 // Resizes and repositions the currently matched element to
10266 // match the size and position of the given target by animating
10267 // it and then executing the given callback.
10268 resizeTo: function resizeTo(target, cb) {
10269 var overlay = this;
10270
10271 var hasNoStyle = $(target).attr('style') === undefined;
10272 overlay.animate($(target).bounds(), cb);
10273 if (hasNoStyle && $(target).attr('style') == '')
10274 $(target).removeAttr('style');
10275 },
10276 // Resizes and repositions the currently matched element to
10277 // match the size and position of the given target by animating
10278 // it, then fades out the currently matched element and
10279 // removes it from the DOM.
10280 resizeToAndFadeOut: function resizeToAndFadeOut(target) {
10281 this.resizeTo(target, function() {
10282 $(this).fadeOut(function() { $(this).remove(); });
10283 });
10284 },
10285 // Removes the class and, if the class attribute is now empty,
10286 // removes the attribute as well (jQuery remove class does not)..
10287 reallyRemoveClass: function reallyRemoveClass(classname) {
10288 this.removeClass(classname).filter('[class=""]').removeAttr('class');
10289 return this;
10290 }
10291 });
10292})(jQuery);
10293(function(jQuery) {
10294 "use strict";
10295
10296 var $ = jQuery;
10297
10298 function makeDoctypeTag(doctype) {
10299 if (!doctype)
10300 return '';
10301 var tag = '<!DOCTYPE ' + doctype.name;
10302 if (doctype.publicId && doctype.publicId.length)
10303 tag += ' PUBLIC "' + doctype.publicId + '"';
10304 if (doctype.systemId && doctype.systemId.length)
10305 tag += ' "' + doctype.systemId + '"';
10306 return tag += '>';
10307 }
10308
10309 jQuery.extend({
10310 openUprootDialog: function(input) {
10311 $(document).uprootIgnoringWebxray(function(html) {
10312 var injectURL = jQuery.webxraySettings.url("hackpubInjectionURL");
10313 var hackpubInfo = {
10314 injectURL: injectURL,
10315 originalURL: window.location.href,
10316 submissionDate: (new Date()).toString()
10317 };
10318 html += '<script>hackpubInfo = ' + JSON.stringify(hackpubInfo) +
10319 '</script>';
10320 html += '<script src="' + injectURL + '"></script>';
10321 jQuery.simpleModalDialog({
10322 input: input,
10323 url: jQuery.webxraySettings.url("uprootDialogURL"),
10324 payload: JSON.stringify({
10325 html: html,
10326 hackpubURL: jQuery.webxraySettings.url("hackpubURL"),
10327 originalURL: hackpubInfo.originalURL,
10328 languages: jQuery.locale.languages
10329 })
10330 });
10331 });
10332 }
10333 });
10334
10335 jQuery.fn.extend({
10336 uprootIgnoringWebxray: function(cb) {
10337 $(document).uproot({
10338 success: cb,
10339 ignore: $(".webxray-hud-box, .webxray-overlay, " +
10340 ".webxray-dialog-overlay, link.webxray, " +
10341 "#webxray-is-active, .webxray-toolbar, " +
10342 ".webxray-style-info, .webxray-tmsg-overlay")
10343 });
10344 },
10345 uproot: function(cb) {
10346 var options = {
10347 ignore: $()
10348 };
10349 if (typeof(cb) == 'object') {
10350 options = cb;
10351 cb = options.success;
10352 }
10353 var elem = this[0];
10354 var document = elem.contentDocument || elem;
10355 if (document.nodeName != "#document")
10356 throw new Error("first item of query must be a document or iframe");
10357 var base = document.createElement('base');
10358 if ($('base', document).length == 0) {
10359 $(base).attr('href', document.location.href);
10360 $(document.head).prepend(base);
10361 }
10362 if (cb)
10363 setTimeout(function() {
10364 var ignore = options.ignore.add('script', document);
10365 var removal = ignore.temporarilyRemove();
10366 var doctype = makeDoctypeTag(document.doctype);
10367 var html = doctype + '\n<html>' +
10368 document.documentElement.innerHTML + '</html>';
10369 removal.undo();
10370 $(base).remove();
10371 cb.call(elem, html);
10372 }, 0);
10373 }
10374 });
10375})(jQuery);
10376(function(jQuery) {
10377 "use strict";
10378
10379 var $ = jQuery;
10380
10381 jQuery.extend({
10382 openBugReportDialog: function(input) {
10383 jQuery.simpleModalDialog({
10384 input: input,
10385 url: jQuery.webxraySettings.url("bugReportDialogURL"),
10386 payload: JSON.stringify({
10387 buildMetadata: buildMetadata,
10388 hackpubURL: jQuery.webxraySettings.url("bugReportHackpubURL"),
10389 originalURL: window.location.href,
10390 languages: jQuery.locale.languages
10391 })
10392 });
10393 }
10394 });
10395})(jQuery);
10396(function(jQuery) {
10397 "use strict";
10398
10399 var $ = jQuery;
10400
10401 var TAG_COLORS = [
10402 "#C60C46",
10403 "#00AEEF",
10404 "#F3739B",
10405 "#FF66FF",
10406 "#E66124",
10407 "#FFC328",
10408 "#B2E725",
10409 "#660066",
10410 "#FF9900"
10411 ];
10412
10413 var NUM_TAG_COLORS = TAG_COLORS.length;
10414
10415 var TAG_COLOR_MAP = {
10416 img: 0,
10417 p: 1,
10418 div: 2,
10419 a: 3,
10420 span: 4,
10421 body: 5,
10422 h1: 6,
10423 html: 7,
10424 footer: 8
10425 };
10426
10427 var DEFAULT_OVERLAY_OPACITY = 0.7;
10428
10429 function tagNameToNumber(tagName) {
10430 var total = 0;
10431 for (var i = 0; i < tagName.length; i++)
10432 total += tagName.charCodeAt(i);
10433 return total;
10434 }
10435
10436 jQuery.extend({
10437 // This is only really exported so unit tests can use it.
10438 NUM_TAG_COLORS: NUM_TAG_COLORS,
10439
10440 // Returns the color hex for the "official" Web X-Ray color
10441 // for the given tag name, excluding angled brackets.
10442 colorForTag: function colorForTag(tagName) {
10443 var colorNumber;
10444
10445 tagName = tagName.toLowerCase();
10446 if (tagName in TAG_COLOR_MAP)
10447 colorNumber = TAG_COLOR_MAP[tagName];
10448 else
10449 colorNumber = (tagNameToNumber(tagName) % NUM_TAG_COLORS);
10450
10451 return TAG_COLORS[colorNumber];
10452 }
10453 });
10454
10455 jQuery.fn.extend({
10456 // Applies the "official" Web X-Ray color for fromElement to
10457 // the current set of matched elements with the given
10458 // optional opacity. Returns the current set of matched
10459 // elements to support chaining.
10460 applyTagColor: function applyTagColor(fromElement, opacity) {
10461 var bgColor;
10462 var baseColor = $.colorForTag($(fromElement).get(0).nodeName);
10463
10464 if (opacity === undefined)
10465 opacity = DEFAULT_OVERLAY_OPACITY;
10466
10467 bgColor = $.makeRGBA(baseColor, opacity);
10468
10469 this.css({backgroundColor: bgColor});
10470 return this;
10471 },
10472 // Like $.overlay(), but applies the "official" Web X-Ray color
10473 // for the element type being overlaid, with the given opacity.
10474 // A default opacity is used if none is provided.
10475 overlayWithTagColor: function overlayWithTagColor(opacity) {
10476 return $(this).overlay().applyTagColor(this, opacity);
10477 }
10478 });
10479})(jQuery);
10480(function(jQuery) {
10481 "use strict";
10482
10483 jQuery.eventEmitter = function eventEmitter(object) {
10484 var handlers = {};
10485
10486 object.emit = function emit(event, data) {
10487 if (event in handlers)
10488 handlers[event].forEach(function(handler) {
10489 handler(data);
10490 });
10491 };
10492
10493 object.on = object.addListener = function on(event, handler) {
10494 if (!(event in handlers))
10495 handlers[event] = [];
10496 handlers[event].push(handler);
10497 };
10498
10499 object.removeListener = function removeListener(event, handler) {
10500 if (event in handlers) {
10501 var index = handlers[event].indexOf(handler);
10502 if (index != -1)
10503 handlers[event].splice(index, 1);
10504 }
10505 };
10506
10507 object.removeAllListeners = function removeAllListeners(type) {
10508 if (type in handlers)
10509 delete handlers[type];
10510 };
10511
10512 return object;
10513 };
10514})(jQuery);
10515(function(jQuery) {
10516 "use strict";
10517
10518 var $ = jQuery;
10519
10520 jQuery.focusedOverlay = function focusedOverlay(options) {
10521 if (!options)
10522 options = {};
10523
10524 var useAnimation = options.useAnimation;
10525 var ancestorIndex = 0;
10526 var ancestorOverlay = null;
10527 var overlay = null;
10528 var element = null;
10529
10530 function labelOverlay(overlay, target, finalSize) {
10531 var parts = ["top", "bottom"];
10532
10533 if ($(target).isVoidElement())
10534 parts = ["top"];
10535
10536 finalSize = finalSize || overlay;
10537 parts.forEach(function(className) {
10538 var part = $('<div class="webxray-base webxray-overlay-label">' +
10539 '</div>');
10540 var tag = target.nodeName.toLowerCase();
10541 part.addClass("webxray-overlay-label-" + className);
10542 part.text("<" + (className == "bottom" ? "/" : "") +
10543 tag + ">");
10544 overlay.append(part);
10545 if (part.width() > $(finalSize).width() ||
10546 part.height() > $(finalSize).height())
10547 part.hide();
10548 });
10549 }
10550
10551 function setAncestorOverlay(ancestor, useAnimation) {
10552 if (ancestorOverlay) {
10553 ancestorOverlay.remove();
10554 ancestorOverlay = null;
10555 }
10556 if (ancestor) {
10557 if (useAnimation) {
10558 var fromElement = instance.getPrimaryElement();
10559 ancestorOverlay = $(fromElement).overlay();
10560 ancestorOverlay.resizeTo(ancestor);
10561 } else
10562 ancestorOverlay = ancestor.overlay();
10563 ancestorOverlay.addClass("webxray-ancestor");
10564 labelOverlay(ancestorOverlay, ancestor[0], ancestor[0]);
10565 instance.ancestor = ancestor[0];
10566 } else {
10567 if (useAnimation && instance.ancestor) {
10568 ancestorOverlay = $(instance.ancestor).overlay();
10569 ancestorOverlay.addClass("webxray-ancestor");
10570 labelOverlay(ancestorOverlay, instance.element, instance.element);
10571 ancestorOverlay.resizeToAndFadeOut(instance.element);
10572 }
10573 instance.ancestor = null;
10574 }
10575 }
10576
10577 var instance = jQuery.eventEmitter({
10578 element: null,
10579 ancestor: null,
10580 getPrimaryElement: function getPrimaryElement() {
10581 return this.ancestor || this.element;
10582 },
10583 upfocus: function upfocus() {
10584 if (!element)
10585 return;
10586 var ancestor = $(element).ancestor(ancestorIndex + 1);
10587
10588 if (ancestor.length && ancestor[0] != document) {
10589 ancestorIndex++;
10590 setAncestorOverlay(ancestor, useAnimation);
10591 }
10592 this.emit('change', this);
10593 },
10594 downfocus: function downfocus() {
10595 if (!element)
10596 return;
10597 if (ancestorOverlay) {
10598 ancestorOverlay.remove();
10599 ancestorOverlay = null;
10600 }
10601 if (ancestorIndex > 0 && --ancestorIndex > 0) {
10602 var ancestor = $(element).ancestor(ancestorIndex);
10603 setAncestorOverlay(ancestor, useAnimation);
10604 } else
10605 setAncestorOverlay(null, useAnimation);
10606 this.emit('change', this);
10607 },
10608 unfocus: function unfocus() {
10609 if (!element)
10610 return;
10611 overlay.remove();
10612 overlay = null;
10613 element = this.element = null;
10614 setAncestorOverlay(null);
10615 ancestorIndex = 0;
10616 this.emit('change', this);
10617 },
10618 set: function set(newElement) {
10619 this.unfocus();
10620 element = this.element = newElement;
10621 overlay = $(element).overlayWithTagColor();
10622 labelOverlay(overlay, element);
10623 this.emit('change', this);
10624 },
10625 destroy: function destroy() {
10626 this.unfocus();
10627 this.removeAllListeners('change');
10628 }
10629 });
10630
10631 return instance;
10632 }
10633})(jQuery);
10634(function(jQuery) {
10635 "use strict";
10636
10637 var $ = jQuery;
10638 var MAX_URL_LENGTH = 35;
10639
10640 jQuery.hudOverlay = function hudOverlay(options) {
10641 if (options === undefined)
10642 options = {};
10643
10644 var hudContainer = $('<div class="webxray-base webxray-hud-box"></div>');
10645 var hud = $('<div class="webxray-base webxray-hud"></div>');
10646 var locale = options.locale || jQuery.locale;
10647 var l10n = locale.scope("hud-overlay");
10648
10649 hudContainer.append(hud);
10650
10651 function showDefaultContent() {
10652 hud.html(options.defaultContent || l10n("default-html"));
10653 }
10654
10655 showDefaultContent();
10656
10657 return {
10658 overlayContainer: hudContainer[0],
10659 overlay: hud[0],
10660 destroy: function destroy() {
10661 this.overlay = null;
10662 hudContainer.remove();
10663 hudContainer = null;
10664 hud = null;
10665 },
10666 onFocusChange: function handleEvent(focused) {
10667 function code(string) {
10668 return $("<code></code>").text(string);
10669 }
10670
10671 function elementInfo(element) {
10672 var info = {
10673 tagName: "<" + element.nodeName.toLowerCase() + ">",
10674 id: element.id,
10675 className: element.className,
10676 url: element.href || element.src || element.action ||
10677 element.currentSrc
10678 };
10679
10680 if (info.url && info.url.length)
10681 info.url = $.shortenText(info.url, MAX_URL_LENGTH);
10682 else
10683 info.url = null;
10684
10685 return info;
10686 }
10687
10688 function elementDesc(element) {
10689 var span = $("<span></span>");
10690 var info = elementInfo(element);
10691 var shortDescKey = "short-element-descriptions:" +
10692 element.nodeName.toLowerCase();
10693
10694 if (locale.has(shortDescKey))
10695 span.emit(code(info.tagName),
10696 " (" + locale.get(shortDescKey) + ") ",
10697 l10n("element"));
10698 else
10699 span.emit(code(info.tagName), " ", l10n("element"));
10700 if (info.id)
10701 span.emit(" ", l10n("with"), " ", l10n("id"), " ",
10702 code(info.id));
10703 if (info.className)
10704 span.emit(" " + (info.id ? l10n("and") : l10n("with")),
10705 " ", l10n("class"), " ",
10706 code(info.className));
10707 if (info.url) {
10708 span.emit((info.id || info.className) ? "," : "",
10709 " ", l10n("pointing-at"), " ",
10710 $('<span class="webxray-url"></span>').text(info.url));
10711 }
10712 return span;
10713 }
10714
10715 if (focused.element) {
10716 var span = $("<span></span>");
10717 span.emit(l10n("focused-intro"), " ",
10718 elementDesc(focused.element), ".");
10719 if (focused.ancestor)
10720 span.emit(" ", l10n("ancestor-intro"), " ",
10721 elementDesc(focused.ancestor), ".");
10722 hud.empty().append(span);
10723 } else
10724 showDefaultContent();
10725 }
10726 };
10727 };
10728})(jQuery);
10729(function(jQuery) {
10730 "use strict";
10731
10732 var $ = jQuery;
10733
10734 function getContentSize(content) {
10735 var staged = $('<div class="webxray-base"></div>');
10736 staged.append(content.clone());
10737 staged.css({float: 'left'});
10738 $(document.body).append(staged);
10739 var width = staged.width();
10740 staged.remove();
10741 return width;
10742 }
10743
10744 function onUserActivity(cb, bindTarget) {
10745 setTimeout(function() {
10746 var events = ['keydown', 'mousemove', 'touchstart'];
10747 function onEvent() {
10748 events.forEach(function(e) { $(bindTarget).unbind(e, onEvent); });
10749 cb();
10750 }
10751 events.forEach(function(e) { $(bindTarget).bind(e, onEvent); });
10752 }, jQuery.USER_ACTIVITY_DELAY);
10753 }
10754
10755 jQuery.extend({
10756 USER_ACTIVITY_DELAY: 100,
10757 transparentMessage: function(content, duration, cb, parent, bindTarget) {
10758 var div = $('<div class="webxray-base webxray-tmsg-overlay">' +
10759 '<div class="webxray-base webxray-tmsg-outer">' +
10760 '<div class="webxray-base webxray-tmsg-middle">' +
10761 '<div class="webxray-base webxray-tmsg-inner">' +
10762 '</div></div></div></div>');
10763
10764 var inner = div.find('.webxray-tmsg-inner');
10765 inner.append(content);
10766 inner.width(getContentSize(content));
10767 parent = parent || document.body;
10768 $(parent).append(div);
10769
10770 function remove() {
10771 div.fadeOut(function() {
10772 div.remove();
10773 if (cb)
10774 cb();
10775 });
10776 }
10777
10778 if (duration)
10779 setTimeout(remove, duration);
10780 else
10781 onUserActivity(remove, bindTarget || window);
10782
10783 return div;
10784 }
10785 });
10786})(jQuery);
10787(function(jQuery) {
10788 "use strict";
10789
10790 var $ = jQuery;
10791
10792 var DEFAULT_PROPERTIES = [
10793 "background-attachment",
10794 "background-clip",
10795 "background-color",
10796 "background-image",
10797 "background-origin",
10798 "background-position",
10799 "background-repeat",
10800 "background-size",
10801 "font-family",
10802 "font-size",
10803 "font-style",
10804 "font-variant",
10805 "font-weight",
10806 "height",
10807 "list-style-image",
10808 "list-style-position",
10809 "list-style-type",
10810 "min-height",
10811 "min-width",
10812 "text-align",
10813 "text-anchor",
10814 "text-decoration",
10815 "text-indent",
10816 "text-overflow",
10817 "text-rendering",
10818 "text-shadow",
10819 "text-transform",
10820 "top",
10821 "left",
10822 "bottom",
10823 "right",
10824 "color",
10825 "clear",
10826 "cursor",
10827 "direction",
10828 "display",
10829 "position",
10830 "float",
10831 "letter-spacing",
10832 "line-height",
10833 "opacity",
10834 "visibility",
10835 "white-space",
10836 "width",
10837 "vertical-align",
10838 "word-spacing",
10839 "word-wrap",
10840 "z-index"
10841 ].sort();
10842
10843 DEFAULT_PROPERTIES.forEach(function(name) {
10844 if (name.match(/image$/))
10845 jQuery.cssHooks[jQuery.camelCase(name)] = {
10846 set: function(elem, value) {
10847 if (value != "none" && !value.match(/^\s*url\(.*\)/))
10848 return "url(" + value + ")";
10849 return value;
10850 }
10851 };
10852 });
10853
10854 function makeCssValueEditable(event) {
10855 var row = $(this);
10856 var widget = row.data("propertyWidget");
10857
10858 if (event.shiftKey) {
10859 open('https://developer.mozilla.org/en/CSS/' + widget.name, 'info');
10860 return;
10861 }
10862
10863 if (widget.isBeingEdited())
10864 return;
10865
10866 var nameCell = $(this).find('.webxray-name');
10867 var valueCell = $(this).find('.webxray-value');
10868 var originalValue = valueCell.text();
10869 var form = $('<form><input type="text"></input></form>');
10870 var textField = form.find("input");
10871
10872 valueCell.empty().append(form);
10873 textField.val(originalValue).select().focus();
10874
10875 // The -1 is needed on Firefox, or else the whole field will
10876 // wrap to the next line.
10877 textField.width(row.width() - nameCell.outerWidth() - 1);
10878
10879 function revertToOriginal() {
10880 form.remove();
10881 valueCell.text(originalValue);
10882 widget.clearPreview();
10883 }
10884
10885 function confirmChange() {
10886 var newValue = textField.val();
10887 revertToOriginal();
10888 widget.changeValue(newValue);
10889 }
10890
10891 textField.blur(confirmChange);
10892 textField.keydown(function(event) {
10893 if (event.keyCode == $.keys.ESC) {
10894 revertToOriginal();
10895 return false;
10896 }
10897 });
10898 textField.keyup(function(event) {
10899 widget.previewValue(textField.val());
10900 });
10901
10902 form.submit(function() {
10903 confirmChange();
10904 return false;
10905 });
10906 }
10907
10908 function buildPropertyWidget(element, row, style, parentStyle, name,
10909 locale, hud) {
10910 var nameCell = $('<div class="webxray-name"></div>');
10911 var valueCell = $('<div class="webxray-value"></div>');
10912
10913 // Replace hyphens with non-breaking ones to keep
10914 // the presentation looking nice.
10915 nameCell.text(name.replace(/-/g, '\u2011'));
10916 row.append(nameCell);
10917 row.append(valueCell);
10918
10919 var lastPreviewValue = null;
10920
10921 var self = {
10922 name: name,
10923 getValue: function() {
10924 return valueCell.text();
10925 },
10926 isBeingEdited: function() {
10927 return (row.find('form').length != 0);
10928 },
10929 refresh: function() {
10930 var value = $.normalizeStyleProperty(style, name);
10931
10932 // TODO: It might be possible for us to return from this
10933 // function when in fact we need to change class information.
10934 // Need to think about this more.
10935 if (valueCell.text() == value)
10936 return;
10937
10938 valueCell.text(value);
10939 valueCell.attr("class", "webxray-value");
10940 if (parentStyle &&
10941 $.normalizeStyleProperty(parentStyle, name) != value)
10942 valueCell.addClass("webxray-value-different-from-parent");
10943 if ($.normalizeStyleProperty(element.style, name) == value)
10944 valueCell.addClass("webxray-value-matches-inline-style");
10945 if (name.match(/color$/)) {
10946 var colorBlock = $('<div class="webxray-color-block"></div>');
10947 colorBlock.css('background-color', value);
10948 valueCell.append(colorBlock);
10949 }
10950 },
10951 clearPreview: function() {
10952 if (lastPreviewValue !== null) {
10953 jQuery.style(element, name, lastPreviewValue);
10954 lastPreviewValue = null;
10955 }
10956 },
10957 previewValue: function(newValue) {
10958 self.clearPreview();
10959 lastPreviewValue = jQuery.style(element, name);
10960 jQuery.style(element, name, newValue);
10961 },
10962 changeValue: function(newValue) {
10963 var originalValue = valueCell.text();
10964 if (newValue != originalValue) {
10965 $(element).css(name, newValue);
10966 self.refresh();
10967 row.trigger('css-property-change');
10968 }
10969 }
10970 };
10971
10972 row.data("propertyWidget", self);
10973 row.mouseover(function() {
10974 var docKey = "css-property-docs:" + name;
10975 if (locale.has(docKey)) {
10976 var moreInfo = $('<span class="webxray-more-info"></span>')
10977 .text(locale.get("style-info:more-info"));
10978 $(hud.overlay).html(locale.get(docKey))
10979 .append(moreInfo)
10980 .find("a").css({textDecoration: "none"});
10981 }
10982 });
10983 self.refresh();
10984 }
10985
10986 function PrimaryTranslucentOverlay(overlay, primary) {
10987 var tOverlay = $(primary).overlayWithTagColor(0.2);
10988
10989 function onCssPropertyChange() {
10990 tOverlay.show();
10991 tOverlay.resizeTo(primary, function() {
10992 tOverlay.fadeOut();
10993 });
10994 }
10995
10996 overlay.bind('css-property-change', onCssPropertyChange);
10997 tOverlay.hide();
10998
10999 return {
11000 destroy: function() {
11001 overlay.unbind('css-property-change', onCssPropertyChange);
11002 tOverlay.remove();
11003 }
11004 };
11005 }
11006
11007 function ModalOverlay(overlay, primary, input) {
11008 var startStyle = $(primary).attr("style");
11009 var translucentOverlay = PrimaryTranslucentOverlay(overlay, primary);
11010
11011 function handleKeyDown(event) {
11012 if (self.isBeingEdited())
11013 return;
11014 switch (event.keyCode) {
11015 case $.keys.ESC:
11016 event.preventDefault();
11017 event.stopPropagation();
11018 self.close();
11019 break;
11020
11021 case $.keys.LEFT:
11022 case $.keys.RIGHT:
11023 input.handleEvent(event);
11024 if (primary.parentNode) {
11025 startStyle = $(primary).attr("style");
11026 overlay.show().find('.webxray-row').each(function() {
11027 $(this).data("propertyWidget").refresh();
11028 });
11029 } else {
11030 // Um, our target element is no longer attached to
11031 // the document. Just exit the style editing mode.
11032
11033 // TODO: Is this the most humane behavior?
11034 self.close();
11035 }
11036 break;
11037 }
11038 }
11039
11040 function recordChanges() {
11041 var endStyle = $(primary).attr("style");
11042 if (startStyle != endStyle) {
11043 if (typeof(startStyle) == 'undefined')
11044 $(primary).removeAttr("style")
11045 else
11046 $(primary).attr("style", startStyle);
11047 startStyle = endStyle;
11048 self.emit('change-style', endStyle);
11049 }
11050 }
11051
11052 overlay.addClass("webxray-style-info-locked");
11053 overlay.bind('css-property-change', recordChanges);
11054 overlay.find('.webxray-row').bind('click', makeCssValueEditable);
11055 window.addEventListener("keydown", handleKeyDown, true);
11056
11057 var self = jQuery.eventEmitter({
11058 isBeingEdited: function() {
11059 return (overlay.find('form').length != 0);
11060 },
11061 close: function() {
11062 overlay.removeClass("webxray-style-info-locked");
11063 overlay.unbind('css-property-change', recordChanges);
11064 overlay.find('.webxray-row').unbind('click', makeCssValueEditable);
11065 overlay.find('.webxray-close-button').unbind('click', self.close);
11066 window.removeEventListener("keydown", handleKeyDown, true);
11067 translucentOverlay.destroy();
11068 self.emit('close');
11069 }
11070 });
11071
11072 overlay.find('.webxray-close-button').bind('click', self.close);
11073
11074 return self;
11075 }
11076
11077 jQuery.extend({
11078 normalizeStyleProperty: function normalizeStyleProperty(style, name) {
11079 var value = style.getPropertyValue(name);
11080
11081 if (name.match(/image$/) && value) {
11082 var urlMatch = value.match(/url\("?([^"]*)"?\)/);
11083
11084 if (urlMatch)
11085 value = urlMatch[1];
11086 }
11087 return value;
11088 },
11089 styleInfoOverlay: function styleInfoOverlay(options) {
11090 var focused = options.focused;
11091 var commandManager = options.commandManager;
11092 var locale = options.locale || jQuery.locale;
11093 var propertyNames = options.propertyNames;
11094 var mouseMonitor = options.mouseMonitor;
11095 var hud = options.hud;
11096 var body = options.body || document.body;
11097 var isVisible = false;
11098 var l10n = locale.scope("style-info");
11099 var modalOverlay = null;
11100
11101 var overlay = $('<div class="webxray-base webxray-style-info"></div>');
11102 $(body).append(overlay);
11103 overlay.hide();
11104
11105 focused.on('change', refresh);
11106
11107 function refresh() {
11108 if (!isVisible || modalOverlay)
11109 return;
11110
11111 var primary = focused.getPrimaryElement();
11112 overlay.empty();
11113
11114 if (primary) {
11115 var info = $(primary).getStyleInfo(propertyNames, locale, hud);
11116 var instructions = $('<div class="webxray-instructions"></div>');
11117 var close = $('<div class="webxray-close-button"></div>');
11118 instructions.html(l10n("tap-space-html"));
11119 close.text(locale.get("dialog-common:ok"));
11120 overlay.append(info).append(instructions).append(close);
11121 overlay.show();
11122 } else {
11123 overlay.hide();
11124 }
11125 }
11126
11127 function isMouseInOverlay() {
11128 var mouse = mouseMonitor.lastPosition;
11129 var pos = overlay.offset();
11130 var width = overlay.width();
11131 var height = overlay.height();
11132 var xDiff = mouse.pageX - pos.left;
11133 var yDiff = mouse.pageY - pos.top;
11134 var isInOverlay = (xDiff > 0 && xDiff < width) &&
11135 (yDiff > 0 && yDiff < height);
11136
11137 return isInOverlay;
11138 }
11139
11140 function maybeSwitchSides() {
11141 if (isMouseInOverlay())
11142 overlay.toggleClass('webxray-on-other-side');
11143 // The overlay switched sides; now see if we're in the
11144 // overlay on the other side.
11145 if (isMouseInOverlay())
11146 // We're on the overlay on the other side too, so we're
11147 // just going to annoy the user if we switch its side.
11148 // So, we'll restore the overlay to its original position.
11149 overlay.toggleClass('webxray-on-other-side');
11150 }
11151
11152 var self = jQuery.eventEmitter({
11153 isVisible: function() {
11154 return isVisible;
11155 },
11156 isLocked: function() {
11157 return (modalOverlay !== null);
11158 },
11159 setPropertyNames: function(newPropertyNames) {
11160 propertyNames = newPropertyNames;
11161 },
11162 lock: function(input) {
11163 var primary = focused.getPrimaryElement();
11164
11165 if (primary) {
11166 input.deactivate();
11167 mouseMonitor.removeListener('move', maybeSwitchSides);
11168 modalOverlay = ModalOverlay(overlay, primary, input);
11169 modalOverlay.on('change-style', function(style) {
11170 commandManager.run("ChangeAttributeCmd", {
11171 name: l10n("style-change"),
11172 attribute: "style",
11173 value: style,
11174 element: primary
11175 });
11176 });
11177 modalOverlay.on('close', function() {
11178 modalOverlay = null;
11179 self.hide();
11180 input.activate();
11181 self.emit('unlock');
11182 });
11183 focused.unfocus();
11184 self.emit('lock', {
11185 element: primary
11186 });
11187 }
11188 },
11189 show: function() {
11190 isVisible = true;
11191 overlay.show();
11192 refresh();
11193 mouseMonitor.on('move', maybeSwitchSides);
11194 maybeSwitchSides();
11195 self.emit('show');
11196 },
11197 hide: function() {
11198 mouseMonitor.removeListener('move', maybeSwitchSides);
11199 isVisible = false;
11200 overlay.hide();
11201 self.emit('hide');
11202 },
11203 destroy: function() {
11204 if (modalOverlay)
11205 modalOverlay.close();
11206 focused.removeListener('change', refresh);
11207 overlay.remove();
11208 }
11209 });
11210
11211 return self;
11212 }
11213 });
11214
11215 jQuery.fn.extend({
11216 getStyleInfo: function getStyleInfo(propertyNames, locale, hud) {
11217 var names = propertyNames || DEFAULT_PROPERTIES;
11218 var element = this.get(0);
11219 var window = element.ownerDocument.defaultView;
11220 var style = window.getComputedStyle(element);
11221 var parentStyle = null;
11222
11223 locale = locale || jQuery.locale;
11224 if (element.nodeName != "HTML")
11225 parentStyle = window.getComputedStyle(element.parentNode);
11226
11227 var info = $('<div class="webxray-rows"></div>');
11228 var NUM_COLS = 1;
11229
11230 for (var i = 0; i < names.length + (NUM_COLS-1); i += NUM_COLS) {
11231 var row = $('<div class="webxray-row"></div>');
11232 for (var j = 0; j < NUM_COLS; j++)
11233 buildPropertyWidget(element, row, style, parentStyle, names[i+j],
11234 locale, hud);
11235 info.append(row);
11236 }
11237
11238 return info;
11239 }
11240 });
11241})(jQuery);
11242(function(jQuery) {
11243 "use strict";
11244
11245 var $ = jQuery;
11246
11247 function NullTransitionEffectManager() {
11248 return {
11249 enableDuring: function enableDuring(fn) { fn(); }
11250 };
11251 }
11252
11253 function TransitionEffectManager(commandManager) {
11254 var isEnabled = false;
11255
11256 commandManager.on('command-created', function(cmd) {
11257 cmd.on('before-replace', function before(elementToReplace) {
11258 if (!isEnabled)
11259 return;
11260 var overlay = $(elementToReplace).overlay();
11261 cmd.on('after-replace', function after(newContent) {
11262 cmd.removeListener('after-replace', after);
11263 overlay.applyTagColor(newContent, 0.25)
11264 .resizeToAndFadeOut(newContent);
11265 });
11266 });
11267 });
11268
11269 return {
11270 enableDuring: function enableDuring(fn) {
11271 if (!isEnabled) {
11272 isEnabled = true;
11273 fn();
11274 isEnabled = false;
11275 } else
11276 fn();
11277 }
11278 };
11279 }
11280
11281 function MixMaster(options) {
11282 var hud = options.hud;
11283 var focused = options.focusedOverlay;
11284 var locale = options.locale || jQuery.locale;
11285 var commandManager = options.commandManager;
11286 var l10n = locale.scope('mix-master');
11287 var dialogPageMods = null;
11288 var transitionEffects;
11289
11290 if (options.disableTransitionEffects)
11291 transitionEffects = NullTransitionEffectManager();
11292 else
11293 transitionEffects = TransitionEffectManager(commandManager);
11294
11295 function updateStatus(verb, command) {
11296 var span = $('<span></span>');
11297 span.text(verb + ' ' + command.name + '.');
11298 $(hud.overlay).empty().append(span);
11299 }
11300
11301 function runCommand(name, options) {
11302 focused.unfocus();
11303 var command = commandManager.run(name, options);
11304 updateStatus(locale.get('command-manager:executed'), command);
11305 }
11306
11307 var self = {
11308 undo: function() {
11309 if (commandManager.canUndo()) {
11310 focused.unfocus();
11311 transitionEffects.enableDuring(function() {
11312 updateStatus(locale.get('command-manager:undid'),
11313 commandManager.undo());
11314 });
11315 } else {
11316 var msg = locale.get('command-manager:cannot-undo-html');
11317 $(hud.overlay).html(msg);
11318 }
11319 },
11320 redo: function() {
11321 if (commandManager.canRedo()) {
11322 focused.unfocus();
11323 transitionEffects.enableDuring(function() {
11324 updateStatus(locale.get('command-manager:redid'),
11325 commandManager.redo());
11326 });
11327 } else {
11328 var msg = locale.get('command-manager:cannot-redo-html');
11329 $(hud.overlay).html(msg);
11330 }
11331 },
11332 htmlToJQuery: function htmlToJQuery(html) {
11333 if (html == '' || typeof(html) != 'string')
11334 return $('<span></span>');
11335 if (html[0] != '<')
11336 html = '<span>' + html + '</span>';
11337 return $(html);
11338 },
11339 deleteFocusedElement: function deleteFocusedElement() {
11340 var elementToDelete = focused.getPrimaryElement();
11341 if (elementToDelete) {
11342 if ($(elementToDelete).is('html, body')) {
11343 var msg = l10n('too-big-to-change');
11344 jQuery.transparentMessage($('<div></div>').text(msg));
11345 return;
11346 }
11347 // Replacing the element with a zero-length invisible
11348 // span is a lot easier than actually deleting the element,
11349 // since it allows us to place a "bookmark" in the DOM
11350 // that can easily be undone if the user wishes.
11351 var placeholder = $('<span class="webxray-deleted"></span>');
11352 transitionEffects.enableDuring(function() {
11353 runCommand("ReplaceWithCmd", {
11354 name: l10n('deletion'),
11355 elementToReplace: elementToDelete,
11356 newContent: placeholder
11357 });
11358 });
11359 }
11360 },
11361 infoForFocusedElement: function infoForFocusedElement(open) {
11362 var element = focused.getPrimaryElement();
11363 open = open || window.open;
11364 if (element) {
11365 var url = 'https://developer.mozilla.org/en/HTML/Element/' +
11366 element.nodeName.toLowerCase();
11367 open(url, 'info');
11368 }
11369 },
11370 replaceElement: function(elementToReplace, html) {
11371 var newContent = self.htmlToJQuery(html);
11372 runCommand("ReplaceWithCmd", {
11373 name: l10n('replacement'),
11374 elementToReplace: elementToReplace,
11375 newContent: newContent
11376 });
11377 return newContent;
11378 },
11379 setDialogPageMods: function(mods) {
11380 dialogPageMods = mods;
11381 },
11382 replaceFocusedElementWithDialog: function(options) {
11383 var input = options.input;
11384 var dialogURL = options.dialogURL;
11385 var sendFullDocument = options.sendFullDocument;
11386 var MAX_HTML_LENGTH = 5000;
11387 var focusedElement = focused.getPrimaryElement();
11388 if (!focusedElement)
11389 return;
11390
11391 // We need to remove any script tags in the element now, or else
11392 // we'll likely re-execute them.
11393 $(focusedElement).find("script").remove();
11394
11395 var focusedHTML = $(focusedElement).outerHtml();
11396
11397 if ($(focusedElement).is('html, body')) {
11398 var msg = l10n("too-big-to-change");
11399 jQuery.transparentMessage($('<div></div>').text(msg));
11400 return;
11401 }
11402
11403 if (focusedHTML.length == 0 ||
11404 focusedHTML.length > MAX_HTML_LENGTH) {
11405 var tagName = focusedElement.nodeName.toLowerCase();
11406 var msg = l10n("too-big-to-remix-html").replace("${tagName}",
11407 tagName);
11408 jQuery.transparentMessage($(msg));
11409 return;
11410 }
11411
11412 if (sendFullDocument) {
11413 $(document).uprootIgnoringWebxray(function (html) {
11414 begin({
11415 html: html,
11416 selector: $(document.body).pathTo(focused.getPrimaryElement())
11417 });
11418 });
11419 } else
11420 begin(focusedHTML);
11421
11422 function begin(startHTML) {
11423 focused.unfocus();
11424 $(focusedElement).addClass('webxray-hidden');
11425
11426 jQuery.morphElementIntoDialog({
11427 input: input,
11428 body: options.body,
11429 url: dialogURL,
11430 element: focusedElement,
11431 onLoad: function(dialog) {
11432 dialog.iframe.postMessage(JSON.stringify({
11433 languages: jQuery.locale.languages,
11434 startHTML: startHTML,
11435 mods: dialogPageMods,
11436 baseURI: document.location.href
11437 }), "*");
11438 dialog.iframe.fadeIn();
11439 dialog.iframe.bind("message", function onMessage(event, data) {
11440 if (data && data.length && data[0] == '{') {
11441 var data = JSON.parse(data);
11442 if (data.msg == "ok") {
11443 // The dialog may have decided to replace all our spaces
11444 // with non-breaking ones, so we'll undo that.
11445 var html = data.endHTML.replace(/\u00a0/g, " ");
11446 var newContent = self.replaceElement(focusedElement, html);
11447
11448 newContent.addClass('webxray-hidden');
11449 $(focusedElement).removeClass('webxray-hidden');
11450 jQuery.morphDialogIntoElement({
11451 dialog: dialog,
11452 input: input,
11453 element: newContent,
11454 onDone: function() {
11455 newContent.reallyRemoveClass('webxray-hidden');
11456 }
11457 });
11458 } else {
11459 // TODO: Re-focus previously focused elements?
11460 $(focusedElement).reallyRemoveClass('webxray-hidden');
11461 dialog.close();
11462 }
11463 }
11464 });
11465 }
11466 });
11467 }
11468 }
11469 };
11470 return self;
11471 }
11472
11473 jQuery.extend({mixMaster: MixMaster});
11474})(jQuery);
11475(function(jQuery) {
11476 "use strict";
11477
11478 var $ = jQuery;
11479
11480 function CommandManager() {
11481 var undoStack = [];
11482 var redoStack = [];
11483
11484 function serializeCommand(cmd) {
11485 var state = cmd.serialize();
11486 state.__cmd__ = cmd.registeredName;
11487 return state;
11488 }
11489
11490 function createCommand(name, options) {
11491 var constructor = registry[name];
11492 var command = constructor(options);
11493 command.registeredName = name;
11494 self.emit('command-created', command);
11495 return command;
11496 }
11497
11498 function deserializeCommand(state) {
11499 // The fallback here is just for backwards compatibility
11500 // with old-style serializations.
11501 var name = state.__cmd__ || "ReplaceWithCmd";
11502 return createCommand(name, {state: state});
11503 }
11504
11505 var registry = {};
11506
11507 var self = jQuery.eventEmitter({
11508 register: function(constructor, name) {
11509 registry[name] = constructor;
11510 },
11511 run: function(name, options) {
11512 var command = createCommand(name, options);
11513 undoStack.push(command);
11514 redoStack.splice(0);
11515 command.execute();
11516 self.emit('state-change');
11517 return command;
11518 },
11519 canUndo: function() {
11520 return (undoStack.length > 0);
11521 },
11522 canRedo: function() {
11523 return (redoStack.length > 0);
11524 },
11525 undo: function() {
11526 var command = undoStack.pop();
11527 redoStack.push(command);
11528 command.undo();
11529 self.emit('state-change');
11530 return command;
11531 },
11532 redo: function() {
11533 var command = redoStack.pop();
11534 undoStack.push(command);
11535 command.execute();
11536 self.emit('state-change');
11537 return command;
11538 },
11539 getRecording: function() {
11540 var recording = [];
11541 var timesUndone = 0;
11542 while (undoStack.length) {
11543 var cmd = undoStack[undoStack.length - 1];
11544 self.undo();
11545 recording.splice(0, 0, serializeCommand(cmd));
11546 timesUndone++;
11547 }
11548 for (var i = 0; i < timesUndone; i++)
11549 self.redo();
11550 return JSON.stringify(recording);
11551 },
11552 playRecording: function(recording) {
11553 recording = JSON.parse(recording);
11554 undoStack.splice(0);
11555 redoStack.splice(0);
11556 for (var i = 0; i < recording.length; i++) {
11557 var cmd = deserializeCommand(recording[i]);
11558 undoStack.push(cmd);
11559 cmd.execute();
11560 }
11561 },
11562 serializeUndoStack: function() {
11563 var commands = [];
11564 var timesUndone = 0;
11565 while (undoStack.length) {
11566 var cmd = undoStack[undoStack.length - 1];
11567 commands.push(serializeCommand(cmd));
11568 self.undo();
11569 timesUndone++;
11570 }
11571 for (var i = 0; i < timesUndone; i++)
11572 self.redo();
11573 return JSON.stringify(commands);
11574 },
11575 deserializeUndoStack: function(commands) {
11576 commands = JSON.parse(commands);
11577 undoStack.splice(0);
11578 redoStack.splice(0);
11579 for (var i = 0; i < commands.length; i++) {
11580 var cmd = deserializeCommand(commands[i]);
11581 undoStack.push(cmd);
11582 self.undo();
11583 }
11584 for (var i = 0; i < commands.length; i++)
11585 self.redo();
11586 }
11587 });
11588
11589 self.register(ReplaceWithCmd, "ReplaceWithCmd");
11590 self.register(ChangeAttributeCmd, "ChangeAttributeCmd");
11591
11592 return self;
11593 }
11594
11595 function ChangeAttributeCmd(options) {
11596 var name = options.name,
11597 element = options.element,
11598 attribute = options.attribute,
11599 value = options.value;
11600
11601 function deserialize(state) {
11602 name = state.name;
11603 attribute = state.attribute;
11604 value = state.value;
11605 element = $(document.documentElement).find(state.selector);
11606 }
11607
11608 if (options.state)
11609 deserialize(options.state);
11610
11611 function applyValue() {
11612 this.emit('before-replace', element);
11613 var oldValue = $(element).attr(attribute);
11614 if (typeof(value) == 'undefined')
11615 $(element).removeAttr(attribute);
11616 else
11617 $(element).attr(attribute, value);
11618 value = oldValue;
11619 this.emit('after-replace', element);
11620 }
11621
11622 return jQuery.eventEmitter({
11623 name: name,
11624 execute: applyValue,
11625 undo: applyValue,
11626 serialize: function() {
11627 var selector = $(document.documentElement).pathTo(element);
11628
11629 return {
11630 name: name,
11631 selector: selector,
11632 attribute: attribute,
11633 value: value
11634 };
11635 }
11636 });
11637 }
11638
11639 function ReplaceWithCmd(options) {
11640 var name = options.name,
11641 elementToReplace = options.elementToReplace,
11642 newContent = options.newContent,
11643 isExecuted = false;
11644
11645 function deserialize(state) {
11646 if (typeof(state.isExecuted) == 'undefined')
11647 isExecuted = true; // support legacy serializations
11648 else
11649 isExecuted = state.isExecuted;
11650 name = state.name;
11651 if (isExecuted) {
11652 newContent = $(document.documentElement).find(state.selector);
11653 elementToReplace = $(state.html);
11654 if (newContent.length != 1)
11655 throw new Error("selector '" + state.selector + "' matches " +
11656 newContent.length + " elements");
11657 } else {
11658 newContent = $(state.html);
11659 elementToReplace = $(document.documentElement).find(state.selector);
11660 if (elementToReplace.length != 1)
11661 throw new Error("selector '" + state.selector + "' matches " +
11662 elementToReplace.length + " elements");
11663 }
11664 }
11665
11666 if (options.state)
11667 deserialize(options.state);
11668
11669 return jQuery.eventEmitter({
11670 name: name,
11671 execute: function() {
11672 if (isExecuted)
11673 throw new Error("command already executed");
11674 this.emit('before-replace', elementToReplace);
11675 $(elementToReplace).replaceWith(newContent);
11676 this.emit('after-replace', newContent);
11677 isExecuted = true;
11678 },
11679 undo: function() {
11680 if (!isExecuted)
11681 throw new Error("command not yet executed");
11682 this.emit('before-replace', newContent);
11683 $(newContent).replaceWith(elementToReplace);
11684 this.emit('after-replace', elementToReplace);
11685 isExecuted = false;
11686 },
11687 serialize: function() {
11688 var selector;
11689 var html;
11690 if (isExecuted) {
11691 selector = $(document.documentElement).pathTo(newContent);
11692 html = $(elementToReplace).outerHtml();
11693 } else {
11694 selector = $(document.documentElement).pathTo(elementToReplace);
11695 html = $(newContent).outerHtml();
11696 }
11697 return {
11698 isExecuted: isExecuted,
11699 name: name,
11700 selector: selector,
11701 html: html
11702 };
11703 }
11704 });
11705 }
11706
11707 jQuery.extend({commandManager: CommandManager});
11708})(jQuery);
11709(function(jQuery) {
11710 "use strict";
11711
11712 var $ = jQuery;
11713
11714 jQuery.extend({
11715 commandManagerPersistence: function CMPersistence(commandManager) {
11716 return {
11717 saveHistoryToDOM: function saveHistoryToDOM() {
11718 $('#webxray-serialized-history-v1').remove();
11719 var serializedHistory = $('<div></div>');
11720 serializedHistory.attr('id', 'webxray-serialized-history-v1')
11721 .text(commandManager.serializeUndoStack()).hide();
11722 $(document.body).append(serializedHistory);
11723 },
11724 loadHistoryFromDOM: function loadHistoryFromDOM() {
11725 var serializedHistory = $('#webxray-serialized-history-v1');
11726 if (serializedHistory.length)
11727 try {
11728 commandManager.deserializeUndoStack(serializedHistory.text());
11729 } catch (e) {
11730 jQuery.warn("deserialization of history in DOM failed", e);
11731 }
11732 }
11733 };
11734 }
11735 });
11736})(jQuery);
11737(function(jQuery) {
11738 "use strict";
11739
11740 var $ = jQuery;
11741
11742 jQuery.fn.extend({
11743 postMessage: function(message, targetOrigin) {
11744 if ((jQuery.browser.mozilla && typeof(self) == "object" &&
11745 self.port && self.port.emit) ||
11746 (typeof(chrome) == "object" && chrome.extension)) {
11747 // We're most likely in a Jetpack, and need to work around
11748 // bug 666547. Or, we're in a Chrome extension and are
11749 // stymied by http://stackoverflow.com/q/4062879.
11750
11751 if (!this.attr("id"))
11752 // Likelyhood of a naming collision here is very low,
11753 // and it's only a temporary workaround anyways.
11754 this.attr("id", "webxray-iframe-" + Math.random());
11755
11756 var script = document.createElement("script");
11757
11758 script.text = "(" + (function(id, message) {
11759 var iframe = document.getElementById(id);
11760 iframe.contentWindow.postMessage(message, "*");
11761 }).toString() + ")(" + JSON.stringify(this.attr("id")) + ", " +
11762 JSON.stringify(message) + ");";
11763
11764 document.body.appendChild(script);
11765 document.body.removeChild(script);
11766 } else
11767 this[0].contentWindow.postMessage(message, targetOrigin);
11768 }
11769 });
11770
11771 jQuery.extend({
11772 getModalDialogDimensions: function() {
11773 var div = $('<div class="webxray-base webxray-dialog-overlay">' +
11774 '<div class="webxray-base webxray-dialog-outer">' +
11775 '<div class="webxray-base webxray-dialog-middle">' +
11776 '<div class="webxray-base webxray-dialog-inner">' +
11777 '<div class="webxray-base webxray-dialog-content">' +
11778 '</div></div></div></div></div>');
11779 $(document.body).append(div);
11780
11781 var content = div.find('.webxray-dialog-content');
11782 var pos = content.offset();
11783 var dimensions = {
11784 top: pos.top,
11785 left: pos.left,
11786 width: content.outerWidth(),
11787 height: content.outerHeight()
11788 };
11789
11790 div.remove();
11791 return dimensions;
11792 },
11793 simpleModalDialog: function(options) {
11794 var dialog = jQuery.modalDialog({
11795 input: options.input,
11796 url: options.url
11797 });
11798 dialog.iframe.one("load", function() {
11799 $(this).postMessage(options.payload, "*");
11800 $(this).show().bind("message", function(event, data) {
11801 if (data == "close")
11802 dialog.close();
11803 });
11804 });
11805 return dialog;
11806 },
11807 modalDialog: function(options) {
11808 var input = options.input;
11809 var body = options.body || document.body;
11810 var url = options.url;
11811 var div = $('<div class="webxray-base webxray-dialog-overlay">' +
11812 '<div class="webxray-base webxray-dialog-outer">' +
11813 '<div class="webxray-base webxray-dialog-middle">' +
11814 '<div class="webxray-base webxray-dialog-inner">' +
11815 '<iframe class="webxray-base" src="' + url + '"></iframe>' +
11816 '</div></div></div></div>');
11817 var iframe = div.find("iframe");
11818
11819 function onMessage(event) {
11820 if (event.source == self.iframe.get(0).contentWindow) {
11821 iframe.trigger("message", [event.data]);
11822 }
11823 }
11824
11825 window.addEventListener("message", onMessage, false);
11826 iframe.hide();
11827
11828 var self = {
11829 iframe: iframe,
11830 close: function close(cb) {
11831 div.fadeOut(function() {
11832 window.removeEventListener("message", onMessage, false);
11833 div.remove();
11834 div = null;
11835
11836 // Firefox seems to trigger a mouseout/mouseover event
11837 // when we remove the dialog div, so we'll wait a moment
11838 // before re-activating input so that we don't distract
11839 // the user by focusing on whatever their mouse happens
11840 // to be over when the dialog closes.
11841 setTimeout(function() {
11842 input.activate();
11843 input = null;
11844 window.focus();
11845 if (cb)
11846 cb();
11847 }, 50);
11848 });
11849 }
11850 };
11851
11852 input.deactivate();
11853 $(body).append(div);
11854
11855 return self;
11856 },
11857 morphElementIntoDialog: function(options) {
11858 var input = options.input;
11859 var element = options.element;
11860 var body = options.body || document.body;
11861 var url = options.url;
11862 var overlay = $(element).overlayWithTagColor(1.0);
11863 var backdrop = $('<div class="webxray-base webxray-dialog-overlay">' +
11864 '</div>');
11865
11866 // Closing the dialog we make later will re-activate this for us.
11867 input.deactivate();
11868
11869 $(body).append(backdrop);
11870 overlay.addClass('webxray-topmost');
11871 overlay.animate(jQuery.getModalDialogDimensions(), function() {
11872 var dialog = jQuery.modalDialog({
11873 input: input,
11874 body: body,
11875 url: url
11876 });
11877
11878 backdrop.remove();
11879
11880 dialog.iframe.one("load", function onLoad() {
11881 overlay.fadeOut(function() {
11882 overlay.remove();
11883 options.onLoad(dialog);
11884 });
11885 });
11886 });
11887 },
11888 morphDialogIntoElement: function(options) {
11889 var element = options.element;
11890 var dialog = options.dialog;
11891 var input = options.input;
11892 var overlay = dialog.iframe.overlay();
11893
11894 overlay.applyTagColor(element, 1.0);
11895 overlay.hide();
11896 overlay.fadeIn(function() {
11897 dialog.close(function() {
11898 // input was just re-activated when the dialog closed, but
11899 // we want to deactivate it again because we're not actually
11900 // done with our transition.
11901 input.deactivate();
11902 overlay.resizeTo(element, function() {
11903 $(this).fadeOut(function() {
11904 $(this).remove();
11905 input.activate();
11906 });
11907 options.onDone();
11908 });
11909 });
11910 });
11911 }
11912 });
11913})(jQuery);
11914(function(jQuery) {
11915 "use strict";
11916
11917 var $ = jQuery;
11918
11919 var keys = {
11920 DELETE: 8,
11921 LEFT: 37,
11922 UP: 38,
11923 RIGHT: 39,
11924 DOWN: 40,
11925 ESC: 27,
11926 SPACE: 32
11927 };
11928
11929 var alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
11930
11931 for (var i = 0; i < alphabet.length; i++)
11932 keys[alphabet[i]] = alphabet.charCodeAt(i);
11933
11934 function isValidFocusTarget(target) {
11935 return (!$(target).hasClass('webxray-base'));
11936 }
11937
11938 // This function attempts to compensate for a browser's lack of support
11939 // for the 'pointer-events' CSS feature.
11940 var maybePassThroughEvent = (function() {
11941 function topmostNoPointerEvents(element) {
11942 var topmost = null;
11943 while (element &&
11944 getComputedStyle(element).pointerEvents == 'none') {
11945 topmost = element;
11946 element = element.parentNode;
11947 }
11948 return topmost;
11949 }
11950
11951 // Annoying that we have to do browser detection here, but unfortunately
11952 // we can't simply test for support of the 'pointer-events' CSS feature,
11953 // as Opera and IE9 support it but only for SVG.
11954 if (jQuery.browser.opera || jQuery.browser.msie)
11955 return function(event) {
11956 if (topmostNoPointerEvents(event.relatedTarget))
11957 return null;
11958
11959 var target = topmostNoPointerEvents(event.target);
11960
11961 if (target) {
11962 $(target).hide();
11963 event = {
11964 target: document.elementFromPoint(event.clientX, event.clientY)
11965 };
11966 $(target).show();
11967 }
11968 return event;
11969 }
11970 else
11971 return function(event) { return event; };
11972 })();
11973
11974 function styleOverlayInputHandlers(options) {
11975 var styleInfo = options.styleInfoOverlay;
11976 var quasimodeKeycode = keys[options.quasimodeKey];
11977 var lockForEditingKeycode = keys[options.lockForEditingKey];
11978 var isQuasimodeActive = false;
11979
11980 return {
11981 keyup: function(event) {
11982 if (event.keyCode == quasimodeKeycode) {
11983 isQuasimodeActive = false;
11984 styleInfo.hide();
11985 return true;
11986 }
11987 return false;
11988 },
11989 keydown: function(event) {
11990 if (event.altKey || event.ctrlKey ||
11991 event.altGraphKey || event.metaKey) {
11992 return false;
11993 }
11994
11995 switch (event.keyCode) {
11996 case lockForEditingKeycode:
11997 if (isQuasimodeActive) {
11998 isQuasimodeActive = false;
11999 styleInfo.lock(this);
12000 }
12001 return true;
12002
12003 case quasimodeKeycode:
12004 if (!isQuasimodeActive) {
12005 isQuasimodeActive = true;
12006 styleInfo.show();
12007 }
12008 return true;
12009 }
12010 return false;
12011 }
12012 };
12013 }
12014
12015 function touchInputHandlers(focused) {
12016 var lastTouch = null;
12017
12018 function onTouchMove(event) {
12019 var touches = event.changedTouches;
12020 var touch = touches[0];
12021 var element = document.elementFromPoint(touch.clientX,
12022 touch.clientY);
12023
12024 if (element == lastTouch)
12025 return false;
12026 lastTouch = element;
12027
12028 if (!isValidFocusTarget(element))
12029 return false;
12030
12031 if (isValidFocusTarget(element))
12032 focused.set(element);
12033 }
12034
12035 return {
12036 touchstart: onTouchMove,
12037 touchmove: onTouchMove,
12038 touchend: function(event) {
12039 lastTouch = null;
12040 }
12041 };
12042 }
12043
12044 jQuery.extend({
12045 keys: keys,
12046 mouseMonitor: function mouseMonitor() {
12047 function onMouseMove(event) {
12048 self.lastPosition.pageX = event.pageX;
12049 self.lastPosition.pageY = event.pageY;
12050 self.emit('move', self);
12051 }
12052 $(document).mousemove(onMouseMove);
12053
12054 var self = jQuery.eventEmitter({
12055 lastPosition: {
12056 pageX: 0,
12057 pageY: 0
12058 },
12059 unload: function() {
12060 $(document).unbind('mousemove', onMouseMove);
12061 self.removeAllListeners();
12062 }
12063 });
12064
12065 return self;
12066 },
12067 inputHandlerChain: function inputHandlerChain(eventTypes, eventSource) {
12068 var handlerChains = {};
12069 var listeners = {};
12070
12071 function eventListener(event) {
12072 for (var i = 0; i < handlerChains[event.type].length; i++) {
12073 if (handlerChains[event.type][i].call(this, event)) {
12074 event.preventDefault();
12075 event.stopPropagation();
12076 return;
12077 }
12078 }
12079 }
12080
12081 eventTypes.forEach(function(eventName) {
12082 handlerChains[eventName] = [];
12083 listeners[eventName] = eventListener;
12084 });
12085
12086 var self = jQuery.inputManager(listeners, eventSource).extend({
12087 add: function(handlers) {
12088 for (var name in handlers)
12089 handlerChains[name].push(handlers[name]);
12090 }
12091 });
12092
12093 return self;
12094 },
12095 inputManager: function inputManager(listeners, eventSource) {
12096 var isActive = false;
12097
12098 var self = jQuery.eventEmitter({
12099 extend: jQuery.extend,
12100 handleEvent: function handleEvent(event) {
12101 if (event.type in listeners)
12102 listeners[event.type].call(self, event);
12103 else
12104 throw new Error("Unexpected event type: " + event.type);
12105 },
12106 activate: function() {
12107 // We're listening during the capture phase to intercept
12108 // any events at the earliest point before they're
12109 // handled by the page itself. Because JQuery's bind() doesn't
12110 // appear to allow for listening during the capture phase,
12111 // we're using document.addEventListener() directly.
12112 if (!isActive) {
12113 isActive = true;
12114 for (var name in listeners)
12115 eventSource.addEventListener(name, self.handleEvent, true);
12116 self.emit('activate');
12117 }
12118 },
12119 deactivate: function() {
12120 if (isActive) {
12121 isActive = false;
12122 for (var name in listeners)
12123 eventSource.removeEventListener(name, self.handleEvent, true);
12124 self.emit('deactivate');
12125 }
12126 }
12127 });
12128
12129 return self;
12130 },
12131 simpleKeyBindings: function simpleKeyBindings() {
12132 var bindings = {};
12133 return {
12134 set: function(keycodes) {
12135 for (var keycode in keycodes) {
12136 if (!(keycode in keys))
12137 throw new Error('unknown key: ' + keycode);
12138 bindings[keys[keycode]] = keycodes[keycode];
12139 }
12140 },
12141 handlers: {
12142 keydown: function(event) {
12143 if (event.altKey || event.ctrlKey ||
12144 event.altGraphKey || event.metaKey)
12145 return false;
12146
12147 if (typeof(bindings[event.keyCode]) == 'function') {
12148 bindings[event.keyCode].call(this, event);
12149 return true;
12150 }
12151 return false;
12152 }
12153 }
12154 };
12155 },
12156 xRayInput: function xRayInput(options) {
12157 var focused = options.focusedOverlay;
12158 var mixMaster = options.mixMaster;
12159 var commandManager = options.commandManager;
12160 var eventSource = options.eventSource;
12161 var onQuit = options.onQuit;
12162 var persistence = options.persistence;
12163 var styleInfo = options.styleInfoOverlay;
12164 var touchesReceived = false;
12165 var self = jQuery.inputHandlerChain([
12166 'keydown',
12167 'keyup',
12168 'click',
12169 'mouseout',
12170 'mouseover',
12171 'touchstart',
12172 'touchmove',
12173 'touchend'
12174 ], eventSource);
12175
12176 self.add({
12177 click: function(event) {
12178 if (isValidFocusTarget(event.target)) {
12179 self.commandBindings['remix'].execute();
12180 return true;
12181 }
12182 },
12183 touchmove: function(event) {
12184 touchesReceived = true;
12185 return false;
12186 },
12187 mouseout: function(event) {
12188 if (touchesReceived)
12189 // We're likely on a tablet, so this is probably a simulated
12190 // mouse event that we want to ignore.
12191 return false;
12192 if ((event = maybePassThroughEvent(event)) == null)
12193 return false;
12194
12195 if (isValidFocusTarget(event.target)) {
12196 focused.unfocus();
12197 return true;
12198 }
12199 },
12200 mouseover: function(event) {
12201 if (touchesReceived)
12202 // We're likely on a tablet, so this is probably a simulated
12203 // mouse event that we want to ignore.
12204 return false;
12205 if ((event = maybePassThroughEvent(event)) == null)
12206 return false;
12207
12208 if (isValidFocusTarget(event.target)) {
12209 focused.set(event.target);
12210 return true;
12211 }
12212 }
12213 });
12214
12215 self.extend({
12216 simpleKeyBindings: jQuery.simpleKeyBindings(),
12217 keyboardHelp: [],
12218 commandBindings: {},
12219 showKeyboardHelp: function() {
12220 var help = jQuery.createKeyboardHelpReference(self.keyboardHelp);
12221 jQuery.transparentMessage(help);
12222 },
12223 addSimpleKeyBindings: function(bindings) {
12224 bindings.forEach(function(binding) {
12225 if (binding.cmd) {
12226 self.keyboardHelp.push(binding);
12227 self.commandBindings[binding.cmd] = binding;
12228 }
12229 if (binding.execute) {
12230 var simpleBinding = {};
12231 simpleBinding[binding.key] = binding.execute;
12232 self.simpleKeyBindings.set(simpleBinding);
12233 }
12234 });
12235 }
12236 });
12237
12238 self.addSimpleKeyBindings([
12239 {
12240 key: 'H',
12241 cmd: 'help',
12242 execute: function() {
12243 self.showKeyboardHelp();
12244 }
12245 },
12246 {
12247 key: 'ESC',
12248 cmd: 'quit',
12249 alwaysInToolbar: true,
12250 execute: function() {
12251 if (onQuit) onQuit();
12252 }
12253 },
12254 {
12255 key: 'R',
12256 cmd: 'remix',
12257 execute: function() {
12258 mixMaster.replaceFocusedElementWithDialog({
12259 input: self,
12260 dialogURL: jQuery.webxraySettings.url("easyRemixDialogURL"),
12261 sendFullDocument: true
12262 });
12263 }
12264 },
12265 {
12266 key: 'C',
12267 cmd: 'css-quasimode'
12268 },
12269 {
12270 key: 'DELETE',
12271 cmd: 'remove',
12272 execute: function() {
12273 mixMaster.deleteFocusedElement();
12274 }
12275 },
12276 {
12277 key: 'LEFT',
12278 cmd: 'undo',
12279 alwaysInToolbar: true,
12280 execute: function() { mixMaster.undo(); }
12281 },
12282 {
12283 key: 'RIGHT',
12284 cmd: 'redo',
12285 alwaysInToolbar: true,
12286 execute: function() { mixMaster.redo(); }
12287 },
12288 {
12289 key: 'UP',
12290 cmd: 'dom-ascend',
12291 execute: function() { focused.upfocus(); }
12292 },
12293 {
12294 key: 'DOWN',
12295 cmd: 'dom-descend',
12296 execute: function() {
12297 focused.downfocus();
12298 }
12299 },
12300 {
12301 key: 'B',
12302 cmd: 'bug-report',
12303 alwaysInToolbar: true,
12304 execute: function() {
12305 jQuery.openBugReportDialog(self);
12306 }
12307 },
12308 {
12309 key: 'P',
12310 cmd: 'uproot',
12311 alwaysInToolbar: true,
12312 execute: function() {
12313 persistence.saveHistoryToDOM();
12314 jQuery.openUprootDialog(self);
12315 }
12316 },
12317 {
12318 key: 'I',
12319 execute: function() {
12320 mixMaster.infoForFocusedElement();
12321 }
12322 }
12323 ]);
12324
12325 self.add(self.simpleKeyBindings.handlers);
12326 self.add(touchInputHandlers(focused));
12327 self.add(styleOverlayInputHandlers({
12328 styleInfoOverlay: styleInfo,
12329 lockForEditingKey: 'SPACE',
12330 quasimodeKey: 'C'
12331 }));
12332
12333 return self;
12334 }
12335 });
12336})(jQuery);
12337(function(jQuery) {
12338 "use strict";
12339
12340 var $ = jQuery;
12341
12342 function canBeTouched() {
12343 return ('ontouchstart' in window);
12344 }
12345
12346 function makeButton(glyph, text, cb) {
12347 var button = $(
12348 '<div class="webxray-toolbar-button">' +
12349 '<div class="webxray-toolbar-button-glyph"></div>' +
12350 '<div class="webxray-toolbar-button-text"></div>' +
12351 '</div>'
12352 );
12353 var glyphDiv = $('.webxray-toolbar-button-glyph', button);
12354 glyphDiv.text(glyph);
12355 if (glyph.length != 1)
12356 glyphDiv.addClass('webxray-toolbar-button-glyph-tiny');
12357 $('.webxray-toolbar-button-text', button).text(text);
12358 button.find('*').andSelf().addClass('webxray-base');
12359 button.bind('touchstart touchmove click', function(event) {
12360 event.preventDefault();
12361 cb.call(this);
12362 });
12363 return button;
12364 }
12365
12366 jQuery.extend({
12367 touchToolbar: function(input, locale, platform) {
12368 locale = locale || jQuery.locale;
12369 platform = platform || navigator.platform;
12370
12371 var toolbar = $('<div class="webxray-base webxray-toolbar"></div>');
12372 var keyNames = locale.scope('key-names');
12373 var shortDescriptions = locale.scope('short-command-descriptions');
12374
12375 input.keyboardHelp.forEach(function(binding) {
12376 if (binding.execute && (canBeTouched() || binding.alwaysInToolbar))
12377 makeButton(jQuery.nameForKey(binding.key, locale, platform),
12378 shortDescriptions(binding.cmd), function() {
12379 binding.execute();
12380 }).appendTo(toolbar);
12381 });
12382
12383 toolbar.appendTo(document.body);
12384 input.on('activate', function() { toolbar.fadeIn(); });
12385 input.on('deactivate', function() { toolbar.fadeOut(); });
12386
12387 return {
12388 unload: function() {
12389 toolbar.remove();
12390 toolbar = null;
12391 }
12392 };
12393 }
12394 });
12395})(jQuery);
12396(function(jQuery) {
12397 "use strict";
12398
12399 var $ = jQuery;
12400
12401 jQuery.extend({
12402 blurIndicator: function(input, focusable, body) {
12403 body = body || document.body;
12404
12405 function showBlurIndicator() {
12406 var blurIndicator = $('<div class="webxray-base ' +
12407 'webxray-dialog-overlay"></div>');
12408 $(body).append(blurIndicator);
12409 $(focusable).one('focus', function() {
12410 // If we wait a moment before removing the indicator, it'll receive
12411 // any click events instead of elements underneath it. We can
12412 // safely assume that any click events made immediately after
12413 // focus are really just intended to focus the page rather
12414 // than click on a specific element, so we want to swallow
12415 // such events rather than e.g. take the user to a new page.
12416 setTimeout(function() {
12417 blurIndicator.remove();
12418 blurIndicator = null;
12419 }, 10);
12420 input.activate();
12421 });
12422 input.deactivate();
12423 }
12424
12425 input.on('activate', function() {
12426 $(focusable).bind('blur', showBlurIndicator);
12427 });
12428 input.on('deactivate', function() {
12429 $(focusable).unbind('blur', showBlurIndicator);
12430 });
12431 }
12432 });
12433})(jQuery);
12434(function(jQuery) {
12435 "use strict";
12436
12437 var $ = jQuery;
12438
12439 function addHelpButton(hud, input) {
12440 var help = $('<div class="webxray-base webxray-help">?</div>');
12441 help.click(input.showKeyboardHelp);
12442 $(hud.overlayContainer).append(help);
12443 }
12444
12445 // If the user has made changes to the page, we don't want them
12446 // to be able to navigate away from it without facing a modal
12447 // dialog.
12448 function ModalUnloadBlocker(commandManager) {
12449 function beforeUnload(event) {
12450 if (commandManager.canUndo()) {
12451 event.preventDefault();
12452 return jQuery.locale.get("input:unload-blocked");
12453 }
12454 }
12455
12456 window.addEventListener("beforeunload", beforeUnload, true);
12457
12458 return {
12459 unload: function() {
12460 window.removeEventListener("beforeunload", beforeUnload, true);
12461 }
12462 };
12463 }
12464
12465 jQuery.extend({
12466 xRayUI: function xRayUI(options) {
12467 var isUnloaded = false;
12468 var hud = jQuery.hudOverlay();
12469 var focused = jQuery.focusedOverlay({
12470 useAnimation: true
12471 });
12472 var commandManager = jQuery.commandManager();
12473 var mixMaster = jQuery.mixMaster({
12474 hud: hud,
12475 focusedOverlay: focused,
12476 commandManager: commandManager
12477 });
12478 var persistence = jQuery.commandManagerPersistence(commandManager);
12479 var mouseMonitor = jQuery.mouseMonitor();
12480 var styleInfo = jQuery.styleInfoOverlay({
12481 focused: focused,
12482 commandManager: commandManager,
12483 mouseMonitor: mouseMonitor,
12484 hud: hud
12485 });
12486 var input = jQuery.xRayInput({
12487 focusedOverlay: focused,
12488 styleInfoOverlay: styleInfo,
12489 mixMaster: mixMaster,
12490 commandManager: commandManager,
12491 persistence: persistence,
12492 eventSource: options.eventSource,
12493 onQuit: function() {
12494 self.emit('quit');
12495 }
12496 });
12497 var touchToolbar = jQuery.touchToolbar(input);
12498 var indicator = jQuery.blurIndicator(input, window);
12499 var modalUnloadBlocker = ModalUnloadBlocker(commandManager);
12500
12501 var self = jQuery.eventEmitter({
12502 persistence: persistence,
12503 start: function() {
12504 persistence.loadHistoryFromDOM();
12505 addHelpButton(hud, input);
12506 $(document.body).append(hud.overlayContainer);
12507 focused.on('change', hud.onFocusChange);
12508 input.activate();
12509 $(window).focus();
12510 },
12511 unload: function() {
12512 if (!isUnloaded) {
12513 isUnloaded = true;
12514 focused.destroy();
12515 focused = null;
12516 input.deactivate();
12517 input = null;
12518 touchToolbar.unload();
12519 touchToolbar = null;
12520 hud.destroy();
12521 hud = null;
12522 styleInfo.destroy();
12523 styleInfo = null;
12524 indicator = null;
12525 mouseMonitor.unload();
12526 mouseMonitor = null;
12527 modalUnloadBlocker.unload();
12528 modalUnloadBlocker = null;
12529 }
12530 },
12531
12532 // These exports are primarily for use by third-party code.
12533 jQuery: jQuery,
12534 focusedOverlay: focused,
12535 hudOverlay: hud,
12536 mixMaster: mixMaster,
12537 styleInfoOverlay: styleInfo,
12538 commandManager: commandManager,
12539 input: input,
12540 modalUnloadBlocker: modalUnloadBlocker
12541 });
12542
12543 return self;
12544 }
12545 });
12546})(jQuery);(function(jQuery) {
12547 "use strict";
12548
12549 var $ = jQuery;
12550 var removeOnUnload = $();
12551
12552 function getMyScript() {
12553 return $('script.webxray, script[src$="webxray.js"]');
12554 }
12555
12556 // If the goggles are already active on this page, just exit.
12557 if ($("#webxray-is-active").length) {
12558 getMyScript().remove();
12559 return;
12560 }
12561
12562 function waitForCSSToLoad() {
12563 // Sadly, link elements don't fire load events on most/all browsers,
12564 // so we'll define a special style in our stylesheet and keep
12565 // polling an element with that style until it has what we've
12566 // defined in the stylesheet.
12567 var div = $('<div id="webxray-wait-for-css-to-load"></div>');
12568 var deferred = jQuery.Deferred();
12569
12570 div.hide();
12571 $(document.body).append(div);
12572
12573 function checkIfLoaded() {
12574 // This works on most browsers.
12575 var content = div.css('content');
12576
12577 // This works on Safari.
12578 var bgColor = div.css('background-color');
12579
12580 if ((content && content.match(/CSS\ is\ loaded/)) ||
12581 (bgColor && bgColor.match(/rgb\(0,\s*1,\s*2\)/))) {
12582 div.remove();
12583 clearInterval(intervalID);
12584 deferred.resolve();
12585 }
12586 }
12587
12588 var intervalID = setInterval(checkIfLoaded, 10);
12589 checkIfLoaded();
12590 return deferred;
12591 }
12592
12593 function waitForPreferencesToLoad() {
12594 var deferred = jQuery.Deferred();
12595
12596 var iframe = document.createElement('iframe');
12597 iframe.src = jQuery.webxraySettings.url('preferencesURL');
12598 $(document.body).append(iframe);
12599 $(iframe).hide();
12600 window.addEventListener('message', function onMessage(event) {
12601 if (event.source == iframe.contentWindow) {
12602 window.removeEventListener('message', onMessage, false);
12603 $(iframe).remove();
12604 try {
12605 var prefs = JSON.parse(event.data);
12606 jQuery.webxraySettings.extend(prefs);
12607 } catch (e) {
12608 jQuery.warn("loading preferences failed");
12609 jQuery.warn("preference data is", event.data);
12610 jQuery.warn("exception thrown is", e);
12611 }
12612 deferred.resolve();
12613 }
12614 }, false);
12615 return deferred;
12616 }
12617
12618 function loadPrerequisites(cb) {
12619 var script = getMyScript();
12620
12621 if (jQuery.webxraySettings.baseURI.length == 0) {
12622 var baseURI = script.attr("src").match(/(.*)webxray\.js$/)[1];
12623 jQuery.webxraySettings.baseURI = baseURI;
12624 }
12625
12626 var cssURL = jQuery.webxraySettings.url("cssURL");
12627 var cssLink = $('link[href="' + cssURL + '"]');
12628 var active = $('<div id="webxray-is-active"></div>');
12629
12630 script.remove();
12631 active.hide();
12632 $(document.body).append(active);
12633
12634 // This is a test to see if we're using legacy bookmarklet code,
12635 // which inserts the link tag itself.
12636 if (cssLink.length == 0) {
12637 cssLink = $('<link rel="stylesheet" class="webxray"></link>');
12638 $(document.head).append(cssLink.attr("href", cssURL));
12639 }
12640
12641 removeOnUnload = removeOnUnload.add([cssLink.get(0), active.get(0)]);
12642
12643 var cssLoaded = waitForCSSToLoad();
12644 var prefsLoaded = waitForPreferencesToLoad();
12645
12646 jQuery.when(prefsLoaded, cssLoaded).done(cb);
12647 }
12648
12649 function loadPlugins(cb) {
12650 var pluginsToLoad = [];
12651
12652 jQuery.webxraySettings.url("pluginURLs").forEach(function(plugin) {
12653 pluginsToLoad.push(jQuery.loadScript(plugin));
12654 });
12655 jQuery.when.apply(jQuery.when, pluginsToLoad).done(cb);
12656 }
12657
12658 jQuery.extend({webxrayBuildMetadata: buildMetadata});
12659
12660 $(window).ready(function() {
12661 if (typeof(console) != 'undefined') {
12662 console.log("Initializing Web X-Ray Goggles built on " +
12663 buildMetadata.date + " (commit " +
12664 buildMetadata.commit + ").");
12665 }
12666
12667 loadPrerequisites(function() {
12668 jQuery.localization.init(["en", jQuery.webxraySettings.language]);
12669
12670 var ui = jQuery.xRayUI({eventSource: document});
12671
12672 window.webxrayUI = ui;
12673 loadPlugins(function() {
12674 var welcomeMsg = $("<div></div>");
12675 welcomeMsg.html(jQuery.locale.get("hud-overlay:default-html"));
12676 jQuery.transparentMessage(welcomeMsg);
12677
12678 ui.start();
12679 Webxray.triggerWhenLoaded(ui);
12680 ui.on('quit', function() {
12681 ui.persistence.saveHistoryToDOM();
12682 $(document).trigger('unload');
12683 delete window.webxrayUI;
12684 });
12685 $(document).unload(function() {
12686 ui.unload();
12687 removeOnUnload.remove();
12688 });
12689 });
12690 });
12691 });
12692})(jQuery);
12693// Make sure we don't conflict in any way with our parent window.
12694jQuery.noConflict(true);
12695})(window);