· 6 years ago · Mar 12, 2019, 08:06 PM
1
2// Add global variable to the window to allow goggles to work on
3// website that have requirejs integrated in
4window.__LOCALIZED_IGNORE_REQUIREJS = true;
5(function(global, ignoreRequireJS, factory) {
6 // AMD. Register as an anonymous module. Also deal with the case
7 // that we've been told to force localized on the global (e.g.,
8 // in cases where require.js might exist in a page and we want to
9 // ignore it and use the global instead).
10 if (typeof define === 'function' &&
11 define.amd &&
12 !ignoreRequireJS) {
13 define(factory);
14 }
15 // Expose a global instead
16 else {
17 global.Localized = factory();
18 }
19}(this, this.__LOCALIZED_IGNORE_REQUIREJS, function() {
20
21 var _strings,
22 _readyCallbacks = [],
23 _requestedStrings = false;
24
25 function fireReadyCallbacks() {
26 // Fire all ready callbacks we have queued up.
27 while(_readyCallbacks.length) {
28 (_readyCallbacks.pop())();
29 }
30 }
31
32 function ready(data) {
33 function domReady() {
34 // If the DOM isn't ready yet, repeat when it is
35 if ( document.readyState !== "complete" ) {
36 document.onreadystatechange = domReady;
37 return;
38 }
39 document.onreadystatechange = null;
40 _strings = data;
41
42 fireReadyCallbacks();
43 }
44
45 domReady();
46 }
47
48 // Get the current lang from the document's HTML element, which the
49 // server set when the page was first rendered. This saves us having
50 // to pass extra locale info around on the URL.
51 function getCurrentLang() {
52 var html = document.querySelector( "html" );
53 return html && html.lang ? html.lang : "en-US";
54 }
55
56 return {
57 /**
58 * gets the localized string for a given key
59 */
60 get: function(key) {
61 if ( !_strings ) {
62 console.error( "[webmaker-i18n] Error: string catalog not found." );
63 return "";
64 }
65 return ( _strings[ key ] || "" );
66 },
67
68 /**
69 * Convert the given language name into Moment.js supported Language name
70 *
71 * lang: 'en-US' return: 'en'
72 * lang: 'en-CA' return: 'en-ca'
73 * lang: 'th-TH' return: 'th'
74 **/
75 langToMomentJSLang: function(lang) {
76 /* The list of moment.js supported languages
77 * Extracted from http://momentjs.com/downloads/moment-with-langs.js
78 */
79 var momentLangMap = ['en', 'ar-ma', 'ar', 'bg', 'br', 'bs', 'ca',
80 'cs', 'cv', 'cy', 'da', 'de', 'el',
81 'en-au', 'en-ca', 'en-gb', 'eo', 'es',
82 'et', 'eu', 'fa', 'fi', 'fo', 'fr-ca',
83 'fr', 'gl', 'he', 'hi', 'hr', 'hu', 'id',
84 'is', 'it', 'ja', 'ka', 'ko', "lt", 'lv',
85 'ml', 'mr', 'ms-my', 'nb', 'ne', 'nl', 'nn',
86 'pl', 'pt-br', 'pt', 'ro', 'ru', 'sk', 'sl',
87 'sq', 'sv', 'th', 'tl-ph', 'tr', 'tzm-la',
88 'tzm', 'uk', 'uz', 'vn', 'zh-cn', 'zh-tw'];
89
90 lang = lang.toLowerCase();
91 var newLang = lang.substr(0,2);
92 if (momentLangMap.indexOf(lang) !== -1) {
93 return lang;
94 } else if (momentLangMap.indexOf(newLang) !== -1) {
95 return newLang;
96 }
97 return 'en';
98 },
99
100 /**
101 * gets the current lang used for the given page, or en-US by default.
102 */
103 getCurrentLang: getCurrentLang,
104
105 /**
106 * initializes the strings locally (i.e., downloads if not already downloaded) and
107 * queues a callback to be fired when the DOM + strings are ready. It is safe to
108 * call ready() multiple times. For cache busting, pass noCache=true on the options arg.
109 */
110 ready: function(options, callback) {
111 var _callback;
112
113 // Allow calling ready with or without options.
114 if (typeof options === 'function') {
115 _callback = options;
116 options = {};
117 } else {
118 _callback = callback || function(){};
119 }
120
121 var noCache = !!options.noCache,
122 url = options.url || '/strings';
123
124 // If given an absolute url (starting in http), we don't process it.
125 // Otherwise we fix it up to include the current lang from <html lang="...">
126 if (url.indexOf( 'http' ) !== 0) {
127 url = url.replace(/^\/?/, '/').replace(/\/?$/, '/');
128 url = url + getCurrentLang();
129 }
130
131 // Add cache busting if requested.
132 url = url + (noCache ? '?bust=' + Date.now() : '');
133
134 if (!_requestedStrings) {
135 _requestedStrings = true;
136 _readyCallbacks.push(_callback);
137
138 var xhr = new XMLHttpRequest();
139 xhr.open('GET', url, true);
140 xhr.onreadystatechange = function(){
141 if (this.readyState !== 4) {
142 return;
143 }
144
145 if (xhr.status !== 200) {
146 console.error("Localized Error: HTTP error " + xhr.status);
147 return;
148 }
149
150 try {
151 ready(JSON.parse(this.responseText));
152 } catch (err) {
153 console.error("Localized Error: " + err);
154 }
155 };
156 xhr.send(null);
157 }
158
159 if (this.isReady()) {
160 fireReadyCallbacks();
161 }
162 },
163
164 /**
165 * returns true if the localized strings have been loaded and can be used.
166 */
167 isReady: function() {
168 return !!_strings;
169 }
170 };
171}));
172(function( originalWindow, undefined ) {
173
174 var window = originalWindow;
175
176// Use the correct document accordingly with window argument (sandbox)
177var document = window.document;
178
179// This value is computed at build time.
180var buildMetadata = {"date":"Tue Mar 12 2019 08:44:00 GMT+0000 (UTC)","commit":"unknown"};
181
182// We might be monkeypatching JSON later; if we do, ensure it's
183// our own private copy of JSON rather than the page's global one.
184var JSON = {
185 stringify: window.JSON && window.JSON.stringify,
186 parse: window.JSON && window.JSON.parse
187};
188
189var defaultLang = "en-US",
190 defaultURI = "https://goggles.mozilla.org" + "/" + defaultLang;
191
192var webxrayScript = document.querySelector(".webxray"),
193 baseURI = baseURI = webxrayScript.getAttribute("data-baseuri") || defaultURI,
194 lang = webxrayScript.getAttribute("data-lang") || defaultLang,
195 xray = {
196 lang: lang,
197 url: baseURI + "/strings/" + lang
198 };
199/*
200 http://www.JSON.org/json2.js
201 2011-10-19
202
203 Public Domain.
204
205 NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
206
207 See http://www.JSON.org/js.html
208
209
210 This code should be minified before deployment.
211 See http://javascript.crockford.com/jsmin.html
212
213 USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
214 NOT CONTROL.
215
216
217 This file creates a global JSON object containing two methods: stringify
218 and parse.
219
220 JSON.stringify(value, replacer, space)
221 value any JavaScript value, usually an object or array.
222
223 replacer an optional parameter that determines how object
224 values are stringified for objects. It can be a
225 function or an array of strings.
226
227 space an optional parameter that specifies the indentation
228 of nested structures. If it is omitted, the text will
229 be packed without extra whitespace. If it is a number,
230 it will specify the number of spaces to indent at each
231 level. If it is a string (such as '\t' or ' '),
232 it contains the characters used to indent at each level.
233
234 This method produces a JSON text from a JavaScript value.
235
236 When an object value is found, if the object contains a toJSON
237 method, its toJSON method will be called and the result will be
238 stringified. A toJSON method does not serialize: it returns the
239 value represented by the name/value pair that should be serialized,
240 or undefined if nothing should be serialized. The toJSON method
241 will be passed the key associated with the value, and this will be
242 bound to the value
243
244 For example, this would serialize Dates as ISO strings.
245
246 Date.prototype.toJSON = function (key) {
247 function f(n) {
248 // Format integers to have at least two digits.
249 return n < 10 ? '0' + n : n;
250 }
251
252 return this.getUTCFullYear() + '-' +
253 f(this.getUTCMonth() + 1) + '-' +
254 f(this.getUTCDate()) + 'T' +
255 f(this.getUTCHours()) + ':' +
256 f(this.getUTCMinutes()) + ':' +
257 f(this.getUTCSeconds()) + 'Z';
258 };
259
260 You can provide an optional replacer method. It will be passed the
261 key and value of each member, with this bound to the containing
262 object. The value that is returned from your method will be
263 serialized. If your method returns undefined, then the member will
264 be excluded from the serialization.
265
266 If the replacer parameter is an array of strings, then it will be
267 used to select the members to be serialized. It filters the results
268 such that only members with keys listed in the replacer array are
269 stringified.
270
271 Values that do not have JSON representations, such as undefined or
272 functions, will not be serialized. Such values in objects will be
273 dropped; in arrays they will be replaced with null. You can use
274 a replacer function to replace those with JSON values.
275 JSON.stringify(undefined) returns undefined.
276
277 The optional space parameter produces a stringification of the
278 value that is filled with line breaks and indentation to make it
279 easier to read.
280
281 If the space parameter is a non-empty string, then that string will
282 be used for indentation. If the space parameter is a number, then
283 the indentation will be that many spaces.
284
285 Example:
286
287 text = JSON.stringify(['e', {pluribus: 'unum'}]);
288 // text is '["e",{"pluribus":"unum"}]'
289
290
291 text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
292 // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
293
294 text = JSON.stringify([new Date()], function (key, value) {
295 return this[key] instanceof Date ?
296 'Date(' + this[key] + ')' : value;
297 });
298 // text is '["Date(---current time---)"]'
299
300
301 JSON.parse(text, reviver)
302 This method parses a JSON text to produce an object or array.
303 It can throw a SyntaxError exception.
304
305 The optional reviver parameter is a function that can filter and
306 transform the results. It receives each of the keys and values,
307 and its return value is used instead of the original value.
308 If it returns what it received, then the structure is not modified.
309 If it returns undefined then the member is deleted.
310
311 Example:
312
313 // Parse the text. Values that look like ISO date strings will
314 // be converted to Date objects.
315
316 myData = JSON.parse(text, function (key, value) {
317 var a;
318 if (typeof value === 'string') {
319 a =
320/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
321 if (a) {
322 return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
323 +a[5], +a[6]));
324 }
325 }
326 return value;
327 });
328
329 myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
330 var d;
331 if (typeof value === 'string' &&
332 value.slice(0, 5) === 'Date(' &&
333 value.slice(-1) === ')') {
334 d = new Date(value.slice(5, -1));
335 if (d) {
336 return d;
337 }
338 }
339 return value;
340 });
341
342
343 This is a reference implementation. You are free to copy, modify, or
344 redistribute.
345*/
346
347/*jslint evil: true, regexp: true */
348
349/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
350 call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
351 getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
352 lastIndex, length, parse, prototype, push, replace, slice, stringify,
353 test, toJSON, toString, valueOf
354*/
355
356
357// Create a JSON object only if one does not already exist. We create the
358// methods in a closure to avoid creating global variables.
359
360var JSON;
361if (!JSON) {
362 JSON = {};
363}
364
365(function () {
366 'use strict';
367
368 function f(n) {
369 // Format integers to have at least two digits.
370 return n < 10 ? '0' + n : n;
371 }
372
373 if (typeof Date.prototype.toJSON !== 'function') {
374
375 Date.prototype.toJSON = function (key) {
376
377 return isFinite(this.valueOf())
378 ? this.getUTCFullYear() + '-' +
379 f(this.getUTCMonth() + 1) + '-' +
380 f(this.getUTCDate()) + 'T' +
381 f(this.getUTCHours()) + ':' +
382 f(this.getUTCMinutes()) + ':' +
383 f(this.getUTCSeconds()) + 'Z'
384 : null;
385 };
386
387 String.prototype.toJSON =
388 Number.prototype.toJSON =
389 Boolean.prototype.toJSON = function (key) {
390 return this.valueOf();
391 };
392 }
393
394 var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
395 escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
396 gap,
397 indent,
398 meta = { // table of character substitutions
399 '\b': '\\b',
400 '\t': '\\t',
401 '\n': '\\n',
402 '\f': '\\f',
403 '\r': '\\r',
404 '"' : '\\"',
405 '\\': '\\\\'
406 },
407 rep;
408
409
410 function quote(string) {
411
412// If the string contains no control characters, no quote characters, and no
413// backslash characters, then we can safely slap some quotes around it.
414// Otherwise we must also replace the offending characters with safe escape
415// sequences.
416
417 escapable.lastIndex = 0;
418 return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
419 var c = meta[a];
420 return typeof c === 'string'
421 ? c
422 : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
423 }) + '"' : '"' + string + '"';
424 }
425
426
427 function str(key, holder) {
428
429// Produce a string from holder[key].
430
431 var i, // The loop counter.
432 k, // The member key.
433 v, // The member value.
434 length,
435 mind = gap,
436 partial,
437 value = holder[key];
438
439// If the value has a toJSON method, call it to obtain a replacement value.
440
441 if (value && typeof value === 'object' &&
442 typeof value.toJSON === 'function') {
443 value = value.toJSON(key);
444 }
445
446// If we were called with a replacer function, then call the replacer to
447// obtain a replacement value.
448
449 if (typeof rep === 'function') {
450 value = rep.call(holder, key, value);
451 }
452
453// What happens next depends on the value's type.
454
455 switch (typeof value) {
456 case 'string':
457 return quote(value);
458
459 case 'number':
460
461// JSON numbers must be finite. Encode non-finite numbers as null.
462
463 return isFinite(value) ? String(value) : 'null';
464
465 case 'boolean':
466 case 'null':
467
468// If the value is a boolean or null, convert it to a string. Note:
469// typeof null does not produce 'null'. The case is included here in
470// the remote chance that this gets fixed someday.
471
472 return String(value);
473
474// If the type is 'object', we might be dealing with an object or an array or
475// null.
476
477 case 'object':
478
479// Due to a specification blunder in ECMAScript, typeof null is 'object',
480// so watch out for that case.
481
482 if (!value) {
483 return 'null';
484 }
485
486// Make an array to hold the partial results of stringifying this object value.
487
488 gap += indent;
489 partial = [];
490
491// Is the value an array?
492
493 if (Object.prototype.toString.apply(value) === '[object Array]') {
494
495// The value is an array. Stringify every element. Use null as a placeholder
496// for non-JSON values.
497
498 length = value.length;
499 for (i = 0; i < length; i += 1) {
500 partial[i] = str(i, value) || 'null';
501 }
502
503// Join all of the elements together, separated with commas, and wrap them in
504// brackets.
505
506 v = partial.length === 0
507 ? '[]'
508 : gap
509 ? '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']'
510 : '[' + partial.join(',') + ']';
511 gap = mind;
512 return v;
513 }
514
515// If the replacer is an array, use it to select the members to be stringified.
516
517 if (rep && typeof rep === 'object') {
518 length = rep.length;
519 for (i = 0; i < length; i += 1) {
520 if (typeof rep[i] === 'string') {
521 k = rep[i];
522 v = str(k, value);
523 if (v) {
524 partial.push(quote(k) + (gap ? ': ' : ':') + v);
525 }
526 }
527 }
528 } else {
529
530// Otherwise, iterate through all of the keys in the object.
531
532 for (k in value) {
533 if (Object.prototype.hasOwnProperty.call(value, k)) {
534 v = str(k, value);
535 if (v) {
536 partial.push(quote(k) + (gap ? ': ' : ':') + v);
537 }
538 }
539 }
540 }
541
542// Join all of the member texts together, separated with commas,
543// and wrap them in braces.
544
545 v = partial.length === 0
546 ? '{}'
547 : gap
548 ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}'
549 : '{' + partial.join(',') + '}';
550 gap = mind;
551 return v;
552 }
553 }
554
555// If the JSON object does not yet have a stringify method, give it one.
556
557 if (typeof JSON.stringify !== 'function') {
558 JSON.stringify = function (value, replacer, space) {
559
560// The stringify method takes a value and an optional replacer, and an optional
561// space parameter, and returns a JSON text. The replacer can be a function
562// that can replace values, or an array of strings that will select the keys.
563// A default replacer method can be provided. Use of the space parameter can
564// produce text that is more easily readable.
565
566 var i;
567 gap = '';
568 indent = '';
569
570// If the space parameter is a number, make an indent string containing that
571// many spaces.
572
573 if (typeof space === 'number') {
574 for (i = 0; i < space; i += 1) {
575 indent += ' ';
576 }
577
578// If the space parameter is a string, it will be used as the indent string.
579
580 } else if (typeof space === 'string') {
581 indent = space;
582 }
583
584// If there is a replacer, it must be a function or an array.
585// Otherwise, throw an error.
586
587 rep = replacer;
588 if (replacer && typeof replacer !== 'function' &&
589 (typeof replacer !== 'object' ||
590 typeof replacer.length !== 'number')) {
591 throw new Error('JSON.stringify');
592 }
593
594// Make a fake root object containing our value under the key of ''.
595// Return the result of stringifying the value.
596
597 return str('', {'': value});
598 };
599 }
600
601
602// If the JSON object does not yet have a parse method, give it one.
603
604 if (typeof JSON.parse !== 'function') {
605 JSON.parse = function (text, reviver) {
606
607// The parse method takes a text and an optional reviver function, and returns
608// a JavaScript value if the text is a valid JSON text.
609
610 var j;
611
612 function walk(holder, key) {
613
614// The walk method is used to recursively walk the resulting structure so
615// that modifications can be made.
616
617 var k, v, value = holder[key];
618 if (value && typeof value === 'object') {
619 for (k in value) {
620 if (Object.prototype.hasOwnProperty.call(value, k)) {
621 v = walk(value, k);
622 if (v !== undefined) {
623 value[k] = v;
624 } else {
625 delete value[k];
626 }
627 }
628 }
629 }
630 return reviver.call(holder, key, value);
631 }
632
633
634// Parsing happens in four stages. In the first stage, we replace certain
635// Unicode characters with escape sequences. JavaScript handles many characters
636// incorrectly, either silently deleting them, or treating them as line endings.
637
638 text = String(text);
639 cx.lastIndex = 0;
640 if (cx.test(text)) {
641 text = text.replace(cx, function (a) {
642 return '\\u' +
643 ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
644 });
645 }
646
647// In the second stage, we run the text against regular expressions that look
648// for non-JSON patterns. We are especially concerned with '()' and 'new'
649// because they can cause invocation, and '=' because it can cause mutation.
650// But just to be safe, we want to reject all unexpected forms.
651
652// We split the second stage into 4 regexp operations in order to work around
653// crippling inefficiencies in IE's and Safari's regexp engines. First we
654// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
655// replace all simple value tokens with ']' characters. Third, we delete all
656// open brackets that follow a colon or comma or that begin the text. Finally,
657// we look to see that the remaining characters are only whitespace or ']' or
658// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
659
660 if (/^[\],:{}\s]*$/
661 .test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
662 .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
663 .replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
664
665// In the third stage we use the eval function to compile the text into a
666// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
667// in JavaScript: it can begin a block or an object literal. We wrap the text
668// in parens to eliminate the ambiguity.
669
670 j = eval('(' + text + ')');
671
672// In the optional fourth stage, we recursively walk the new structure, passing
673// each name/value pair to a reviver function for possible transformation.
674
675 return typeof reviver === 'function'
676 ? walk({'': j}, '')
677 : j;
678 }
679
680// If the text is not JSON parseable, then a SyntaxError is thrown.
681
682 throw new SyntaxError('JSON.parse');
683 };
684 }
685}());
686
687// Override JSON.stringify with our safe version within the
688// goggles to avoid Array.prototype.toJSON getting in the way.
689// See http://stackoverflow.com/questions/710586/json-stringify-bizarreness
690JSON._unsafeStringify = JSON.stringify;
691JSON.stringify = function(value){
692 var restore = Array.prototype.toJSON;
693 try {
694 delete Array.prototype.toJSON;
695 var stringified = this._unsafeStringify(value);
696 } finally {
697 Array.prototype.toJSON = restore;
698 }
699 return stringified;
700};
701var jQuery = (function() {
702
703// Define a local copy of jQuery
704var jQuery = function( selector, context ) {
705 // The jQuery object is actually just the init constructor 'enhanced'
706 return new jQuery.fn.init( selector, context, rootjQuery );
707 },
708
709 // Map over jQuery in case of overwrite
710 _jQuery = window.jQuery,
711
712 // Map over the $ in case of overwrite
713 _$ = window.$,
714
715 // A central reference to the root jQuery(document)
716 rootjQuery,
717
718 // A simple way to check for HTML strings or ID strings
719 // Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
720 quickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,
721
722 // Check if a string has a non-whitespace character in it
723 rnotwhite = /\S/,
724
725 // Used for trimming whitespace
726 trimLeft = /^\s+/,
727 trimRight = /\s+$/,
728
729 // Check for digits
730 rdigit = /\d/,
731
732 // Match a standalone tag
733 rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/,
734
735 // JSON RegExp
736 rvalidchars = /^[\],:{}\s]*$/,
737 rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,
738 rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,
739 rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g,
740
741 // Useragent RegExp
742 rwebkit = /(webkit)[ \/]([\w.]+)/,
743 ropera = /(opera)(?:.*version)?[ \/]([\w.]+)/,
744 rmsie = /(msie) ([\w.]+)/,
745 rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/,
746
747 // Matches dashed string for camelizing
748 rdashAlpha = /-([a-z]|[0-9])/ig,
749 rmsPrefix = /^-ms-/,
750
751 // Used by jQuery.camelCase as callback to replace()
752 fcamelCase = function( all, letter ) {
753 return ( letter + "" ).toUpperCase();
754 },
755
756 // Keep a UserAgent string for use with jQuery.browser
757 userAgent = navigator.userAgent,
758
759 // For matching the engine and version of the browser
760 browserMatch,
761
762 // The deferred used on DOM ready
763 readyList,
764
765 // The ready event handler
766 DOMContentLoaded,
767
768 // Save a reference to some core methods
769 toString = Object.prototype.toString,
770 hasOwn = Object.prototype.hasOwnProperty,
771 push = Array.prototype.push,
772 slice = Array.prototype.slice,
773 trim = String.prototype.trim,
774 indexOf = Array.prototype.indexOf,
775
776 // [[Class]] -> type pairs
777 class2type = {};
778
779jQuery.fn = jQuery.prototype = {
780 constructor: jQuery,
781 init: function( selector, context, rootjQuery ) {
782 var match, elem, ret, doc;
783
784 // Handle $(""), $(null), or $(undefined)
785 if ( !selector ) {
786 return this;
787 }
788
789 // Handle $(DOMElement)
790 if ( selector.nodeType ) {
791 this.context = this[0] = selector;
792 this.length = 1;
793 return this;
794 }
795
796 // The body element only exists once, optimize finding it
797 if ( selector === "body" && !context && document.body ) {
798 this.context = document;
799 this[0] = document.body;
800 this.selector = selector;
801 this.length = 1;
802 return this;
803 }
804
805 // Handle HTML strings
806 if ( typeof selector === "string" ) {
807 // Are we dealing with HTML string or an ID?
808 if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
809 // Assume that strings that start and end with <> are HTML and skip the regex check
810 match = [ null, selector, null ];
811
812 } else {
813 match = quickExpr.exec( selector );
814 }
815
816 // Verify a match, and that no context was specified for #id
817 if ( match && (match[1] || !context) ) {
818
819 // HANDLE: $(html) -> $(array)
820 if ( match[1] ) {
821 context = context instanceof jQuery ? context[0] : context;
822 doc = ( context ? context.ownerDocument || context : document );
823
824 // If a single string is passed in and it's a single tag
825 // just do a createElement and skip the rest
826 ret = rsingleTag.exec( selector );
827
828 if ( ret ) {
829 if ( jQuery.isPlainObject( context ) ) {
830 selector = [ document.createElement( ret[1] ) ];
831 jQuery.fn.attr.call( selector, context, true );
832
833 } else {
834 selector = [ doc.createElement( ret[1] ) ];
835 }
836
837 } else {
838 ret = jQuery.buildFragment( [ match[1] ], [ doc ] );
839 selector = ( ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment ).childNodes;
840 }
841
842 return jQuery.merge( this, selector );
843
844 // HANDLE: $("#id")
845 } else {
846 elem = document.getElementById( match[2] );
847
848 // Check parentNode to catch when Blackberry 4.6 returns
849 // nodes that are no longer in the document #6963
850 if ( elem && elem.parentNode ) {
851 // Handle the case where IE and Opera return items
852 // by name instead of ID
853 if ( elem.id !== match[2] ) {
854 return rootjQuery.find( selector );
855 }
856
857 // Otherwise, we inject the element directly into the jQuery object
858 this.length = 1;
859 this[0] = elem;
860 }
861
862 this.context = document;
863 this.selector = selector;
864 return this;
865 }
866
867 // HANDLE: $(expr, $(...))
868 } else if ( !context || context.jquery ) {
869 return ( context || rootjQuery ).find( selector );
870
871 // HANDLE: $(expr, context)
872 // (which is just equivalent to: $(context).find(expr)
873 } else {
874 return this.constructor( context ).find( selector );
875 }
876
877 // HANDLE: $(function)
878 // Shortcut for document ready
879 } else if ( jQuery.isFunction( selector ) ) {
880 return rootjQuery.ready( selector );
881 }
882
883 if ( selector.selector !== undefined ) {
884 this.selector = selector.selector;
885 this.context = selector.context;
886 }
887
888 return jQuery.makeArray( selector, this );
889 },
890
891 // Start with an empty selector
892 selector: "",
893
894 // The current version of jQuery being used
895 jquery: "@VERSION",
896
897 // The default length of a jQuery object is 0
898 length: 0,
899
900 // The number of elements contained in the matched element set
901 size: function() {
902 return this.length;
903 },
904
905 toArray: function() {
906 return slice.call( this, 0 );
907 },
908
909 // Get the Nth element in the matched element set OR
910 // Get the whole matched element set as a clean array
911 get: function( num ) {
912 return num == null ?
913
914 // Return a 'clean' array
915 this.toArray() :
916
917 // Return just the object
918 ( num < 0 ? this[ this.length + num ] : this[ num ] );
919 },
920
921 // Take an array of elements and push it onto the stack
922 // (returning the new matched element set)
923 pushStack: function( elems, name, selector ) {
924 // Build a new jQuery matched element set
925 var ret = this.constructor();
926
927 if ( jQuery.isArray( elems ) ) {
928 push.apply( ret, elems );
929
930 } else {
931 jQuery.merge( ret, elems );
932 }
933
934 // Add the old object onto the stack (as a reference)
935 ret.prevObject = this;
936
937 ret.context = this.context;
938
939 if ( name === "find" ) {
940 ret.selector = this.selector + ( this.selector ? " " : "" ) + selector;
941 } else if ( name ) {
942 ret.selector = this.selector + "." + name + "(" + selector + ")";
943 }
944
945 // Return the newly-formed element set
946 return ret;
947 },
948
949 // Execute a callback for every element in the matched set.
950 // (You can seed the arguments with an array of args, but this is
951 // only used internally.)
952 each: function( callback, args ) {
953 return jQuery.each( this, callback, args );
954 },
955
956 ready: function( fn ) {
957 // Attach the listeners
958 jQuery.bindReady();
959
960 // Add the callback
961 readyList.add( fn );
962
963 return this;
964 },
965
966 eq: function( i ) {
967 return i === -1 ?
968 this.slice( i ) :
969 this.slice( i, +i + 1 );
970 },
971
972 first: function() {
973 return this.eq( 0 );
974 },
975
976 last: function() {
977 return this.eq( -1 );
978 },
979
980 slice: function() {
981 return this.pushStack( slice.apply( this, arguments ),
982 "slice", slice.call(arguments).join(",") );
983 },
984
985 map: function( callback ) {
986 return this.pushStack( jQuery.map(this, function( elem, i ) {
987 return callback.call( elem, i, elem );
988 }));
989 },
990
991 end: function() {
992 return this.prevObject || this.constructor(null);
993 },
994
995 // For internal use only.
996 // Behaves like an Array's method, not like a jQuery method.
997 push: push,
998 sort: [].sort,
999 splice: [].splice
1000};
1001
1002// Give the init function the jQuery prototype for later instantiation
1003jQuery.fn.init.prototype = jQuery.fn;
1004
1005jQuery.extend = jQuery.fn.extend = function() {
1006 var options, name, src, copy, copyIsArray, clone,
1007 target = arguments[0] || {},
1008 i = 1,
1009 length = arguments.length,
1010 deep = false;
1011
1012 // Handle a deep copy situation
1013 if ( typeof target === "boolean" ) {
1014 deep = target;
1015 target = arguments[1] || {};
1016 // skip the boolean and the target
1017 i = 2;
1018 }
1019
1020 // Handle case when target is a string or something (possible in deep copy)
1021 if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
1022 target = {};
1023 }
1024
1025 // extend jQuery itself if only one argument is passed
1026 if ( length === i ) {
1027 target = this;
1028 --i;
1029 }
1030
1031 for ( ; i < length; i++ ) {
1032 // Only deal with non-null/undefined values
1033 if ( (options = arguments[ i ]) != null ) {
1034 // Extend the base object
1035 for ( name in options ) {
1036 src = target[ name ];
1037 copy = options[ name ];
1038
1039 // Prevent never-ending loop
1040 if ( target === copy ) {
1041 continue;
1042 }
1043
1044 // Recurse if we're merging plain objects or arrays
1045 if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
1046 if ( copyIsArray ) {
1047 copyIsArray = false;
1048 clone = src && jQuery.isArray(src) ? src : [];
1049
1050 } else {
1051 clone = src && jQuery.isPlainObject(src) ? src : {};
1052 }
1053
1054 // Never move original objects, clone them
1055 target[ name ] = jQuery.extend( deep, clone, copy );
1056
1057 // Don't bring in undefined values
1058 } else if ( copy !== undefined ) {
1059 target[ name ] = copy;
1060 }
1061 }
1062 }
1063 }
1064
1065 // Return the modified object
1066 return target;
1067};
1068
1069jQuery.extend({
1070 noConflict: function( deep ) {
1071 if ( window.$ === jQuery ) {
1072 window.$ = _$;
1073 }
1074
1075 if ( deep && window.jQuery === jQuery ) {
1076 window.jQuery = _jQuery;
1077 }
1078
1079 return jQuery;
1080 },
1081
1082 // Is the DOM ready to be used? Set to true once it occurs.
1083 isReady: false,
1084
1085 // A counter to track how many items to wait for before
1086 // the ready event fires. See #6781
1087 readyWait: 1,
1088
1089 // Hold (or release) the ready event
1090 holdReady: function( hold ) {
1091 if ( hold ) {
1092 jQuery.readyWait++;
1093 } else {
1094 jQuery.ready( true );
1095 }
1096 },
1097
1098 // Handle when the DOM is ready
1099 ready: function( wait ) {
1100 // Either a released hold or an DOMready/load event and not yet ready
1101 if ( (wait === true && !--jQuery.readyWait) || (wait !== true && !jQuery.isReady) ) {
1102 // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
1103 if ( !document.body ) {
1104 return setTimeout( jQuery.ready, 1 );
1105 }
1106
1107 // Remember that the DOM is ready
1108 jQuery.isReady = true;
1109
1110 // If a normal DOM Ready event fired, decrement, and wait if need be
1111 if ( wait !== true && --jQuery.readyWait > 0 ) {
1112 return;
1113 }
1114
1115 // If there are functions bound, to execute
1116 readyList.fireWith( document, [ jQuery ] );
1117
1118 // Trigger any bound ready events
1119 if ( jQuery.fn.trigger ) {
1120 jQuery( document ).trigger( "ready" ).unbind( "ready" );
1121 }
1122 }
1123 },
1124
1125 bindReady: function() {
1126 if ( readyList ) {
1127 return;
1128 }
1129
1130 readyList = jQuery.Callbacks( "once memory" );
1131
1132 // Catch cases where $(document).ready() is called after the
1133 // browser event has already occurred.
1134 if ( document.readyState === "complete" ) {
1135 // Handle it asynchronously to allow scripts the opportunity to delay ready
1136 return setTimeout( jQuery.ready, 1 );
1137 }
1138
1139 // Mozilla, Opera and webkit nightlies currently support this event
1140 if ( document.addEventListener ) {
1141 // Use the handy event callback
1142 document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
1143
1144 // A fallback to window.onload, that will always work
1145 window.addEventListener( "load", jQuery.ready, false );
1146
1147 // If IE event model is used
1148 } else if ( document.attachEvent ) {
1149 // ensure firing before onload,
1150 // maybe late but safe also for iframes
1151 document.attachEvent( "onreadystatechange", DOMContentLoaded );
1152
1153 // A fallback to window.onload, that will always work
1154 window.attachEvent( "onload", jQuery.ready );
1155
1156 // If IE and not a frame
1157 // continually check to see if the document is ready
1158 var toplevel = false;
1159
1160 try {
1161 toplevel = window.frameElement == null;
1162 } catch(e) {}
1163
1164 if ( document.documentElement.doScroll && toplevel ) {
1165 doScrollCheck();
1166 }
1167 }
1168 },
1169
1170 // See test/unit/core.js for details concerning isFunction.
1171 // Since version 1.3, DOM methods and functions like alert
1172 // aren't supported. They return false on IE (#2968).
1173 isFunction: function( obj ) {
1174 return jQuery.type(obj) === "function";
1175 },
1176
1177 isArray: Array.isArray || function( obj ) {
1178 return jQuery.type(obj) === "array";
1179 },
1180
1181 // A crude way of determining if an object is a window
1182 isWindow: function( obj ) {
1183 return obj && typeof obj === "object" && "setInterval" in obj;
1184 },
1185
1186 isNumeric: function( obj ) {
1187 return obj != null && rdigit.test( obj ) && !isNaN( obj );
1188 },
1189
1190 type: function( obj ) {
1191 return obj == null ?
1192 String( obj ) :
1193 class2type[ toString.call(obj) ] || "object";
1194 },
1195
1196 isPlainObject: function( obj ) {
1197 // Must be an Object.
1198 // Because of IE, we also have to check the presence of the constructor property.
1199 // Make sure that DOM nodes and window objects don't pass through, as well
1200 if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
1201 return false;
1202 }
1203
1204 try {
1205 // Not own constructor property must be Object
1206 if ( obj.constructor &&
1207 !hasOwn.call(obj, "constructor") &&
1208 !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
1209 return false;
1210 }
1211 } catch ( e ) {
1212 // IE8,9 Will throw exceptions on certain host objects #9897
1213 return false;
1214 }
1215
1216 // Own properties are enumerated firstly, so to speed up,
1217 // if last one is own, then all properties are own.
1218
1219 var key;
1220 for ( key in obj ) {}
1221
1222 return key === undefined || hasOwn.call( obj, key );
1223 },
1224
1225 isEmptyObject: function( obj ) {
1226 for ( var name in obj ) {
1227 return false;
1228 }
1229 return true;
1230 },
1231
1232 error: function( msg ) {
1233 throw msg;
1234 },
1235
1236 parseJSON: function( data ) {
1237 if ( typeof data !== "string" || !data ) {
1238 return null;
1239 }
1240
1241 // Make sure leading/trailing whitespace is removed (IE can't handle it)
1242 data = jQuery.trim( data );
1243
1244 // Attempt to parse using the native JSON parser first
1245 if ( window.JSON && window.JSON.parse ) {
1246 return window.JSON.parse( data );
1247 }
1248
1249 // Make sure the incoming data is actual JSON
1250 // Logic borrowed from http://json.org/json2.js
1251 if ( rvalidchars.test( data.replace( rvalidescape, "@" )
1252 .replace( rvalidtokens, "]" )
1253 .replace( rvalidbraces, "")) ) {
1254
1255 return ( new Function( "return " + data ) )();
1256
1257 }
1258 jQuery.error( "Invalid JSON: " + data );
1259 },
1260
1261 // Cross-browser xml parsing
1262 parseXML: function( data ) {
1263 var xml, tmp;
1264 try {
1265 if ( window.DOMParser ) { // Standard
1266 tmp = new DOMParser();
1267 xml = tmp.parseFromString( data , "text/xml" );
1268 } else { // IE
1269 xml = new ActiveXObject( "Microsoft.XMLDOM" );
1270 xml.async = "false";
1271 xml.loadXML( data );
1272 }
1273 } catch( e ) {
1274 xml = undefined;
1275 }
1276 if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) {
1277 jQuery.error( "Invalid XML: " + data );
1278 }
1279 return xml;
1280 },
1281
1282 noop: function() {},
1283
1284 // Evaluates a script in a global context
1285 // Workarounds based on findings by Jim Driscoll
1286 // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context
1287 globalEval: function( data ) {
1288 if ( data && rnotwhite.test( data ) ) {
1289 // We use execScript on Internet Explorer
1290 // We use an anonymous function so that context is window
1291 // rather than jQuery in Firefox
1292 ( window.execScript || function( data ) {
1293 window[ "eval" ].call( window, data );
1294 } )( data );
1295 }
1296 },
1297
1298 // Convert dashed to camelCase; used by the css and data modules
1299 // Microsoft forgot to hump their vendor prefix (#9572)
1300 camelCase: function( string ) {
1301 return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
1302 },
1303
1304 nodeName: function( elem, name ) {
1305 return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase();
1306 },
1307
1308 // args is for internal usage only
1309 each: function( object, callback, args ) {
1310 var name, i = 0,
1311 length = object.length,
1312 isObj = length === undefined || jQuery.isFunction( object );
1313
1314 if ( args ) {
1315 if ( isObj ) {
1316 for ( name in object ) {
1317 if ( callback.apply( object[ name ], args ) === false ) {
1318 break;
1319 }
1320 }
1321 } else {
1322 for ( ; i < length; ) {
1323 if ( callback.apply( object[ i++ ], args ) === false ) {
1324 break;
1325 }
1326 }
1327 }
1328
1329 // A special, fast, case for the most common use of each
1330 } else {
1331 if ( isObj ) {
1332 for ( name in object ) {
1333 if ( callback.call( object[ name ], name, object[ name ] ) === false ) {
1334 break;
1335 }
1336 }
1337 } else {
1338 for ( ; i < length; ) {
1339 if ( callback.call( object[ i ], i, object[ i++ ] ) === false ) {
1340 break;
1341 }
1342 }
1343 }
1344 }
1345
1346 return object;
1347 },
1348
1349 // Use native String.trim function wherever possible
1350 trim: trim ?
1351 function( text ) {
1352 return text == null ?
1353 "" :
1354 trim.call( text );
1355 } :
1356
1357 // Otherwise use our own trimming functionality
1358 function( text ) {
1359 return text == null ?
1360 "" :
1361 text.toString().replace( trimLeft, "" ).replace( trimRight, "" );
1362 },
1363
1364 // results is for internal usage only
1365 makeArray: function( array, results ) {
1366 var ret = results || [];
1367
1368 if ( array != null ) {
1369 // The window, strings (and functions) also have 'length'
1370 // The extra typeof function check is to prevent crashes
1371 // in Safari 2 (See: #3039)
1372 // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930
1373 var type = jQuery.type( array );
1374
1375 if ( array.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( array ) ) {
1376 push.call( ret, array );
1377 } else {
1378 jQuery.merge( ret, array );
1379 }
1380 }
1381
1382 return ret;
1383 },
1384
1385 inArray: function( elem, array, i ) {
1386 var len;
1387
1388 if ( array ) {
1389 if ( indexOf ) {
1390 return indexOf.call( array, elem, i );
1391 }
1392
1393 len = array.length;
1394 i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0;
1395
1396 for ( ; i < len; i++ ) {
1397 // Skip accessing in sparse arrays
1398 if ( i in array && array[ i ] === elem ) {
1399 return i;
1400 }
1401 }
1402 }
1403
1404 return -1;
1405 },
1406
1407 merge: function( first, second ) {
1408 var i = first.length,
1409 j = 0;
1410
1411 if ( typeof second.length === "number" ) {
1412 for ( var l = second.length; j < l; j++ ) {
1413 first[ i++ ] = second[ j ];
1414 }
1415
1416 } else {
1417 while ( second[j] !== undefined ) {
1418 first[ i++ ] = second[ j++ ];
1419 }
1420 }
1421
1422 first.length = i;
1423
1424 return first;
1425 },
1426
1427 grep: function( elems, callback, inv ) {
1428 var ret = [], retVal;
1429 inv = !!inv;
1430
1431 // Go through the array, only saving the items
1432 // that pass the validator function
1433 for ( var i = 0, length = elems.length; i < length; i++ ) {
1434 retVal = !!callback( elems[ i ], i );
1435 if ( inv !== retVal ) {
1436 ret.push( elems[ i ] );
1437 }
1438 }
1439
1440 return ret;
1441 },
1442
1443 // arg is for internal usage only
1444 map: function( elems, callback, arg ) {
1445 var value, key, ret = [],
1446 i = 0,
1447 length = elems.length,
1448 // jquery objects are treated as arrays
1449 isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ;
1450
1451 // Go through the array, translating each of the items to their
1452 if ( isArray ) {
1453 for ( ; i < length; i++ ) {
1454 value = callback( elems[ i ], i, arg );
1455
1456 if ( value != null ) {
1457 ret[ ret.length ] = value;
1458 }
1459 }
1460
1461 // Go through every key on the object,
1462 } else {
1463 for ( key in elems ) {
1464 value = callback( elems[ key ], key, arg );
1465
1466 if ( value != null ) {
1467 ret[ ret.length ] = value;
1468 }
1469 }
1470 }
1471
1472 // Flatten any nested arrays
1473 return ret.concat.apply( [], ret );
1474 },
1475
1476 // A global GUID counter for objects
1477 guid: 1,
1478
1479 // Bind a function to a context, optionally partially applying any
1480 // arguments.
1481 proxy: function( fn, context ) {
1482 if ( typeof context === "string" ) {
1483 var tmp = fn[ context ];
1484 context = fn;
1485 fn = tmp;
1486 }
1487
1488 // Quick check to determine if target is callable, in the spec
1489 // this throws a TypeError, but we will just return undefined.
1490 if ( !jQuery.isFunction( fn ) ) {
1491 return undefined;
1492 }
1493
1494 // Simulated bind
1495 var args = slice.call( arguments, 2 ),
1496 proxy = function() {
1497 return fn.apply( context, args.concat( slice.call( arguments ) ) );
1498 };
1499
1500 // Set the guid of unique handler to the same of original handler, so it can be removed
1501 proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++;
1502
1503 return proxy;
1504 },
1505
1506 // Mutifunctional method to get and set values to a collection
1507 // The value/s can optionally be executed if it's a function
1508 access: function( elems, key, value, exec, fn, pass ) {
1509 var length = elems.length;
1510
1511 // Setting many attributes
1512 if ( typeof key === "object" ) {
1513 for ( var k in key ) {
1514 jQuery.access( elems, k, key[k], exec, fn, value );
1515 }
1516 return elems;
1517 }
1518
1519 // Setting one attribute
1520 if ( value !== undefined ) {
1521 // Optionally, function values get executed if exec is true
1522 exec = !pass && exec && jQuery.isFunction(value);
1523
1524 for ( var i = 0; i < length; i++ ) {
1525 fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass );
1526 }
1527
1528 return elems;
1529 }
1530
1531 // Getting an attribute
1532 return length ? fn( elems[0], key ) : undefined;
1533 },
1534
1535 now: function() {
1536 return ( new Date() ).getTime();
1537 },
1538
1539 // Use of jQuery.browser is frowned upon.
1540 // More details: http://docs.jquery.com/Utilities/jQuery.browser
1541 uaMatch: function( ua ) {
1542 ua = ua.toLowerCase();
1543
1544 var match = rwebkit.exec( ua ) ||
1545 ropera.exec( ua ) ||
1546 rmsie.exec( ua ) ||
1547 ua.indexOf("compatible") < 0 && rmozilla.exec( ua ) ||
1548 [];
1549
1550 return { browser: match[1] || "", version: match[2] || "0" };
1551 },
1552
1553 sub: function() {
1554 function jQuerySub( selector, context ) {
1555 return new jQuerySub.fn.init( selector, context );
1556 }
1557 jQuery.extend( true, jQuerySub, this );
1558 jQuerySub.superclass = this;
1559 jQuerySub.fn = jQuerySub.prototype = this();
1560 jQuerySub.fn.constructor = jQuerySub;
1561 jQuerySub.sub = this.sub;
1562 jQuerySub.fn.init = function init( selector, context ) {
1563 if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) {
1564 context = jQuerySub( context );
1565 }
1566
1567 return jQuery.fn.init.call( this, selector, context, rootjQuerySub );
1568 };
1569 jQuerySub.fn.init.prototype = jQuerySub.fn;
1570 var rootjQuerySub = jQuerySub(document);
1571 return jQuerySub;
1572 },
1573
1574 browser: {}
1575});
1576
1577// Populate the class2type map
1578jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) {
1579 class2type[ "[object " + name + "]" ] = name.toLowerCase();
1580});
1581
1582browserMatch = jQuery.uaMatch( userAgent );
1583if ( browserMatch.browser ) {
1584 jQuery.browser[ browserMatch.browser ] = true;
1585 jQuery.browser.version = browserMatch.version;
1586}
1587
1588// Deprecated, use jQuery.browser.webkit instead
1589if ( jQuery.browser.webkit ) {
1590 jQuery.browser.safari = true;
1591}
1592
1593// IE doesn't match non-breaking spaces with \s
1594if ( rnotwhite.test( "\xA0" ) ) {
1595 trimLeft = /^[\s\xA0]+/;
1596 trimRight = /[\s\xA0]+$/;
1597}
1598
1599// All jQuery objects should point back to these
1600rootjQuery = jQuery(document);
1601
1602// Cleanup functions for the document ready method
1603if ( document.addEventListener ) {
1604 DOMContentLoaded = function() {
1605 document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false );
1606 jQuery.ready();
1607 };
1608
1609} else if ( document.attachEvent ) {
1610 DOMContentLoaded = function() {
1611 // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
1612 if ( document.readyState === "complete" ) {
1613 document.detachEvent( "onreadystatechange", DOMContentLoaded );
1614 jQuery.ready();
1615 }
1616 };
1617}
1618
1619// The DOM ready check for Internet Explorer
1620function doScrollCheck() {
1621 if ( jQuery.isReady ) {
1622 return;
1623 }
1624
1625 try {
1626 // If IE is used, use the trick by Diego Perini
1627 // http://javascript.nwbox.com/IEContentLoaded/
1628 document.documentElement.doScroll("left");
1629 } catch(e) {
1630 setTimeout( doScrollCheck, 1 );
1631 return;
1632 }
1633
1634 // and execute any waiting functions
1635 jQuery.ready();
1636}
1637
1638// Expose jQuery as an AMD module, but only for AMD loaders that
1639// understand the issues with loading multiple versions of jQuery
1640// in a page that all might call define(). The loader will indicate
1641// they have special allowances for multiple jQuery versions by
1642// specifying define.amd.jQuery = true. Register as a named module,
1643// since jQuery can be concatenated with other files that may use define,
1644// but not use a proper concatenation script that understands anonymous
1645// AMD modules. A named AMD is safest and most robust way to register.
1646// Lowercase jquery is used because AMD module names are derived from
1647// file names, and jQuery is normally delivered in a lowercase file name.
1648if ( typeof define === "function" && define.amd && define.amd.jQuery ) {
1649 define( "jquery", [], function () { return jQuery; } );
1650}
1651
1652return jQuery;
1653
1654})();
1655(function( jQuery ) {
1656
1657// String to Object flags format cache
1658var flagsCache = {};
1659
1660// Convert String-formatted flags into Object-formatted ones and store in cache
1661function createFlags( flags ) {
1662 var object = flagsCache[ flags ] = {},
1663 i, length;
1664 flags = flags.split( /\s+/ );
1665 for ( i = 0, length = flags.length; i < length; i++ ) {
1666 object[ flags[i] ] = true;
1667 }
1668 return object;
1669}
1670
1671/*
1672 * Create a callback list using the following parameters:
1673 *
1674 * flags: an optional list of space-separated flags that will change how
1675 * the callback list behaves
1676 *
1677 * By default a callback list will act like an event callback list and can be
1678 * "fired" multiple times.
1679 *
1680 * Possible flags:
1681 *
1682 * once: will ensure the callback list can only be fired once (like a Deferred)
1683 *
1684 * memory: will keep track of previous values and will call any callback added
1685 * after the list has been fired right away with the latest "memorized"
1686 * values (like a Deferred)
1687 *
1688 * unique: will ensure a callback can only be added once (no duplicate in the list)
1689 *
1690 * stopOnFalse: interrupt callings when a callback returns false
1691 *
1692 */
1693jQuery.Callbacks = function( flags ) {
1694
1695 // Convert flags from String-formatted to Object-formatted
1696 // (we check in cache first)
1697 flags = flags ? ( flagsCache[ flags ] || createFlags( flags ) ) : {};
1698
1699 var // Actual callback list
1700 list = [],
1701 // Stack of fire calls for repeatable lists
1702 stack = [],
1703 // Last fire value (for non-forgettable lists)
1704 memory,
1705 // Flag to know if list is currently firing
1706 firing,
1707 // First callback to fire (used internally by add and fireWith)
1708 firingStart,
1709 // End of the loop when firing
1710 firingLength,
1711 // Index of currently firing callback (modified by remove if needed)
1712 firingIndex,
1713 // Add one or several callbacks to the list
1714 add = function( args ) {
1715 var i,
1716 length,
1717 elem,
1718 type,
1719 actual;
1720 for ( i = 0, length = args.length; i < length; i++ ) {
1721 elem = args[ i ];
1722 type = jQuery.type( elem );
1723 if ( type === "array" ) {
1724 // Inspect recursively
1725 add( elem );
1726 } else if ( type === "function" ) {
1727 // Add if not in unique mode and callback is not in
1728 if ( !flags.unique || !self.has( elem ) ) {
1729 list.push( elem );
1730 }
1731 }
1732 }
1733 },
1734 // Fire callbacks
1735 fire = function( context, args ) {
1736 args = args || [];
1737 memory = !flags.memory || [ context, args ];
1738 firing = true;
1739 firingIndex = firingStart || 0;
1740 firingStart = 0;
1741 firingLength = list.length;
1742 for ( ; list && firingIndex < firingLength; firingIndex++ ) {
1743 if ( list[ firingIndex ].apply( context, args ) === false && flags.stopOnFalse ) {
1744 memory = true; // Mark as halted
1745 break;
1746 }
1747 }
1748 firing = false;
1749 if ( list ) {
1750 if ( !flags.once ) {
1751 if ( stack && stack.length ) {
1752 memory = stack.shift();
1753 self.fireWith( memory[ 0 ], memory[ 1 ] );
1754 }
1755 } else if ( memory === true ) {
1756 self.disable();
1757 } else {
1758 list = [];
1759 }
1760 }
1761 },
1762 // Actual Callbacks object
1763 self = {
1764 // Add a callback or a collection of callbacks to the list
1765 add: function() {
1766 if ( list ) {
1767 var length = list.length;
1768 add( arguments );
1769 // Do we need to add the callbacks to the
1770 // current firing batch?
1771 if ( firing ) {
1772 firingLength = list.length;
1773 // With memory, if we're not firing then
1774 // we should call right away, unless previous
1775 // firing was halted (stopOnFalse)
1776 } else if ( memory && memory !== true ) {
1777 firingStart = length;
1778 fire( memory[ 0 ], memory[ 1 ] );
1779 }
1780 }
1781 return this;
1782 },
1783 // Remove a callback from the list
1784 remove: function() {
1785 if ( list ) {
1786 var args = arguments,
1787 argIndex = 0,
1788 argLength = args.length;
1789 for ( ; argIndex < argLength ; argIndex++ ) {
1790 for ( var i = 0; i < list.length; i++ ) {
1791 if ( args[ argIndex ] === list[ i ] ) {
1792 // Handle firingIndex and firingLength
1793 if ( firing ) {
1794 if ( i <= firingLength ) {
1795 firingLength--;
1796 if ( i <= firingIndex ) {
1797 firingIndex--;
1798 }
1799 }
1800 }
1801 // Remove the element
1802 list.splice( i--, 1 );
1803 // If we have some unicity property then
1804 // we only need to do this once
1805 if ( flags.unique ) {
1806 break;
1807 }
1808 }
1809 }
1810 }
1811 }
1812 return this;
1813 },
1814 // Control if a given callback is in the list
1815 has: function( fn ) {
1816 if ( list ) {
1817 var i = 0,
1818 length = list.length;
1819 for ( ; i < length; i++ ) {
1820 if ( fn === list[ i ] ) {
1821 return true;
1822 }
1823 }
1824 }
1825 return false;
1826 },
1827 // Remove all callbacks from the list
1828 empty: function() {
1829 list = [];
1830 return this;
1831 },
1832 // Have the list do nothing anymore
1833 disable: function() {
1834 list = stack = memory = undefined;
1835 return this;
1836 },
1837 // Is it disabled?
1838 disabled: function() {
1839 return !list;
1840 },
1841 // Lock the list in its current state
1842 lock: function() {
1843 stack = undefined;
1844 if ( !memory || memory === true ) {
1845 self.disable();
1846 }
1847 return this;
1848 },
1849 // Is it locked?
1850 locked: function() {
1851 return !stack;
1852 },
1853 // Call all callbacks with the given context and arguments
1854 fireWith: function( context, args ) {
1855 if ( stack ) {
1856 if ( firing ) {
1857 if ( !flags.once ) {
1858 stack.push( [ context, args ] );
1859 }
1860 } else if ( !( flags.once && memory ) ) {
1861 fire( context, args );
1862 }
1863 }
1864 return this;
1865 },
1866 // Call all the callbacks with the given arguments
1867 fire: function() {
1868 self.fireWith( this, arguments );
1869 return this;
1870 },
1871 // To know if the callbacks have already been called at least once
1872 fired: function() {
1873 return !!memory;
1874 }
1875 };
1876
1877 return self;
1878};
1879
1880})( jQuery );
1881(function( jQuery ) {
1882
1883var // Static reference to slice
1884 sliceDeferred = [].slice;
1885
1886jQuery.extend({
1887
1888 Deferred: function( func ) {
1889 var doneList = jQuery.Callbacks( "once memory" ),
1890 failList = jQuery.Callbacks( "once memory" ),
1891 progressList = jQuery.Callbacks( "memory" ),
1892 state = "pending",
1893 lists = {
1894 resolve: doneList,
1895 reject: failList,
1896 notify: progressList
1897 },
1898 promise = {
1899 done: doneList.add,
1900 fail: failList.add,
1901 progress: progressList.add,
1902
1903 state: function() {
1904 return state;
1905 },
1906
1907 // Deprecated
1908 isResolved: doneList.fired,
1909 isRejected: failList.fired,
1910
1911 then: function( doneCallbacks, failCallbacks, progressCallbacks ) {
1912 deferred.done( doneCallbacks ).fail( failCallbacks ).progress( progressCallbacks );
1913 return this;
1914 },
1915 always: function() {
1916 return deferred.done.apply( deferred, arguments ).fail.apply( deferred, arguments );
1917 },
1918 pipe: function( fnDone, fnFail, fnProgress ) {
1919 return jQuery.Deferred(function( newDefer ) {
1920 jQuery.each( {
1921 done: [ fnDone, "resolve" ],
1922 fail: [ fnFail, "reject" ],
1923 progress: [ fnProgress, "notify" ]
1924 }, function( handler, data ) {
1925 var fn = data[ 0 ],
1926 action = data[ 1 ],
1927 returned;
1928 if ( jQuery.isFunction( fn ) ) {
1929 deferred[ handler ](function() {
1930 returned = fn.apply( this, arguments );
1931 if ( returned && jQuery.isFunction( returned.promise ) ) {
1932 returned.promise().then( newDefer.resolve, newDefer.reject, newDefer.notify );
1933 } else {
1934 newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] );
1935 }
1936 });
1937 } else {
1938 deferred[ handler ]( newDefer[ action ] );
1939 }
1940 });
1941 }).promise();
1942 },
1943 // Get a promise for this deferred
1944 // If obj is provided, the promise aspect is added to the object
1945 promise: function( obj ) {
1946 if ( obj == null ) {
1947 obj = promise;
1948 } else {
1949 for ( var key in promise ) {
1950 obj[ key ] = promise[ key ];
1951 }
1952 }
1953 return obj;
1954 }
1955 },
1956 deferred = promise.promise({}),
1957 key;
1958
1959 for ( key in lists ) {
1960 deferred[ key ] = lists[ key ].fire;
1961 deferred[ key + "With" ] = lists[ key ].fireWith;
1962 }
1963
1964 // Handle state
1965 deferred.done( function() {
1966 state = "resolved";
1967 }, failList.disable, progressList.lock ).fail( function() {
1968 state = "rejected";
1969 }, doneList.disable, progressList.lock );
1970
1971 // Call given func if any
1972 if ( func ) {
1973 func.call( deferred, deferred );
1974 }
1975
1976 // All done!
1977 return deferred;
1978 },
1979
1980 // Deferred helper
1981 when: function( firstParam ) {
1982 var args = sliceDeferred.call( arguments, 0 ),
1983 i = 0,
1984 length = args.length,
1985 pValues = new Array( length ),
1986 count = length,
1987 pCount = length,
1988 deferred = length <= 1 && firstParam && jQuery.isFunction( firstParam.promise ) ?
1989 firstParam :
1990 jQuery.Deferred(),
1991 promise = deferred.promise();
1992 function resolveFunc( i ) {
1993 return function( value ) {
1994 args[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value;
1995 if ( !( --count ) ) {
1996 deferred.resolveWith( deferred, args );
1997 }
1998 };
1999 }
2000 function progressFunc( i ) {
2001 return function( value ) {
2002 pValues[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value;
2003 deferred.notifyWith( promise, pValues );
2004 };
2005 }
2006 if ( length > 1 ) {
2007 for ( ; i < length; i++ ) {
2008 if ( args[ i ] && args[ i ].promise && jQuery.isFunction( args[ i ].promise ) ) {
2009 args[ i ].promise().then( resolveFunc(i), deferred.reject, progressFunc(i) );
2010 } else {
2011 --count;
2012 }
2013 }
2014 if ( !count ) {
2015 deferred.resolveWith( deferred, args );
2016 }
2017 } else if ( deferred !== firstParam ) {
2018 deferred.resolveWith( deferred, length ? [ firstParam ] : [] );
2019 }
2020 return promise;
2021 }
2022});
2023
2024})( jQuery );
2025(function( jQuery ) {
2026
2027jQuery.support = (function() {
2028
2029 var div = document.createElement( "div" ),
2030 documentElement = document.documentElement,
2031 all,
2032 a,
2033 select,
2034 opt,
2035 input,
2036 marginDiv,
2037 support,
2038 fragment,
2039 body,
2040 testElementParent,
2041 testElement,
2042 testElementStyle,
2043 tds,
2044 events,
2045 eventName,
2046 i,
2047 isSupported;
2048
2049 // Preliminary tests
2050 div.setAttribute("className", "t");
2051 div.innerHTML = " <link/><table></table><a href='/a' style='top:1px;float:left;opacity:.55;'>a</a><input type='checkbox'/><nav></nav>";
2052
2053
2054 all = div.getElementsByTagName( "*" );
2055 a = div.getElementsByTagName( "a" )[ 0 ];
2056
2057 // Can't get basic test support
2058 if ( !all || !all.length || !a ) {
2059 return {};
2060 }
2061
2062 // First batch of supports tests
2063 select = document.createElement( "select" );
2064 opt = select.appendChild( document.createElement("option") );
2065 input = div.getElementsByTagName( "input" )[ 0 ];
2066
2067 support = {
2068 // IE strips leading whitespace when .innerHTML is used
2069 leadingWhitespace: ( div.firstChild.nodeType === 3 ),
2070
2071 // Make sure that tbody elements aren't automatically inserted
2072 // IE will insert them into empty tables
2073 tbody: !div.getElementsByTagName( "tbody" ).length,
2074
2075 // Make sure that link elements get serialized correctly by innerHTML
2076 // This requires a wrapper element in IE
2077 htmlSerialize: !!div.getElementsByTagName( "link" ).length,
2078
2079 // Get the style information from getAttribute
2080 // (IE uses .cssText instead)
2081 style: /top/.test( a.getAttribute("style") ),
2082
2083 // Make sure that URLs aren't manipulated
2084 // (IE normalizes it by default)
2085 hrefNormalized: ( a.getAttribute( "href" ) === "/a" ),
2086
2087 // Make sure that element opacity exists
2088 // (IE uses filter instead)
2089 // Use a regex to work around a WebKit issue. See #5145
2090 opacity: /^0.55/.test( a.style.opacity ),
2091
2092 // Verify style float existence
2093 // (IE uses styleFloat instead of cssFloat)
2094 cssFloat: !!a.style.cssFloat,
2095
2096 // Make sure unknown elements (like HTML5 elems) are handled appropriately
2097 unknownElems: !!div.getElementsByTagName( "nav" ).length,
2098
2099 // Make sure that if no value is specified for a checkbox
2100 // that it defaults to "on".
2101 // (WebKit defaults to "" instead)
2102 checkOn: ( input.value === "on" ),
2103
2104 // Make sure that a selected-by-default option has a working selected property.
2105 // (WebKit defaults to false instead of true, IE too, if it's in an optgroup)
2106 optSelected: opt.selected,
2107
2108 // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7)
2109 getSetAttribute: div.className !== "t",
2110
2111 // Tests for enctype support on a form(#6743)
2112 enctype: !!document.createElement("form").enctype,
2113
2114 // Will be defined later
2115 submitBubbles: true,
2116 changeBubbles: true,
2117 focusinBubbles: false,
2118 deleteExpando: true,
2119 noCloneEvent: true,
2120 inlineBlockNeedsLayout: false,
2121 shrinkWrapBlocks: false,
2122 reliableMarginRight: true
2123 };
2124
2125 // Make sure checked status is properly cloned
2126 input.checked = true;
2127 support.noCloneChecked = input.cloneNode( true ).checked;
2128
2129 // Make sure that the options inside disabled selects aren't marked as disabled
2130 // (WebKit marks them as disabled)
2131 select.disabled = true;
2132 support.optDisabled = !opt.disabled;
2133
2134 // Test to see if it's possible to delete an expando from an element
2135 // Fails in Internet Explorer
2136 try {
2137 delete div.test;
2138 } catch( e ) {
2139 support.deleteExpando = false;
2140 }
2141
2142 if ( !div.addEventListener && div.attachEvent && div.fireEvent ) {
2143 div.attachEvent( "onclick", function() {
2144 // Cloning a node shouldn't copy over any
2145 // bound event handlers (IE does this)
2146 support.noCloneEvent = false;
2147 });
2148 div.cloneNode( true ).fireEvent( "onclick" );
2149 }
2150
2151 // Check if a radio maintains its value
2152 // after being appended to the DOM
2153 input = document.createElement("input");
2154 input.value = "t";
2155 input.setAttribute("type", "radio");
2156 support.radioValue = input.value === "t";
2157
2158 input.setAttribute("checked", "checked");
2159 div.appendChild( input );
2160 fragment = document.createDocumentFragment();
2161 fragment.appendChild( div.lastChild );
2162
2163 // WebKit doesn't clone checked state correctly in fragments
2164 support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked;
2165
2166 div.innerHTML = "";
2167
2168 // Figure out if the W3C box model works as expected
2169 div.style.width = div.style.paddingLeft = "1px";
2170
2171 // We don't want to do body-related feature tests on frameset
2172 // documents, which lack a body. So we use
2173 // document.getElementsByTagName("body")[0], which is undefined in
2174 // frameset documents, while document.body isn’t. (7398)
2175 body = document.getElementsByTagName("body")[ 0 ];
2176 // We use our own, invisible, body unless the body is already present
2177 // in which case we use a div (#9239)
2178 testElement = document.createElement( body ? "div" : "body" );
2179 testElementStyle = {
2180 visibility: "hidden",
2181 width: 0,
2182 height: 0,
2183 border: 0,
2184 margin: 0,
2185 background: "none"
2186 };
2187 if ( body ) {
2188 jQuery.extend( testElementStyle, {
2189 position: "absolute",
2190 left: "-999px",
2191 top: "-999px"
2192 });
2193 }
2194 for ( i in testElementStyle ) {
2195 testElement.style[ i ] = testElementStyle[ i ];
2196 }
2197 testElement.appendChild( div );
2198 testElementParent = body || documentElement;
2199 testElementParent.insertBefore( testElement, testElementParent.firstChild );
2200
2201 // Check if a disconnected checkbox will retain its checked
2202 // value of true after appended to the DOM (IE6/7)
2203 support.appendChecked = input.checked;
2204
2205 support.boxModel = div.offsetWidth === 2;
2206
2207 if ( "zoom" in div.style ) {
2208 // Check if natively block-level elements act like inline-block
2209 // elements when setting their display to 'inline' and giving
2210 // them layout
2211 // (IE < 8 does this)
2212 div.style.display = "inline";
2213 div.style.zoom = 1;
2214 support.inlineBlockNeedsLayout = ( div.offsetWidth === 2 );
2215
2216 // Check if elements with layout shrink-wrap their children
2217 // (IE 6 does this)
2218 div.style.display = "";
2219 div.innerHTML = "<div style='width:4px;'></div>";
2220 support.shrinkWrapBlocks = ( div.offsetWidth !== 2 );
2221 }
2222
2223 div.innerHTML = "<table><tr><td style='padding:0;border:0;display:none'></td><td>t</td></tr></table>";
2224 tds = div.getElementsByTagName( "td" );
2225
2226 // Check if table cells still have offsetWidth/Height when they are set
2227 // to display:none and there are still other visible table cells in a
2228 // table row; if so, offsetWidth/Height are not reliable for use when
2229 // determining if an element has been hidden directly using
2230 // display:none (it is still safe to use offsets if a parent element is
2231 // hidden; don safety goggles and see bug #4512 for more information).
2232 // (only IE 8 fails this test)
2233 isSupported = ( tds[ 0 ].offsetHeight === 0 );
2234
2235 tds[ 0 ].style.display = "";
2236 tds[ 1 ].style.display = "none";
2237
2238 // Check if empty table cells still have offsetWidth/Height
2239 // (IE < 8 fail this test)
2240 support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 );
2241 div.innerHTML = "";
2242
2243 // Check if div with explicit width and no margin-right incorrectly
2244 // gets computed margin-right based on width of container. For more
2245 // info see bug #3333
2246 // Fails in WebKit before Feb 2011 nightlies
2247 // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
2248 if ( document.defaultView && document.defaultView.getComputedStyle ) {
2249 marginDiv = document.createElement( "div" );
2250 marginDiv.style.width = "0";
2251 marginDiv.style.marginRight = "0";
2252 div.appendChild( marginDiv );
2253 support.reliableMarginRight =
2254 ( parseInt( ( document.defaultView.getComputedStyle( marginDiv, null ) || { marginRight: 0 } ).marginRight, 10 ) || 0 ) === 0;
2255 }
2256
2257 // Technique from Juriy Zaytsev
2258 // http://perfectionkills.com/detecting-event-support-without-browser-sniffing/
2259 // We only care about the case where non-standard event systems
2260 // are used, namely in IE. Short-circuiting here helps us to
2261 // avoid an eval call (in setAttribute) which can cause CSP
2262 // to go haywire. See: https://developer.mozilla.org/en/Security/CSP
2263 if ( div.attachEvent ) {
2264 for( i in {
2265 submit: 1,
2266 change: 1,
2267 focusin: 1
2268 } ) {
2269 eventName = "on" + i;
2270 isSupported = ( eventName in div );
2271 if ( !isSupported ) {
2272 div.setAttribute( eventName, "return;" );
2273 isSupported = ( typeof div[ eventName ] === "function" );
2274 }
2275 support[ i + "Bubbles" ] = isSupported;
2276 }
2277 }
2278
2279 // Run fixed position tests at doc ready to avoid a crash
2280 // related to the invisible body in IE8
2281 jQuery(function() {
2282 var container, outer, inner, table, td, offsetSupport,
2283 conMarginTop = 1,
2284 ptlm = "position:absolute;top:0;left:0;width:1px;height:1px;margin:0;",
2285 vb = "visibility:hidden;border:0;",
2286 style = "style='" + ptlm + "border:5px solid #000;padding:0;'",
2287 html = "<div " + style + "><div></div></div>" +
2288 "<table " + style + " cellpadding='0' cellspacing='0'>" +
2289 "<tr><td></td></tr></table>";
2290
2291 // Reconstruct a container
2292 body = document.getElementsByTagName("body")[0];
2293 if ( !body ) {
2294 // Return for frameset docs that don't have a body
2295 // These tests cannot be done
2296 return;
2297 }
2298
2299 container = document.createElement("div");
2300 container.style.cssText = vb + "width:0;height:0;position:static;top:0;margin-top:" + conMarginTop + "px";
2301 body.insertBefore( container, body.firstChild );
2302
2303 // Construct a test element
2304 testElement = document.createElement("div");
2305 testElement.style.cssText = ptlm + vb;
2306
2307 testElement.innerHTML = html;
2308 container.appendChild( testElement );
2309 outer = testElement.firstChild;
2310 inner = outer.firstChild;
2311 td = outer.nextSibling.firstChild.firstChild;
2312
2313 offsetSupport = {
2314 doesNotAddBorder: ( inner.offsetTop !== 5 ),
2315 doesAddBorderForTableAndCells: ( td.offsetTop === 5 )
2316 };
2317
2318 inner.style.position = "fixed";
2319 inner.style.top = "20px";
2320
2321 // safari subtracts parent border width here which is 5px
2322 offsetSupport.fixedPosition = ( inner.offsetTop === 20 || inner.offsetTop === 15 );
2323 inner.style.position = inner.style.top = "";
2324
2325 outer.style.overflow = "hidden";
2326 outer.style.position = "relative";
2327
2328 offsetSupport.subtractsBorderForOverflowNotVisible = ( inner.offsetTop === -5 );
2329 offsetSupport.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== conMarginTop );
2330
2331 body.removeChild( container );
2332 testElement = container = null;
2333
2334 jQuery.extend( support, offsetSupport );
2335 });
2336
2337 testElement.innerHTML = "";
2338 testElementParent.removeChild( testElement );
2339
2340 // Null connected elements to avoid leaks in IE
2341 testElement = fragment = select = opt = body = marginDiv = div = input = null;
2342
2343 return support;
2344})();
2345
2346// Keep track of boxModel
2347jQuery.boxModel = jQuery.support.boxModel;
2348
2349})( jQuery );
2350(function( jQuery ) {
2351
2352var rbrace = /^(?:\{.*\}|\[.*\])$/,
2353 rmultiDash = /([A-Z])/g;
2354
2355jQuery.extend({
2356 cache: {},
2357
2358 // Please use with caution
2359 uuid: 0,
2360
2361 // Unique for each copy of jQuery on the page
2362 // Non-digits removed to match rinlinejQuery
2363 expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ),
2364
2365 // The following elements throw uncatchable exceptions if you
2366 // attempt to add expando properties to them.
2367 noData: {
2368 "embed": true,
2369 // Ban all objects except for Flash (which handle expandos)
2370 "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",
2371 "applet": true
2372 },
2373
2374 hasData: function( elem ) {
2375 elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];
2376 return !!elem && !isEmptyDataObject( elem );
2377 },
2378
2379 data: function( elem, name, data, pvt /* Internal Use Only */ ) {
2380 if ( !jQuery.acceptData( elem ) ) {
2381 return;
2382 }
2383
2384 var privateCache, thisCache, ret,
2385 internalKey = jQuery.expando,
2386 getByName = typeof name === "string",
2387
2388 // We have to handle DOM nodes and JS objects differently because IE6-7
2389 // can't GC object references properly across the DOM-JS boundary
2390 isNode = elem.nodeType,
2391
2392 // Only DOM nodes need the global jQuery cache; JS object data is
2393 // attached directly to the object so GC can occur automatically
2394 cache = isNode ? jQuery.cache : elem,
2395
2396 // Only defining an ID for JS objects if its cache already exists allows
2397 // the code to shortcut on the same path as a DOM node with no cache
2398 id = isNode ? elem[ jQuery.expando ] : elem[ jQuery.expando ] && jQuery.expando,
2399 isEvents = name === "events";
2400
2401 // Avoid doing any more work than we need to when trying to get data on an
2402 // object that has no data at all
2403 if ( (!id || !cache[id] || (!isEvents && !pvt && !cache[id].data)) && getByName && data === undefined ) {
2404 return;
2405 }
2406
2407 if ( !id ) {
2408 // Only DOM nodes need a new unique ID for each element since their data
2409 // ends up in the global cache
2410 if ( isNode ) {
2411 elem[ jQuery.expando ] = id = ++jQuery.uuid;
2412 } else {
2413 id = jQuery.expando;
2414 }
2415 }
2416
2417 if ( !cache[ id ] ) {
2418 cache[ id ] = {};
2419
2420 // Avoids exposing jQuery metadata on plain JS objects when the object
2421 // is serialized using JSON.stringify
2422 if ( !isNode ) {
2423 cache[ id ].toJSON = jQuery.noop;
2424 }
2425 }
2426
2427 // An object can be passed to jQuery.data instead of a key/value pair; this gets
2428 // shallow copied over onto the existing cache
2429 if ( typeof name === "object" || typeof name === "function" ) {
2430 if ( pvt ) {
2431 cache[ id ] = jQuery.extend( cache[ id ], name );
2432 } else {
2433 cache[ id ].data = jQuery.extend( cache[ id ].data, name );
2434 }
2435 }
2436
2437 privateCache = thisCache = cache[ id ];
2438
2439 // jQuery data() is stored in a separate object inside the object's internal data
2440 // cache in order to avoid key collisions between internal data and user-defined
2441 // data.
2442 if ( !pvt ) {
2443 if ( !thisCache.data ) {
2444 thisCache.data = {};
2445 }
2446
2447 thisCache = thisCache.data;
2448 }
2449
2450 if ( data !== undefined ) {
2451 thisCache[ jQuery.camelCase( name ) ] = data;
2452 }
2453
2454 // Users should not attempt to inspect the internal events object using jQuery.data,
2455 // it is undocumented and subject to change. But does anyone listen? No.
2456 if ( isEvents && !thisCache[ name ] ) {
2457 return privateCache.events;
2458 }
2459
2460 // Check for both converted-to-camel and non-converted data property names
2461 // If a data property was specified
2462 if ( getByName ) {
2463
2464 // First Try to find as-is property data
2465 ret = thisCache[ name ];
2466
2467 // Test for null|undefined property data
2468 if ( ret == null ) {
2469
2470 // Try to find the camelCased property
2471 ret = thisCache[ jQuery.camelCase( name ) ];
2472 }
2473 } else {
2474 ret = thisCache;
2475 }
2476
2477 return ret;
2478 },
2479
2480 removeData: function( elem, name, pvt /* Internal Use Only */ ) {
2481 if ( !jQuery.acceptData( elem ) ) {
2482 return;
2483 }
2484
2485 var thisCache, i, l,
2486
2487 // Reference to internal data cache key
2488 internalKey = jQuery.expando,
2489
2490 isNode = elem.nodeType,
2491
2492 // See jQuery.data for more information
2493 cache = isNode ? jQuery.cache : elem,
2494
2495 // See jQuery.data for more information
2496 id = isNode ? elem[ jQuery.expando ] : jQuery.expando;
2497
2498 // If there is already no cache entry for this object, there is no
2499 // purpose in continuing
2500 if ( !cache[ id ] ) {
2501 return;
2502 }
2503
2504 if ( name ) {
2505
2506 thisCache = pvt ? cache[ id ] : cache[ id ].data;
2507
2508 if ( thisCache ) {
2509
2510 // Support space separated names
2511 if ( jQuery.isArray( name ) ) {
2512 name = name;
2513 } else if ( name in thisCache ) {
2514 name = [ name ];
2515 } else {
2516
2517 // split the camel cased version by spaces
2518 name = jQuery.camelCase( name );
2519 if ( name in thisCache ) {
2520 name = [ name ];
2521 } else {
2522 name = name.split( " " );
2523 }
2524 }
2525
2526 for ( i = 0, l = name.length; i < l; i++ ) {
2527 delete thisCache[ name[i] ];
2528 }
2529
2530 // If there is no data left in the cache, we want to continue
2531 // and let the cache object itself get destroyed
2532 if ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) {
2533 return;
2534 }
2535 }
2536 }
2537
2538 // See jQuery.data for more information
2539 if ( !pvt ) {
2540 delete cache[ id ].data;
2541
2542 // Don't destroy the parent cache unless the internal data object
2543 // had been the only thing left in it
2544 if ( !isEmptyDataObject(cache[ id ]) ) {
2545 return;
2546 }
2547 }
2548
2549 // Browsers that fail expando deletion also refuse to delete expandos on
2550 // the window, but it will allow it on all other JS objects; other browsers
2551 // don't care
2552 // Ensure that `cache` is not a window object #10080
2553 if ( jQuery.support.deleteExpando || !cache.setInterval ) {
2554 delete cache[ id ];
2555 } else {
2556 cache[ id ] = null;
2557 }
2558
2559 // We destroyed the cache and need to eliminate the expando on the node to avoid
2560 // false lookups in the cache for entries that no longer exist
2561 if ( isNode ) {
2562 // IE does not allow us to delete expando properties from nodes,
2563 // nor does it have a removeAttribute function on Document nodes;
2564 // we must handle all of these cases
2565 if ( jQuery.support.deleteExpando ) {
2566 delete elem[ jQuery.expando ];
2567 } else if ( elem.removeAttribute ) {
2568 elem.removeAttribute( jQuery.expando );
2569 } else {
2570 elem[ jQuery.expando ] = null;
2571 }
2572 }
2573 },
2574
2575 // For internal use only.
2576 _data: function( elem, name, data ) {
2577 return jQuery.data( elem, name, data, true );
2578 },
2579
2580 // A method for determining if a DOM node can handle the data expando
2581 acceptData: function( elem ) {
2582 if ( elem.nodeName ) {
2583 var match = jQuery.noData[ elem.nodeName.toLowerCase() ];
2584
2585 if ( match ) {
2586 return !(match === true || elem.getAttribute("classid") !== match);
2587 }
2588 }
2589
2590 return true;
2591 }
2592});
2593
2594jQuery.fn.extend({
2595 data: function( key, value ) {
2596 var parts, attr, name,
2597 data = null;
2598
2599 if ( typeof key === "undefined" ) {
2600 if ( this.length ) {
2601 data = jQuery.data( this[0] );
2602
2603 if ( this[0].nodeType === 1 && !jQuery._data( this[0], "parsedAttrs" ) ) {
2604 attr = this[0].attributes;
2605 for ( var i = 0, l = attr.length; i < l; i++ ) {
2606 name = attr[i].name;
2607
2608 if ( name.indexOf( "data-" ) === 0 ) {
2609 name = jQuery.camelCase( name.substring(5) );
2610
2611 dataAttr( this[0], name, data[ name ] );
2612 }
2613 }
2614 jQuery._data( this[0], "parsedAttrs", true );
2615 }
2616 }
2617
2618 return data;
2619
2620 } else if ( typeof key === "object" ) {
2621 return this.each(function() {
2622 jQuery.data( this, key );
2623 });
2624 }
2625
2626 parts = key.split(".");
2627 parts[1] = parts[1] ? "." + parts[1] : "";
2628
2629 if ( value === undefined ) {
2630 data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]);
2631
2632 // Try to fetch any internally stored data first
2633 if ( data === undefined && this.length ) {
2634 data = jQuery.data( this[0], key );
2635 data = dataAttr( this[0], key, data );
2636 }
2637
2638 return data === undefined && parts[1] ?
2639 this.data( parts[0] ) :
2640 data;
2641
2642 } else {
2643 return this.each(function() {
2644 var $this = jQuery( this ),
2645 args = [ parts[0], value ];
2646
2647 $this.triggerHandler( "setData" + parts[1] + "!", args );
2648 jQuery.data( this, key, value );
2649 $this.triggerHandler( "changeData" + parts[1] + "!", args );
2650 });
2651 }
2652 },
2653
2654 removeData: function( key ) {
2655 return this.each(function() {
2656 jQuery.removeData( this, key );
2657 });
2658 }
2659});
2660
2661function dataAttr( elem, key, data ) {
2662 // If nothing was found internally, try to fetch any
2663 // data from the HTML5 data-* attribute
2664 if ( data === undefined && elem.nodeType === 1 ) {
2665
2666 var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase();
2667
2668 data = elem.getAttribute( name );
2669
2670 if ( typeof data === "string" ) {
2671 try {
2672 data = data === "true" ? true :
2673 data === "false" ? false :
2674 data === "null" ? null :
2675 jQuery.isNumeric( data ) ? parseFloat( data ) :
2676 rbrace.test( data ) ? jQuery.parseJSON( data ) :
2677 data;
2678 } catch( e ) {}
2679
2680 // Make sure we set the data so it isn't changed later
2681 jQuery.data( elem, key, data );
2682
2683 } else {
2684 data = undefined;
2685 }
2686 }
2687
2688 return data;
2689}
2690
2691// checks a cache object for emptiness
2692function isEmptyDataObject( obj ) {
2693 for ( var name in obj ) {
2694
2695 // if the public data object is empty, the private is still empty
2696 if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) {
2697 continue;
2698 }
2699 if ( name !== "toJSON" ) {
2700 return false;
2701 }
2702 }
2703
2704 return true;
2705}
2706
2707})( jQuery );
2708(function( jQuery ) {
2709
2710function handleQueueMarkDefer( elem, type, src ) {
2711 var deferDataKey = type + "defer",
2712 queueDataKey = type + "queue",
2713 markDataKey = type + "mark",
2714 defer = jQuery._data( elem, deferDataKey );
2715 if ( defer &&
2716 ( src === "queue" || !jQuery._data(elem, queueDataKey) ) &&
2717 ( src === "mark" || !jQuery._data(elem, markDataKey) ) ) {
2718 // Give room for hard-coded callbacks to fire first
2719 // and eventually mark/queue something else on the element
2720 setTimeout( function() {
2721 if ( !jQuery._data( elem, queueDataKey ) &&
2722 !jQuery._data( elem, markDataKey ) ) {
2723 jQuery.removeData( elem, deferDataKey, true );
2724 defer.fire();
2725 }
2726 }, 0 );
2727 }
2728}
2729
2730jQuery.extend({
2731
2732 _mark: function( elem, type ) {
2733 if ( elem ) {
2734 type = ( type || "fx" ) + "mark";
2735 jQuery._data( elem, type, (jQuery._data( elem, type ) || 0) + 1 );
2736 }
2737 },
2738
2739 _unmark: function( force, elem, type ) {
2740 if ( force !== true ) {
2741 type = elem;
2742 elem = force;
2743 force = false;
2744 }
2745 if ( elem ) {
2746 type = type || "fx";
2747 var key = type + "mark",
2748 count = force ? 0 : ( (jQuery._data( elem, key ) || 1) - 1 );
2749 if ( count ) {
2750 jQuery._data( elem, key, count );
2751 } else {
2752 jQuery.removeData( elem, key, true );
2753 handleQueueMarkDefer( elem, type, "mark" );
2754 }
2755 }
2756 },
2757
2758 queue: function( elem, type, data ) {
2759 var q;
2760 if ( elem ) {
2761 type = ( type || "fx" ) + "queue";
2762 q = jQuery._data( elem, type );
2763
2764 // Speed up dequeue by getting out quickly if this is just a lookup
2765 if ( data ) {
2766 if ( !q || jQuery.isArray(data) ) {
2767 q = jQuery._data( elem, type, jQuery.makeArray(data) );
2768 } else {
2769 q.push( data );
2770 }
2771 }
2772 return q || [];
2773 }
2774 },
2775
2776 dequeue: function( elem, type ) {
2777 type = type || "fx";
2778
2779 var queue = jQuery.queue( elem, type ),
2780 fn = queue.shift(),
2781 hooks = {};
2782
2783 // If the fx queue is dequeued, always remove the progress sentinel
2784 if ( fn === "inprogress" ) {
2785 fn = queue.shift();
2786 }
2787
2788 if ( fn ) {
2789 // Add a progress sentinel to prevent the fx queue from being
2790 // automatically dequeued
2791 if ( type === "fx" ) {
2792 queue.unshift( "inprogress" );
2793 }
2794
2795 jQuery._data( elem, type + ".run", hooks );
2796 fn.call( elem, function() {
2797 jQuery.dequeue( elem, type );
2798 }, hooks );
2799 }
2800
2801 if ( !queue.length ) {
2802 jQuery.removeData( elem, type + "queue " + type + ".run", true );
2803 handleQueueMarkDefer( elem, type, "queue" );
2804 }
2805 }
2806});
2807
2808jQuery.fn.extend({
2809 queue: function( type, data ) {
2810 if ( typeof type !== "string" ) {
2811 data = type;
2812 type = "fx";
2813 }
2814
2815 if ( data === undefined ) {
2816 return jQuery.queue( this[0], type );
2817 }
2818 return this.each(function() {
2819 var queue = jQuery.queue( this, type, data );
2820
2821 if ( type === "fx" && queue[0] !== "inprogress" ) {
2822 jQuery.dequeue( this, type );
2823 }
2824 });
2825 },
2826 dequeue: function( type ) {
2827 return this.each(function() {
2828 jQuery.dequeue( this, type );
2829 });
2830 },
2831 // Based off of the plugin by Clint Helfers, with permission.
2832 // http://blindsignals.com/index.php/2009/07/jquery-delay/
2833 delay: function( time, type ) {
2834 time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
2835 type = type || "fx";
2836
2837 return this.queue( type, function( next, hooks ) {
2838 var timeout = setTimeout( next, time );
2839 hooks.stop = function() {
2840 clearTimeout( timeout );
2841 };
2842 });
2843 },
2844 clearQueue: function( type ) {
2845 return this.queue( type || "fx", [] );
2846 },
2847 // Get a promise resolved when queues of a certain type
2848 // are emptied (fx is the type by default)
2849 promise: function( type, object ) {
2850 if ( typeof type !== "string" ) {
2851 object = type;
2852 type = undefined;
2853 }
2854 type = type || "fx";
2855 var defer = jQuery.Deferred(),
2856 elements = this,
2857 i = elements.length,
2858 count = 1,
2859 deferDataKey = type + "defer",
2860 queueDataKey = type + "queue",
2861 markDataKey = type + "mark",
2862 tmp;
2863 function resolve() {
2864 if ( !( --count ) ) {
2865 defer.resolveWith( elements, [ elements ] );
2866 }
2867 }
2868 while( i-- ) {
2869 if (( tmp = jQuery.data( elements[ i ], deferDataKey, undefined, true ) ||
2870 ( jQuery.data( elements[ i ], queueDataKey, undefined, true ) ||
2871 jQuery.data( elements[ i ], markDataKey, undefined, true ) ) &&
2872 jQuery.data( elements[ i ], deferDataKey, jQuery.Callbacks( "once memory" ), true ) )) {
2873 count++;
2874 tmp.add( resolve );
2875 }
2876 }
2877 resolve();
2878 return defer.promise();
2879 }
2880});
2881
2882})( jQuery );
2883(function( jQuery ) {
2884
2885var rclass = /[\n\t\r]/g,
2886 rspace = /\s+/,
2887 rreturn = /\r/g,
2888 rtype = /^(?:button|input)$/i,
2889 rfocusable = /^(?:button|input|object|select|textarea)$/i,
2890 rclickable = /^a(?:rea)?$/i,
2891 rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,
2892 getSetAttribute = jQuery.support.getSetAttribute,
2893 nodeHook, boolHook, fixSpecified;
2894
2895jQuery.fn.extend({
2896 attr: function( name, value ) {
2897 return jQuery.access( this, name, value, true, jQuery.attr );
2898 },
2899
2900 removeAttr: function( name ) {
2901 return this.each(function() {
2902 jQuery.removeAttr( this, name );
2903 });
2904 },
2905
2906 prop: function( name, value ) {
2907 return jQuery.access( this, name, value, true, jQuery.prop );
2908 },
2909
2910 removeProp: function( name ) {
2911 name = jQuery.propFix[ name ] || name;
2912 return this.each(function() {
2913 // try/catch handles cases where IE balks (such as removing a property on window)
2914 try {
2915 this[ name ] = undefined;
2916 delete this[ name ];
2917 } catch( e ) {}
2918 });
2919 },
2920
2921 addClass: function( value ) {
2922 var classNames, i, l, elem,
2923 setClass, c, cl;
2924
2925 if ( jQuery.isFunction( value ) ) {
2926 return this.each(function( j ) {
2927 jQuery( this ).addClass( value.call(this, j, this.className) );
2928 });
2929 }
2930
2931 if ( value && typeof value === "string" ) {
2932 classNames = value.split( rspace );
2933
2934 for ( i = 0, l = this.length; i < l; i++ ) {
2935 elem = this[ i ];
2936
2937 if ( elem.nodeType === 1 ) {
2938 if ( !elem.className && classNames.length === 1 ) {
2939 elem.className = value;
2940
2941 } else {
2942 setClass = " " + elem.className + " ";
2943
2944 for ( c = 0, cl = classNames.length; c < cl; c++ ) {
2945 if ( !~setClass.indexOf( " " + classNames[ c ] + " " ) ) {
2946 setClass += classNames[ c ] + " ";
2947 }
2948 }
2949 elem.className = jQuery.trim( setClass );
2950 }
2951 }
2952 }
2953 }
2954
2955 return this;
2956 },
2957
2958 removeClass: function( value ) {
2959 var classNames, i, l, elem, className, c, cl;
2960
2961 if ( jQuery.isFunction( value ) ) {
2962 return this.each(function( j ) {
2963 jQuery( this ).removeClass( value.call(this, j, this.className) );
2964 });
2965 }
2966
2967 if ( (value && typeof value === "string") || value === undefined ) {
2968 classNames = ( value || "" ).split( rspace );
2969
2970 for ( i = 0, l = this.length; i < l; i++ ) {
2971 elem = this[ i ];
2972
2973 if ( elem.nodeType === 1 && elem.className ) {
2974 if ( value ) {
2975 className = (" " + elem.className + " ").replace( rclass, " " );
2976 for ( c = 0, cl = classNames.length; c < cl; c++ ) {
2977 className = className.replace(" " + classNames[ c ] + " ", " ");
2978 }
2979 elem.className = jQuery.trim( className );
2980
2981 } else {
2982 elem.className = "";
2983 }
2984 }
2985 }
2986 }
2987
2988 return this;
2989 },
2990
2991 toggleClass: function( value, stateVal ) {
2992 var type = typeof value,
2993 isBool = typeof stateVal === "boolean";
2994
2995 if ( jQuery.isFunction( value ) ) {
2996 return this.each(function( i ) {
2997 jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );
2998 });
2999 }
3000
3001 return this.each(function() {
3002 if ( type === "string" ) {
3003 // toggle individual class names
3004 var className,
3005 i = 0,
3006 self = jQuery( this ),
3007 state = stateVal,
3008 classNames = value.split( rspace );
3009
3010 while ( (className = classNames[ i++ ]) ) {
3011 // check each className given, space seperated list
3012 state = isBool ? state : !self.hasClass( className );
3013 self[ state ? "addClass" : "removeClass" ]( className );
3014 }
3015
3016 } else if ( type === "undefined" || type === "boolean" ) {
3017 if ( this.className ) {
3018 // store className if set
3019 jQuery._data( this, "__className__", this.className );
3020 }
3021
3022 // toggle whole className
3023 this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || "";
3024 }
3025 });
3026 },
3027
3028 hasClass: function( selector ) {
3029 var className = " " + selector + " ",
3030 i = 0,
3031 l = this.length;
3032 for ( ; i < l; i++ ) {
3033 if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) {
3034 return true;
3035 }
3036 }
3037
3038 return false;
3039 },
3040
3041 val: function( value ) {
3042 var hooks, ret, isFunction,
3043 elem = this[0];
3044
3045 if ( !arguments.length ) {
3046 if ( elem ) {
3047 hooks = jQuery.valHooks[ elem.nodeName.toLowerCase() ] || jQuery.valHooks[ elem.type ];
3048
3049 if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) {
3050 return ret;
3051 }
3052
3053 ret = elem.value;
3054
3055 return typeof ret === "string" ?
3056 // handle most common string cases
3057 ret.replace(rreturn, "") :
3058 // handle cases where value is null/undef or number
3059 ret == null ? "" : ret;
3060 }
3061
3062 return undefined;
3063 }
3064
3065 isFunction = jQuery.isFunction( value );
3066
3067 return this.each(function( i ) {
3068 var self = jQuery(this), val;
3069
3070 if ( this.nodeType !== 1 ) {
3071 return;
3072 }
3073
3074 if ( isFunction ) {
3075 val = value.call( this, i, self.val() );
3076 } else {
3077 val = value;
3078 }
3079
3080 // Treat null/undefined as ""; convert numbers to string
3081 if ( val == null ) {
3082 val = "";
3083 } else if ( typeof val === "number" ) {
3084 val += "";
3085 } else if ( jQuery.isArray( val ) ) {
3086 val = jQuery.map(val, function ( value ) {
3087 return value == null ? "" : value + "";
3088 });
3089 }
3090
3091 hooks = jQuery.valHooks[ this.nodeName.toLowerCase() ] || jQuery.valHooks[ this.type ];
3092
3093 // If set returns undefined, fall back to normal setting
3094 if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) {
3095 this.value = val;
3096 }
3097 });
3098 }
3099});
3100
3101jQuery.extend({
3102 valHooks: {
3103 option: {
3104 get: function( elem ) {
3105 // attributes.value is undefined in Blackberry 4.7 but
3106 // uses .value. See #6932
3107 var val = elem.attributes.value;
3108 return !val || val.specified ? elem.value : elem.text;
3109 }
3110 },
3111 select: {
3112 get: function( elem ) {
3113 var value, i, max, option,
3114 index = elem.selectedIndex,
3115 values = [],
3116 options = elem.options,
3117 one = elem.type === "select-one";
3118
3119 // Nothing was selected
3120 if ( index < 0 ) {
3121 return null;
3122 }
3123
3124 // Loop through all the selected options
3125 i = one ? index : 0;
3126 max = one ? index + 1 : options.length;
3127 for ( ; i < max; i++ ) {
3128 option = options[ i ];
3129
3130 // Don't return options that are disabled or in a disabled optgroup
3131 if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) &&
3132 (!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) {
3133
3134 // Get the specific value for the option
3135 value = jQuery( option ).val();
3136
3137 // We don't need an array for one selects
3138 if ( one ) {
3139 return value;
3140 }
3141
3142 // Multi-Selects return an array
3143 values.push( value );
3144 }
3145 }
3146
3147 // Fixes Bug #2551 -- select.val() broken in IE after form.reset()
3148 if ( one && !values.length && options.length ) {
3149 return jQuery( options[ index ] ).val();
3150 }
3151
3152 return values;
3153 },
3154
3155 set: function( elem, value ) {
3156 var values = jQuery.makeArray( value );
3157
3158 jQuery(elem).find("option").each(function() {
3159 this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0;
3160 });
3161
3162 if ( !values.length ) {
3163 elem.selectedIndex = -1;
3164 }
3165 return values;
3166 }
3167 }
3168 },
3169
3170 attrFn: {
3171 val: true,
3172 css: true,
3173 html: true,
3174 text: true,
3175 data: true,
3176 width: true,
3177 height: true,
3178 offset: true
3179 },
3180
3181 attr: function( elem, name, value, pass ) {
3182 var ret, hooks, notxml,
3183 nType = elem.nodeType;
3184
3185 // don't get/set attributes on text, comment and attribute nodes
3186 if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
3187 return undefined;
3188 }
3189
3190 if ( pass && name in jQuery.attrFn ) {
3191 return jQuery( elem )[ name ]( value );
3192 }
3193
3194 // Fallback to prop when attributes are not supported
3195 if ( !("getAttribute" in elem) ) {
3196 return jQuery.prop( elem, name, value );
3197 }
3198
3199 notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
3200
3201 // All attributes are lowercase
3202 // Grab necessary hook if one is defined
3203 if ( notxml ) {
3204 name = name.toLowerCase();
3205 hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook );
3206 }
3207
3208 if ( value !== undefined ) {
3209
3210 if ( value === null ) {
3211 jQuery.removeAttr( elem, name );
3212 return undefined;
3213
3214 } else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) {
3215 return ret;
3216
3217 } else {
3218 elem.setAttribute( name, "" + value );
3219 return value;
3220 }
3221
3222 } else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) {
3223 return ret;
3224
3225 } else {
3226
3227 ret = elem.getAttribute( name );
3228
3229 // Non-existent attributes return null, we normalize to undefined
3230 return ret === null ?
3231 undefined :
3232 ret;
3233 }
3234 },
3235
3236 removeAttr: function( elem, value ) {
3237 var propName, attrNames, name, l,
3238 i = 0;
3239
3240 if ( elem.nodeType === 1 ) {
3241 attrNames = ( value || "" ).split( rspace );
3242 l = attrNames.length;
3243
3244 for ( ; i < l; i++ ) {
3245 name = attrNames[ i ].toLowerCase();
3246 propName = jQuery.propFix[ name ] || name;
3247
3248 // See #9699 for explanation of this approach (setting first, then removal)
3249 jQuery.attr( elem, name, "" );
3250 elem.removeAttribute( getSetAttribute ? name : propName );
3251
3252 // Set corresponding property to false for boolean attributes
3253 if ( rboolean.test( name ) && propName in elem ) {
3254 elem[ propName ] = false;
3255 }
3256 }
3257 }
3258 },
3259
3260 attrHooks: {
3261 type: {
3262 set: function( elem, value ) {
3263 // We can't allow the type property to be changed (since it causes problems in IE)
3264 if ( rtype.test( elem.nodeName ) && elem.parentNode ) {
3265 jQuery.error( "type property can't be changed" );
3266 } else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) {
3267 // Setting the type on a radio button after the value resets the value in IE6-9
3268 // Reset value to it's default in case type is set after value
3269 // This is for element creation
3270 var val = elem.value;
3271 elem.setAttribute( "type", value );
3272 if ( val ) {
3273 elem.value = val;
3274 }
3275 return value;
3276 }
3277 }
3278 },
3279 // Use the value property for back compat
3280 // Use the nodeHook for button elements in IE6/7 (#1954)
3281 value: {
3282 get: function( elem, name ) {
3283 if ( nodeHook && jQuery.nodeName( elem, "button" ) ) {
3284 return nodeHook.get( elem, name );
3285 }
3286 return name in elem ?
3287 elem.value :
3288 null;
3289 },
3290 set: function( elem, value, name ) {
3291 if ( nodeHook && jQuery.nodeName( elem, "button" ) ) {
3292 return nodeHook.set( elem, value, name );
3293 }
3294 // Does not return so that setAttribute is also used
3295 elem.value = value;
3296 }
3297 }
3298 },
3299
3300 propFix: {
3301 tabindex: "tabIndex",
3302 readonly: "readOnly",
3303 "for": "htmlFor",
3304 "class": "className",
3305 maxlength: "maxLength",
3306 cellspacing: "cellSpacing",
3307 cellpadding: "cellPadding",
3308 rowspan: "rowSpan",
3309 colspan: "colSpan",
3310 usemap: "useMap",
3311 frameborder: "frameBorder",
3312 contenteditable: "contentEditable"
3313 },
3314
3315 prop: function( elem, name, value ) {
3316 var ret, hooks, notxml,
3317 nType = elem.nodeType;
3318
3319 // don't get/set properties on text, comment and attribute nodes
3320 if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
3321 return undefined;
3322 }
3323
3324 notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
3325
3326 if ( notxml ) {
3327 // Fix name and attach hooks
3328 name = jQuery.propFix[ name ] || name;
3329 hooks = jQuery.propHooks[ name ];
3330 }
3331
3332 if ( value !== undefined ) {
3333 if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
3334 return ret;
3335
3336 } else {
3337 return ( elem[ name ] = value );
3338 }
3339
3340 } else {
3341 if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
3342 return ret;
3343
3344 } else {
3345 return elem[ name ];
3346 }
3347 }
3348 },
3349
3350 propHooks: {
3351 tabIndex: {
3352 get: function( elem ) {
3353 // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set
3354 // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
3355 var attributeNode = elem.getAttributeNode("tabindex");
3356
3357 return attributeNode && attributeNode.specified ?
3358 parseInt( attributeNode.value, 10 ) :
3359 rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?
3360 0 :
3361 undefined;
3362 }
3363 }
3364 }
3365});
3366
3367// Add the tabIndex propHook to attrHooks for back-compat (different case is intentional)
3368jQuery.attrHooks.tabindex = jQuery.propHooks.tabIndex;
3369
3370// Hook for boolean attributes
3371boolHook = {
3372 get: function( elem, name ) {
3373 // Align boolean attributes with corresponding properties
3374 // Fall back to attribute presence where some booleans are not supported
3375 var attrNode,
3376 property = jQuery.prop( elem, name );
3377 return property === true || typeof property !== "boolean" && ( attrNode = elem.getAttributeNode(name) ) && attrNode.nodeValue !== false ?
3378 name.toLowerCase() :
3379 undefined;
3380 },
3381 set: function( elem, value, name ) {
3382 var propName;
3383 if ( value === false ) {
3384 // Remove boolean attributes when set to false
3385 jQuery.removeAttr( elem, name );
3386 } else {
3387 // value is true since we know at this point it's type boolean and not false
3388 // Set boolean attributes to the same name and set the DOM property
3389 propName = jQuery.propFix[ name ] || name;
3390 if ( propName in elem ) {
3391 // Only set the IDL specifically if it already exists on the element
3392 elem[ propName ] = true;
3393 }
3394
3395 elem.setAttribute( name, name.toLowerCase() );
3396 }
3397 return name;
3398 }
3399};
3400
3401// IE6/7 do not support getting/setting some attributes with get/setAttribute
3402if ( !getSetAttribute ) {
3403
3404 fixSpecified = {
3405 name: true,
3406 id: true
3407 };
3408
3409 // Use this for any attribute in IE6/7
3410 // This fixes almost every IE6/7 issue
3411 nodeHook = jQuery.valHooks.button = {
3412 get: function( elem, name ) {
3413 var ret;
3414 ret = elem.getAttributeNode( name );
3415 return ret && ( fixSpecified[ name ] ? ret.nodeValue !== "" : ret.specified ) ?
3416 ret.nodeValue :
3417 undefined;
3418 },
3419 set: function( elem, value, name ) {
3420 // Set the existing or create a new attribute node
3421 var ret = elem.getAttributeNode( name );
3422 if ( !ret ) {
3423 ret = document.createAttribute( name );
3424 elem.setAttributeNode( ret );
3425 }
3426 return ( ret.nodeValue = value + "" );
3427 }
3428 };
3429
3430 // Apply the nodeHook to tabindex
3431 jQuery.attrHooks.tabindex.set = nodeHook.set;
3432
3433 // Set width and height to auto instead of 0 on empty string( Bug #8150 )
3434 // This is for removals
3435 jQuery.each([ "width", "height" ], function( i, name ) {
3436 jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {
3437 set: function( elem, value ) {
3438 if ( value === "" ) {
3439 elem.setAttribute( name, "auto" );
3440 return value;
3441 }
3442 }
3443 });
3444 });
3445
3446 // Set contenteditable to false on removals(#10429)
3447 // Setting to empty string throws an error as an invalid value
3448 jQuery.attrHooks.contenteditable = {
3449 get: nodeHook.get,
3450 set: function( elem, value, name ) {
3451 if ( value === "" ) {
3452 value = "false";
3453 }
3454 nodeHook.set( elem, value, name );
3455 }
3456 };
3457}
3458
3459
3460// Some attributes require a special call on IE
3461if ( !jQuery.support.hrefNormalized ) {
3462 jQuery.each([ "href", "src", "width", "height" ], function( i, name ) {
3463 jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {
3464 get: function( elem ) {
3465 var ret = elem.getAttribute( name, 2 );
3466 return ret === null ? undefined : ret;
3467 }
3468 });
3469 });
3470}
3471
3472if ( !jQuery.support.style ) {
3473 jQuery.attrHooks.style = {
3474 get: function( elem ) {
3475 // Return undefined in the case of empty string
3476 // Normalize to lowercase since IE uppercases css property names
3477 return elem.style.cssText.toLowerCase() || undefined;
3478 },
3479 set: function( elem, value ) {
3480 return ( elem.style.cssText = "" + value );
3481 }
3482 };
3483}
3484
3485// Safari mis-reports the default selected property of an option
3486// Accessing the parent's selectedIndex property fixes it
3487if ( !jQuery.support.optSelected ) {
3488 jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, {
3489 get: function( elem ) {
3490 var parent = elem.parentNode;
3491
3492 if ( parent ) {
3493 parent.selectedIndex;
3494
3495 // Make sure that it also works with optgroups, see #5701
3496 if ( parent.parentNode ) {
3497 parent.parentNode.selectedIndex;
3498 }
3499 }
3500 return null;
3501 }
3502 });
3503}
3504
3505// IE6/7 call enctype encoding
3506if ( !jQuery.support.enctype ) {
3507 jQuery.propFix.enctype = "encoding";
3508}
3509
3510// Radios and checkboxes getter/setter
3511if ( !jQuery.support.checkOn ) {
3512 jQuery.each([ "radio", "checkbox" ], function() {
3513 jQuery.valHooks[ this ] = {
3514 get: function( elem ) {
3515 // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified
3516 return elem.getAttribute("value") === null ? "on" : elem.value;
3517 }
3518 };
3519 });
3520}
3521jQuery.each([ "radio", "checkbox" ], function() {
3522 jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], {
3523 set: function( elem, value ) {
3524 if ( jQuery.isArray( value ) ) {
3525 return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 );
3526 }
3527 }
3528 });
3529});
3530
3531})( jQuery );
3532(function( jQuery ) {
3533
3534var rnamespaces = /\.(.*)$/,
3535 rformElems = /^(?:textarea|input|select)$/i,
3536 rperiod = /\./g,
3537 rspaces = / /g,
3538 rescape = /[^\w\s.|`]/g,
3539 rtypenamespace = /^([^\.]*)?(?:\.(.+))?$/,
3540 rhoverHack = /\bhover(\.\S+)?/,
3541 rkeyEvent = /^key/,
3542 rmouseEvent = /^(?:mouse|contextmenu)|click/,
3543 rquickIs = /^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/,
3544 quickParse = function( selector ) {
3545 var quick = rquickIs.exec( selector );
3546 if ( quick ) {
3547 // 0 1 2 3
3548 // [ _, tag, id, class ]
3549 quick[1] = ( quick[1] || "" ).toLowerCase();
3550 quick[3] = quick[3] && new RegExp( "(?:^|\\s)" + quick[3] + "(?:\\s|$)" );
3551 }
3552 return quick;
3553 },
3554 quickIs = function( elem, m ) {
3555 return (
3556 (!m[1] || elem.nodeName.toLowerCase() === m[1]) &&
3557 (!m[2] || elem.id === m[2]) &&
3558 (!m[3] || m[3].test( elem.className ))
3559 );
3560 },
3561 hoverHack = function( events ) {
3562 return jQuery.event.special.hover ? events : events.replace( rhoverHack, "mouseenter$1 mouseleave$1" );
3563 };
3564
3565/*
3566 * Helper functions for managing events -- not part of the public interface.
3567 * Props to Dean Edwards' addEvent library for many of the ideas.
3568 */
3569jQuery.event = {
3570
3571 add: function( elem, types, handler, data, selector ) {
3572
3573 var elemData, eventHandle, events,
3574 t, tns, type, namespaces, handleObj,
3575 handleObjIn, quick, handlers, special;
3576
3577 // Don't attach events to noData or text/comment nodes (allow plain objects tho)
3578 if ( elem.nodeType === 3 || elem.nodeType === 8 || !types || !handler || !(elemData = jQuery._data( elem )) ) {
3579 return;
3580 }
3581
3582 // Caller can pass in an object of custom data in lieu of the handler
3583 if ( handler.handler ) {
3584 handleObjIn = handler;
3585 handler = handleObjIn.handler;
3586 }
3587
3588 // Make sure that the handler has a unique ID, used to find/remove it later
3589 if ( !handler.guid ) {
3590 handler.guid = jQuery.guid++;
3591 }
3592
3593 // Init the element's event structure and main handler, if this is the first
3594 events = elemData.events;
3595 if ( !events ) {
3596 elemData.events = events = {};
3597 }
3598 eventHandle = elemData.handle;
3599 if ( !eventHandle ) {
3600 elemData.handle = eventHandle = function( e ) {
3601 // Discard the second event of a jQuery.event.trigger() and
3602 // when an event is called after a page has unloaded
3603 return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ?
3604 jQuery.event.dispatch.apply( eventHandle.elem, arguments ) :
3605 undefined;
3606 };
3607 // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events
3608 eventHandle.elem = elem;
3609 }
3610
3611 // Handle multiple events separated by a space
3612 // jQuery(...).bind("mouseover mouseout", fn);
3613 types = hoverHack(types).split( " " );
3614 for ( t = 0; t < types.length; t++ ) {
3615
3616 tns = rtypenamespace.exec( types[t] ) || [];
3617 type = tns[1];
3618 namespaces = ( tns[2] || "" ).split( "." ).sort();
3619
3620 // If event changes its type, use the special event handlers for the changed type
3621 special = jQuery.event.special[ type ] || {};
3622
3623 // If selector defined, determine special event api type, otherwise given type
3624 type = ( selector ? special.delegateType : special.bindType ) || type;
3625
3626 // Update special based on newly reset type
3627 special = jQuery.event.special[ type ] || {};
3628
3629 // handleObj is passed to all event handlers
3630 handleObj = jQuery.extend({
3631 type: type,
3632 origType: tns[1],
3633 data: data,
3634 handler: handler,
3635 guid: handler.guid,
3636 selector: selector,
3637 namespace: namespaces.join(".")
3638 }, handleObjIn );
3639
3640 // Delegated event; pre-analyze selector so it's processed quickly on event dispatch
3641 if ( selector ) {
3642 handleObj.quick = quickParse( selector );
3643 if ( !handleObj.quick && jQuery.expr.match.POS.test( selector ) ) {
3644 handleObj.isPositional = true;
3645 }
3646 }
3647
3648 // Init the event handler queue if we're the first
3649 handlers = events[ type ];
3650 if ( !handlers ) {
3651 handlers = events[ type ] = [];
3652 handlers.delegateCount = 0;
3653
3654 // Only use addEventListener/attachEvent if the special events handler returns false
3655 if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
3656 // Bind the global event handler to the element
3657 if ( elem.addEventListener ) {
3658 elem.addEventListener( type, eventHandle, false );
3659
3660 } else if ( elem.attachEvent ) {
3661 elem.attachEvent( "on" + type, eventHandle );
3662 }
3663 }
3664 }
3665
3666 if ( special.add ) {
3667 special.add.call( elem, handleObj );
3668
3669 if ( !handleObj.handler.guid ) {
3670 handleObj.handler.guid = handler.guid;
3671 }
3672 }
3673
3674 // Add to the element's handler list, delegates in front
3675 if ( selector ) {
3676 handlers.splice( handlers.delegateCount++, 0, handleObj );
3677 } else {
3678 handlers.push( handleObj );
3679 }
3680
3681 // Keep track of which events have ever been used, for event optimization
3682 jQuery.event.global[ type ] = true;
3683 }
3684
3685 // Nullify elem to prevent memory leaks in IE
3686 elem = null;
3687 },
3688
3689 global: {},
3690
3691 // Detach an event or set of events from an element
3692 remove: function( elem, types, handler, selector ) {
3693
3694 var elemData = jQuery.hasData( elem ) && jQuery._data( elem ),
3695 t, tns, type, namespaces, origCount,
3696 j, events, special, handle, eventType, handleObj;
3697
3698 if ( !elemData || !(events = elemData.events) ) {
3699 return;
3700 }
3701
3702 // Once for each type.namespace in types; type may be omitted
3703 types = hoverHack( types || "" ).split(" ");
3704 for ( t = 0; t < types.length; t++ ) {
3705 tns = rtypenamespace.exec( types[t] ) || [];
3706 type = tns[1];
3707 namespaces = tns[2];
3708
3709 // Unbind all events (on this namespace, if provided) for the element
3710 if ( !type ) {
3711 namespaces = namespaces? "." + namespaces : "";
3712 for ( j in events ) {
3713 jQuery.event.remove( elem, j + namespaces, handler, selector );
3714 }
3715 return;
3716 }
3717
3718 special = jQuery.event.special[ type ] || {};
3719 type = ( selector? special.delegateType : special.bindType ) || type;
3720 eventType = events[ type ] || [];
3721 origCount = eventType.length;
3722 namespaces = namespaces ? new RegExp("(^|\\.)" + namespaces.split(".").sort().join("\\.(?:.*\\.)?") + "(\\.|$)") : null;
3723
3724 // Only need to loop for special events or selective removal
3725 if ( handler || namespaces || selector || special.remove ) {
3726 for ( j = 0; j < eventType.length; j++ ) {
3727 handleObj = eventType[ j ];
3728
3729 if ( !handler || handler.guid === handleObj.guid ) {
3730 if ( !namespaces || namespaces.test( handleObj.namespace ) ) {
3731 if ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) {
3732 eventType.splice( j--, 1 );
3733
3734 if ( handleObj.selector ) {
3735 eventType.delegateCount--;
3736 }
3737 if ( special.remove ) {
3738 special.remove.call( elem, handleObj );
3739 }
3740 }
3741 }
3742 }
3743 }
3744 } else {
3745 // Removing all events
3746 eventType.length = 0;
3747 }
3748
3749 // Remove generic event handler if we removed something and no more handlers exist
3750 // (avoids potential for endless recursion during removal of special event handlers)
3751 if ( eventType.length === 0 && origCount !== eventType.length ) {
3752 if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) {
3753 jQuery.removeEvent( elem, type, elemData.handle );
3754 }
3755
3756 delete events[ type ];
3757 }
3758 }
3759
3760 // Remove the expando if it's no longer used
3761 if ( jQuery.isEmptyObject( events ) ) {
3762 handle = elemData.handle;
3763 if ( handle ) {
3764 handle.elem = null;
3765 }
3766
3767 // removeData also checks for emptiness and clears the expando if empty
3768 // so use it instead of delete
3769 jQuery.removeData( elem, [ "events", "handle" ], true );
3770 }
3771 },
3772
3773 // Events that are safe to short-circuit if no handlers are attached.
3774 // Native DOM events should not be added, they may have inline handlers.
3775 customEvent: {
3776 "getData": true,
3777 "setData": true,
3778 "changeData": true
3779 },
3780
3781 trigger: function( event, data, elem, onlyHandlers ) {
3782 // Don't do events on text and comment nodes
3783 if ( elem && (elem.nodeType === 3 || elem.nodeType === 8) ) {
3784 return;
3785 }
3786
3787 // Event object or event type
3788 var type = event.type || event,
3789 namespaces = [],
3790 cache, exclusive, i, cur, old, ontype, special, handle, eventPath, bubbleType;
3791
3792 if ( type.indexOf( "!" ) >= 0 ) {
3793 // Exclusive events trigger only for the exact event (no namespaces)
3794 type = type.slice(0, -1);
3795 exclusive = true;
3796 }
3797
3798 if ( type.indexOf( "." ) >= 0 ) {
3799 // Namespaced trigger; create a regexp to match event type in handle()
3800 namespaces = type.split(".");
3801 type = namespaces.shift();
3802 namespaces.sort();
3803 }
3804
3805 if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) {
3806 // No jQuery handlers for this event type, and it can't have inline handlers
3807 return;
3808 }
3809
3810 // Caller can pass in an Event, Object, or just an event type string
3811 event = typeof event === "object" ?
3812 // jQuery.Event object
3813 event[ jQuery.expando ] ? event :
3814 // Object literal
3815 new jQuery.Event( type, event ) :
3816 // Just the event type (string)
3817 new jQuery.Event( type );
3818
3819 event.type = type;
3820 event.isTrigger = true;
3821 event.exclusive = exclusive;
3822 event.namespace = namespaces.join( "." );
3823 event.namespace_re = event.namespace? new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.)?") + "(\\.|$)") : null;
3824 ontype = type.indexOf( ":" ) < 0 ? "on" + type : "";
3825
3826 // triggerHandler() and global events don't bubble or run the default action
3827 if ( onlyHandlers || !elem ) {
3828 event.preventDefault();
3829 }
3830
3831 // Handle a global trigger
3832 if ( !elem ) {
3833
3834 // TODO: Stop taunting the data cache; remove global events and always attach to document
3835 cache = jQuery.cache;
3836 for ( i in cache ) {
3837 if ( cache[ i ].events && cache[ i ].events[ type ] ) {
3838 jQuery.event.trigger( event, data, cache[ i ].handle.elem, true );
3839 }
3840 }
3841 return;
3842 }
3843
3844 // Clean up the event in case it is being reused
3845 event.result = undefined;
3846 if ( !event.target ) {
3847 event.target = elem;
3848 }
3849
3850 // Clone any incoming data and prepend the event, creating the handler arg list
3851 data = data != null ? jQuery.makeArray( data ) : [];
3852 data.unshift( event );
3853
3854 // Allow special events to draw outside the lines
3855 special = jQuery.event.special[ type ] || {};
3856 if ( special.trigger && special.trigger.apply( elem, data ) === false ) {
3857 return;
3858 }
3859
3860 // Determine event propagation path in advance, per W3C events spec (#9951)
3861 // Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
3862 eventPath = [[ elem, special.bindType || type ]];
3863 if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {
3864
3865 bubbleType = special.delegateType || type;
3866 old = null;
3867 for ( cur = elem.parentNode; cur; cur = cur.parentNode ) {
3868 eventPath.push([ cur, bubbleType ]);
3869 old = cur;
3870 }
3871
3872 // Only add window if we got to document (e.g., not plain obj or detached DOM)
3873 if ( old && old === elem.ownerDocument ) {
3874 eventPath.push([ old.defaultView || old.parentWindow || window, bubbleType ]);
3875 }
3876 }
3877
3878 // Fire handlers on the event path
3879 for ( i = 0; i < eventPath.length; i++ ) {
3880
3881 cur = eventPath[i][0];
3882 event.type = eventPath[i][1];
3883
3884 handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" );
3885 if ( handle ) {
3886 handle.apply( cur, data );
3887 }
3888 handle = ontype && cur[ ontype ];
3889 if ( handle && jQuery.acceptData( cur ) ) {
3890 handle.apply( cur, data );
3891 }
3892
3893 if ( event.isPropagationStopped() ) {
3894 break;
3895 }
3896 }
3897 event.type = type;
3898
3899 // If nobody prevented the default action, do it now
3900 if ( !event.isDefaultPrevented() ) {
3901
3902 if ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) &&
3903 !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) {
3904
3905 // Call a native DOM method on the target with the same name name as the event.
3906 // Can't use an .isFunction() check here because IE6/7 fails that test.
3907 // Don't do default actions on window, that's where global variables be (#6170)
3908 // IE<9 dies on focus/blur to hidden element (#1486)
3909 if ( ontype && elem[ type ] && ((type !== "focus" && type !== "blur") || event.target.offsetWidth !== 0) && !jQuery.isWindow( elem ) ) {
3910
3911 // Don't re-trigger an onFOO event when we call its FOO() method
3912 old = elem[ ontype ];
3913
3914 if ( old ) {
3915 elem[ ontype ] = null;
3916 }
3917
3918 // Prevent re-triggering of the same event, since we already bubbled it above
3919 jQuery.event.triggered = type;
3920 elem[ type ]();
3921 jQuery.event.triggered = undefined;
3922
3923 if ( old ) {
3924 elem[ ontype ] = old;
3925 }
3926 }
3927 }
3928 }
3929
3930 return event.result;
3931 },
3932
3933 dispatch: function( event ) {
3934
3935 // Make a writable jQuery.Event from the native event object
3936 event = jQuery.event.fix( event || window.event );
3937
3938 var handlers = ( (jQuery._data( this, "events" ) || {} )[ event.type ] || []),
3939 delegateCount = handlers.delegateCount,
3940 args = [].slice.call( arguments, 0 ),
3941 run_all = !event.exclusive && !event.namespace,
3942 specialHandle = ( jQuery.event.special[ event.type ] || {} ).handle,
3943 handlerQueue = [],
3944 i, j, cur, ret, selMatch, matched, matches, handleObj, sel, hit, related;
3945
3946 // Use the fix-ed jQuery.Event rather than the (read-only) native event
3947 args[0] = event;
3948 event.delegateTarget = this;
3949
3950 // Determine handlers that should run if there are delegated events
3951 // Avoid disabled elements in IE (#6911) and non-left-click bubbling in Firefox (#3861)
3952 if ( delegateCount && !event.target.disabled && !(event.button && event.type === "click") ) {
3953
3954 for ( cur = event.target; cur != this; cur = cur.parentNode || this ) {
3955 selMatch = {};
3956 matches = [];
3957 for ( i = 0; i < delegateCount; i++ ) {
3958 handleObj = handlers[ i ];
3959 sel = handleObj.selector;
3960 hit = selMatch[ sel ];
3961
3962 if ( handleObj.isPositional ) {
3963 // Since .is() does not work for positionals; see http://jsfiddle.net/eJ4yd/3/
3964 hit = ( hit || (selMatch[ sel ] = jQuery( sel )) ).index( cur ) >= 0;
3965 } else if ( hit === undefined ) {
3966 hit = selMatch[ sel ] = ( handleObj.quick ? quickIs( cur, handleObj.quick ) : jQuery( cur ).is( sel ) );
3967 }
3968 if ( hit ) {
3969 matches.push( handleObj );
3970 }
3971 }
3972 if ( matches.length ) {
3973 handlerQueue.push({ elem: cur, matches: matches });
3974 }
3975 }
3976 }
3977
3978 // Add the remaining (directly-bound) handlers
3979 if ( handlers.length > delegateCount ) {
3980 handlerQueue.push({ elem: this, matches: handlers.slice( delegateCount ) });
3981 }
3982
3983 // Run delegates first; they may want to stop propagation beneath us
3984 for ( i = 0; i < handlerQueue.length && !event.isPropagationStopped(); i++ ) {
3985 matched = handlerQueue[ i ];
3986 event.currentTarget = matched.elem;
3987
3988 for ( j = 0; j < matched.matches.length && !event.isImmediatePropagationStopped(); j++ ) {
3989 handleObj = matched.matches[ j ];
3990
3991 // Triggered event must either 1) be non-exclusive and have no namespace, or
3992 // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace).
3993 if ( run_all || (!event.namespace && !handleObj.namespace) || event.namespace_re && event.namespace_re.test( handleObj.namespace ) ) {
3994
3995 event.data = handleObj.data;
3996 event.handleObj = handleObj;
3997
3998 ret = ( specialHandle || handleObj.handler ).apply( matched.elem, args );
3999
4000 if ( ret !== undefined ) {
4001 event.result = ret;
4002 if ( ret === false ) {
4003 event.preventDefault();
4004 event.stopPropagation();
4005 }
4006 }
4007 }
4008 }
4009 }
4010
4011 return event.result;
4012 },
4013
4014 // Includes some event props shared by KeyEvent and MouseEvent
4015 // *** attrChange attrName relatedNode srcElement are not normalized, non-W3C, deprecated, will be removed in 1.8 ***
4016 props: "attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),
4017
4018 fixHooks: {},
4019
4020 keyHooks: {
4021 props: "char charCode key keyCode".split(" "),
4022 filter: function( event, original ) {
4023
4024 // Add which for key events
4025 if ( event.which == null ) {
4026 event.which = original.charCode != null ? original.charCode : original.keyCode;
4027 }
4028
4029 return event;
4030 }
4031 },
4032
4033 mouseHooks: {
4034 props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement wheelDelta".split(" "),
4035 filter: function( event, original ) {
4036 var eventDoc, doc, body,
4037 button = original.button,
4038 fromElement = original.fromElement;
4039
4040 // Calculate pageX/Y if missing and clientX/Y available
4041 if ( event.pageX == null && original.clientX != null ) {
4042 eventDoc = event.target.ownerDocument || document;
4043 doc = eventDoc.documentElement;
4044 body = eventDoc.body;
4045
4046 event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 );
4047 event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 );
4048 }
4049
4050 // Add relatedTarget, if necessary
4051 if ( !event.relatedTarget && fromElement ) {
4052 event.relatedTarget = fromElement === event.target ? original.toElement : fromElement;
4053 }
4054
4055 // Add which for click: 1 === left; 2 === middle; 3 === right
4056 // Note: button is not normalized, so don't use it
4057 if ( !event.which && button !== undefined ) {
4058 event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );
4059 }
4060
4061 return event;
4062 }
4063 },
4064
4065 fix: function( event ) {
4066 if ( event[ jQuery.expando ] ) {
4067 return event;
4068 }
4069
4070 // Create a writable copy of the event object and normalize some properties
4071 var i, prop,
4072 originalEvent = event,
4073 fixHook = jQuery.event.fixHooks[ event.type ] || {},
4074 copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props;
4075
4076 event = jQuery.Event( originalEvent );
4077
4078 for ( i = copy.length; i; ) {
4079 prop = copy[ --i ];
4080 event[ prop ] = originalEvent[ prop ];
4081 }
4082
4083 // Fix target property, if necessary (#1925, IE 6/7/8 & Safari2)
4084 if ( !event.target ) {
4085 event.target = originalEvent.srcElement || document;
4086 }
4087
4088 // Target should not be a text node (#504, Safari)
4089 if ( event.target.nodeType === 3 ) {
4090 event.target = event.target.parentNode;
4091 }
4092
4093 // For mouse/key events; add metaKey if it's not there (#3368, IE6/7/8)
4094 if ( event.metaKey === undefined ) {
4095 event.metaKey = event.ctrlKey;
4096 }
4097
4098 return fixHook.filter? fixHook.filter( event, originalEvent ) : event;
4099 },
4100
4101 special: {
4102 ready: {
4103 // Make sure the ready event is setup
4104 setup: jQuery.bindReady
4105 },
4106
4107 focus: {
4108 delegateType: "focusin",
4109 noBubble: true
4110 },
4111 blur: {
4112 delegateType: "focusout",
4113 noBubble: true
4114 },
4115
4116 beforeunload: {
4117 setup: function( data, namespaces, eventHandle ) {
4118 // We only want to do this special case on windows
4119 if ( jQuery.isWindow( this ) ) {
4120 this.onbeforeunload = eventHandle;
4121 }
4122 },
4123
4124 teardown: function( namespaces, eventHandle ) {
4125 if ( this.onbeforeunload === eventHandle ) {
4126 this.onbeforeunload = null;
4127 }
4128 }
4129 }
4130 },
4131
4132 simulate: function( type, elem, event, bubble ) {
4133 // Piggyback on a donor event to simulate a different one.
4134 // Fake originalEvent to avoid donor's stopPropagation, but if the
4135 // simulated event prevents default then we do the same on the donor.
4136 var e = jQuery.extend(
4137 new jQuery.Event(),
4138 event,
4139 { type: type,
4140 isSimulated: true,
4141 originalEvent: {}
4142 }
4143 );
4144 if ( bubble ) {
4145 jQuery.event.trigger( e, null, elem );
4146 } else {
4147 jQuery.event.dispatch.call( elem, e );
4148 }
4149 if ( e.isDefaultPrevented() ) {
4150 event.preventDefault();
4151 }
4152 }
4153};
4154
4155// Some plugins are using, but it's undocumented/deprecated and will be removed.
4156// The 1.7 special event interface should provide all the hooks needed now.
4157jQuery.event.handle = jQuery.event.dispatch;
4158
4159jQuery.removeEvent = document.removeEventListener ?
4160 function( elem, type, handle ) {
4161 if ( elem.removeEventListener ) {
4162 elem.removeEventListener( type, handle, false );
4163 }
4164 } :
4165 function( elem, type, handle ) {
4166 if ( elem.detachEvent ) {
4167 elem.detachEvent( "on" + type, handle );
4168 }
4169 };
4170
4171jQuery.Event = function( src, props ) {
4172 // Allow instantiation without the 'new' keyword
4173 if ( !(this instanceof jQuery.Event) ) {
4174 return new jQuery.Event( src, props );
4175 }
4176
4177 // Event object
4178 if ( src && src.type ) {
4179 this.originalEvent = src;
4180 this.type = src.type;
4181
4182 // Events bubbling up the document may have been marked as prevented
4183 // by a handler lower down the tree; reflect the correct value.
4184 this.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false ||
4185 src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse;
4186
4187 // Event type
4188 } else {
4189 this.type = src;
4190 }
4191
4192 // Put explicitly provided properties onto the event object
4193 if ( props ) {
4194 jQuery.extend( this, props );
4195 }
4196
4197 // Create a timestamp if incoming event doesn't have one
4198 this.timeStamp = src && src.timeStamp || jQuery.now();
4199
4200 // Mark it as fixed
4201 this[ jQuery.expando ] = true;
4202};
4203
4204function returnFalse() {
4205 return false;
4206}
4207function returnTrue() {
4208 return true;
4209}
4210
4211// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
4212// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
4213jQuery.Event.prototype = {
4214 preventDefault: function() {
4215 this.isDefaultPrevented = returnTrue;
4216
4217 var e = this.originalEvent;
4218 if ( !e ) {
4219 return;
4220 }
4221
4222 // if preventDefault exists run it on the original event
4223 if ( e.preventDefault ) {
4224 e.preventDefault();
4225
4226 // otherwise set the returnValue property of the original event to false (IE)
4227 } else {
4228 e.returnValue = false;
4229 }
4230 },
4231 stopPropagation: function() {
4232 this.isPropagationStopped = returnTrue;
4233
4234 var e = this.originalEvent;
4235 if ( !e ) {
4236 return;
4237 }
4238 // if stopPropagation exists run it on the original event
4239 if ( e.stopPropagation ) {
4240 e.stopPropagation();
4241 }
4242 // otherwise set the cancelBubble property of the original event to true (IE)
4243 e.cancelBubble = true;
4244 },
4245 stopImmediatePropagation: function() {
4246 this.isImmediatePropagationStopped = returnTrue;
4247 this.stopPropagation();
4248 },
4249 isDefaultPrevented: returnFalse,
4250 isPropagationStopped: returnFalse,
4251 isImmediatePropagationStopped: returnFalse
4252};
4253
4254// Create mouseenter/leave events using mouseover/out and event-time checks
4255jQuery.each({
4256 mouseenter: "mouseover",
4257 mouseleave: "mouseout"
4258}, function( orig, fix ) {
4259 jQuery.event.special[ orig ] = jQuery.event.special[ fix ] = {
4260 delegateType: fix,
4261 bindType: fix,
4262
4263 handle: function( event ) {
4264 var target = this,
4265 related = event.relatedTarget,
4266 handleObj = event.handleObj,
4267 selector = handleObj.selector,
4268 oldType, ret;
4269
4270 // For a real mouseover/out, always call the handler; for
4271 // mousenter/leave call the handler if related is outside the target.
4272 // NB: No relatedTarget if the mouse left/entered the browser window
4273 if ( !related || handleObj.origType === event.type || (related !== target && !jQuery.contains( target, related )) ) {
4274 oldType = event.type;
4275 event.type = handleObj.origType;
4276 ret = handleObj.handler.apply( this, arguments );
4277 event.type = oldType;
4278 }
4279 return ret;
4280 }
4281 };
4282});
4283
4284// IE submit delegation
4285if ( !jQuery.support.submitBubbles ) {
4286
4287 jQuery.event.special.submit = {
4288 setup: function() {
4289 // Only need this for delegated form submit events
4290 if ( jQuery.nodeName( this, "form" ) ) {
4291 return false;
4292 }
4293
4294 // Lazy-add a submit handler when a descendant form may potentially be submitted
4295 jQuery.event.add( this, "click._submit keypress._submit", function( e ) {
4296 // Node name check avoids a VML-related crash in IE (#9807)
4297 var elem = e.target,
4298 form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined;
4299 if ( form && !form._submit_attached ) {
4300 jQuery.event.add( form, "submit._submit", function( event ) {
4301 // Form was submitted, bubble the event up the tree
4302 if ( this.parentNode ) {
4303 jQuery.event.simulate( "submit", this.parentNode, event, true );
4304 }
4305 });
4306 form._submit_attached = true;
4307 }
4308 });
4309 // return undefined since we don't need an event listener
4310 },
4311
4312 teardown: function() {
4313 // Only need this for delegated form submit events
4314 if ( jQuery.nodeName( this, "form" ) ) {
4315 return false;
4316 }
4317
4318 // Remove delegated handlers; cleanData eventually reaps submit handlers attached above
4319 jQuery.event.remove( this, "._submit" );
4320 }
4321 };
4322}
4323
4324// IE change delegation and checkbox/radio fix
4325if ( !jQuery.support.changeBubbles ) {
4326
4327 jQuery.event.special.change = {
4328
4329 setup: function() {
4330
4331 if ( rformElems.test( this.nodeName ) ) {
4332 // IE doesn't fire change on a check/radio until blur; trigger it on click
4333 // after a propertychange. Eat the blur-change in special.change.handle.
4334 // This still fires onchange a second time for check/radio after blur.
4335 if ( this.type === "checkbox" || this.type === "radio" ) {
4336 jQuery.event.add( this, "propertychange._change", function( event ) {
4337 if ( event.originalEvent.propertyName === "checked" ) {
4338 this._just_changed = true;
4339 }
4340 });
4341 jQuery.event.add( this, "click._change", function( event ) {
4342 if ( this._just_changed ) {
4343 this._just_changed = false;
4344 jQuery.event.simulate( "change", this, event, true );
4345 }
4346 });
4347 }
4348 return false;
4349 }
4350 // Delegated event; lazy-add a change handler on descendant inputs
4351 jQuery.event.add( this, "beforeactivate._change", function( e ) {
4352 var elem = e.target;
4353
4354 if ( rformElems.test( elem.nodeName ) && !elem._change_attached ) {
4355 jQuery.event.add( elem, "change._change", function( event ) {
4356 if ( this.parentNode && !event.isSimulated ) {
4357 jQuery.event.simulate( "change", this.parentNode, event, true );
4358 }
4359 });
4360 elem._change_attached = true;
4361 }
4362 });
4363 },
4364
4365 handle: function( event ) {
4366 var elem = event.target;
4367
4368 // Swallow native change events from checkbox/radio, we already triggered them above
4369 if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) {
4370 return event.handleObj.handler.apply( this, arguments );
4371 }
4372 },
4373
4374 teardown: function() {
4375 jQuery.event.remove( this, "._change" );
4376
4377 return rformElems.test( this.nodeName );
4378 }
4379 };
4380}
4381
4382// Create "bubbling" focus and blur events
4383if ( !jQuery.support.focusinBubbles ) {
4384 jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
4385
4386 // Attach a single capturing handler while someone wants focusin/focusout
4387 var attaches = 0,
4388 handler = function( event ) {
4389 jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true );
4390 };
4391
4392 jQuery.event.special[ fix ] = {
4393 setup: function() {
4394 if ( attaches++ === 0 ) {
4395 document.addEventListener( orig, handler, true );
4396 }
4397 },
4398 teardown: function() {
4399 if ( --attaches === 0 ) {
4400 document.removeEventListener( orig, handler, true );
4401 }
4402 }
4403 };
4404 });
4405}
4406
4407jQuery.fn.extend({
4408
4409 on: function( types, selector, data, fn, /*INTERNAL*/ one ) {
4410 var origFn, type;
4411
4412 // Types can be a map of types/handlers
4413 if ( typeof types === "object" ) {
4414 // ( types-Object, selector, data )
4415 if ( typeof selector !== "string" ) {
4416 // ( types-Object, data )
4417 data = selector;
4418 selector = undefined;
4419 }
4420 for ( type in types ) {
4421 this.on( type, selector, data, types[ type ], one );
4422 }
4423 return this;
4424 }
4425
4426 if ( data == null && fn == null ) {
4427 // ( types, fn )
4428 fn = selector;
4429 data = selector = undefined;
4430 } else if ( fn == null ) {
4431 if ( typeof selector === "string" ) {
4432 // ( types, selector, fn )
4433 fn = data;
4434 data = undefined;
4435 } else {
4436 // ( types, data, fn )
4437 fn = data;
4438 data = selector;
4439 selector = undefined;
4440 }
4441 }
4442 if ( fn === false ) {
4443 fn = returnFalse;
4444 } else if ( !fn ) {
4445 return this;
4446 }
4447
4448 if ( one === 1 ) {
4449 origFn = fn;
4450 fn = function( event ) {
4451 // Can use an empty set, since event contains the info
4452 jQuery().off( event );
4453 return origFn.apply( this, arguments );
4454 };
4455 // Use same guid so caller can remove using origFn
4456 fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
4457 }
4458 return this.each( function() {
4459 jQuery.event.add( this, types, fn, data, selector );
4460 });
4461 },
4462 one: function( types, selector, data, fn ) {
4463 return this.on.call( this, types, selector, data, fn, 1 );
4464 },
4465 off: function( types, selector, fn ) {
4466 if ( types && types.preventDefault && types.handleObj ) {
4467 // ( event ) dispatched jQuery.Event
4468 var handleObj = types.handleObj;
4469 jQuery( types.delegateTarget ).off(
4470 handleObj.namespace? handleObj.type + "." + handleObj.namespace : handleObj.type,
4471 handleObj.selector,
4472 handleObj.handler
4473 );
4474 return this;
4475 }
4476 if ( typeof types === "object" ) {
4477 // ( types-object [, selector] )
4478 for ( var type in types ) {
4479 this.off( type, selector, types[ type ] );
4480 }
4481 return this;
4482 }
4483 if ( selector === false || typeof selector === "function" ) {
4484 // ( types [, fn] )
4485 fn = selector;
4486 selector = undefined;
4487 }
4488 if ( fn === false ) {
4489 fn = returnFalse;
4490 }
4491 return this.each(function() {
4492 jQuery.event.remove( this, types, fn, selector );
4493 });
4494 },
4495
4496 bind: function( types, data, fn ) {
4497 return this.on( types, null, data, fn );
4498 },
4499 unbind: function( types, fn ) {
4500 return this.off( types, null, fn );
4501 },
4502
4503 live: function( types, data, fn ) {
4504 jQuery( this.context ).on( types, this.selector, data, fn );
4505 return this;
4506 },
4507 die: function( types, fn ) {
4508 jQuery( this.context ).off( types, this.selector || "**", fn );
4509 return this;
4510 },
4511
4512 delegate: function( selector, types, data, fn ) {
4513 return this.on( types, selector, data, fn );
4514 },
4515 undelegate: function( selector, types, fn ) {
4516 // ( namespace ) or ( selector, types [, fn] )
4517 return arguments.length == 1? this.off( selector, "**" ) : this.off( types, selector, fn );
4518 },
4519
4520 trigger: function( type, data ) {
4521 return this.each(function() {
4522 jQuery.event.trigger( type, data, this );
4523 });
4524 },
4525 triggerHandler: function( type, data ) {
4526 if ( this[0] ) {
4527 return jQuery.event.trigger( type, data, this[0], true );
4528 }
4529 },
4530
4531 toggle: function( fn ) {
4532 // Save reference to arguments for access in closure
4533 var args = arguments,
4534 guid = fn.guid || jQuery.guid++,
4535 i = 0,
4536 toggler = function( event ) {
4537 // Figure out which function to execute
4538 var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i;
4539 jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 );
4540
4541 // Make sure that clicks stop
4542 event.preventDefault();
4543
4544 // and execute the function
4545 return args[ lastToggle ].apply( this, arguments ) || false;
4546 };
4547
4548 // link all the functions, so any of them can unbind this click handler
4549 toggler.guid = guid;
4550 while ( i < args.length ) {
4551 args[ i++ ].guid = guid;
4552 }
4553
4554 return this.click( toggler );
4555 },
4556
4557 hover: function( fnOver, fnOut ) {
4558 return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
4559 }
4560});
4561
4562jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
4563 "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
4564 "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) {
4565
4566 // Handle event binding
4567 jQuery.fn[ name ] = function( data, fn ) {
4568 if ( fn == null ) {
4569 fn = data;
4570 data = null;
4571 }
4572
4573 return arguments.length > 0 ?
4574 this.bind( name, data, fn ) :
4575 this.trigger( name );
4576 };
4577
4578 if ( jQuery.attrFn ) {
4579 jQuery.attrFn[ name ] = true;
4580 }
4581
4582 if ( rkeyEvent.test( name ) ) {
4583 jQuery.event.fixHooks[ name ] = jQuery.event.keyHooks;
4584 }
4585
4586 if ( rmouseEvent.test( name ) ) {
4587 jQuery.event.fixHooks[ name ] = jQuery.event.mouseHooks;
4588 }
4589});
4590
4591})( jQuery );
4592
4593/*!
4594 * Sizzle CSS Selector Engine
4595 * Copyright 2011, The Dojo Foundation
4596 * Released under the MIT, BSD, and GPL Licenses.
4597 * More information: http://sizzlejs.com/
4598 */
4599(function(){
4600
4601var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
4602 expando = "sizcache" + (Math.random() + '').replace('.', ''),
4603 done = 0,
4604 toString = Object.prototype.toString,
4605 hasDuplicate = false,
4606 baseHasDuplicate = true,
4607 rBackslash = /\\/g,
4608 rReturn = /\r\n/g,
4609 rNonWord = /\W/;
4610
4611// Here we check if the JavaScript engine is using some sort of
4612// optimization where it does not always call our comparision
4613// function. If that is the case, discard the hasDuplicate value.
4614// Thus far that includes Google Chrome.
4615[0, 0].sort(function() {
4616 baseHasDuplicate = false;
4617 return 0;
4618});
4619
4620var Sizzle = function( selector, context, results, seed ) {
4621 results = results || [];
4622 context = context || document;
4623
4624 var origContext = context;
4625
4626 if ( context.nodeType !== 1 && context.nodeType !== 9 ) {
4627 return [];
4628 }
4629
4630 if ( !selector || typeof selector !== "string" ) {
4631 return results;
4632 }
4633
4634 var m, set, checkSet, extra, ret, cur, pop, i,
4635 prune = true,
4636 contextXML = Sizzle.isXML( context ),
4637 parts = [],
4638 soFar = selector;
4639
4640 // Reset the position of the chunker regexp (start from head)
4641 do {
4642 chunker.exec( "" );
4643 m = chunker.exec( soFar );
4644
4645 if ( m ) {
4646 soFar = m[3];
4647
4648 parts.push( m[1] );
4649
4650 if ( m[2] ) {
4651 extra = m[3];
4652 break;
4653 }
4654 }
4655 } while ( m );
4656
4657 if ( parts.length > 1 && origPOS.exec( selector ) ) {
4658
4659 if ( parts.length === 2 && Expr.relative[ parts[0] ] ) {
4660 set = posProcess( parts[0] + parts[1], context, seed );
4661
4662 } else {
4663 set = Expr.relative[ parts[0] ] ?
4664 [ context ] :
4665 Sizzle( parts.shift(), context );
4666
4667 while ( parts.length ) {
4668 selector = parts.shift();
4669
4670 if ( Expr.relative[ selector ] ) {
4671 selector += parts.shift();
4672 }
4673
4674 set = posProcess( selector, set, seed );
4675 }
4676 }
4677
4678 } else {
4679 // Take a shortcut and set the context if the root selector is an ID
4680 // (but not if it'll be faster if the inner selector is an ID)
4681 if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML &&
4682 Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) {
4683
4684 ret = Sizzle.find( parts.shift(), context, contextXML );
4685 context = ret.expr ?
4686 Sizzle.filter( ret.expr, ret.set )[0] :
4687 ret.set[0];
4688 }
4689
4690 if ( context ) {
4691 ret = seed ?
4692 { expr: parts.pop(), set: makeArray(seed) } :
4693 Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML );
4694
4695 set = ret.expr ?
4696 Sizzle.filter( ret.expr, ret.set ) :
4697 ret.set;
4698
4699 if ( parts.length > 0 ) {
4700 checkSet = makeArray( set );
4701
4702 } else {
4703 prune = false;
4704 }
4705
4706 while ( parts.length ) {
4707 cur = parts.pop();
4708 pop = cur;
4709
4710 if ( !Expr.relative[ cur ] ) {
4711 cur = "";
4712 } else {
4713 pop = parts.pop();
4714 }
4715
4716 if ( pop == null ) {
4717 pop = context;
4718 }
4719
4720 Expr.relative[ cur ]( checkSet, pop, contextXML );
4721 }
4722
4723 } else {
4724 checkSet = parts = [];
4725 }
4726 }
4727
4728 if ( !checkSet ) {
4729 checkSet = set;
4730 }
4731
4732 if ( !checkSet ) {
4733 Sizzle.error( cur || selector );
4734 }
4735
4736 if ( toString.call(checkSet) === "[object Array]" ) {
4737 if ( !prune ) {
4738 results.push.apply( results, checkSet );
4739
4740 } else if ( context && context.nodeType === 1 ) {
4741 for ( i = 0; checkSet[i] != null; i++ ) {
4742 if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && Sizzle.contains(context, checkSet[i])) ) {
4743 results.push( set[i] );
4744 }
4745 }
4746
4747 } else {
4748 for ( i = 0; checkSet[i] != null; i++ ) {
4749 if ( checkSet[i] && checkSet[i].nodeType === 1 ) {
4750 results.push( set[i] );
4751 }
4752 }
4753 }
4754
4755 } else {
4756 makeArray( checkSet, results );
4757 }
4758
4759 if ( extra ) {
4760 Sizzle( extra, origContext, results, seed );
4761 Sizzle.uniqueSort( results );
4762 }
4763
4764 return results;
4765};
4766
4767Sizzle.uniqueSort = function( results ) {
4768 if ( sortOrder ) {
4769 hasDuplicate = baseHasDuplicate;
4770 results.sort( sortOrder );
4771
4772 if ( hasDuplicate ) {
4773 for ( var i = 1; i < results.length; i++ ) {
4774 if ( results[i] === results[ i - 1 ] ) {
4775 results.splice( i--, 1 );
4776 }
4777 }
4778 }
4779 }
4780
4781 return results;
4782};
4783
4784Sizzle.matches = function( expr, set ) {
4785 return Sizzle( expr, null, null, set );
4786};
4787
4788Sizzle.matchesSelector = function( node, expr ) {
4789 return Sizzle( expr, null, null, [node] ).length > 0;
4790};
4791
4792Sizzle.find = function( expr, context, isXML ) {
4793 var set, i, len, match, type, left;
4794
4795 if ( !expr ) {
4796 return [];
4797 }
4798
4799 for ( i = 0, len = Expr.order.length; i < len; i++ ) {
4800 type = Expr.order[i];
4801
4802 if ( (match = Expr.leftMatch[ type ].exec( expr )) ) {
4803 left = match[1];
4804 match.splice( 1, 1 );
4805
4806 if ( left.substr( left.length - 1 ) !== "\\" ) {
4807 match[1] = (match[1] || "").replace( rBackslash, "" );
4808 set = Expr.find[ type ]( match, context, isXML );
4809
4810 if ( set != null ) {
4811 expr = expr.replace( Expr.match[ type ], "" );
4812 break;
4813 }
4814 }
4815 }
4816 }
4817
4818 if ( !set ) {
4819 set = typeof context.getElementsByTagName !== "undefined" ?
4820 context.getElementsByTagName( "*" ) :
4821 [];
4822 }
4823
4824 return { set: set, expr: expr };
4825};
4826
4827Sizzle.filter = function( expr, set, inplace, not ) {
4828 var match, anyFound,
4829 type, found, item, filter, left,
4830 i, pass,
4831 old = expr,
4832 result = [],
4833 curLoop = set,
4834 isXMLFilter = set && set[0] && Sizzle.isXML( set[0] );
4835
4836 while ( expr && set.length ) {
4837 for ( type in Expr.filter ) {
4838 if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) {
4839 filter = Expr.filter[ type ];
4840 left = match[1];
4841
4842 anyFound = false;
4843
4844 match.splice(1,1);
4845
4846 if ( left.substr( left.length - 1 ) === "\\" ) {
4847 continue;
4848 }
4849
4850 if ( curLoop === result ) {
4851 result = [];
4852 }
4853
4854 if ( Expr.preFilter[ type ] ) {
4855 match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter );
4856
4857 if ( !match ) {
4858 anyFound = found = true;
4859
4860 } else if ( match === true ) {
4861 continue;
4862 }
4863 }
4864
4865 if ( match ) {
4866 for ( i = 0; (item = curLoop[i]) != null; i++ ) {
4867 if ( item ) {
4868 found = filter( item, match, i, curLoop );
4869 pass = not ^ found;
4870
4871 if ( inplace && found != null ) {
4872 if ( pass ) {
4873 anyFound = true;
4874
4875 } else {
4876 curLoop[i] = false;
4877 }
4878
4879 } else if ( pass ) {
4880 result.push( item );
4881 anyFound = true;
4882 }
4883 }
4884 }
4885 }
4886
4887 if ( found !== undefined ) {
4888 if ( !inplace ) {
4889 curLoop = result;
4890 }
4891
4892 expr = expr.replace( Expr.match[ type ], "" );
4893
4894 if ( !anyFound ) {
4895 return [];
4896 }
4897
4898 break;
4899 }
4900 }
4901 }
4902
4903 // Improper expression
4904 if ( expr === old ) {
4905 if ( anyFound == null ) {
4906 Sizzle.error( expr );
4907
4908 } else {
4909 break;
4910 }
4911 }
4912
4913 old = expr;
4914 }
4915
4916 return curLoop;
4917};
4918
4919Sizzle.error = function( msg ) {
4920 throw "Syntax error, unrecognized expression: " + msg;
4921};
4922
4923/**
4924 * Utility function for retreiving the text value of an array of DOM nodes
4925 * @param {Array|Element} elem
4926 */
4927var getText = Sizzle.getText = function( elem ) {
4928 var i, node,
4929 nodeType = elem.nodeType,
4930 ret = "";
4931
4932 if ( nodeType ) {
4933 if ( nodeType === 1 ) {
4934 // Use textContent || innerText for elements
4935 if ( typeof elem.textContent === 'string' ) {
4936 return elem.textContent;
4937 } else if ( typeof elem.innerText === 'string' ) {
4938 // Replace IE's carriage returns
4939 return elem.innerText.replace( rReturn, '' );
4940 } else {
4941 // Traverse it's children
4942 for ( elem = elem.firstChild; elem; elem = elem.nextSibling) {
4943 ret += getText( elem );
4944 }
4945 }
4946 } else if ( nodeType === 3 || nodeType === 4 ) {
4947 return elem.nodeValue;
4948 }
4949 } else {
4950
4951 // If no nodeType, this is expected to be an array
4952 for ( i = 0; (node = elem[i]); i++ ) {
4953 // Do not traverse comment nodes
4954 if ( node.nodeType !== 8 ) {
4955 ret += getText( node );
4956 }
4957 }
4958 }
4959 return ret;
4960};
4961
4962var Expr = Sizzle.selectors = {
4963 order: [ "ID", "NAME", "TAG" ],
4964
4965 match: {
4966 ID: /#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,
4967 CLASS: /\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,
4968 NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,
4969 ATTR: /\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/,
4970 TAG: /^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,
4971 CHILD: /:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/,
4972 POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,
4973 PSEUDO: /:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/
4974 },
4975
4976 leftMatch: {},
4977
4978 attrMap: {
4979 "class": "className",
4980 "for": "htmlFor"
4981 },
4982
4983 attrHandle: {
4984 href: function( elem ) {
4985 return elem.getAttribute( "href" );
4986 },
4987 type: function( elem ) {
4988 return elem.getAttribute( "type" );
4989 }
4990 },
4991
4992 relative: {
4993 "+": function(checkSet, part){
4994 var isPartStr = typeof part === "string",
4995 isTag = isPartStr && !rNonWord.test( part ),
4996 isPartStrNotTag = isPartStr && !isTag;
4997
4998 if ( isTag ) {
4999 part = part.toLowerCase();
5000 }
5001
5002 for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) {
5003 if ( (elem = checkSet[i]) ) {
5004 while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {}
5005
5006 checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ?
5007 elem || false :
5008 elem === part;
5009 }
5010 }
5011
5012 if ( isPartStrNotTag ) {
5013 Sizzle.filter( part, checkSet, true );
5014 }
5015 },
5016
5017 ">": function( checkSet, part ) {
5018 var elem,
5019 isPartStr = typeof part === "string",
5020 i = 0,
5021 l = checkSet.length;
5022
5023 if ( isPartStr && !rNonWord.test( part ) ) {
5024 part = part.toLowerCase();
5025
5026 for ( ; i < l; i++ ) {
5027 elem = checkSet[i];
5028
5029 if ( elem ) {
5030 var parent = elem.parentNode;
5031 checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false;
5032 }
5033 }
5034
5035 } else {
5036 for ( ; i < l; i++ ) {
5037 elem = checkSet[i];
5038
5039 if ( elem ) {
5040 checkSet[i] = isPartStr ?
5041 elem.parentNode :
5042 elem.parentNode === part;
5043 }
5044 }
5045
5046 if ( isPartStr ) {
5047 Sizzle.filter( part, checkSet, true );
5048 }
5049 }
5050 },
5051
5052 "": function(checkSet, part, isXML){
5053 var nodeCheck,
5054 doneName = done++,
5055 checkFn = dirCheck;
5056
5057 if ( typeof part === "string" && !rNonWord.test( part ) ) {
5058 part = part.toLowerCase();
5059 nodeCheck = part;
5060 checkFn = dirNodeCheck;
5061 }
5062
5063 checkFn( "parentNode", part, doneName, checkSet, nodeCheck, isXML );
5064 },
5065
5066 "~": function( checkSet, part, isXML ) {
5067 var nodeCheck,
5068 doneName = done++,
5069 checkFn = dirCheck;
5070
5071 if ( typeof part === "string" && !rNonWord.test( part ) ) {
5072 part = part.toLowerCase();
5073 nodeCheck = part;
5074 checkFn = dirNodeCheck;
5075 }
5076
5077 checkFn( "previousSibling", part, doneName, checkSet, nodeCheck, isXML );
5078 }
5079 },
5080
5081 find: {
5082 ID: function( match, context, isXML ) {
5083 if ( typeof context.getElementById !== "undefined" && !isXML ) {
5084 var m = context.getElementById(match[1]);
5085 // Check parentNode to catch when Blackberry 4.6 returns
5086 // nodes that are no longer in the document #6963
5087 return m && m.parentNode ? [m] : [];
5088 }
5089 },
5090
5091 NAME: function( match, context ) {
5092 if ( typeof context.getElementsByName !== "undefined" ) {
5093 var ret = [],
5094 results = context.getElementsByName( match[1] );
5095
5096 for ( var i = 0, l = results.length; i < l; i++ ) {
5097 if ( results[i].getAttribute("name") === match[1] ) {
5098 ret.push( results[i] );
5099 }
5100 }
5101
5102 return ret.length === 0 ? null : ret;
5103 }
5104 },
5105
5106 TAG: function( match, context ) {
5107 if ( typeof context.getElementsByTagName !== "undefined" ) {
5108 return context.getElementsByTagName( match[1] );
5109 }
5110 }
5111 },
5112 preFilter: {
5113 CLASS: function( match, curLoop, inplace, result, not, isXML ) {
5114 match = " " + match[1].replace( rBackslash, "" ) + " ";
5115
5116 if ( isXML ) {
5117 return match;
5118 }
5119
5120 for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) {
5121 if ( elem ) {
5122 if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n\r]/g, " ").indexOf(match) >= 0) ) {
5123 if ( !inplace ) {
5124 result.push( elem );
5125 }
5126
5127 } else if ( inplace ) {
5128 curLoop[i] = false;
5129 }
5130 }
5131 }
5132
5133 return false;
5134 },
5135
5136 ID: function( match ) {
5137 return match[1].replace( rBackslash, "" );
5138 },
5139
5140 TAG: function( match, curLoop ) {
5141 return match[1].replace( rBackslash, "" ).toLowerCase();
5142 },
5143
5144 CHILD: function( match ) {
5145 if ( match[1] === "nth" ) {
5146 if ( !match[2] ) {
5147 Sizzle.error( match[0] );
5148 }
5149
5150 match[2] = match[2].replace(/^\+|\s*/g, '');
5151
5152 // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'
5153 var test = /(-?)(\d*)(?:n([+\-]?\d*))?/.exec(
5154 match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" ||
5155 !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]);
5156
5157 // calculate the numbers (first)n+(last) including if they are negative
5158 match[2] = (test[1] + (test[2] || 1)) - 0;
5159 match[3] = test[3] - 0;
5160 }
5161 else if ( match[2] ) {
5162 Sizzle.error( match[0] );
5163 }
5164
5165 // TODO: Move to normal caching system
5166 match[0] = done++;
5167
5168 return match;
5169 },
5170
5171 ATTR: function( match, curLoop, inplace, result, not, isXML ) {
5172 var name = match[1] = match[1].replace( rBackslash, "" );
5173
5174 if ( !isXML && Expr.attrMap[name] ) {
5175 match[1] = Expr.attrMap[name];
5176 }
5177
5178 // Handle if an un-quoted value was used
5179 match[4] = ( match[4] || match[5] || "" ).replace( rBackslash, "" );
5180
5181 if ( match[2] === "~=" ) {
5182 match[4] = " " + match[4] + " ";
5183 }
5184
5185 return match;
5186 },
5187
5188 PSEUDO: function( match, curLoop, inplace, result, not ) {
5189 if ( match[1] === "not" ) {
5190 // If we're dealing with a complex expression, or a simple one
5191 if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) {
5192 match[3] = Sizzle(match[3], null, null, curLoop);
5193
5194 } else {
5195 var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not);
5196
5197 if ( !inplace ) {
5198 result.push.apply( result, ret );
5199 }
5200
5201 return false;
5202 }
5203
5204 } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) {
5205 return true;
5206 }
5207
5208 return match;
5209 },
5210
5211 POS: function( match ) {
5212 match.unshift( true );
5213
5214 return match;
5215 }
5216 },
5217
5218 filters: {
5219 enabled: function( elem ) {
5220 return elem.disabled === false && elem.type !== "hidden";
5221 },
5222
5223 disabled: function( elem ) {
5224 return elem.disabled === true;
5225 },
5226
5227 checked: function( elem ) {
5228 return elem.checked === true;
5229 },
5230
5231 selected: function( elem ) {
5232 // Accessing this property makes selected-by-default
5233 // options in Safari work properly
5234 if ( elem.parentNode ) {
5235 elem.parentNode.selectedIndex;
5236 }
5237
5238 return elem.selected === true;
5239 },
5240
5241 parent: function( elem ) {
5242 return !!elem.firstChild;
5243 },
5244
5245 empty: function( elem ) {
5246 return !elem.firstChild;
5247 },
5248
5249 has: function( elem, i, match ) {
5250 return !!Sizzle( match[3], elem ).length;
5251 },
5252
5253 header: function( elem ) {
5254 return (/h\d/i).test( elem.nodeName );
5255 },
5256
5257 text: function( elem ) {
5258 var attr = elem.getAttribute( "type" ), type = elem.type;
5259 // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc)
5260 // use getAttribute instead to test this case
5261 return elem.nodeName.toLowerCase() === "input" && "text" === type && ( attr === type || attr === null );
5262 },
5263
5264 radio: function( elem ) {
5265 return elem.nodeName.toLowerCase() === "input" && "radio" === elem.type;
5266 },
5267
5268 checkbox: function( elem ) {
5269 return elem.nodeName.toLowerCase() === "input" && "checkbox" === elem.type;
5270 },
5271
5272 file: function( elem ) {
5273 return elem.nodeName.toLowerCase() === "input" && "file" === elem.type;
5274 },
5275
5276 password: function( elem ) {
5277 return elem.nodeName.toLowerCase() === "input" && "password" === elem.type;
5278 },
5279
5280 submit: function( elem ) {
5281 var name = elem.nodeName.toLowerCase();
5282 return (name === "input" || name === "button") && "submit" === elem.type;
5283 },
5284
5285 image: function( elem ) {
5286 return elem.nodeName.toLowerCase() === "input" && "image" === elem.type;
5287 },
5288
5289 reset: function( elem ) {
5290 var name = elem.nodeName.toLowerCase();
5291 return (name === "input" || name === "button") && "reset" === elem.type;
5292 },
5293
5294 button: function( elem ) {
5295 var name = elem.nodeName.toLowerCase();
5296 return name === "input" && "button" === elem.type || name === "button";
5297 },
5298
5299 input: function( elem ) {
5300 return (/input|select|textarea|button/i).test( elem.nodeName );
5301 },
5302
5303 focus: function( elem ) {
5304 return elem === elem.ownerDocument.activeElement;
5305 }
5306 },
5307 setFilters: {
5308 first: function( elem, i ) {
5309 return i === 0;
5310 },
5311
5312 last: function( elem, i, match, array ) {
5313 return i === array.length - 1;
5314 },
5315
5316 even: function( elem, i ) {
5317 return i % 2 === 0;
5318 },
5319
5320 odd: function( elem, i ) {
5321 return i % 2 === 1;
5322 },
5323
5324 lt: function( elem, i, match ) {
5325 return i < match[3] - 0;
5326 },
5327
5328 gt: function( elem, i, match ) {
5329 return i > match[3] - 0;
5330 },
5331
5332 nth: function( elem, i, match ) {
5333 return match[3] - 0 === i;
5334 },
5335
5336 eq: function( elem, i, match ) {
5337 return match[3] - 0 === i;
5338 }
5339 },
5340 filter: {
5341 PSEUDO: function( elem, match, i, array ) {
5342 var name = match[1],
5343 filter = Expr.filters[ name ];
5344
5345 if ( filter ) {
5346 return filter( elem, i, match, array );
5347
5348 } else if ( name === "contains" ) {
5349 return (elem.textContent || elem.innerText || getText([ elem ]) || "").indexOf(match[3]) >= 0;
5350
5351 } else if ( name === "not" ) {
5352 var not = match[3];
5353
5354 for ( var j = 0, l = not.length; j < l; j++ ) {
5355 if ( not[j] === elem ) {
5356 return false;
5357 }
5358 }
5359
5360 return true;
5361
5362 } else {
5363 Sizzle.error( name );
5364 }
5365 },
5366
5367 CHILD: function( elem, match ) {
5368 var first, last,
5369 doneName, parent, cache,
5370 count, diff,
5371 type = match[1],
5372 node = elem;
5373
5374 switch ( type ) {
5375 case "only":
5376 case "first":
5377 while ( (node = node.previousSibling) ) {
5378 if ( node.nodeType === 1 ) {
5379 return false;
5380 }
5381 }
5382
5383 if ( type === "first" ) {
5384 return true;
5385 }
5386
5387 node = elem;
5388
5389 case "last":
5390 while ( (node = node.nextSibling) ) {
5391 if ( node.nodeType === 1 ) {
5392 return false;
5393 }
5394 }
5395
5396 return true;
5397
5398 case "nth":
5399 first = match[2];
5400 last = match[3];
5401
5402 if ( first === 1 && last === 0 ) {
5403 return true;
5404 }
5405
5406 doneName = match[0];
5407 parent = elem.parentNode;
5408
5409 if ( parent && (parent[ expando ] !== doneName || !elem.nodeIndex) ) {
5410 count = 0;
5411
5412 for ( node = parent.firstChild; node; node = node.nextSibling ) {
5413 if ( node.nodeType === 1 ) {
5414 node.nodeIndex = ++count;
5415 }
5416 }
5417
5418 parent[ expando ] = doneName;
5419 }
5420
5421 diff = elem.nodeIndex - last;
5422
5423 if ( first === 0 ) {
5424 return diff === 0;
5425
5426 } else {
5427 return ( diff % first === 0 && diff / first >= 0 );
5428 }
5429 }
5430 },
5431
5432 ID: function( elem, match ) {
5433 return elem.nodeType === 1 && elem.getAttribute("id") === match;
5434 },
5435
5436 TAG: function( elem, match ) {
5437 return (match === "*" && elem.nodeType === 1) || !!elem.nodeName && elem.nodeName.toLowerCase() === match;
5438 },
5439
5440 CLASS: function( elem, match ) {
5441 return (" " + (elem.className || elem.getAttribute("class")) + " ")
5442 .indexOf( match ) > -1;
5443 },
5444
5445 ATTR: function( elem, match ) {
5446 var name = match[1],
5447 result = Sizzle.attr ?
5448 Sizzle.attr( elem, name ) :
5449 Expr.attrHandle[ name ] ?
5450 Expr.attrHandle[ name ]( elem ) :
5451 elem[ name ] != null ?
5452 elem[ name ] :
5453 elem.getAttribute( name ),
5454 value = result + "",
5455 type = match[2],
5456 check = match[4];
5457
5458 return result == null ?
5459 type === "!=" :
5460 !type && Sizzle.attr ?
5461 result != null :
5462 type === "=" ?
5463 value === check :
5464 type === "*=" ?
5465 value.indexOf(check) >= 0 :
5466 type === "~=" ?
5467 (" " + value + " ").indexOf(check) >= 0 :
5468 !check ?
5469 value && result !== false :
5470 type === "!=" ?
5471 value !== check :
5472 type === "^=" ?
5473 value.indexOf(check) === 0 :
5474 type === "$=" ?
5475 value.substr(value.length - check.length) === check :
5476 type === "|=" ?
5477 value === check || value.substr(0, check.length + 1) === check + "-" :
5478 false;
5479 },
5480
5481 POS: function( elem, match, i, array ) {
5482 var name = match[2],
5483 filter = Expr.setFilters[ name ];
5484
5485 if ( filter ) {
5486 return filter( elem, i, match, array );
5487 }
5488 }
5489 }
5490};
5491
5492var origPOS = Expr.match.POS,
5493 fescape = function(all, num){
5494 return "\\" + (num - 0 + 1);
5495 };
5496
5497for ( var type in Expr.match ) {
5498 Expr.match[ type ] = new RegExp( Expr.match[ type ].source + (/(?![^\[]*\])(?![^\(]*\))/.source) );
5499 Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, fescape) );
5500}
5501
5502var makeArray = function( array, results ) {
5503 array = Array.prototype.slice.call( array, 0 );
5504
5505 if ( results ) {
5506 results.push.apply( results, array );
5507 return results;
5508 }
5509
5510 return array;
5511};
5512
5513// Perform a simple check to determine if the browser is capable of
5514// converting a NodeList to an array using builtin methods.
5515// Also verifies that the returned array holds DOM nodes
5516// (which is not the case in the Blackberry browser)
5517try {
5518 Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType;
5519
5520// Provide a fallback method if it does not work
5521} catch( e ) {
5522 makeArray = function( array, results ) {
5523 var i = 0,
5524 ret = results || [];
5525
5526 if ( toString.call(array) === "[object Array]" ) {
5527 Array.prototype.push.apply( ret, array );
5528
5529 } else {
5530 if ( typeof array.length === "number" ) {
5531 for ( var l = array.length; i < l; i++ ) {
5532 ret.push( array[i] );
5533 }
5534
5535 } else {
5536 for ( ; array[i]; i++ ) {
5537 ret.push( array[i] );
5538 }
5539 }
5540 }
5541
5542 return ret;
5543 };
5544}
5545
5546var sortOrder, siblingCheck;
5547
5548if ( document.documentElement.compareDocumentPosition ) {
5549 sortOrder = function( a, b ) {
5550 if ( a === b ) {
5551 hasDuplicate = true;
5552 return 0;
5553 }
5554
5555 if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) {
5556 return a.compareDocumentPosition ? -1 : 1;
5557 }
5558
5559 return a.compareDocumentPosition(b) & 4 ? -1 : 1;
5560 };
5561
5562} else {
5563 sortOrder = function( a, b ) {
5564 // The nodes are identical, we can exit early
5565 if ( a === b ) {
5566 hasDuplicate = true;
5567 return 0;
5568
5569 // Fallback to using sourceIndex (in IE) if it's available on both nodes
5570 } else if ( a.sourceIndex && b.sourceIndex ) {
5571 return a.sourceIndex - b.sourceIndex;
5572 }
5573
5574 var al, bl,
5575 ap = [],
5576 bp = [],
5577 aup = a.parentNode,
5578 bup = b.parentNode,
5579 cur = aup;
5580
5581 // If the nodes are siblings (or identical) we can do a quick check
5582 if ( aup === bup ) {
5583 return siblingCheck( a, b );
5584
5585 // If no parents were found then the nodes are disconnected
5586 } else if ( !aup ) {
5587 return -1;
5588
5589 } else if ( !bup ) {
5590 return 1;
5591 }
5592
5593 // Otherwise they're somewhere else in the tree so we need
5594 // to build up a full list of the parentNodes for comparison
5595 while ( cur ) {
5596 ap.unshift( cur );
5597 cur = cur.parentNode;
5598 }
5599
5600 cur = bup;
5601
5602 while ( cur ) {
5603 bp.unshift( cur );
5604 cur = cur.parentNode;
5605 }
5606
5607 al = ap.length;
5608 bl = bp.length;
5609
5610 // Start walking down the tree looking for a discrepancy
5611 for ( var i = 0; i < al && i < bl; i++ ) {
5612 if ( ap[i] !== bp[i] ) {
5613 return siblingCheck( ap[i], bp[i] );
5614 }
5615 }
5616
5617 // We ended someplace up the tree so do a sibling check
5618 return i === al ?
5619 siblingCheck( a, bp[i], -1 ) :
5620 siblingCheck( ap[i], b, 1 );
5621 };
5622
5623 siblingCheck = function( a, b, ret ) {
5624 if ( a === b ) {
5625 return ret;
5626 }
5627
5628 var cur = a.nextSibling;
5629
5630 while ( cur ) {
5631 if ( cur === b ) {
5632 return -1;
5633 }
5634
5635 cur = cur.nextSibling;
5636 }
5637
5638 return 1;
5639 };
5640}
5641
5642// Check to see if the browser returns elements by name when
5643// querying by getElementById (and provide a workaround)
5644(function(){
5645 // We're going to inject a fake input element with a specified name
5646 var form = document.createElement("div"),
5647 id = "script" + (new Date()).getTime(),
5648 root = document.documentElement;
5649
5650 form.innerHTML = "<a name='" + id + "'/>";
5651
5652 // Inject it into the root element, check its status, and remove it quickly
5653 root.insertBefore( form, root.firstChild );
5654
5655 // The workaround has to do additional checks after a getElementById
5656 // Which slows things down for other browsers (hence the branching)
5657 if ( document.getElementById( id ) ) {
5658 Expr.find.ID = function( match, context, isXML ) {
5659 if ( typeof context.getElementById !== "undefined" && !isXML ) {
5660 var m = context.getElementById(match[1]);
5661
5662 return m ?
5663 m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ?
5664 [m] :
5665 undefined :
5666 [];
5667 }
5668 };
5669
5670 Expr.filter.ID = function( elem, match ) {
5671 var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id");
5672
5673 return elem.nodeType === 1 && node && node.nodeValue === match;
5674 };
5675 }
5676
5677 root.removeChild( form );
5678
5679 // release memory in IE
5680 root = form = null;
5681})();
5682
5683(function(){
5684 // Check to see if the browser returns only elements
5685 // when doing getElementsByTagName("*")
5686
5687 // Create a fake element
5688 var div = document.createElement("div");
5689 div.appendChild( document.createComment("") );
5690
5691 // Make sure no comments are found
5692 if ( div.getElementsByTagName("*").length > 0 ) {
5693 Expr.find.TAG = function( match, context ) {
5694 var results = context.getElementsByTagName( match[1] );
5695
5696 // Filter out possible comments
5697 if ( match[1] === "*" ) {
5698 var tmp = [];
5699
5700 for ( var i = 0; results[i]; i++ ) {
5701 if ( results[i].nodeType === 1 ) {
5702 tmp.push( results[i] );
5703 }
5704 }
5705
5706 results = tmp;
5707 }
5708
5709 return results;
5710 };
5711 }
5712
5713 // Check to see if an attribute returns normalized href attributes
5714 div.innerHTML = "<a href='#'></a>";
5715
5716 if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" &&
5717 div.firstChild.getAttribute("href") !== "#" ) {
5718
5719 Expr.attrHandle.href = function( elem ) {
5720 return elem.getAttribute( "href", 2 );
5721 };
5722 }
5723
5724 // release memory in IE
5725 div = null;
5726})();
5727
5728if ( document.querySelectorAll ) {
5729 (function(){
5730 var oldSizzle = Sizzle,
5731 div = document.createElement("div"),
5732 id = "__sizzle__";
5733
5734 div.innerHTML = "<p class='TEST'></p>";
5735
5736 // Safari can't handle uppercase or unicode characters when
5737 // in quirks mode.
5738 if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) {
5739 return;
5740 }
5741
5742 Sizzle = function( query, context, extra, seed ) {
5743 context = context || document;
5744
5745 // Only use querySelectorAll on non-XML documents
5746 // (ID selectors don't work in non-HTML documents)
5747 if ( !seed && !Sizzle.isXML(context) ) {
5748 // See if we find a selector to speed up
5749 var match = /^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec( query );
5750
5751 if ( match && (context.nodeType === 1 || context.nodeType === 9) ) {
5752 // Speed-up: Sizzle("TAG")
5753 if ( match[1] ) {
5754 return makeArray( context.getElementsByTagName( query ), extra );
5755
5756 // Speed-up: Sizzle(".CLASS")
5757 } else if ( match[2] && Expr.find.CLASS && context.getElementsByClassName ) {
5758 return makeArray( context.getElementsByClassName( match[2] ), extra );
5759 }
5760 }
5761
5762 if ( context.nodeType === 9 ) {
5763 // Speed-up: Sizzle("body")
5764 // The body element only exists once, optimize finding it
5765 if ( query === "body" && context.body ) {
5766 return makeArray( [ context.body ], extra );
5767
5768 // Speed-up: Sizzle("#ID")
5769 } else if ( match && match[3] ) {
5770 var elem = context.getElementById( match[3] );
5771
5772 // Check parentNode to catch when Blackberry 4.6 returns
5773 // nodes that are no longer in the document #6963
5774 if ( elem && elem.parentNode ) {
5775 // Handle the case where IE and Opera return items
5776 // by name instead of ID
5777 if ( elem.id === match[3] ) {
5778 return makeArray( [ elem ], extra );
5779 }
5780
5781 } else {
5782 return makeArray( [], extra );
5783 }
5784 }
5785
5786 try {
5787 return makeArray( context.querySelectorAll(query), extra );
5788 } catch(qsaError) {}
5789
5790 // qSA works strangely on Element-rooted queries
5791 // We can work around this by specifying an extra ID on the root
5792 // and working up from there (Thanks to Andrew Dupont for the technique)
5793 // IE 8 doesn't work on object elements
5794 } else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
5795 var oldContext = context,
5796 old = context.getAttribute( "id" ),
5797 nid = old || id,
5798 hasParent = context.parentNode,
5799 relativeHierarchySelector = /^\s*[+~]/.test( query );
5800
5801 if ( !old ) {
5802 context.setAttribute( "id", nid );
5803 } else {
5804 nid = nid.replace( /'/g, "\\$&" );
5805 }
5806 if ( relativeHierarchySelector && hasParent ) {
5807 context = context.parentNode;
5808 }
5809
5810 try {
5811 if ( !relativeHierarchySelector || hasParent ) {
5812 return makeArray( context.querySelectorAll( "[id='" + nid + "'] " + query ), extra );
5813 }
5814
5815 } catch(pseudoError) {
5816 } finally {
5817 if ( !old ) {
5818 oldContext.removeAttribute( "id" );
5819 }
5820 }
5821 }
5822 }
5823
5824 return oldSizzle(query, context, extra, seed);
5825 };
5826
5827 for ( var prop in oldSizzle ) {
5828 Sizzle[ prop ] = oldSizzle[ prop ];
5829 }
5830
5831 // release memory in IE
5832 div = null;
5833 })();
5834}
5835
5836(function(){
5837 var html = document.documentElement,
5838 matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector;
5839
5840 if ( matches ) {
5841 // Check to see if it's possible to do matchesSelector
5842 // on a disconnected node (IE 9 fails this)
5843 var disconnectedMatch = !matches.call( document.createElement( "div" ), "div" ),
5844 pseudoWorks = false;
5845
5846 try {
5847 // This should fail with an exception
5848 // Gecko does not error, returns false instead
5849 matches.call( document.documentElement, "[test!='']:sizzle" );
5850
5851 } catch( pseudoError ) {
5852 pseudoWorks = true;
5853 }
5854
5855 Sizzle.matchesSelector = function( node, expr ) {
5856 // Make sure that attribute selectors are quoted
5857 expr = expr.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']");
5858
5859 if ( !Sizzle.isXML( node ) ) {
5860 try {
5861 if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) {
5862 var ret = matches.call( node, expr );
5863
5864 // IE 9's matchesSelector returns false on disconnected nodes
5865 if ( ret || !disconnectedMatch ||
5866 // As well, disconnected nodes are said to be in a document
5867 // fragment in IE 9, so check for that
5868 node.document && node.document.nodeType !== 11 ) {
5869 return ret;
5870 }
5871 }
5872 } catch(e) {}
5873 }
5874
5875 return Sizzle(expr, null, null, [node]).length > 0;
5876 };
5877 }
5878})();
5879
5880(function(){
5881 var div = document.createElement("div");
5882
5883 div.innerHTML = "<div class='test e'></div><div class='test'></div>";
5884
5885 // Opera can't find a second classname (in 9.6)
5886 // Also, make sure that getElementsByClassName actually exists
5887 if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) {
5888 return;
5889 }
5890
5891 // Safari caches class attributes, doesn't catch changes (in 3.2)
5892 div.lastChild.className = "e";
5893
5894 if ( div.getElementsByClassName("e").length === 1 ) {
5895 return;
5896 }
5897
5898 Expr.order.splice(1, 0, "CLASS");
5899 Expr.find.CLASS = function( match, context, isXML ) {
5900 if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) {
5901 return context.getElementsByClassName(match[1]);
5902 }
5903 };
5904
5905 // release memory in IE
5906 div = null;
5907})();
5908
5909function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
5910 for ( var i = 0, l = checkSet.length; i < l; i++ ) {
5911 var elem = checkSet[i];
5912
5913 if ( elem ) {
5914 var match = false;
5915
5916 elem = elem[dir];
5917
5918 while ( elem ) {
5919 if ( elem[ expando ] === doneName ) {
5920 match = checkSet[elem.sizset];
5921 break;
5922 }
5923
5924 if ( elem.nodeType === 1 && !isXML ){
5925 elem[ expando ] = doneName;
5926 elem.sizset = i;
5927 }
5928
5929 if ( elem.nodeName.toLowerCase() === cur ) {
5930 match = elem;
5931 break;
5932 }
5933
5934 elem = elem[dir];
5935 }
5936
5937 checkSet[i] = match;
5938 }
5939 }
5940}
5941
5942function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
5943 for ( var i = 0, l = checkSet.length; i < l; i++ ) {
5944 var elem = checkSet[i];
5945
5946 if ( elem ) {
5947 var match = false;
5948
5949 elem = elem[dir];
5950
5951 while ( elem ) {
5952 if ( elem[ expando ] === doneName ) {
5953 match = checkSet[elem.sizset];
5954 break;
5955 }
5956
5957 if ( elem.nodeType === 1 ) {
5958 if ( !isXML ) {
5959 elem[ expando ] = doneName;
5960 elem.sizset = i;
5961 }
5962
5963 if ( typeof cur !== "string" ) {
5964 if ( elem === cur ) {
5965 match = true;
5966 break;
5967 }
5968
5969 } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) {
5970 match = elem;
5971 break;
5972 }
5973 }
5974
5975 elem = elem[dir];
5976 }
5977
5978 checkSet[i] = match;
5979 }
5980 }
5981}
5982
5983if ( document.documentElement.contains ) {
5984 Sizzle.contains = function( a, b ) {
5985 return a !== b && (a.contains ? a.contains(b) : true);
5986 };
5987
5988} else if ( document.documentElement.compareDocumentPosition ) {
5989 Sizzle.contains = function( a, b ) {
5990 return !!(a.compareDocumentPosition(b) & 16);
5991 };
5992
5993} else {
5994 Sizzle.contains = function() {
5995 return false;
5996 };
5997}
5998
5999Sizzle.isXML = function( elem ) {
6000 // documentElement is verified for cases where it doesn't yet exist
6001 // (such as loading iframes in IE - #4833)
6002 var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement;
6003
6004 return documentElement ? documentElement.nodeName !== "HTML" : false;
6005};
6006
6007var posProcess = function( selector, context, seed ) {
6008 var match,
6009 tmpSet = [],
6010 later = "",
6011 root = context.nodeType ? [context] : context;
6012
6013 // Position selectors must be done after the filter
6014 // And so must :not(positional) so we move all PSEUDOs to the end
6015 while ( (match = Expr.match.PSEUDO.exec( selector )) ) {
6016 later += match[0];
6017 selector = selector.replace( Expr.match.PSEUDO, "" );
6018 }
6019
6020 selector = Expr.relative[selector] ? selector + "*" : selector;
6021
6022 for ( var i = 0, l = root.length; i < l; i++ ) {
6023 Sizzle( selector, root[i], tmpSet, seed );
6024 }
6025
6026 return Sizzle.filter( later, tmpSet );
6027};
6028
6029// EXPOSE
6030// Override sizzle attribute retrieval
6031Sizzle.attr = jQuery.attr;
6032Sizzle.selectors.attrMap = {};
6033jQuery.find = Sizzle;
6034jQuery.expr = Sizzle.selectors;
6035jQuery.expr[":"] = jQuery.expr.filters;
6036jQuery.unique = Sizzle.uniqueSort;
6037jQuery.text = Sizzle.getText;
6038jQuery.isXMLDoc = Sizzle.isXML;
6039jQuery.contains = Sizzle.contains;
6040
6041
6042})();
6043(function( jQuery ) {
6044
6045var runtil = /Until$/,
6046 rparentsprev = /^(?:parents|prevUntil|prevAll)/,
6047 // Note: This RegExp should be improved, or likely pulled from Sizzle
6048 rmultiselector = /,/,
6049 isSimple = /^.[^:#\[\.,]*$/,
6050 slice = Array.prototype.slice,
6051 POS = jQuery.expr.match.POS,
6052 // methods guaranteed to produce a unique set when starting from a unique set
6053 guaranteedUnique = {
6054 children: true,
6055 contents: true,
6056 next: true,
6057 prev: true
6058 };
6059
6060jQuery.fn.extend({
6061 find: function( selector ) {
6062 var self = this,
6063 i, l;
6064
6065 if ( typeof selector !== "string" ) {
6066 return jQuery( selector ).filter(function() {
6067 for ( i = 0, l = self.length; i < l; i++ ) {
6068 if ( jQuery.contains( self[ i ], this ) ) {
6069 return true;
6070 }
6071 }
6072 });
6073 }
6074
6075 var ret = this.pushStack( "", "find", selector ),
6076 length, n, r;
6077
6078 for ( i = 0, l = this.length; i < l; i++ ) {
6079 length = ret.length;
6080 jQuery.find( selector, this[i], ret );
6081
6082 if ( i > 0 ) {
6083 // Make sure that the results are unique
6084 for ( n = length; n < ret.length; n++ ) {
6085 for ( r = 0; r < length; r++ ) {
6086 if ( ret[r] === ret[n] ) {
6087 ret.splice(n--, 1);
6088 break;
6089 }
6090 }
6091 }
6092 }
6093 }
6094
6095 return ret;
6096 },
6097
6098 has: function( target ) {
6099 var targets = jQuery( target );
6100 return this.filter(function() {
6101 for ( var i = 0, l = targets.length; i < l; i++ ) {
6102 if ( jQuery.contains( this, targets[i] ) ) {
6103 return true;
6104 }
6105 }
6106 });
6107 },
6108
6109 not: function( selector ) {
6110 return this.pushStack( winnow(this, selector, false), "not", selector);
6111 },
6112
6113 filter: function( selector ) {
6114 return this.pushStack( winnow(this, selector, true), "filter", selector );
6115 },
6116
6117 is: function( selector ) {
6118 return !!selector && (
6119 typeof selector === "string" ?
6120 // If this is a positional selector, check membership in the returned set
6121 // so $("p:first").is("p:last") won't return true for a doc with two "p".
6122 POS.test( selector ) ?
6123 jQuery( selector, this.context ).index( this[0] ) >= 0 :
6124 jQuery.filter( selector, this ).length > 0 :
6125 this.filter( selector ).length > 0 );
6126 },
6127
6128 closest: function( selectors, context ) {
6129 var ret = [], i, l, cur = this[0];
6130
6131 // Array (deprecated as of jQuery 1.7)
6132 if ( jQuery.isArray( selectors ) ) {
6133 var level = 1;
6134
6135 while ( cur && cur.ownerDocument && cur !== context ) {
6136 for ( i = 0; i < selectors.length; i++ ) {
6137
6138 if ( jQuery( cur ).is( selectors[ i ] ) ) {
6139 ret.push({ selector: selectors[ i ], elem: cur, level: level });
6140 }
6141 }
6142
6143 cur = cur.parentNode;
6144 level++;
6145 }
6146
6147 return ret;
6148 }
6149
6150 // String
6151 var pos = POS.test( selectors ) || typeof selectors !== "string" ?
6152 jQuery( selectors, context || this.context ) :
6153 0;
6154
6155 for ( i = 0, l = this.length; i < l; i++ ) {
6156 cur = this[i];
6157
6158 while ( cur ) {
6159 if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) {
6160 ret.push( cur );
6161 break;
6162
6163 } else {
6164 cur = cur.parentNode;
6165 if ( !cur || !cur.ownerDocument || cur === context || cur.nodeType === 11 ) {
6166 break;
6167 }
6168 }
6169 }
6170 }
6171
6172 ret = ret.length > 1 ? jQuery.unique( ret ) : ret;
6173
6174 return this.pushStack( ret, "closest", selectors );
6175 },
6176
6177 // Determine the position of an element within
6178 // the matched set of elements
6179 index: function( elem ) {
6180
6181 // No argument, return index in parent
6182 if ( !elem ) {
6183 return ( this[0] && this[0].parentNode ) ? this.prevAll().length : -1;
6184 }
6185
6186 // index in selector
6187 if ( typeof elem === "string" ) {
6188 return jQuery.inArray( this[0], jQuery( elem ) );
6189 }
6190
6191 // Locate the position of the desired element
6192 return jQuery.inArray(
6193 // If it receives a jQuery object, the first element is used
6194 elem.jquery ? elem[0] : elem, this );
6195 },
6196
6197 add: function( selector, context ) {
6198 var set = typeof selector === "string" ?
6199 jQuery( selector, context ) :
6200 jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ),
6201 all = jQuery.merge( this.get(), set );
6202
6203 return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ?
6204 all :
6205 jQuery.unique( all ) );
6206 },
6207
6208 andSelf: function() {
6209 return this.add( this.prevObject );
6210 }
6211});
6212
6213// A painfully simple check to see if an element is disconnected
6214// from a document (should be improved, where feasible).
6215function isDisconnected( node ) {
6216 return !node || !node.parentNode || node.parentNode.nodeType === 11;
6217}
6218
6219jQuery.each({
6220 parent: function( elem ) {
6221 var parent = elem.parentNode;
6222 return parent && parent.nodeType !== 11 ? parent : null;
6223 },
6224 parents: function( elem ) {
6225 return jQuery.dir( elem, "parentNode" );
6226 },
6227 parentsUntil: function( elem, i, until ) {
6228 return jQuery.dir( elem, "parentNode", until );
6229 },
6230 next: function( elem ) {
6231 return jQuery.nth( elem, 2, "nextSibling" );
6232 },
6233 prev: function( elem ) {
6234 return jQuery.nth( elem, 2, "previousSibling" );
6235 },
6236 nextAll: function( elem ) {
6237 return jQuery.dir( elem, "nextSibling" );
6238 },
6239 prevAll: function( elem ) {
6240 return jQuery.dir( elem, "previousSibling" );
6241 },
6242 nextUntil: function( elem, i, until ) {
6243 return jQuery.dir( elem, "nextSibling", until );
6244 },
6245 prevUntil: function( elem, i, until ) {
6246 return jQuery.dir( elem, "previousSibling", until );
6247 },
6248 siblings: function( elem ) {
6249 return jQuery.sibling( elem.parentNode.firstChild, elem );
6250 },
6251 children: function( elem ) {
6252 return jQuery.sibling( elem.firstChild );
6253 },
6254 contents: function( elem ) {
6255 return jQuery.nodeName( elem, "iframe" ) ?
6256 elem.contentDocument || elem.contentWindow.document :
6257 jQuery.makeArray( elem.childNodes );
6258 }
6259}, function( name, fn ) {
6260 jQuery.fn[ name ] = function( until, selector ) {
6261 var ret = jQuery.map( this, fn, until ),
6262 // The variable 'args' was introduced in
6263 // https://github.com/jquery/jquery/commit/52a0238
6264 // to work around a bug in Chrome 10 (Dev) and should be removed when the bug is fixed.
6265 // http://code.google.com/p/v8/issues/detail?id=1050
6266 args = slice.call(arguments);
6267
6268 if ( !runtil.test( name ) ) {
6269 selector = until;
6270 }
6271
6272 if ( selector && typeof selector === "string" ) {
6273 ret = jQuery.filter( selector, ret );
6274 }
6275
6276 ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret;
6277
6278 if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) {
6279 ret = ret.reverse();
6280 }
6281
6282 return this.pushStack( ret, name, args.join(",") );
6283 };
6284});
6285
6286jQuery.extend({
6287 filter: function( expr, elems, not ) {
6288 if ( not ) {
6289 expr = ":not(" + expr + ")";
6290 }
6291
6292 return elems.length === 1 ?
6293 jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] :
6294 jQuery.find.matches(expr, elems);
6295 },
6296
6297 dir: function( elem, dir, until ) {
6298 var matched = [],
6299 cur = elem[ dir ];
6300
6301 while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {
6302 if ( cur.nodeType === 1 ) {
6303 matched.push( cur );
6304 }
6305 cur = cur[dir];
6306 }
6307 return matched;
6308 },
6309
6310 nth: function( cur, result, dir, elem ) {
6311 result = result || 1;
6312 var num = 0;
6313
6314 for ( ; cur; cur = cur[dir] ) {
6315 if ( cur.nodeType === 1 && ++num === result ) {
6316 break;
6317 }
6318 }
6319
6320 return cur;
6321 },
6322
6323 sibling: function( n, elem ) {
6324 var r = [];
6325
6326 for ( ; n; n = n.nextSibling ) {
6327 if ( n.nodeType === 1 && n !== elem ) {
6328 r.push( n );
6329 }
6330 }
6331
6332 return r;
6333 }
6334});
6335
6336// Implement the identical functionality for filter and not
6337function winnow( elements, qualifier, keep ) {
6338
6339 // Can't pass null or undefined to indexOf in Firefox 4
6340 // Set to 0 to skip string check
6341 qualifier = qualifier || 0;
6342
6343 if ( jQuery.isFunction( qualifier ) ) {
6344 return jQuery.grep(elements, function( elem, i ) {
6345 var retVal = !!qualifier.call( elem, i, elem );
6346 return retVal === keep;
6347 });
6348
6349 } else if ( qualifier.nodeType ) {
6350 return jQuery.grep(elements, function( elem, i ) {
6351 return ( elem === qualifier ) === keep;
6352 });
6353
6354 } else if ( typeof qualifier === "string" ) {
6355 var filtered = jQuery.grep(elements, function( elem ) {
6356 return elem.nodeType === 1;
6357 });
6358
6359 if ( isSimple.test( qualifier ) ) {
6360 return jQuery.filter(qualifier, filtered, !keep);
6361 } else {
6362 qualifier = jQuery.filter( qualifier, filtered );
6363 }
6364 }
6365
6366 return jQuery.grep(elements, function( elem, i ) {
6367 return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep;
6368 });
6369}
6370
6371})( jQuery );
6372(function( jQuery ) {
6373
6374function createSafeFragment( document ) {
6375 var list = nodeNames.split( " " ),
6376 safeFrag = document.createDocumentFragment();
6377
6378 if ( safeFrag.createElement ) {
6379 while ( list.length ) {
6380 safeFrag.createElement(
6381 list.pop()
6382 );
6383 }
6384 }
6385 return safeFrag;
6386}
6387
6388var nodeNames = "abbr article aside audio canvas datalist details figcaption figure footer " +
6389 "header hgroup mark meter nav output progress section summary time video",
6390 rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g,
6391 rleadingWhitespace = /^\s+/,
6392 rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,
6393 rtagName = /<([\w:]+)/,
6394 rtbody = /<tbody/i,
6395 rhtml = /<|&#?\w+;/,
6396 rnoInnerhtml = /<(?:script|style)/i,
6397 rnocache = /<(?:script|object|embed|option|style)/i,
6398 rnoshimcache = new RegExp("<(?:" + nodeNames.replace(" ", "|") + ")", "i"),
6399 // checked="checked" or checked
6400 rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
6401 rscriptType = /\/(java|ecma)script/i,
6402 rcleanScript = /^\s*<!(?:\[CDATA\[|\-\-)/,
6403 wrapMap = {
6404 option: [ 1, "<select multiple='multiple'>", "</select>" ],
6405 legend: [ 1, "<fieldset>", "</fieldset>" ],
6406 thead: [ 1, "<table>", "</table>" ],
6407 tr: [ 2, "<table><tbody>", "</tbody></table>" ],
6408 td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
6409 col: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ],
6410 area: [ 1, "<map>", "</map>" ],
6411 _default: [ 0, "", "" ]
6412 },
6413 safeFragment = createSafeFragment( document );
6414
6415wrapMap.optgroup = wrapMap.option;
6416wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
6417wrapMap.th = wrapMap.td;
6418
6419// IE can't serialize <link> and <script> tags normally
6420if ( !jQuery.support.htmlSerialize ) {
6421 wrapMap._default = [ 1, "div<div>", "</div>" ];
6422}
6423
6424jQuery.fn.extend({
6425 text: function( text ) {
6426 if ( jQuery.isFunction(text) ) {
6427 return this.each(function(i) {
6428 var self = jQuery( this );
6429
6430 self.text( text.call(this, i, self.text()) );
6431 });
6432 }
6433
6434 if ( typeof text !== "object" && text !== undefined ) {
6435 return this.empty().append( (this[0] && this[0].ownerDocument || document).createTextNode( text ) );
6436 }
6437
6438 return jQuery.text( this );
6439 },
6440
6441 wrapAll: function( html ) {
6442 if ( jQuery.isFunction( html ) ) {
6443 return this.each(function(i) {
6444 jQuery(this).wrapAll( html.call(this, i) );
6445 });
6446 }
6447
6448 if ( this[0] ) {
6449 // The elements to wrap the target around
6450 var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true);
6451
6452 if ( this[0].parentNode ) {
6453 wrap.insertBefore( this[0] );
6454 }
6455
6456 wrap.map(function() {
6457 var elem = this;
6458
6459 while ( elem.firstChild && elem.firstChild.nodeType === 1 ) {
6460 elem = elem.firstChild;
6461 }
6462
6463 return elem;
6464 }).append( this );
6465 }
6466
6467 return this;
6468 },
6469
6470 wrapInner: function( html ) {
6471 if ( jQuery.isFunction( html ) ) {
6472 return this.each(function(i) {
6473 jQuery(this).wrapInner( html.call(this, i) );
6474 });
6475 }
6476
6477 return this.each(function() {
6478 var self = jQuery( this ),
6479 contents = self.contents();
6480
6481 if ( contents.length ) {
6482 contents.wrapAll( html );
6483
6484 } else {
6485 self.append( html );
6486 }
6487 });
6488 },
6489
6490 wrap: function( html ) {
6491 return this.each(function() {
6492 jQuery( this ).wrapAll( html );
6493 });
6494 },
6495
6496 unwrap: function() {
6497 return this.parent().each(function() {
6498 if ( !jQuery.nodeName( this, "body" ) ) {
6499 jQuery( this ).replaceWith( this.childNodes );
6500 }
6501 }).end();
6502 },
6503
6504 append: function() {
6505 return this.domManip(arguments, true, function( elem ) {
6506 if ( this.nodeType === 1 ) {
6507 this.appendChild( elem );
6508 }
6509 });
6510 },
6511
6512 prepend: function() {
6513 return this.domManip(arguments, true, function( elem ) {
6514 if ( this.nodeType === 1 ) {
6515 this.insertBefore( elem, this.firstChild );
6516 }
6517 });
6518 },
6519
6520 before: function() {
6521 if ( this[0] && this[0].parentNode ) {
6522 return this.domManip(arguments, false, function( elem ) {
6523 this.parentNode.insertBefore( elem, this );
6524 });
6525 } else if ( arguments.length ) {
6526 var set = jQuery(arguments[0]);
6527 set.push.apply( set, this.toArray() );
6528 return this.pushStack( set, "before", arguments );
6529 }
6530 },
6531
6532 after: function() {
6533 if ( this[0] && this[0].parentNode ) {
6534 return this.domManip(arguments, false, function( elem ) {
6535 this.parentNode.insertBefore( elem, this.nextSibling );
6536 });
6537 } else if ( arguments.length ) {
6538 var set = this.pushStack( this, "after", arguments );
6539 set.push.apply( set, jQuery(arguments[0]).toArray() );
6540 return set;
6541 }
6542 },
6543
6544 // keepData is for internal use only--do not document
6545 remove: function( selector, keepData ) {
6546 for ( var i = 0, elem; (elem = this[i]) != null; i++ ) {
6547 if ( !selector || jQuery.filter( selector, [ elem ] ).length ) {
6548 if ( !keepData && elem.nodeType === 1 ) {
6549 jQuery.cleanData( elem.getElementsByTagName("*") );
6550 jQuery.cleanData( [ elem ] );
6551 }
6552
6553 if ( elem.parentNode ) {
6554 elem.parentNode.removeChild( elem );
6555 }
6556 }
6557 }
6558
6559 return this;
6560 },
6561
6562 empty: function() {
6563 for ( var i = 0, elem; (elem = this[i]) != null; i++ ) {
6564 // Remove element nodes and prevent memory leaks
6565 if ( elem.nodeType === 1 ) {
6566 jQuery.cleanData( elem.getElementsByTagName("*") );
6567 }
6568
6569 // Remove any remaining nodes
6570 while ( elem.firstChild ) {
6571 elem.removeChild( elem.firstChild );
6572 }
6573 }
6574
6575 return this;
6576 },
6577
6578 clone: function( dataAndEvents, deepDataAndEvents ) {
6579 dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
6580 deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
6581
6582 return this.map( function () {
6583 return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
6584 });
6585 },
6586
6587 html: function( value ) {
6588 if ( value === undefined ) {
6589 return this[0] && this[0].nodeType === 1 ?
6590 this[0].innerHTML.replace(rinlinejQuery, "") :
6591 null;
6592
6593 // See if we can take a shortcut and just use innerHTML
6594 } else if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
6595 (jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value )) &&
6596 !wrapMap[ (rtagName.exec( value ) || ["", ""])[1].toLowerCase() ] ) {
6597
6598 value = value.replace(rxhtmlTag, "<$1></$2>");
6599
6600 try {
6601 for ( var i = 0, l = this.length; i < l; i++ ) {
6602 // Remove element nodes and prevent memory leaks
6603 if ( this[i].nodeType === 1 ) {
6604 jQuery.cleanData( this[i].getElementsByTagName("*") );
6605 this[i].innerHTML = value;
6606 }
6607 }
6608
6609 // If using innerHTML throws an exception, use the fallback method
6610 } catch(e) {
6611 this.empty().append( value );
6612 }
6613
6614 } else if ( jQuery.isFunction( value ) ) {
6615 this.each(function(i){
6616 var self = jQuery( this );
6617
6618 self.html( value.call(this, i, self.html()) );
6619 });
6620
6621 } else {
6622 this.empty().append( value );
6623 }
6624
6625 return this;
6626 },
6627
6628 replaceWith: function( value ) {
6629 if ( this[0] && this[0].parentNode ) {
6630 // Make sure that the elements are removed from the DOM before they are inserted
6631 // this can help fix replacing a parent with child elements
6632 if ( jQuery.isFunction( value ) ) {
6633 return this.each(function(i) {
6634 var self = jQuery(this), old = self.html();
6635 self.replaceWith( value.call( this, i, old ) );
6636 });
6637 }
6638
6639 if ( typeof value !== "string" ) {
6640 value = jQuery( value ).detach();
6641 }
6642
6643 return this.each(function() {
6644 var next = this.nextSibling,
6645 parent = this.parentNode;
6646
6647 jQuery( this ).remove();
6648
6649 if ( next ) {
6650 jQuery(next).before( value );
6651 } else {
6652 jQuery(parent).append( value );
6653 }
6654 });
6655 } else {
6656 return this.length ?
6657 this.pushStack( jQuery(jQuery.isFunction(value) ? value() : value), "replaceWith", value ) :
6658 this;
6659 }
6660 },
6661
6662 detach: function( selector ) {
6663 return this.remove( selector, true );
6664 },
6665
6666 domManip: function( args, table, callback ) {
6667 var results, first, fragment, parent,
6668 value = args[0],
6669 scripts = [];
6670
6671 // We can't cloneNode fragments that contain checked, in WebKit
6672 if ( !jQuery.support.checkClone && arguments.length === 3 && typeof value === "string" && rchecked.test( value ) ) {
6673 return this.each(function() {
6674 jQuery(this).domManip( args, table, callback, true );
6675 });
6676 }
6677
6678 if ( jQuery.isFunction(value) ) {
6679 return this.each(function(i) {
6680 var self = jQuery(this);
6681 args[0] = value.call(this, i, table ? self.html() : undefined);
6682 self.domManip( args, table, callback );
6683 });
6684 }
6685
6686 if ( this[0] ) {
6687 parent = value && value.parentNode;
6688
6689 // If we're in a fragment, just use that instead of building a new one
6690 if ( jQuery.support.parentNode && parent && parent.nodeType === 11 && parent.childNodes.length === this.length ) {
6691 results = { fragment: parent };
6692
6693 } else {
6694 results = jQuery.buildFragment( args, this, scripts );
6695 }
6696
6697 fragment = results.fragment;
6698
6699 if ( fragment.childNodes.length === 1 ) {
6700 first = fragment = fragment.firstChild;
6701 } else {
6702 first = fragment.firstChild;
6703 }
6704
6705 if ( first ) {
6706 table = table && jQuery.nodeName( first, "tr" );
6707
6708 for ( var i = 0, l = this.length, lastIndex = l - 1; i < l; i++ ) {
6709 callback.call(
6710 table ?
6711 root(this[i], first) :
6712 this[i],
6713 // Make sure that we do not leak memory by inadvertently discarding
6714 // the original fragment (which might have attached data) instead of
6715 // using it; in addition, use the original fragment object for the last
6716 // item instead of first because it can end up being emptied incorrectly
6717 // in certain situations (Bug #8070).
6718 // Fragments from the fragment cache must always be cloned and never used
6719 // in place.
6720 results.cacheable || ( l > 1 && i < lastIndex ) ?
6721 jQuery.clone( fragment, true, true ) :
6722 fragment
6723 );
6724 }
6725 }
6726
6727 if ( scripts.length ) {
6728 jQuery.each( scripts, evalScript );
6729 }
6730 }
6731
6732 return this;
6733 }
6734});
6735
6736function root( elem, cur ) {
6737 return jQuery.nodeName(elem, "table") ?
6738 (elem.getElementsByTagName("tbody")[0] ||
6739 elem.appendChild(elem.ownerDocument.createElement("tbody"))) :
6740 elem;
6741}
6742
6743function cloneCopyEvent( src, dest ) {
6744
6745 if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) {
6746 return;
6747 }
6748
6749 var type, i, l,
6750 oldData = jQuery._data( src ),
6751 curData = jQuery._data( dest, oldData ),
6752 events = oldData.events;
6753
6754 if ( events ) {
6755 delete curData.handle;
6756 curData.events = {};
6757
6758 for ( type in events ) {
6759 for ( i = 0, l = events[ type ].length; i < l; i++ ) {
6760 jQuery.event.add( dest, type + ( events[ type ][ i ].namespace ? "." : "" ) + events[ type ][ i ].namespace, events[ type ][ i ], events[ type ][ i ].data );
6761 }
6762 }
6763 }
6764
6765 // make the cloned public data object a copy from the original
6766 if ( curData.data ) {
6767 curData.data = jQuery.extend( {}, curData.data );
6768 }
6769}
6770
6771function cloneFixAttributes( src, dest ) {
6772 var nodeName;
6773
6774 // We do not need to do anything for non-Elements
6775 if ( dest.nodeType !== 1 ) {
6776 return;
6777 }
6778
6779 // clearAttributes removes the attributes, which we don't want,
6780 // but also removes the attachEvent events, which we *do* want
6781 if ( dest.clearAttributes ) {
6782 dest.clearAttributes();
6783 }
6784
6785 // mergeAttributes, in contrast, only merges back on the
6786 // original attributes, not the events
6787 if ( dest.mergeAttributes ) {
6788 dest.mergeAttributes( src );
6789 }
6790
6791 nodeName = dest.nodeName.toLowerCase();
6792
6793 // IE6-8 fail to clone children inside object elements that use
6794 // the proprietary classid attribute value (rather than the type
6795 // attribute) to identify the type of content to display
6796 if ( nodeName === "object" ) {
6797 dest.outerHTML = src.outerHTML;
6798
6799 } else if ( nodeName === "input" && (src.type === "checkbox" || src.type === "radio") ) {
6800 // IE6-8 fails to persist the checked state of a cloned checkbox
6801 // or radio button. Worse, IE6-7 fail to give the cloned element
6802 // a checked appearance if the defaultChecked value isn't also set
6803 if ( src.checked ) {
6804 dest.defaultChecked = dest.checked = src.checked;
6805 }
6806
6807 // IE6-7 get confused and end up setting the value of a cloned
6808 // checkbox/radio button to an empty string instead of "on"
6809 if ( dest.value !== src.value ) {
6810 dest.value = src.value;
6811 }
6812
6813 // IE6-8 fails to return the selected option to the default selected
6814 // state when cloning options
6815 } else if ( nodeName === "option" ) {
6816 dest.selected = src.defaultSelected;
6817
6818 // IE6-8 fails to set the defaultValue to the correct value when
6819 // cloning other types of input fields
6820 } else if ( nodeName === "input" || nodeName === "textarea" ) {
6821 dest.defaultValue = src.defaultValue;
6822 }
6823
6824 // Event data gets referenced instead of copied if the expando
6825 // gets copied too
6826 dest.removeAttribute( jQuery.expando );
6827}
6828
6829jQuery.buildFragment = function( args, nodes, scripts ) {
6830 var fragment, cacheable, cacheresults, doc,
6831 first = args[ 0 ];
6832
6833 // nodes may contain either an explicit document object,
6834 // a jQuery collection or context object.
6835 // If nodes[0] contains a valid object to assign to doc
6836 if ( nodes && nodes[0] ) {
6837 doc = nodes[0].ownerDocument || nodes[0];
6838 }
6839
6840 // Ensure that an attr object doesn't incorrectly stand in as a document object
6841 // Chrome and Firefox seem to allow this to occur and will throw exception
6842 // Fixes #8950
6843 if ( !doc.createDocumentFragment ) {
6844 doc = document;
6845 }
6846
6847 // Only cache "small" (1/2 KB) HTML strings that are associated with the main document
6848 // Cloning options loses the selected state, so don't cache them
6849 // IE 6 doesn't like it when you put <object> or <embed> elements in a fragment
6850 // Also, WebKit does not clone 'checked' attributes on cloneNode, so don't cache
6851 // Lastly, IE6,7,8 will not correctly reuse cached fragments that were created from unknown elems #10501
6852 if ( args.length === 1 && typeof first === "string" && first.length < 512 && doc === document &&
6853 first.charAt(0) === "<" && !rnocache.test( first ) &&
6854 (jQuery.support.checkClone || !rchecked.test( first )) &&
6855 (!jQuery.support.unknownElems && rnoshimcache.test( first )) ) {
6856
6857 cacheable = true;
6858
6859 cacheresults = jQuery.fragments[ first ];
6860 if ( cacheresults && cacheresults !== 1 ) {
6861 fragment = cacheresults;
6862 }
6863 }
6864
6865 if ( !fragment ) {
6866 fragment = doc.createDocumentFragment();
6867 jQuery.clean( args, doc, fragment, scripts );
6868 }
6869
6870 if ( cacheable ) {
6871 jQuery.fragments[ first ] = cacheresults ? fragment : 1;
6872 }
6873
6874 return { fragment: fragment, cacheable: cacheable };
6875};
6876
6877jQuery.fragments = {};
6878
6879jQuery.each({
6880 appendTo: "append",
6881 prependTo: "prepend",
6882 insertBefore: "before",
6883 insertAfter: "after",
6884 replaceAll: "replaceWith"
6885}, function( name, original ) {
6886 jQuery.fn[ name ] = function( selector ) {
6887 var ret = [],
6888 insert = jQuery( selector ),
6889 parent = this.length === 1 && this[0].parentNode;
6890
6891 if ( parent && parent.nodeType === 11 && parent.childNodes.length === 1 && insert.length === 1 ) {
6892 insert[ original ]( this[0] );
6893 return this;
6894
6895 } else {
6896 for ( var i = 0, l = insert.length; i < l; i++ ) {
6897 var elems = ( i > 0 ? this.clone(true) : this ).get();
6898 jQuery( insert[i] )[ original ]( elems );
6899 ret = ret.concat( elems );
6900 }
6901
6902 return this.pushStack( ret, name, insert.selector );
6903 }
6904 };
6905});
6906
6907function getAll( elem ) {
6908 if ( typeof elem.getElementsByTagName !== "undefined" ) {
6909 return elem.getElementsByTagName( "*" );
6910
6911 } else if ( typeof elem.querySelectorAll !== "undefined" ) {
6912 return elem.querySelectorAll( "*" );
6913
6914 } else {
6915 return [];
6916 }
6917}
6918
6919// Used in clean, fixes the defaultChecked property
6920function fixDefaultChecked( elem ) {
6921 if ( elem.type === "checkbox" || elem.type === "radio" ) {
6922 elem.defaultChecked = elem.checked;
6923 }
6924}
6925// Finds all inputs and passes them to fixDefaultChecked
6926function findInputs( elem ) {
6927 var nodeName = ( elem.nodeName || "" ).toLowerCase();
6928 if ( nodeName === "input" ) {
6929 fixDefaultChecked( elem );
6930 // Skip scripts, get other children
6931 } else if ( nodeName !== "script" && typeof elem.getElementsByTagName !== "undefined" ) {
6932 jQuery.grep( elem.getElementsByTagName("input"), fixDefaultChecked );
6933 }
6934}
6935
6936jQuery.extend({
6937 clone: function( elem, dataAndEvents, deepDataAndEvents ) {
6938 var clone = elem.cloneNode(true),
6939 srcElements,
6940 destElements,
6941 i;
6942
6943 if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) &&
6944 (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) {
6945 // IE copies events bound via attachEvent when using cloneNode.
6946 // Calling detachEvent on the clone will also remove the events
6947 // from the original. In order to get around this, we use some
6948 // proprietary methods to clear the events. Thanks to MooTools
6949 // guys for this hotness.
6950
6951 cloneFixAttributes( elem, clone );
6952
6953 // Using Sizzle here is crazy slow, so we use getElementsByTagName
6954 // instead
6955 srcElements = getAll( elem );
6956 destElements = getAll( clone );
6957
6958 // Weird iteration because IE will replace the length property
6959 // with an element if you are cloning the body and one of the
6960 // elements on the page has a name or id of "length"
6961 for ( i = 0; srcElements[i]; ++i ) {
6962 // Ensure that the destination node is not null; Fixes #9587
6963 if ( destElements[i] ) {
6964 cloneFixAttributes( srcElements[i], destElements[i] );
6965 }
6966 }
6967 }
6968
6969 // Copy the events from the original to the clone
6970 if ( dataAndEvents ) {
6971 cloneCopyEvent( elem, clone );
6972
6973 if ( deepDataAndEvents ) {
6974 srcElements = getAll( elem );
6975 destElements = getAll( clone );
6976
6977 for ( i = 0; srcElements[i]; ++i ) {
6978 cloneCopyEvent( srcElements[i], destElements[i] );
6979 }
6980 }
6981 }
6982
6983 srcElements = destElements = null;
6984
6985 // Return the cloned set
6986 return clone;
6987 },
6988
6989 clean: function( elems, context, fragment, scripts ) {
6990 var checkScriptType;
6991
6992 context = context || document;
6993
6994 // !context.createElement fails in IE with an error but returns typeof 'object'
6995 if ( typeof context.createElement === "undefined" ) {
6996 context = context.ownerDocument || context[0] && context[0].ownerDocument || document;
6997 }
6998
6999 var ret = [], j;
7000
7001 for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
7002 if ( typeof elem === "number" ) {
7003 elem += "";
7004 }
7005
7006 if ( !elem ) {
7007 continue;
7008 }
7009
7010 // Convert html string into DOM nodes
7011 if ( typeof elem === "string" ) {
7012 if ( !rhtml.test( elem ) ) {
7013 elem = context.createTextNode( elem );
7014 } else {
7015 // Fix "XHTML"-style tags in all browsers
7016 elem = elem.replace(rxhtmlTag, "<$1></$2>");
7017
7018 // Trim whitespace, otherwise indexOf won't work as expected
7019 var tag = ( rtagName.exec( elem ) || ["", ""] )[1].toLowerCase(),
7020 wrap = wrapMap[ tag ] || wrapMap._default,
7021 depth = wrap[0],
7022 div = context.createElement("div");
7023
7024 // Append wrapper element to unknown element safe doc fragment
7025 if ( context === document ) {
7026 // Use the fragment we've already created for this document
7027 safeFragment.appendChild( div );
7028 } else {
7029 // Use a fragment created with the owner document
7030 createSafeFragment( context ).appendChild( div );
7031 }
7032
7033 // Go to html and back, then peel off extra wrappers
7034 div.innerHTML = wrap[1] + elem + wrap[2];
7035
7036 // Move to the right depth
7037 while ( depth-- ) {
7038 div = div.lastChild;
7039 }
7040
7041 // Remove IE's autoinserted <tbody> from table fragments
7042 if ( !jQuery.support.tbody ) {
7043
7044 // String was a <table>, *may* have spurious <tbody>
7045 var hasBody = rtbody.test(elem),
7046 tbody = tag === "table" && !hasBody ?
7047 div.firstChild && div.firstChild.childNodes :
7048
7049 // String was a bare <thead> or <tfoot>
7050 wrap[1] === "<table>" && !hasBody ?
7051 div.childNodes :
7052 [];
7053
7054 for ( j = tbody.length - 1; j >= 0 ; --j ) {
7055 if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length ) {
7056 tbody[ j ].parentNode.removeChild( tbody[ j ] );
7057 }
7058 }
7059 }
7060
7061 // IE completely kills leading whitespace when innerHTML is used
7062 if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {
7063 div.insertBefore( context.createTextNode( rleadingWhitespace.exec(elem)[0] ), div.firstChild );
7064 }
7065
7066 elem = div.childNodes;
7067 }
7068 }
7069
7070 // Resets defaultChecked for any radios and checkboxes
7071 // about to be appended to the DOM in IE 6/7 (#8060)
7072 var len;
7073 if ( !jQuery.support.appendChecked ) {
7074 if ( elem[0] && typeof (len = elem.length) === "number" ) {
7075 for ( j = 0; j < len; j++ ) {
7076 findInputs( elem[j] );
7077 }
7078 } else {
7079 findInputs( elem );
7080 }
7081 }
7082
7083 if ( elem.nodeType ) {
7084 ret.push( elem );
7085 } else {
7086 ret = jQuery.merge( ret, elem );
7087 }
7088 }
7089
7090 if ( fragment ) {
7091 checkScriptType = function( elem ) {
7092 return !elem.type || rscriptType.test( elem.type );
7093 };
7094 for ( i = 0; ret[i]; i++ ) {
7095 if ( scripts && jQuery.nodeName( ret[i], "script" ) && (!ret[i].type || ret[i].type.toLowerCase() === "text/javascript") ) {
7096 scripts.push( ret[i].parentNode ? ret[i].parentNode.removeChild( ret[i] ) : ret[i] );
7097
7098 } else {
7099 if ( ret[i].nodeType === 1 ) {
7100 var jsTags = jQuery.grep( ret[i].getElementsByTagName( "script" ), checkScriptType );
7101
7102 ret.splice.apply( ret, [i + 1, 0].concat( jsTags ) );
7103 }
7104 fragment.appendChild( ret[i] );
7105 }
7106 }
7107 }
7108
7109 return ret;
7110 },
7111
7112 cleanData: function( elems ) {
7113 var data, id,
7114 cache = jQuery.cache,
7115 special = jQuery.event.special,
7116 deleteExpando = jQuery.support.deleteExpando;
7117
7118 for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
7119 if ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) {
7120 continue;
7121 }
7122
7123 id = elem[ jQuery.expando ];
7124
7125 if ( id ) {
7126 data = cache[ id ];
7127
7128 if ( data && data.events ) {
7129 for ( var type in data.events ) {
7130 if ( special[ type ] ) {
7131 jQuery.event.remove( elem, type );
7132
7133 // This is a shortcut to avoid jQuery.event.remove's overhead
7134 } else {
7135 jQuery.removeEvent( elem, type, data.handle );
7136 }
7137 }
7138
7139 // Null the DOM reference to avoid IE6/7/8 leak (#7054)
7140 if ( data.handle ) {
7141 data.handle.elem = null;
7142 }
7143 }
7144
7145 if ( deleteExpando ) {
7146 delete elem[ jQuery.expando ];
7147
7148 } else if ( elem.removeAttribute ) {
7149 elem.removeAttribute( jQuery.expando );
7150 }
7151
7152 delete cache[ id ];
7153 }
7154 }
7155 }
7156});
7157
7158function evalScript( i, elem ) {
7159 if ( elem.src ) {
7160 jQuery.ajax({
7161 url: elem.src,
7162 async: false,
7163 dataType: "script"
7164 });
7165 } else {
7166 jQuery.globalEval( ( elem.text || elem.textContent || elem.innerHTML || "" ).replace( rcleanScript, "/*$0*/" ) );
7167 }
7168
7169 if ( elem.parentNode ) {
7170 elem.parentNode.removeChild( elem );
7171 }
7172}
7173
7174})( jQuery );
7175(function( jQuery ) {
7176
7177var ralpha = /alpha\([^)]*\)/i,
7178 ropacity = /opacity=([^)]*)/,
7179 // fixed for IE9, see #8346
7180 rupper = /([A-Z]|^ms)/g,
7181 rnumpx = /^-?\d+(?:px)?$/i,
7182 rnum = /^-?\d/,
7183 rrelNum = /^([\-+])=([\-+.\de]+)/,
7184
7185 cssShow = { position: "absolute", visibility: "hidden", display: "block" },
7186 cssWidth = [ "Left", "Right" ],
7187 cssHeight = [ "Top", "Bottom" ],
7188 curCSS,
7189
7190 getComputedStyle,
7191 currentStyle;
7192
7193jQuery.fn.css = function( name, value ) {
7194 // Setting 'undefined' is a no-op
7195 if ( arguments.length === 2 && value === undefined ) {
7196 return this;
7197 }
7198
7199 return jQuery.access( this, name, value, true, function( elem, name, value ) {
7200 return value !== undefined ?
7201 jQuery.style( elem, name, value ) :
7202 jQuery.css( elem, name );
7203 });
7204};
7205
7206jQuery.extend({
7207 // Add in style property hooks for overriding the default
7208 // behavior of getting and setting a style property
7209 cssHooks: {
7210 opacity: {
7211 get: function( elem, computed ) {
7212 if ( computed ) {
7213 // We should always get a number back from opacity
7214 var ret = curCSS( elem, "opacity", "opacity" );
7215 return ret === "" ? "1" : ret;
7216
7217 } else {
7218 return elem.style.opacity;
7219 }
7220 }
7221 }
7222 },
7223
7224 // Exclude the following css properties to add px
7225 cssNumber: {
7226 "fillOpacity": true,
7227 "fontWeight": true,
7228 "lineHeight": true,
7229 "opacity": true,
7230 "orphans": true,
7231 "widows": true,
7232 "zIndex": true,
7233 "zoom": true
7234 },
7235
7236 // Add in properties whose names you wish to fix before
7237 // setting or getting the value
7238 cssProps: {
7239 // normalize float css property
7240 "float": jQuery.support.cssFloat ? "cssFloat" : "styleFloat"
7241 },
7242
7243 // Get and set the style property on a DOM Node
7244 style: function( elem, name, value, extra ) {
7245 // Don't set styles on text and comment nodes
7246 if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
7247 return;
7248 }
7249
7250 // Make sure that we're working with the right name
7251 var ret, type, origName = jQuery.camelCase( name ),
7252 style = elem.style, hooks = jQuery.cssHooks[ origName ];
7253
7254 name = jQuery.cssProps[ origName ] || origName;
7255
7256 // Check if we're setting a value
7257 if ( value !== undefined ) {
7258 type = typeof value;
7259
7260 // convert relative number strings (+= or -=) to relative numbers. #7345
7261 if ( type === "string" && (ret = rrelNum.exec( value )) ) {
7262 value = ( +( ret[1] + 1) * +ret[2] ) + parseFloat( jQuery.css( elem, name ) );
7263 // Fixes bug #9237
7264 type = "number";
7265 }
7266
7267 // Make sure that NaN and null values aren't set. See: #7116
7268 if ( value == null || type === "number" && isNaN( value ) ) {
7269 return;
7270 }
7271
7272 // If a number was passed in, add 'px' to the (except for certain CSS properties)
7273 if ( type === "number" && !jQuery.cssNumber[ origName ] ) {
7274 value += "px";
7275 }
7276
7277 // If a hook was provided, use that value, otherwise just set the specified value
7278 if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value )) !== undefined ) {
7279 // Wrapped to prevent IE from throwing errors when 'invalid' values are provided
7280 // Fixes bug #5509
7281 try {
7282 style[ name ] = value;
7283 } catch(e) {}
7284 }
7285
7286 } else {
7287 // If a hook was provided get the non-computed value from there
7288 if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {
7289 return ret;
7290 }
7291
7292 // Otherwise just get the value from the style object
7293 return style[ name ];
7294 }
7295 },
7296
7297 css: function( elem, name, extra ) {
7298 var ret, hooks;
7299
7300 // Make sure that we're working with the right name
7301 name = jQuery.camelCase( name );
7302 hooks = jQuery.cssHooks[ name ];
7303 name = jQuery.cssProps[ name ] || name;
7304
7305 // cssFloat needs a special treatment
7306 if ( name === "cssFloat" ) {
7307 name = "float";
7308 }
7309
7310 // If a hook was provided get the computed value from there
7311 if ( hooks && "get" in hooks && (ret = hooks.get( elem, true, extra )) !== undefined ) {
7312 return ret;
7313
7314 // Otherwise, if a way to get the computed value exists, use that
7315 } else if ( curCSS ) {
7316 return curCSS( elem, name );
7317 }
7318 },
7319
7320 // A method for quickly swapping in/out CSS properties to get correct calculations
7321 swap: function( elem, options, callback ) {
7322 var old = {};
7323
7324 // Remember the old values, and insert the new ones
7325 for ( var name in options ) {
7326 old[ name ] = elem.style[ name ];
7327 elem.style[ name ] = options[ name ];
7328 }
7329
7330 callback.call( elem );
7331
7332 // Revert the old values
7333 for ( name in options ) {
7334 elem.style[ name ] = old[ name ];
7335 }
7336 }
7337});
7338
7339// DEPRECATED, Use jQuery.css() instead
7340jQuery.curCSS = jQuery.css;
7341
7342jQuery.each(["height", "width"], function( i, name ) {
7343 jQuery.cssHooks[ name ] = {
7344 get: function( elem, computed, extra ) {
7345 var val;
7346
7347 if ( computed ) {
7348 if ( elem.offsetWidth !== 0 ) {
7349 return getWH( elem, name, extra );
7350 } else {
7351 jQuery.swap( elem, cssShow, function() {
7352 val = getWH( elem, name, extra );
7353 });
7354 }
7355
7356 return val;
7357 }
7358 },
7359
7360 set: function( elem, value ) {
7361 if ( rnumpx.test( value ) ) {
7362 // ignore negative width and height values #1599
7363 value = parseFloat( value );
7364
7365 if ( value >= 0 ) {
7366 return value + "px";
7367 }
7368
7369 } else {
7370 return value;
7371 }
7372 }
7373 };
7374});
7375
7376if ( !jQuery.support.opacity ) {
7377 jQuery.cssHooks.opacity = {
7378 get: function( elem, computed ) {
7379 // IE uses filters for opacity
7380 return ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "" ) ?
7381 ( parseFloat( RegExp.$1 ) / 100 ) + "" :
7382 computed ? "1" : "";
7383 },
7384
7385 set: function( elem, value ) {
7386 var style = elem.style,
7387 currentStyle = elem.currentStyle,
7388 opacity = jQuery.isNumeric( value ) ? "alpha(opacity=" + value * 100 + ")" : "",
7389 filter = currentStyle && currentStyle.filter || style.filter || "";
7390
7391 // IE has trouble with opacity if it does not have layout
7392 // Force it by setting the zoom level
7393 style.zoom = 1;
7394
7395 // if setting opacity to 1, and no other filters exist - attempt to remove filter attribute #6652
7396 if ( value >= 1 && jQuery.trim( filter.replace( ralpha, "" ) ) === "" ) {
7397
7398 // Setting style.filter to null, "" & " " still leave "filter:" in the cssText
7399 // if "filter:" is present at all, clearType is disabled, we want to avoid this
7400 // style.removeAttribute is IE Only, but so apparently is this code path...
7401 style.removeAttribute( "filter" );
7402
7403 // if there there is no filter style applied in a css rule, we are done
7404 if ( currentStyle && !currentStyle.filter ) {
7405 return;
7406 }
7407 }
7408
7409 // otherwise, set new filter values
7410 style.filter = ralpha.test( filter ) ?
7411 filter.replace( ralpha, opacity ) :
7412 filter + " " + opacity;
7413 }
7414 };
7415}
7416
7417jQuery(function() {
7418 // This hook cannot be added until DOM ready because the support test
7419 // for it is not run until after DOM ready
7420 if ( !jQuery.support.reliableMarginRight ) {
7421 jQuery.cssHooks.marginRight = {
7422 get: function( elem, computed ) {
7423 // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
7424 // Work around by temporarily setting element display to inline-block
7425 var ret;
7426 jQuery.swap( elem, { "display": "inline-block" }, function() {
7427 if ( computed ) {
7428 ret = curCSS( elem, "margin-right", "marginRight" );
7429 } else {
7430 ret = elem.style.marginRight;
7431 }
7432 });
7433 return ret;
7434 }
7435 };
7436 }
7437});
7438
7439if ( document.defaultView && document.defaultView.getComputedStyle ) {
7440 getComputedStyle = function( elem, name ) {
7441 var ret, defaultView, computedStyle;
7442
7443 name = name.replace( rupper, "-$1" ).toLowerCase();
7444
7445 if ( !(defaultView = elem.ownerDocument.defaultView) ) {
7446 return undefined;
7447 }
7448
7449 if ( (computedStyle = defaultView.getComputedStyle( elem, null )) ) {
7450 ret = computedStyle.getPropertyValue( name );
7451 if ( ret === "" && !jQuery.contains( elem.ownerDocument.documentElement, elem ) ) {
7452 ret = jQuery.style( elem, name );
7453 }
7454 }
7455
7456 return ret;
7457 };
7458}
7459
7460if ( document.documentElement.currentStyle ) {
7461 currentStyle = function( elem, name ) {
7462 var left, rsLeft, uncomputed,
7463 ret = elem.currentStyle && elem.currentStyle[ name ],
7464 style = elem.style;
7465
7466 // Avoid setting ret to empty string here
7467 // so we don't default to auto
7468 if ( ret === null && style && (uncomputed = style[ name ]) ) {
7469 ret = uncomputed;
7470 }
7471
7472 // From the awesome hack by Dean Edwards
7473 // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
7474
7475 // If we're not dealing with a regular pixel number
7476 // but a number that has a weird ending, we need to convert it to pixels
7477 if ( !rnumpx.test( ret ) && rnum.test( ret ) ) {
7478
7479 // Remember the original values
7480 left = style.left;
7481 rsLeft = elem.runtimeStyle && elem.runtimeStyle.left;
7482
7483 // Put in the new values to get a computed value out
7484 if ( rsLeft ) {
7485 elem.runtimeStyle.left = elem.currentStyle.left;
7486 }
7487 style.left = name === "fontSize" ? "1em" : ( ret || 0 );
7488 ret = style.pixelLeft + "px";
7489
7490 // Revert the changed values
7491 style.left = left;
7492 if ( rsLeft ) {
7493 elem.runtimeStyle.left = rsLeft;
7494 }
7495 }
7496
7497 return ret === "" ? "auto" : ret;
7498 };
7499}
7500
7501curCSS = getComputedStyle || currentStyle;
7502
7503function getWH( elem, name, extra ) {
7504
7505 // Start with offset property
7506 var val = name === "width" ? elem.offsetWidth : elem.offsetHeight,
7507 which = name === "width" ? cssWidth : cssHeight;
7508
7509 if ( val > 0 ) {
7510 if ( extra !== "border" ) {
7511 jQuery.each( which, function() {
7512 if ( !extra ) {
7513 val -= parseFloat( jQuery.css( elem, "padding" + this ) ) || 0;
7514 }
7515 if ( extra === "margin" ) {
7516 val += parseFloat( jQuery.css( elem, extra + this ) ) || 0;
7517 } else {
7518 val -= parseFloat( jQuery.css( elem, "border" + this + "Width" ) ) || 0;
7519 }
7520 });
7521 }
7522
7523 return val + "px";
7524 }
7525
7526 // Fall back to computed then uncomputed css if necessary
7527 val = curCSS( elem, name, name );
7528 if ( val < 0 || val == null ) {
7529 val = elem.style[ name ] || 0;
7530 }
7531 // Normalize "", auto, and prepare for extra
7532 val = parseFloat( val ) || 0;
7533
7534 // Add padding, border, margin
7535 if ( extra ) {
7536 jQuery.each( which, function() {
7537 val += parseFloat( jQuery.css( elem, "padding" + this ) ) || 0;
7538 if ( extra !== "padding" ) {
7539 val += parseFloat( jQuery.css( elem, "border" + this + "Width" ) ) || 0;
7540 }
7541 if ( extra === "margin" ) {
7542 val += parseFloat( jQuery.css( elem, extra + this ) ) || 0;
7543 }
7544 });
7545 }
7546
7547 return val + "px";
7548}
7549
7550if ( jQuery.expr && jQuery.expr.filters ) {
7551 jQuery.expr.filters.hidden = function( elem ) {
7552 var width = elem.offsetWidth,
7553 height = elem.offsetHeight;
7554
7555 return ( width === 0 && height === 0 ) || (!jQuery.support.reliableHiddenOffsets && ((elem.style && elem.style.display) || jQuery.css( elem, "display" )) === "none");
7556 };
7557
7558 jQuery.expr.filters.visible = function( elem ) {
7559 return !jQuery.expr.filters.hidden( elem );
7560 };
7561}
7562
7563})( jQuery );
7564(function( jQuery ) {
7565
7566var r20 = /%20/g,
7567 rbracket = /\[\]$/,
7568 rCRLF = /\r?\n/g,
7569 rhash = /#.*$/,
7570 rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL
7571 rinput = /^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,
7572 // #7653, #8125, #8152: local protocol detection
7573 rlocalProtocol = /^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,
7574 rnoContent = /^(?:GET|HEAD)$/,
7575 rprotocol = /^\/\//,
7576 rquery = /\?/,
7577 rscript = /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,
7578 rselectTextarea = /^(?:select|textarea)/i,
7579 rspacesAjax = /\s+/,
7580 rts = /([?&])_=[^&]*/,
7581 rurl = /^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,
7582
7583 // Keep a copy of the old load method
7584 _load = jQuery.fn.load,
7585
7586 /* Prefilters
7587 * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
7588 * 2) These are called:
7589 * - BEFORE asking for a transport
7590 * - AFTER param serialization (s.data is a string if s.processData is true)
7591 * 3) key is the dataType
7592 * 4) the catchall symbol "*" can be used
7593 * 5) execution will start with transport dataType and THEN continue down to "*" if needed
7594 */
7595 prefilters = {},
7596
7597 /* Transports bindings
7598 * 1) key is the dataType
7599 * 2) the catchall symbol "*" can be used
7600 * 3) selection will start with transport dataType and THEN go to "*" if needed
7601 */
7602 transports = {},
7603
7604 // Document location
7605 ajaxLocation,
7606
7607 // Document location segments
7608 ajaxLocParts,
7609
7610 // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
7611 allTypes = ["*/"] + ["*"];
7612
7613// #8138, IE may throw an exception when accessing
7614// a field from window.location if document.domain has been set
7615try {
7616 ajaxLocation = location.href;
7617} catch( e ) {
7618 // Use the href attribute of an A element
7619 // since IE will modify it given document.location
7620 ajaxLocation = document.createElement( "a" );
7621 ajaxLocation.href = "";
7622 ajaxLocation = ajaxLocation.href;
7623}
7624
7625// Segment location into parts
7626ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];
7627
7628// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
7629function addToPrefiltersOrTransports( structure ) {
7630
7631 // dataTypeExpression is optional and defaults to "*"
7632 return function( dataTypeExpression, func ) {
7633
7634 if ( typeof dataTypeExpression !== "string" ) {
7635 func = dataTypeExpression;
7636 dataTypeExpression = "*";
7637 }
7638
7639 if ( jQuery.isFunction( func ) ) {
7640 var dataTypes = dataTypeExpression.toLowerCase().split( rspacesAjax ),
7641 i = 0,
7642 length = dataTypes.length,
7643 dataType,
7644 list,
7645 placeBefore;
7646
7647 // For each dataType in the dataTypeExpression
7648 for ( ; i < length; i++ ) {
7649 dataType = dataTypes[ i ];
7650 // We control if we're asked to add before
7651 // any existing element
7652 placeBefore = /^\+/.test( dataType );
7653 if ( placeBefore ) {
7654 dataType = dataType.substr( 1 ) || "*";
7655 }
7656 list = structure[ dataType ] = structure[ dataType ] || [];
7657 // then we add to the structure accordingly
7658 list[ placeBefore ? "unshift" : "push" ]( func );
7659 }
7660 }
7661 };
7662}
7663
7664// Base inspection function for prefilters and transports
7665function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR,
7666 dataType /* internal */, inspected /* internal */ ) {
7667
7668 dataType = dataType || options.dataTypes[ 0 ];
7669 inspected = inspected || {};
7670
7671 inspected[ dataType ] = true;
7672
7673 var list = structure[ dataType ],
7674 i = 0,
7675 length = list ? list.length : 0,
7676 executeOnly = ( structure === prefilters ),
7677 selection;
7678
7679 for ( ; i < length && ( executeOnly || !selection ); i++ ) {
7680 selection = list[ i ]( options, originalOptions, jqXHR );
7681 // If we got redirected to another dataType
7682 // we try there if executing only and not done already
7683 if ( typeof selection === "string" ) {
7684 if ( !executeOnly || inspected[ selection ] ) {
7685 selection = undefined;
7686 } else {
7687 options.dataTypes.unshift( selection );
7688 selection = inspectPrefiltersOrTransports(
7689 structure, options, originalOptions, jqXHR, selection, inspected );
7690 }
7691 }
7692 }
7693 // If we're only executing or nothing was selected
7694 // we try the catchall dataType if not done already
7695 if ( ( executeOnly || !selection ) && !inspected[ "*" ] ) {
7696 selection = inspectPrefiltersOrTransports(
7697 structure, options, originalOptions, jqXHR, "*", inspected );
7698 }
7699 // unnecessary when only executing (prefilters)
7700 // but it'll be ignored by the caller in that case
7701 return selection;
7702}
7703
7704// A special extend for ajax options
7705// that takes "flat" options (not to be deep extended)
7706// Fixes #9887
7707function ajaxExtend( target, src ) {
7708 var key, deep,
7709 flatOptions = jQuery.ajaxSettings.flatOptions || {};
7710 for ( key in src ) {
7711 if ( src[ key ] !== undefined ) {
7712 ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ];
7713 }
7714 }
7715 if ( deep ) {
7716 jQuery.extend( true, target, deep );
7717 }
7718}
7719
7720jQuery.fn.extend({
7721 load: function( url, params, callback ) {
7722 if ( typeof url !== "string" && _load ) {
7723 return _load.apply( this, arguments );
7724
7725 // Don't do a request if no elements are being requested
7726 } else if ( !this.length ) {
7727 return this;
7728 }
7729
7730 var off = url.indexOf( " " );
7731 if ( off >= 0 ) {
7732 var selector = url.slice( off, url.length );
7733 url = url.slice( 0, off );
7734 }
7735
7736 // Default to a GET request
7737 var type = "GET";
7738
7739 // If the second parameter was provided
7740 if ( params ) {
7741 // If it's a function
7742 if ( jQuery.isFunction( params ) ) {
7743 // We assume that it's the callback
7744 callback = params;
7745 params = undefined;
7746
7747 // Otherwise, build a param string
7748 } else if ( typeof params === "object" ) {
7749 params = jQuery.param( params, jQuery.ajaxSettings.traditional );
7750 type = "POST";
7751 }
7752 }
7753
7754 var self = this;
7755
7756 // Request the remote document
7757 jQuery.ajax({
7758 url: url,
7759 type: type,
7760 dataType: "html",
7761 data: params,
7762 // Complete callback (responseText is used internally)
7763 complete: function( jqXHR, status, responseText ) {
7764 // Store the response as specified by the jqXHR object
7765 responseText = jqXHR.responseText;
7766 // If successful, inject the HTML into all the matched elements
7767 if ( jqXHR.isResolved() ) {
7768 // #4825: Get the actual response in case
7769 // a dataFilter is present in ajaxSettings
7770 jqXHR.done(function( r ) {
7771 responseText = r;
7772 });
7773 // See if a selector was specified
7774 self.html( selector ?
7775 // Create a dummy div to hold the results
7776 jQuery("<div>")
7777 // inject the contents of the document in, removing the scripts
7778 // to avoid any 'Permission Denied' errors in IE
7779 .append(responseText.replace(rscript, ""))
7780
7781 // Locate the specified elements
7782 .find(selector) :
7783
7784 // If not, just inject the full result
7785 responseText );
7786 }
7787
7788 if ( callback ) {
7789 self.each( callback, [ responseText, status, jqXHR ] );
7790 }
7791 }
7792 });
7793
7794 return this;
7795 },
7796
7797 serialize: function() {
7798 return jQuery.param( this.serializeArray() );
7799 },
7800
7801 serializeArray: function() {
7802 return this.map(function(){
7803 return this.elements ? jQuery.makeArray( this.elements ) : this;
7804 })
7805 .filter(function(){
7806 return this.name && !this.disabled &&
7807 ( this.checked || rselectTextarea.test( this.nodeName ) ||
7808 rinput.test( this.type ) );
7809 })
7810 .map(function( i, elem ){
7811 var val = jQuery( this ).val();
7812
7813 return val == null ?
7814 null :
7815 jQuery.isArray( val ) ?
7816 jQuery.map( val, function( val, i ){
7817 return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
7818 }) :
7819 { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
7820 }).get();
7821 }
7822});
7823
7824// Attach a bunch of functions for handling common AJAX events
7825jQuery.each( "ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split( " " ), function( i, o ){
7826 jQuery.fn[ o ] = function( f ){
7827 return this.bind( o, f );
7828 };
7829});
7830
7831jQuery.each( [ "get", "post" ], function( i, method ) {
7832 jQuery[ method ] = function( url, data, callback, type ) {
7833 // shift arguments if data argument was omitted
7834 if ( jQuery.isFunction( data ) ) {
7835 type = type || callback;
7836 callback = data;
7837 data = undefined;
7838 }
7839
7840 return jQuery.ajax({
7841 type: method,
7842 url: url,
7843 data: data,
7844 success: callback,
7845 dataType: type
7846 });
7847 };
7848});
7849
7850jQuery.extend({
7851
7852 getScript: function( url, callback ) {
7853 return jQuery.get( url, undefined, callback, "script" );
7854 },
7855
7856 getJSON: function( url, data, callback ) {
7857 return jQuery.get( url, data, callback, "json" );
7858 },
7859
7860 // Creates a full fledged settings object into target
7861 // with both ajaxSettings and settings fields.
7862 // If target is omitted, writes into ajaxSettings.
7863 ajaxSetup: function( target, settings ) {
7864 if ( settings ) {
7865 // Building a settings object
7866 ajaxExtend( target, jQuery.ajaxSettings );
7867 } else {
7868 // Extending ajaxSettings
7869 settings = target;
7870 target = jQuery.ajaxSettings;
7871 }
7872 ajaxExtend( target, settings );
7873 return target;
7874 },
7875
7876 ajaxSettings: {
7877 url: ajaxLocation,
7878 isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),
7879 global: true,
7880 type: "GET",
7881 contentType: "application/x-www-form-urlencoded",
7882 processData: true,
7883 async: true,
7884 /*
7885 timeout: 0,
7886 data: null,
7887 dataType: null,
7888 username: null,
7889 password: null,
7890 cache: null,
7891 traditional: false,
7892 headers: {},
7893 */
7894
7895 accepts: {
7896 xml: "application/xml, text/xml",
7897 html: "text/html",
7898 text: "text/plain",
7899 json: "application/json, text/javascript",
7900 "*": allTypes
7901 },
7902
7903 contents: {
7904 xml: /xml/,
7905 html: /html/,
7906 json: /json/
7907 },
7908
7909 responseFields: {
7910 xml: "responseXML",
7911 text: "responseText"
7912 },
7913
7914 // List of data converters
7915 // 1) key format is "source_type destination_type" (a single space in-between)
7916 // 2) the catchall symbol "*" can be used for source_type
7917 converters: {
7918
7919 // Convert anything to text
7920 "* text": window.String,
7921
7922 // Text to html (true = no transformation)
7923 "text html": true,
7924
7925 // Evaluate text as a json expression
7926 "text json": jQuery.parseJSON,
7927
7928 // Parse text as xml
7929 "text xml": jQuery.parseXML
7930 },
7931
7932 // For options that shouldn't be deep extended:
7933 // you can add your own custom options here if
7934 // and when you create one that shouldn't be
7935 // deep extended (see ajaxExtend)
7936 flatOptions: {
7937 context: true,
7938 url: true
7939 }
7940 },
7941
7942 ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
7943 ajaxTransport: addToPrefiltersOrTransports( transports ),
7944
7945 // Main method
7946 ajax: function( url, options ) {
7947
7948 // If url is an object, simulate pre-1.5 signature
7949 if ( typeof url === "object" ) {
7950 options = url;
7951 url = undefined;
7952 }
7953
7954 // Force options to be an object
7955 options = options || {};
7956
7957 var // Create the final options object
7958 s = jQuery.ajaxSetup( {}, options ),
7959 // Callbacks context
7960 callbackContext = s.context || s,
7961 // Context for global events
7962 // It's the callbackContext if one was provided in the options
7963 // and if it's a DOM node or a jQuery collection
7964 globalEventContext = callbackContext !== s &&
7965 ( callbackContext.nodeType || callbackContext instanceof jQuery ) ?
7966 jQuery( callbackContext ) : jQuery.event,
7967 // Deferreds
7968 deferred = jQuery.Deferred(),
7969 completeDeferred = jQuery.Callbacks( "once memory" ),
7970 // Status-dependent callbacks
7971 statusCode = s.statusCode || {},
7972 // ifModified key
7973 ifModifiedKey,
7974 // Headers (they are sent all at once)
7975 requestHeaders = {},
7976 requestHeadersNames = {},
7977 // Response headers
7978 responseHeadersString,
7979 responseHeaders,
7980 // transport
7981 transport,
7982 // timeout handle
7983 timeoutTimer,
7984 // Cross-domain detection vars
7985 parts,
7986 // The jqXHR state
7987 state = 0,
7988 // To know if global events are to be dispatched
7989 fireGlobals,
7990 // Loop variable
7991 i,
7992 // Fake xhr
7993 jqXHR = {
7994
7995 readyState: 0,
7996
7997 // Caches the header
7998 setRequestHeader: function( name, value ) {
7999 if ( !state ) {
8000 var lname = name.toLowerCase();
8001 name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;
8002 requestHeaders[ name ] = value;
8003 }
8004 return this;
8005 },
8006
8007 // Raw string
8008 getAllResponseHeaders: function() {
8009 return state === 2 ? responseHeadersString : null;
8010 },
8011
8012 // Builds headers hashtable if needed
8013 getResponseHeader: function( key ) {
8014 var match;
8015 if ( state === 2 ) {
8016 if ( !responseHeaders ) {
8017 responseHeaders = {};
8018 while( ( match = rheaders.exec( responseHeadersString ) ) ) {
8019 responseHeaders[ match[1].toLowerCase() ] = match[ 2 ];
8020 }
8021 }
8022 match = responseHeaders[ key.toLowerCase() ];
8023 }
8024 return match === undefined ? null : match;
8025 },
8026
8027 // Overrides response content-type header
8028 overrideMimeType: function( type ) {
8029 if ( !state ) {
8030 s.mimeType = type;
8031 }
8032 return this;
8033 },
8034
8035 // Cancel the request
8036 abort: function( statusText ) {
8037 statusText = statusText || "abort";
8038 if ( transport ) {
8039 transport.abort( statusText );
8040 }
8041 done( 0, statusText );
8042 return this;
8043 }
8044 };
8045
8046 // Callback for when everything is done
8047 // It is defined here because jslint complains if it is declared
8048 // at the end of the function (which would be more logical and readable)
8049 function done( status, nativeStatusText, responses, headers ) {
8050
8051 // Called once
8052 if ( state === 2 ) {
8053 return;
8054 }
8055
8056 // State is "done" now
8057 state = 2;
8058
8059 // Clear timeout if it exists
8060 if ( timeoutTimer ) {
8061 clearTimeout( timeoutTimer );
8062 }
8063
8064 // Dereference transport for early garbage collection
8065 // (no matter how long the jqXHR object will be used)
8066 transport = undefined;
8067
8068 // Cache response headers
8069 responseHeadersString = headers || "";
8070
8071 // Set readyState
8072 jqXHR.readyState = status > 0 ? 4 : 0;
8073
8074 var isSuccess,
8075 success,
8076 error,
8077 statusText = nativeStatusText,
8078 response = responses ? ajaxHandleResponses( s, jqXHR, responses ) : undefined,
8079 lastModified,
8080 etag;
8081
8082 // If successful, handle type chaining
8083 if ( status >= 200 && status < 300 || status === 304 ) {
8084
8085 // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
8086 if ( s.ifModified ) {
8087
8088 if ( ( lastModified = jqXHR.getResponseHeader( "Last-Modified" ) ) ) {
8089 jQuery.lastModified[ ifModifiedKey ] = lastModified;
8090 }
8091 if ( ( etag = jqXHR.getResponseHeader( "Etag" ) ) ) {
8092 jQuery.etag[ ifModifiedKey ] = etag;
8093 }
8094 }
8095
8096 // If not modified
8097 if ( status === 304 ) {
8098
8099 statusText = "notmodified";
8100 isSuccess = true;
8101
8102 // If we have data
8103 } else {
8104
8105 try {
8106 success = ajaxConvert( s, response );
8107 statusText = "success";
8108 isSuccess = true;
8109 } catch(e) {
8110 // We have a parsererror
8111 statusText = "parsererror";
8112 error = e;
8113 }
8114 }
8115 } else {
8116 // We extract error from statusText
8117 // then normalize statusText and status for non-aborts
8118 error = statusText;
8119 if ( !statusText || status ) {
8120 statusText = "error";
8121 if ( status < 0 ) {
8122 status = 0;
8123 }
8124 }
8125 }
8126
8127 // Set data for the fake xhr object
8128 jqXHR.status = status;
8129 jqXHR.statusText = "" + ( nativeStatusText || statusText );
8130
8131 // Success/Error
8132 if ( isSuccess ) {
8133 deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
8134 } else {
8135 deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
8136 }
8137
8138 // Status-dependent callbacks
8139 jqXHR.statusCode( statusCode );
8140 statusCode = undefined;
8141
8142 if ( fireGlobals ) {
8143 globalEventContext.trigger( "ajax" + ( isSuccess ? "Success" : "Error" ),
8144 [ jqXHR, s, isSuccess ? success : error ] );
8145 }
8146
8147 // Complete
8148 completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );
8149
8150 if ( fireGlobals ) {
8151 globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
8152 // Handle the global AJAX counter
8153 if ( !( --jQuery.active ) ) {
8154 jQuery.event.trigger( "ajaxStop" );
8155 }
8156 }
8157 }
8158
8159 // Attach deferreds
8160 deferred.promise( jqXHR );
8161 jqXHR.success = jqXHR.done;
8162 jqXHR.error = jqXHR.fail;
8163 jqXHR.complete = completeDeferred.add;
8164
8165 // Status-dependent callbacks
8166 jqXHR.statusCode = function( map ) {
8167 if ( map ) {
8168 var tmp;
8169 if ( state < 2 ) {
8170 for ( tmp in map ) {
8171 statusCode[ tmp ] = [ statusCode[tmp], map[tmp] ];
8172 }
8173 } else {
8174 tmp = map[ jqXHR.status ];
8175 jqXHR.then( tmp, tmp );
8176 }
8177 }
8178 return this;
8179 };
8180
8181 // Remove hash character (#7531: and string promotion)
8182 // Add protocol if not provided (#5866: IE7 issue with protocol-less urls)
8183 // We also use the url parameter if available
8184 s.url = ( ( url || s.url ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" );
8185
8186 // Extract dataTypes list
8187 s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().split( rspacesAjax );
8188
8189 // Determine if a cross-domain request is in order
8190 if ( s.crossDomain == null ) {
8191 parts = rurl.exec( s.url.toLowerCase() );
8192 s.crossDomain = !!( parts &&
8193 ( parts[ 1 ] != ajaxLocParts[ 1 ] || parts[ 2 ] != ajaxLocParts[ 2 ] ||
8194 ( parts[ 3 ] || ( parts[ 1 ] === "http:" ? 80 : 443 ) ) !=
8195 ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? 80 : 443 ) ) )
8196 );
8197 }
8198
8199 // Convert data if not already a string
8200 if ( s.data && s.processData && typeof s.data !== "string" ) {
8201 s.data = jQuery.param( s.data, s.traditional );
8202 }
8203
8204 // Apply prefilters
8205 inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
8206
8207 // If request was aborted inside a prefiler, stop there
8208 if ( state === 2 ) {
8209 return false;
8210 }
8211
8212 // We can fire global events as of now if asked to
8213 fireGlobals = s.global;
8214
8215 // Uppercase the type
8216 s.type = s.type.toUpperCase();
8217
8218 // Determine if request has content
8219 s.hasContent = !rnoContent.test( s.type );
8220
8221 // Watch for a new set of requests
8222 if ( fireGlobals && jQuery.active++ === 0 ) {
8223 jQuery.event.trigger( "ajaxStart" );
8224 }
8225
8226 // More options handling for requests with no content
8227 if ( !s.hasContent ) {
8228
8229 // If data is available, append data to url
8230 if ( s.data ) {
8231 s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.data;
8232 // #9682: remove data so that it's not used in an eventual retry
8233 delete s.data;
8234 }
8235
8236 // Get ifModifiedKey before adding the anti-cache parameter
8237 ifModifiedKey = s.url;
8238
8239 // Add anti-cache in url if needed
8240 if ( s.cache === false ) {
8241
8242 var ts = jQuery.now(),
8243 // try replacing _= if it is there
8244 ret = s.url.replace( rts, "$1_=" + ts );
8245
8246 // if nothing was replaced, add timestamp to the end
8247 s.url = ret + ( ( ret === s.url ) ? ( rquery.test( s.url ) ? "&" : "?" ) + "_=" + ts : "" );
8248 }
8249 }
8250
8251 // Set the correct header, if data is being sent
8252 if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
8253 jqXHR.setRequestHeader( "Content-Type", s.contentType );
8254 }
8255
8256 // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
8257 if ( s.ifModified ) {
8258 ifModifiedKey = ifModifiedKey || s.url;
8259 if ( jQuery.lastModified[ ifModifiedKey ] ) {
8260 jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ ifModifiedKey ] );
8261 }
8262 if ( jQuery.etag[ ifModifiedKey ] ) {
8263 jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ ifModifiedKey ] );
8264 }
8265 }
8266
8267 // Set the Accepts header for the server, depending on the dataType
8268 jqXHR.setRequestHeader(
8269 "Accept",
8270 s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?
8271 s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
8272 s.accepts[ "*" ]
8273 );
8274
8275 // Check for headers option
8276 for ( i in s.headers ) {
8277 jqXHR.setRequestHeader( i, s.headers[ i ] );
8278 }
8279
8280 // Allow custom headers/mimetypes and early abort
8281 if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {
8282 // Abort if not done already
8283 jqXHR.abort();
8284 return false;
8285
8286 }
8287
8288 // Install callbacks on deferreds
8289 for ( i in { success: 1, error: 1, complete: 1 } ) {
8290 jqXHR[ i ]( s[ i ] );
8291 }
8292
8293 // Get transport
8294 transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
8295
8296 // If no transport, we auto-abort
8297 if ( !transport ) {
8298 done( -1, "No Transport" );
8299 } else {
8300 jqXHR.readyState = 1;
8301 // Send global event
8302 if ( fireGlobals ) {
8303 globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
8304 }
8305 // Timeout
8306 if ( s.async && s.timeout > 0 ) {
8307 timeoutTimer = setTimeout( function(){
8308 jqXHR.abort( "timeout" );
8309 }, s.timeout );
8310 }
8311
8312 try {
8313 state = 1;
8314 transport.send( requestHeaders, done );
8315 } catch (e) {
8316 // Propagate exception as error if not done
8317 if ( state < 2 ) {
8318 done( -1, e );
8319 // Simply rethrow otherwise
8320 } else {
8321 jQuery.error( e );
8322 }
8323 }
8324 }
8325
8326 return jqXHR;
8327 },
8328
8329 // Serialize an array of form elements or a set of
8330 // key/values into a query string
8331 param: function( a, traditional ) {
8332 var s = [],
8333 add = function( key, value ) {
8334 // If value is a function, invoke it and return its value
8335 value = jQuery.isFunction( value ) ? value() : value;
8336 s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value );
8337 };
8338
8339 // Set traditional to true for jQuery <= 1.3.2 behavior.
8340 if ( traditional === undefined ) {
8341 traditional = jQuery.ajaxSettings.traditional;
8342 }
8343
8344 // If an array was passed in, assume that it is an array of form elements.
8345 if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
8346 // Serialize the form elements
8347 jQuery.each( a, function() {
8348 add( this.name, this.value );
8349 });
8350
8351 } else {
8352 // If traditional, encode the "old" way (the way 1.3.2 or older
8353 // did it), otherwise encode params recursively.
8354 for ( var prefix in a ) {
8355 buildParams( prefix, a[ prefix ], traditional, add );
8356 }
8357 }
8358
8359 // Return the resulting serialization
8360 return s.join( "&" ).replace( r20, "+" );
8361 }
8362});
8363
8364function buildParams( prefix, obj, traditional, add ) {
8365 if ( jQuery.isArray( obj ) ) {
8366 // Serialize array item.
8367 jQuery.each( obj, function( i, v ) {
8368 if ( traditional || rbracket.test( prefix ) ) {
8369 // Treat each array item as a scalar.
8370 add( prefix, v );
8371
8372 } else {
8373 // If array item is non-scalar (array or object), encode its
8374 // numeric index to resolve deserialization ambiguity issues.
8375 // Note that rack (as of 1.0.0) can't currently deserialize
8376 // nested arrays properly, and attempting to do so may cause
8377 // a server error. Possible fixes are to modify rack's
8378 // deserialization algorithm or to provide an option or flag
8379 // to force array serialization to be shallow.
8380 buildParams( prefix + "[" + ( typeof v === "object" || jQuery.isArray(v) ? i : "" ) + "]", v, traditional, add );
8381 }
8382 });
8383
8384 } else if ( !traditional && obj != null && typeof obj === "object" ) {
8385 // Serialize object item.
8386 for ( var name in obj ) {
8387 buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
8388 }
8389
8390 } else {
8391 // Serialize scalar item.
8392 add( prefix, obj );
8393 }
8394}
8395
8396// This is still on the jQuery object... for now
8397// Want to move this to jQuery.ajax some day
8398jQuery.extend({
8399
8400 // Counter for holding the number of active queries
8401 active: 0,
8402
8403 // Last-Modified header cache for next request
8404 lastModified: {},
8405 etag: {}
8406
8407});
8408
8409/* Handles responses to an ajax request:
8410 * - sets all responseXXX fields accordingly
8411 * - finds the right dataType (mediates between content-type and expected dataType)
8412 * - returns the corresponding response
8413 */
8414function ajaxHandleResponses( s, jqXHR, responses ) {
8415
8416 var contents = s.contents,
8417 dataTypes = s.dataTypes,
8418 responseFields = s.responseFields,
8419 ct,
8420 type,
8421 finalDataType,
8422 firstDataType;
8423
8424 // Fill responseXXX fields
8425 for ( type in responseFields ) {
8426 if ( type in responses ) {
8427 jqXHR[ responseFields[type] ] = responses[ type ];
8428 }
8429 }
8430
8431 // Remove auto dataType and get content-type in the process
8432 while( dataTypes[ 0 ] === "*" ) {
8433 dataTypes.shift();
8434 if ( ct === undefined ) {
8435 ct = s.mimeType || jqXHR.getResponseHeader( "content-type" );
8436 }
8437 }
8438
8439 // Check if we're dealing with a known content-type
8440 if ( ct ) {
8441 for ( type in contents ) {
8442 if ( contents[ type ] && contents[ type ].test( ct ) ) {
8443 dataTypes.unshift( type );
8444 break;
8445 }
8446 }
8447 }
8448
8449 // Check to see if we have a response for the expected dataType
8450 if ( dataTypes[ 0 ] in responses ) {
8451 finalDataType = dataTypes[ 0 ];
8452 } else {
8453 // Try convertible dataTypes
8454 for ( type in responses ) {
8455 if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) {
8456 finalDataType = type;
8457 break;
8458 }
8459 if ( !firstDataType ) {
8460 firstDataType = type;
8461 }
8462 }
8463 // Or just use first one
8464 finalDataType = finalDataType || firstDataType;
8465 }
8466
8467 // If we found a dataType
8468 // We add the dataType to the list if needed
8469 // and return the corresponding response
8470 if ( finalDataType ) {
8471 if ( finalDataType !== dataTypes[ 0 ] ) {
8472 dataTypes.unshift( finalDataType );
8473 }
8474 return responses[ finalDataType ];
8475 }
8476}
8477
8478// Chain conversions given the request and the original response
8479function ajaxConvert( s, response ) {
8480
8481 // Apply the dataFilter if provided
8482 if ( s.dataFilter ) {
8483 response = s.dataFilter( response, s.dataType );
8484 }
8485
8486 var dataTypes = s.dataTypes,
8487 converters = {},
8488 i,
8489 key,
8490 length = dataTypes.length,
8491 tmp,
8492 // Current and previous dataTypes
8493 current = dataTypes[ 0 ],
8494 prev,
8495 // Conversion expression
8496 conversion,
8497 // Conversion function
8498 conv,
8499 // Conversion functions (transitive conversion)
8500 conv1,
8501 conv2;
8502
8503 // For each dataType in the chain
8504 for ( i = 1; i < length; i++ ) {
8505
8506 // Create converters map
8507 // with lowercased keys
8508 if ( i === 1 ) {
8509 for ( key in s.converters ) {
8510 if ( typeof key === "string" ) {
8511 converters[ key.toLowerCase() ] = s.converters[ key ];
8512 }
8513 }
8514 }
8515
8516 // Get the dataTypes
8517 prev = current;
8518 current = dataTypes[ i ];
8519
8520 // If current is auto dataType, update it to prev
8521 if ( current === "*" ) {
8522 current = prev;
8523 // If no auto and dataTypes are actually different
8524 } else if ( prev !== "*" && prev !== current ) {
8525
8526 // Get the converter
8527 conversion = prev + " " + current;
8528 conv = converters[ conversion ] || converters[ "* " + current ];
8529
8530 // If there is no direct converter, search transitively
8531 if ( !conv ) {
8532 conv2 = undefined;
8533 for ( conv1 in converters ) {
8534 tmp = conv1.split( " " );
8535 if ( tmp[ 0 ] === prev || tmp[ 0 ] === "*" ) {
8536 conv2 = converters[ tmp[1] + " " + current ];
8537 if ( conv2 ) {
8538 conv1 = converters[ conv1 ];
8539 if ( conv1 === true ) {
8540 conv = conv2;
8541 } else if ( conv2 === true ) {
8542 conv = conv1;
8543 }
8544 break;
8545 }
8546 }
8547 }
8548 }
8549 // If we found no converter, dispatch an error
8550 if ( !( conv || conv2 ) ) {
8551 jQuery.error( "No conversion from " + conversion.replace(" "," to ") );
8552 }
8553 // If found converter is not an equivalence
8554 if ( conv !== true ) {
8555 // Convert with 1 or 2 converters accordingly
8556 response = conv ? conv( response ) : conv2( conv1(response) );
8557 }
8558 }
8559 }
8560 return response;
8561}
8562
8563})( jQuery );
8564(function( jQuery ) {
8565
8566var jsc = jQuery.now(),
8567 jsre = /(\=)\?(&|$)|\?\?/i;
8568
8569// Default jsonp settings
8570jQuery.ajaxSetup({
8571 jsonp: "callback",
8572 jsonpCallback: function() {
8573 return jQuery.expando + "_" + ( jsc++ );
8574 }
8575});
8576
8577// Detect, normalize options and install callbacks for jsonp requests
8578jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
8579
8580 var inspectData = s.contentType === "application/x-www-form-urlencoded" &&
8581 ( typeof s.data === "string" );
8582
8583 if ( s.dataTypes[ 0 ] === "jsonp" ||
8584 s.jsonp !== false && ( jsre.test( s.url ) ||
8585 inspectData && jsre.test( s.data ) ) ) {
8586
8587 var responseContainer,
8588 jsonpCallback = s.jsonpCallback =
8589 jQuery.isFunction( s.jsonpCallback ) ? s.jsonpCallback() : s.jsonpCallback,
8590 previous = window[ jsonpCallback ],
8591 url = s.url,
8592 data = s.data,
8593 replace = "$1" + jsonpCallback + "$2";
8594
8595 if ( s.jsonp !== false ) {
8596 url = url.replace( jsre, replace );
8597 if ( s.url === url ) {
8598 if ( inspectData ) {
8599 data = data.replace( jsre, replace );
8600 }
8601 if ( s.data === data ) {
8602 // Add callback manually
8603 url += (/\?/.test( url ) ? "&" : "?") + s.jsonp + "=" + jsonpCallback;
8604 }
8605 }
8606 }
8607
8608 s.url = url;
8609 s.data = data;
8610
8611 // Install callback
8612 window[ jsonpCallback ] = function( response ) {
8613 responseContainer = [ response ];
8614 };
8615
8616 // Clean-up function
8617 jqXHR.always(function() {
8618 // Set callback back to previous value
8619 window[ jsonpCallback ] = previous;
8620 // Call if it was a function and we have a response
8621 if ( responseContainer && jQuery.isFunction( previous ) ) {
8622 window[ jsonpCallback ]( responseContainer[ 0 ] );
8623 }
8624 });
8625
8626 // Use data converter to retrieve json after script execution
8627 s.converters["script json"] = function() {
8628 if ( !responseContainer ) {
8629 jQuery.error( jsonpCallback + " was not called" );
8630 }
8631 return responseContainer[ 0 ];
8632 };
8633
8634 // force json dataType
8635 s.dataTypes[ 0 ] = "json";
8636
8637 // Delegate to script
8638 return "script";
8639 }
8640});
8641
8642})( jQuery );
8643(function( jQuery ) {
8644
8645// Install script dataType
8646jQuery.ajaxSetup({
8647 accepts: {
8648 script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
8649 },
8650 contents: {
8651 script: /javascript|ecmascript/
8652 },
8653 converters: {
8654 "text script": function( text ) {
8655 jQuery.globalEval( text );
8656 return text;
8657 }
8658 }
8659});
8660
8661// Handle cache's special case and global
8662jQuery.ajaxPrefilter( "script", function( s ) {
8663 if ( s.cache === undefined ) {
8664 s.cache = false;
8665 }
8666 if ( s.crossDomain ) {
8667 s.type = "GET";
8668 s.global = false;
8669 }
8670});
8671
8672// Bind script tag hack transport
8673jQuery.ajaxTransport( "script", function(s) {
8674
8675 // This transport only deals with cross domain requests
8676 if ( s.crossDomain ) {
8677
8678 var script,
8679 head = document.head || document.getElementsByTagName( "head" )[0] || document.documentElement;
8680
8681 return {
8682
8683 send: function( _, callback ) {
8684
8685 script = document.createElement( "script" );
8686
8687 script.async = "async";
8688
8689 if ( s.scriptCharset ) {
8690 script.charset = s.scriptCharset;
8691 }
8692
8693 script.src = s.url;
8694
8695 // Attach handlers for all browsers
8696 script.onload = script.onreadystatechange = function( _, isAbort ) {
8697
8698 if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) {
8699
8700 // Handle memory leak in IE
8701 script.onload = script.onreadystatechange = null;
8702
8703 // Remove the script
8704 if ( head && script.parentNode ) {
8705 head.removeChild( script );
8706 }
8707
8708 // Dereference the script
8709 script = undefined;
8710
8711 // Callback if not abort
8712 if ( !isAbort ) {
8713 callback( 200, "success" );
8714 }
8715 }
8716 };
8717 // Use insertBefore instead of appendChild to circumvent an IE6 bug.
8718 // This arises when a base node is used (#2709 and #4378).
8719 head.insertBefore( script, head.firstChild );
8720 },
8721
8722 abort: function() {
8723 if ( script ) {
8724 script.onload( 0, 1 );
8725 }
8726 }
8727 };
8728 }
8729});
8730
8731})( jQuery );
8732(function( jQuery ) {
8733
8734var // #5280: Internet Explorer will keep connections alive if we don't abort on unload
8735 xhrOnUnloadAbort = window.ActiveXObject ? function() {
8736 // Abort all pending requests
8737 for ( var key in xhrCallbacks ) {
8738 xhrCallbacks[ key ]( 0, 1 );
8739 }
8740 } : false,
8741 xhrId = 0,
8742 xhrCallbacks;
8743
8744// Functions to create xhrs
8745function createStandardXHR() {
8746 try {
8747 return new window.XMLHttpRequest();
8748 } catch( e ) {}
8749}
8750
8751function createActiveXHR() {
8752 try {
8753 return new window.ActiveXObject( "Microsoft.XMLHTTP" );
8754 } catch( e ) {}
8755}
8756
8757// Create the request object
8758// (This is still attached to ajaxSettings for backward compatibility)
8759jQuery.ajaxSettings.xhr = window.ActiveXObject ?
8760 /* Microsoft failed to properly
8761 * implement the XMLHttpRequest in IE7 (can't request local files),
8762 * so we use the ActiveXObject when it is available
8763 * Additionally XMLHttpRequest can be disabled in IE7/IE8 so
8764 * we need a fallback.
8765 */
8766 function() {
8767 return !this.isLocal && createStandardXHR() || createActiveXHR();
8768 } :
8769 // For all other browsers, use the standard XMLHttpRequest object
8770 createStandardXHR;
8771
8772// Determine support properties
8773(function( xhr ) {
8774 jQuery.extend( jQuery.support, {
8775 ajax: !!xhr,
8776 cors: !!xhr && ( "withCredentials" in xhr )
8777 });
8778})( jQuery.ajaxSettings.xhr() );
8779
8780// Create transport if the browser can provide an xhr
8781if ( jQuery.support.ajax ) {
8782
8783 jQuery.ajaxTransport(function( s ) {
8784 // Cross domain only allowed if supported through XMLHttpRequest
8785 if ( !s.crossDomain || jQuery.support.cors ) {
8786
8787 var callback;
8788
8789 return {
8790 send: function( headers, complete ) {
8791
8792 // Get a new xhr
8793 var xhr = s.xhr(),
8794 handle,
8795 i;
8796
8797 // Open the socket
8798 // Passing null username, generates a login popup on Opera (#2865)
8799 if ( s.username ) {
8800 xhr.open( s.type, s.url, s.async, s.username, s.password );
8801 } else {
8802 xhr.open( s.type, s.url, s.async );
8803 }
8804
8805 // Apply custom fields if provided
8806 if ( s.xhrFields ) {
8807 for ( i in s.xhrFields ) {
8808 xhr[ i ] = s.xhrFields[ i ];
8809 }
8810 }
8811
8812 // Override mime type if needed
8813 if ( s.mimeType && xhr.overrideMimeType ) {
8814 xhr.overrideMimeType( s.mimeType );
8815 }
8816
8817 // X-Requested-With header
8818 // For cross-domain requests, seeing as conditions for a preflight are
8819 // akin to a jigsaw puzzle, we simply never set it to be sure.
8820 // (it can always be set on a per-request basis or even using ajaxSetup)
8821 // For same-domain requests, won't change header if already provided.
8822 if ( !s.crossDomain && !headers["X-Requested-With"] ) {
8823 headers[ "X-Requested-With" ] = "XMLHttpRequest";
8824 }
8825
8826 // Need an extra try/catch for cross domain requests in Firefox 3
8827 try {
8828 for ( i in headers ) {
8829 xhr.setRequestHeader( i, headers[ i ] );
8830 }
8831 } catch( _ ) {}
8832
8833 // Do send the request
8834 // This may raise an exception which is actually
8835 // handled in jQuery.ajax (so no try/catch here)
8836 xhr.send( ( s.hasContent && s.data ) || null );
8837
8838 // Listener
8839 callback = function( _, isAbort ) {
8840
8841 var status,
8842 statusText,
8843 responseHeaders,
8844 responses,
8845 xml;
8846
8847 // Firefox throws exceptions when accessing properties
8848 // of an xhr when a network error occured
8849 // http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_(NS_ERROR_NOT_AVAILABLE)
8850 try {
8851
8852 // Was never called and is aborted or complete
8853 if ( callback && ( isAbort || xhr.readyState === 4 ) ) {
8854
8855 // Only called once
8856 callback = undefined;
8857
8858 // Do not keep as active anymore
8859 if ( handle ) {
8860 xhr.onreadystatechange = jQuery.noop;
8861 if ( xhrOnUnloadAbort ) {
8862 delete xhrCallbacks[ handle ];
8863 }
8864 }
8865
8866 // If it's an abort
8867 if ( isAbort ) {
8868 // Abort it manually if needed
8869 if ( xhr.readyState !== 4 ) {
8870 xhr.abort();
8871 }
8872 } else {
8873 status = xhr.status;
8874 responseHeaders = xhr.getAllResponseHeaders();
8875 responses = {};
8876 xml = xhr.responseXML;
8877
8878 // Construct response list
8879 if ( xml && xml.documentElement /* #4958 */ ) {
8880 responses.xml = xml;
8881 }
8882 responses.text = xhr.responseText;
8883
8884 // Firefox throws an exception when accessing
8885 // statusText for faulty cross-domain requests
8886 try {
8887 statusText = xhr.statusText;
8888 } catch( e ) {
8889 // We normalize with Webkit giving an empty statusText
8890 statusText = "";
8891 }
8892
8893 // Filter status for non standard behaviors
8894
8895 // If the request is local and we have data: assume a success
8896 // (success with no data won't get notified, that's the best we
8897 // can do given current implementations)
8898 if ( !status && s.isLocal && !s.crossDomain ) {
8899 status = responses.text ? 200 : 404;
8900 // IE - #1450: sometimes returns 1223 when it should be 204
8901 } else if ( status === 1223 ) {
8902 status = 204;
8903 }
8904 }
8905 }
8906 } catch( firefoxAccessException ) {
8907 if ( !isAbort ) {
8908 complete( -1, firefoxAccessException );
8909 }
8910 }
8911
8912 // Call complete if needed
8913 if ( responses ) {
8914 complete( status, statusText, responses, responseHeaders );
8915 }
8916 };
8917
8918 // if we're in sync mode or it's in cache
8919 // and has been retrieved directly (IE6 & IE7)
8920 // we need to manually fire the callback
8921 if ( !s.async || xhr.readyState === 4 ) {
8922 callback();
8923 } else {
8924 handle = ++xhrId;
8925 if ( xhrOnUnloadAbort ) {
8926 // Create the active xhrs callbacks list if needed
8927 // and attach the unload handler
8928 if ( !xhrCallbacks ) {
8929 xhrCallbacks = {};
8930 jQuery( window ).unload( xhrOnUnloadAbort );
8931 }
8932 // Add to list of active xhrs callbacks
8933 xhrCallbacks[ handle ] = callback;
8934 }
8935 xhr.onreadystatechange = callback;
8936 }
8937 },
8938
8939 abort: function() {
8940 if ( callback ) {
8941 callback(0,1);
8942 }
8943 }
8944 };
8945 }
8946 });
8947}
8948
8949})( jQuery );
8950(function( jQuery ) {
8951
8952var elemdisplay = {},
8953 iframe, iframeDoc,
8954 rfxtypes = /^(?:toggle|show|hide)$/,
8955 rfxnum = /^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,
8956 timerId,
8957 fxAttrs = [
8958 // height animations
8959 [ "height", "marginTop", "marginBottom", "paddingTop", "paddingBottom" ],
8960 // width animations
8961 [ "width", "marginLeft", "marginRight", "paddingLeft", "paddingRight" ],
8962 // opacity animations
8963 [ "opacity" ]
8964 ],
8965 fxNow;
8966
8967jQuery.fn.extend({
8968 show: function( speed, easing, callback ) {
8969 var elem, display;
8970
8971 if ( speed || speed === 0 ) {
8972 return this.animate( genFx("show", 3), speed, easing, callback );
8973
8974 } else {
8975 for ( var i = 0, j = this.length; i < j; i++ ) {
8976 elem = this[ i ];
8977
8978 if ( elem.style ) {
8979 display = elem.style.display;
8980
8981 // Reset the inline display of this element to learn if it is
8982 // being hidden by cascaded rules or not
8983 if ( !jQuery._data(elem, "olddisplay") && display === "none" ) {
8984 display = elem.style.display = "";
8985 }
8986
8987 // Set elements which have been overridden with display: none
8988 // in a stylesheet to whatever the default browser style is
8989 // for such an element
8990 if ( display === "" && jQuery.css(elem, "display") === "none" ) {
8991 jQuery._data( elem, "olddisplay", defaultDisplay(elem.nodeName) );
8992 }
8993 }
8994 }
8995
8996 // Set the display of most of the elements in a second loop
8997 // to avoid the constant reflow
8998 for ( i = 0; i < j; i++ ) {
8999 elem = this[ i ];
9000
9001 if ( elem.style ) {
9002 display = elem.style.display;
9003
9004 if ( display === "" || display === "none" ) {
9005 elem.style.display = jQuery._data( elem, "olddisplay" ) || "";
9006 }
9007 }
9008 }
9009
9010 return this;
9011 }
9012 },
9013
9014 hide: function( speed, easing, callback ) {
9015 if ( speed || speed === 0 ) {
9016 return this.animate( genFx("hide", 3), speed, easing, callback);
9017
9018 } else {
9019 var elem, display,
9020 i = 0,
9021 j = this.length;
9022
9023 for ( ; i < j; i++ ) {
9024 elem = this[i];
9025 if ( elem.style ) {
9026 display = jQuery.css( elem, "display" );
9027
9028 if ( display !== "none" && !jQuery._data( elem, "olddisplay" ) ) {
9029 jQuery._data( elem, "olddisplay", display );
9030 }
9031 }
9032 }
9033
9034 // Set the display of the elements in a second loop
9035 // to avoid the constant reflow
9036 for ( i = 0; i < j; i++ ) {
9037 if ( this[i].style ) {
9038 this[i].style.display = "none";
9039 }
9040 }
9041
9042 return this;
9043 }
9044 },
9045
9046 // Save the old toggle function
9047 _toggle: jQuery.fn.toggle,
9048
9049 toggle: function( fn, fn2, callback ) {
9050 var bool = typeof fn === "boolean";
9051
9052 if ( jQuery.isFunction(fn) && jQuery.isFunction(fn2) ) {
9053 this._toggle.apply( this, arguments );
9054
9055 } else if ( fn == null || bool ) {
9056 this.each(function() {
9057 var state = bool ? fn : jQuery(this).is(":hidden");
9058 jQuery(this)[ state ? "show" : "hide" ]();
9059 });
9060
9061 } else {
9062 this.animate(genFx("toggle", 3), fn, fn2, callback);
9063 }
9064
9065 return this;
9066 },
9067
9068 fadeTo: function( speed, to, easing, callback ) {
9069 return this.filter(":hidden").css("opacity", 0).show().end()
9070 .animate({opacity: to}, speed, easing, callback);
9071 },
9072
9073 animate: function( prop, speed, easing, callback ) {
9074 var optall = jQuery.speed( speed, easing, callback );
9075
9076 if ( jQuery.isEmptyObject( prop ) ) {
9077 return this.each( optall.complete, [ false ] );
9078 }
9079
9080 // Do not change referenced properties as per-property easing will be lost
9081 prop = jQuery.extend( {}, prop );
9082
9083 function doAnimation() {
9084 // XXX 'this' does not always have a nodeName when running the
9085 // test suite
9086
9087 if ( optall.queue === false ) {
9088 jQuery._mark( this );
9089 }
9090
9091 var opt = jQuery.extend( {}, optall ),
9092 isElement = this.nodeType === 1,
9093 hidden = isElement && jQuery(this).is(":hidden"),
9094 name, val, p, e,
9095 parts, start, end, unit,
9096 method;
9097
9098 // will store per property easing and be used to determine when an animation is complete
9099 opt.animatedProperties = {};
9100
9101 for ( p in prop ) {
9102
9103 // property name normalization
9104 name = jQuery.camelCase( p );
9105 if ( p !== name ) {
9106 prop[ name ] = prop[ p ];
9107 delete prop[ p ];
9108 }
9109
9110 val = prop[ name ];
9111
9112 // easing resolution: per property > opt.specialEasing > opt.easing > 'swing' (default)
9113 if ( jQuery.isArray( val ) ) {
9114 opt.animatedProperties[ name ] = val[ 1 ];
9115 val = prop[ name ] = val[ 0 ];
9116 } else {
9117 opt.animatedProperties[ name ] = opt.specialEasing && opt.specialEasing[ name ] || opt.easing || 'swing';
9118 }
9119
9120 if ( val === "hide" && hidden || val === "show" && !hidden ) {
9121 return opt.complete.call( this );
9122 }
9123
9124 if ( isElement && ( name === "height" || name === "width" ) ) {
9125 // Make sure that nothing sneaks out
9126 // Record all 3 overflow attributes because IE does not
9127 // change the overflow attribute when overflowX and
9128 // overflowY are set to the same value
9129 opt.overflow = [ this.style.overflow, this.style.overflowX, this.style.overflowY ];
9130
9131 // Set display property to inline-block for height/width
9132 // animations on inline elements that are having width/height animated
9133 if ( jQuery.css( this, "display" ) === "inline" &&
9134 jQuery.css( this, "float" ) === "none" ) {
9135
9136 // inline-level elements accept inline-block;
9137 // block-level elements need to be inline with layout
9138 if ( !jQuery.support.inlineBlockNeedsLayout || defaultDisplay( this.nodeName ) === "inline" ) {
9139 this.style.display = "inline-block";
9140
9141 } else {
9142 this.style.zoom = 1;
9143 }
9144 }
9145 }
9146 }
9147
9148 if ( opt.overflow != null ) {
9149 this.style.overflow = "hidden";
9150 }
9151
9152 for ( p in prop ) {
9153 e = new jQuery.fx( this, opt, p );
9154 val = prop[ p ];
9155
9156 if ( rfxtypes.test( val ) ) {
9157
9158 // Tracks whether to show or hide based on private
9159 // data attached to the element
9160 method = jQuery._data( this, "toggle" + p ) || ( val === "toggle" ? hidden ? "show" : "hide" : 0 );
9161 if ( method ) {
9162 jQuery._data( this, "toggle" + p, method === "show" ? "hide" : "show" );
9163 e[ method ]();
9164 } else {
9165 e[ val ]();
9166 }
9167
9168 } else {
9169 parts = rfxnum.exec( val );
9170 start = e.cur();
9171
9172 if ( parts ) {
9173 end = parseFloat( parts[2] );
9174 unit = parts[3] || ( jQuery.cssNumber[ p ] ? "" : "px" );
9175
9176 // We need to compute starting value
9177 if ( unit !== "px" ) {
9178 jQuery.style( this, p, (end || 1) + unit);
9179 start = ( (end || 1) / e.cur() ) * start;
9180 jQuery.style( this, p, start + unit);
9181 }
9182
9183 // If a +=/-= token was provided, we're doing a relative animation
9184 if ( parts[1] ) {
9185 end = ( (parts[ 1 ] === "-=" ? -1 : 1) * end ) + start;
9186 }
9187
9188 e.custom( start, end, unit );
9189
9190 } else {
9191 e.custom( start, val, "" );
9192 }
9193 }
9194 }
9195
9196 // For JS strict compliance
9197 return true;
9198 }
9199
9200 return optall.queue === false ?
9201 this.each( doAnimation ) :
9202 this.queue( optall.queue, doAnimation );
9203 },
9204
9205 stop: function( type, clearQueue, gotoEnd ) {
9206 if ( typeof type !== "string" ) {
9207 gotoEnd = clearQueue;
9208 clearQueue = type;
9209 type = undefined;
9210 }
9211 if ( clearQueue && type !== false ) {
9212 this.queue( type || "fx", [] );
9213 }
9214
9215 return this.each(function() {
9216 var i,
9217 hadTimers = false,
9218 timers = jQuery.timers,
9219 data = jQuery._data( this );
9220
9221 // clear marker counters if we know they won't be
9222 if ( !gotoEnd ) {
9223 jQuery._unmark( true, this );
9224 }
9225
9226 function stopQueue( elem, data, i ) {
9227 var hooks = data[ i ];
9228 jQuery.removeData( elem, i, true );
9229 hooks.stop( gotoEnd );
9230 }
9231
9232 if ( type == null ) {
9233 for ( i in data ) {
9234 if ( data[ i ].stop && i.indexOf(".run") === i.length - 4 ) {
9235 stopQueue( this, data, i );
9236 }
9237 }
9238 } else if ( data[ i = type + ".run" ] && data[ i ].stop ){
9239 stopQueue( this, data, i );
9240 }
9241
9242 for ( i = timers.length; i--; ) {
9243 if ( timers[ i ].elem === this && (type == null || timers[ i ].queue === type) ) {
9244 if ( gotoEnd ) {
9245
9246 // force the next step to be the last
9247 timers[ i ]( true );
9248 } else {
9249 timers[ i ].saveState();
9250 }
9251 hadTimers = true;
9252 timers.splice( i, 1 );
9253 }
9254 }
9255
9256 // start the next in the queue if the last step wasn't forced
9257 // timers currently will call their complete callbacks, which will dequeue
9258 // but only if they were gotoEnd
9259 if ( !( gotoEnd && hadTimers ) ) {
9260 jQuery.dequeue( this, type );
9261 }
9262 });
9263 }
9264
9265});
9266
9267// Animations created synchronously will run synchronously
9268function createFxNow() {
9269 setTimeout( clearFxNow, 0 );
9270 return ( fxNow = jQuery.now() );
9271}
9272
9273function clearFxNow() {
9274 fxNow = undefined;
9275}
9276
9277// Generate parameters to create a standard animation
9278function genFx( type, num ) {
9279 var obj = {};
9280
9281 jQuery.each( fxAttrs.concat.apply([], fxAttrs.slice( 0, num )), function() {
9282 obj[ this ] = type;
9283 });
9284
9285 return obj;
9286}
9287
9288// Generate shortcuts for custom animations
9289jQuery.each({
9290 slideDown: genFx( "show", 1 ),
9291 slideUp: genFx( "hide", 1 ),
9292 slideToggle: genFx( "toggle", 1 ),
9293 fadeIn: { opacity: "show" },
9294 fadeOut: { opacity: "hide" },
9295 fadeToggle: { opacity: "toggle" }
9296}, function( name, props ) {
9297 jQuery.fn[ name ] = function( speed, easing, callback ) {
9298 return this.animate( props, speed, easing, callback );
9299 };
9300});
9301
9302jQuery.extend({
9303 speed: function( speed, easing, fn ) {
9304 var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
9305 complete: fn || !fn && easing ||
9306 jQuery.isFunction( speed ) && speed,
9307 duration: speed,
9308 easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing
9309 };
9310
9311 opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
9312 opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;
9313
9314 // normalize opt.queue - true/undefined/null -> "fx"
9315 if ( opt.queue == null || opt.queue === true ) {
9316 opt.queue = "fx";
9317 }
9318
9319 // Queueing
9320 opt.old = opt.complete;
9321
9322 opt.complete = function( noUnmark ) {
9323 if ( jQuery.isFunction( opt.old ) ) {
9324 opt.old.call( this );
9325 }
9326
9327 if ( opt.queue ) {
9328 jQuery.dequeue( this, opt.queue );
9329 } else if ( noUnmark !== false ) {
9330 jQuery._unmark( this );
9331 }
9332 };
9333
9334 return opt;
9335 },
9336
9337 easing: {
9338 linear: function( p, n, firstNum, diff ) {
9339 return firstNum + diff * p;
9340 },
9341 swing: function( p, n, firstNum, diff ) {
9342 return ( ( -Math.cos( p*Math.PI ) / 2 ) + 0.5 ) * diff + firstNum;
9343 }
9344 },
9345
9346 timers: [],
9347
9348 fx: function( elem, options, prop ) {
9349 this.options = options;
9350 this.elem = elem;
9351 this.prop = prop;
9352
9353 options.orig = options.orig || {};
9354 }
9355
9356});
9357
9358jQuery.fx.prototype = {
9359 // Simple function for setting a style value
9360 update: function() {
9361 if ( this.options.step ) {
9362 this.options.step.call( this.elem, this.now, this );
9363 }
9364
9365 ( jQuery.fx.step[ this.prop ] || jQuery.fx.step._default )( this );
9366 },
9367
9368 // Get the current size
9369 cur: function() {
9370 if ( this.elem[ this.prop ] != null && (!this.elem.style || this.elem.style[ this.prop ] == null) ) {
9371 return this.elem[ this.prop ];
9372 }
9373
9374 var parsed,
9375 r = jQuery.css( this.elem, this.prop );
9376 // Empty strings, null, undefined and "auto" are converted to 0,
9377 // complex values such as "rotate(1rad)" are returned as is,
9378 // simple values such as "10px" are parsed to Float.
9379 return isNaN( parsed = parseFloat( r ) ) ? !r || r === "auto" ? 0 : r : parsed;
9380 },
9381
9382 // Start an animation from one number to another
9383 custom: function( from, to, unit ) {
9384 var self = this,
9385 fx = jQuery.fx;
9386
9387 this.startTime = fxNow || createFxNow();
9388 this.end = to;
9389 this.now = this.start = from;
9390 this.pos = this.state = 0;
9391 this.unit = unit || this.unit || ( jQuery.cssNumber[ this.prop ] ? "" : "px" );
9392
9393 function t( gotoEnd ) {
9394 return self.step( gotoEnd );
9395 }
9396
9397 t.queue = this.options.queue;
9398 t.elem = this.elem;
9399 t.saveState = function() {
9400 if ( self.options.hide && jQuery._data( self.elem, "fxshow" + self.prop ) === undefined ) {
9401 jQuery._data( self.elem, "fxshow" + self.prop, self.start );
9402 }
9403 };
9404
9405 if ( t() && jQuery.timers.push(t) && !timerId ) {
9406 timerId = setInterval( fx.tick, fx.interval );
9407 }
9408 },
9409
9410 // Simple 'show' function
9411 show: function() {
9412 var dataShow = jQuery._data( this.elem, "fxshow" + this.prop );
9413
9414 // Remember where we started, so that we can go back to it later
9415 this.options.orig[ this.prop ] = dataShow || jQuery.style( this.elem, this.prop );
9416 this.options.show = true;
9417
9418 // Begin the animation
9419 // Make sure that we start at a small width/height to avoid any flash of content
9420 if ( dataShow !== undefined ) {
9421 // This show is picking up where a previous hide or show left off
9422 this.custom( this.cur(), dataShow );
9423 } else {
9424 this.custom( this.prop === "width" || this.prop === "height" ? 1 : 0, this.cur() );
9425 }
9426
9427 // Start by showing the element
9428 jQuery( this.elem ).show();
9429 },
9430
9431 // Simple 'hide' function
9432 hide: function() {
9433 // Remember where we started, so that we can go back to it later
9434 this.options.orig[ this.prop ] = jQuery._data( this.elem, "fxshow" + this.prop ) || jQuery.style( this.elem, this.prop );
9435 this.options.hide = true;
9436
9437 // Begin the animation
9438 this.custom( this.cur(), 0 );
9439 },
9440
9441 // Each step of an animation
9442 step: function( gotoEnd ) {
9443 var p, n, complete,
9444 t = fxNow || createFxNow(),
9445 done = true,
9446 elem = this.elem,
9447 options = this.options;
9448
9449 if ( gotoEnd || t >= options.duration + this.startTime ) {
9450 this.now = this.end;
9451 this.pos = this.state = 1;
9452 this.update();
9453
9454 options.animatedProperties[ this.prop ] = true;
9455
9456 for ( p in options.animatedProperties ) {
9457 if ( options.animatedProperties[ p ] !== true ) {
9458 done = false;
9459 }
9460 }
9461
9462 if ( done ) {
9463 // Reset the overflow
9464 if ( options.overflow != null && !jQuery.support.shrinkWrapBlocks ) {
9465
9466 jQuery.each( [ "", "X", "Y" ], function( index, value ) {
9467 elem.style[ "overflow" + value ] = options.overflow[ index ];
9468 });
9469 }
9470
9471 // Hide the element if the "hide" operation was done
9472 if ( options.hide ) {
9473 jQuery( elem ).hide();
9474 }
9475
9476 // Reset the properties, if the item has been hidden or shown
9477 if ( options.hide || options.show ) {
9478 for ( p in options.animatedProperties ) {
9479 jQuery.style( elem, p, options.orig[ p ] );
9480 jQuery.removeData( elem, "fxshow" + p, true );
9481 // Toggle data is no longer needed
9482 jQuery.removeData( elem, "toggle" + p, true );
9483 }
9484 }
9485
9486 // Execute the complete function
9487 // in the event that the complete function throws an exception
9488 // we must ensure it won't be called twice. #5684
9489
9490 complete = options.complete;
9491 if ( complete ) {
9492
9493 options.complete = false;
9494 complete.call( elem );
9495 }
9496 }
9497
9498 return false;
9499
9500 } else {
9501 // classical easing cannot be used with an Infinity duration
9502 if ( options.duration == Infinity ) {
9503 this.now = t;
9504 } else {
9505 n = t - this.startTime;
9506 this.state = n / options.duration;
9507
9508 // Perform the easing function, defaults to swing
9509 this.pos = jQuery.easing[ options.animatedProperties[this.prop] ]( this.state, n, 0, 1, options.duration );
9510 this.now = this.start + ( (this.end - this.start) * this.pos );
9511 }
9512 // Perform the next step of the animation
9513 this.update();
9514 }
9515
9516 return true;
9517 }
9518};
9519
9520jQuery.extend( jQuery.fx, {
9521 tick: function() {
9522 var timer,
9523 timers = jQuery.timers,
9524 i = 0;
9525
9526 for ( ; i < timers.length; i++ ) {
9527 timer = timers[ i ];
9528 // Checks the timer has not already been removed
9529 if ( !timer() && timers[ i ] === timer ) {
9530 timers.splice( i--, 1 );
9531 }
9532 }
9533
9534 if ( !timers.length ) {
9535 jQuery.fx.stop();
9536 }
9537 },
9538
9539 interval: 13,
9540
9541 stop: function() {
9542 clearInterval( timerId );
9543 timerId = null;
9544 },
9545
9546 speeds: {
9547 slow: 600,
9548 fast: 200,
9549 // Default speed
9550 _default: 400
9551 },
9552
9553 step: {
9554 opacity: function( fx ) {
9555 jQuery.style( fx.elem, "opacity", fx.now );
9556 },
9557
9558 _default: function( fx ) {
9559 if ( fx.elem.style && fx.elem.style[ fx.prop ] != null ) {
9560 fx.elem.style[ fx.prop ] = fx.now + fx.unit;
9561 } else {
9562 fx.elem[ fx.prop ] = fx.now;
9563 }
9564 }
9565 }
9566});
9567
9568// Adds width/height step functions
9569// Do not set anything below 0
9570jQuery.each([ "width", "height" ], function( i, prop ) {
9571 jQuery.fx.step[ prop ] = function( fx ) {
9572 jQuery.style( fx.elem, prop, Math.max(0, fx.now) );
9573 };
9574});
9575
9576if ( jQuery.expr && jQuery.expr.filters ) {
9577 jQuery.expr.filters.animated = function( elem ) {
9578 return jQuery.grep(jQuery.timers, function( fn ) {
9579 return elem === fn.elem;
9580 }).length;
9581 };
9582}
9583
9584// Try to restore the default display value of an element
9585function defaultDisplay( nodeName ) {
9586
9587 if ( !elemdisplay[ nodeName ] ) {
9588
9589 var body = document.body,
9590 elem = jQuery( "<" + nodeName + ">" ).appendTo( body ),
9591 display = elem.css( "display" );
9592 elem.remove();
9593
9594 // If the simple way fails,
9595 // get element's real default display by attaching it to a temp iframe
9596 if ( display === "none" || display === "" ) {
9597 // No iframe to use yet, so create it
9598 if ( !iframe ) {
9599 iframe = document.createElement( "iframe" );
9600 iframe.frameBorder = iframe.width = iframe.height = 0;
9601 }
9602
9603 body.appendChild( iframe );
9604
9605 // Create a cacheable copy of the iframe document on first call.
9606 // IE and Opera will allow us to reuse the iframeDoc without re-writing the fake HTML
9607 // document to it; WebKit & Firefox won't allow reusing the iframe document.
9608 if ( !iframeDoc || !iframe.createElement ) {
9609 iframeDoc = ( iframe.contentWindow || iframe.contentDocument ).document;
9610 iframeDoc.write( ( document.compatMode === "CSS1Compat" ? "<!doctype html>" : "" ) + "<html><body>" );
9611 iframeDoc.close();
9612 }
9613
9614 elem = iframeDoc.createElement( nodeName );
9615
9616 iframeDoc.body.appendChild( elem );
9617
9618 display = jQuery.css( elem, "display" );
9619 body.removeChild( iframe );
9620 }
9621
9622 // Store the correct default display
9623 elemdisplay[ nodeName ] = display;
9624 }
9625
9626 return elemdisplay[ nodeName ];
9627}
9628
9629})( jQuery );
9630(function( jQuery ) {
9631
9632var rtable = /^t(?:able|d|h)$/i,
9633 rroot = /^(?:body|html)$/i;
9634
9635if ( "getBoundingClientRect" in document.documentElement ) {
9636 jQuery.fn.offset = function( options ) {
9637 var elem = this[0], box;
9638
9639 if ( options ) {
9640 return this.each(function( i ) {
9641 jQuery.offset.setOffset( this, options, i );
9642 });
9643 }
9644
9645 if ( !elem || !elem.ownerDocument ) {
9646 return null;
9647 }
9648
9649 if ( elem === elem.ownerDocument.body ) {
9650 return jQuery.offset.bodyOffset( elem );
9651 }
9652
9653 try {
9654 box = elem.getBoundingClientRect();
9655 } catch(e) {}
9656
9657 var doc = elem.ownerDocument,
9658 docElem = doc.documentElement;
9659
9660 // Make sure we're not dealing with a disconnected DOM node
9661 if ( !box || !jQuery.contains( docElem, elem ) ) {
9662 return box ? { top: box.top, left: box.left } : { top: 0, left: 0 };
9663 }
9664
9665 var body = doc.body,
9666 win = getWindow(doc),
9667 clientTop = docElem.clientTop || body.clientTop || 0,
9668 clientLeft = docElem.clientLeft || body.clientLeft || 0,
9669 scrollTop = win.pageYOffset || jQuery.support.boxModel && docElem.scrollTop || body.scrollTop,
9670 scrollLeft = win.pageXOffset || jQuery.support.boxModel && docElem.scrollLeft || body.scrollLeft,
9671 top = box.top + scrollTop - clientTop,
9672 left = box.left + scrollLeft - clientLeft;
9673
9674 return { top: top, left: left };
9675 };
9676
9677} else {
9678 jQuery.fn.offset = function( options ) {
9679 var elem = this[0];
9680
9681 if ( options ) {
9682 return this.each(function( i ) {
9683 jQuery.offset.setOffset( this, options, i );
9684 });
9685 }
9686
9687 if ( !elem || !elem.ownerDocument ) {
9688 return null;
9689 }
9690
9691 if ( elem === elem.ownerDocument.body ) {
9692 return jQuery.offset.bodyOffset( elem );
9693 }
9694
9695 var computedStyle,
9696 offsetParent = elem.offsetParent,
9697 prevOffsetParent = elem,
9698 doc = elem.ownerDocument,
9699 docElem = doc.documentElement,
9700 body = doc.body,
9701 defaultView = doc.defaultView,
9702 prevComputedStyle = defaultView ? defaultView.getComputedStyle( elem, null ) : elem.currentStyle,
9703 top = elem.offsetTop,
9704 left = elem.offsetLeft;
9705
9706 while ( (elem = elem.parentNode) && elem !== body && elem !== docElem ) {
9707 if ( jQuery.support.fixedPosition && prevComputedStyle.position === "fixed" ) {
9708 break;
9709 }
9710
9711 computedStyle = defaultView ? defaultView.getComputedStyle(elem, null) : elem.currentStyle;
9712 top -= elem.scrollTop;
9713 left -= elem.scrollLeft;
9714
9715 if ( elem === offsetParent ) {
9716 top += elem.offsetTop;
9717 left += elem.offsetLeft;
9718
9719 if ( jQuery.support.doesNotAddBorder && !(jQuery.support.doesAddBorderForTableAndCells && rtable.test(elem.nodeName)) ) {
9720 top += parseFloat( computedStyle.borderTopWidth ) || 0;
9721 left += parseFloat( computedStyle.borderLeftWidth ) || 0;
9722 }
9723
9724 prevOffsetParent = offsetParent;
9725 offsetParent = elem.offsetParent;
9726 }
9727
9728 if ( jQuery.support.subtractsBorderForOverflowNotVisible && computedStyle.overflow !== "visible" ) {
9729 top += parseFloat( computedStyle.borderTopWidth ) || 0;
9730 left += parseFloat( computedStyle.borderLeftWidth ) || 0;
9731 }
9732
9733 prevComputedStyle = computedStyle;
9734 }
9735
9736 if ( prevComputedStyle.position === "relative" || prevComputedStyle.position === "static" ) {
9737 top += body.offsetTop;
9738 left += body.offsetLeft;
9739 }
9740
9741 if ( jQuery.support.fixedPosition && prevComputedStyle.position === "fixed" ) {
9742 top += Math.max( docElem.scrollTop, body.scrollTop );
9743 left += Math.max( docElem.scrollLeft, body.scrollLeft );
9744 }
9745
9746 return { top: top, left: left };
9747 };
9748}
9749
9750jQuery.offset = {
9751
9752 bodyOffset: function( body ) {
9753 var top = body.offsetTop,
9754 left = body.offsetLeft;
9755
9756 if ( jQuery.support.doesNotIncludeMarginInBodyOffset ) {
9757 top += parseFloat( jQuery.css(body, "marginTop") ) || 0;
9758 left += parseFloat( jQuery.css(body, "marginLeft") ) || 0;
9759 }
9760
9761 return { top: top, left: left };
9762 },
9763
9764 setOffset: function( elem, options, i ) {
9765 var position = jQuery.css( elem, "position" );
9766
9767 // set position first, in-case top/left are set even on static elem
9768 if ( position === "static" ) {
9769 elem.style.position = "relative";
9770 }
9771
9772 var curElem = jQuery( elem ),
9773 curOffset = curElem.offset(),
9774 curCSSTop = jQuery.css( elem, "top" ),
9775 curCSSLeft = jQuery.css( elem, "left" ),
9776 calculatePosition = ( position === "absolute" || position === "fixed" ) && jQuery.inArray("auto", [curCSSTop, curCSSLeft]) > -1,
9777 props = {}, curPosition = {}, curTop, curLeft;
9778
9779 // need to be able to calculate position if either top or left is auto and position is either absolute or fixed
9780 if ( calculatePosition ) {
9781 curPosition = curElem.position();
9782 curTop = curPosition.top;
9783 curLeft = curPosition.left;
9784 } else {
9785 curTop = parseFloat( curCSSTop ) || 0;
9786 curLeft = parseFloat( curCSSLeft ) || 0;
9787 }
9788
9789 if ( jQuery.isFunction( options ) ) {
9790 options = options.call( elem, i, curOffset );
9791 }
9792
9793 if ( options.top != null ) {
9794 props.top = ( options.top - curOffset.top ) + curTop;
9795 }
9796 if ( options.left != null ) {
9797 props.left = ( options.left - curOffset.left ) + curLeft;
9798 }
9799
9800 if ( "using" in options ) {
9801 options.using.call( elem, props );
9802 } else {
9803 curElem.css( props );
9804 }
9805 }
9806};
9807
9808
9809jQuery.fn.extend({
9810
9811 position: function() {
9812 if ( !this[0] ) {
9813 return null;
9814 }
9815
9816 var elem = this[0],
9817
9818 // Get *real* offsetParent
9819 offsetParent = this.offsetParent(),
9820
9821 // Get correct offsets
9822 offset = this.offset(),
9823 parentOffset = rroot.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset();
9824
9825 // Subtract element margins
9826 // note: when an element has margin: auto the offsetLeft and marginLeft
9827 // are the same in Safari causing offset.left to incorrectly be 0
9828 offset.top -= parseFloat( jQuery.css(elem, "marginTop") ) || 0;
9829 offset.left -= parseFloat( jQuery.css(elem, "marginLeft") ) || 0;
9830
9831 // Add offsetParent borders
9832 parentOffset.top += parseFloat( jQuery.css(offsetParent[0], "borderTopWidth") ) || 0;
9833 parentOffset.left += parseFloat( jQuery.css(offsetParent[0], "borderLeftWidth") ) || 0;
9834
9835 // Subtract the two offsets
9836 return {
9837 top: offset.top - parentOffset.top,
9838 left: offset.left - parentOffset.left
9839 };
9840 },
9841
9842 offsetParent: function() {
9843 return this.map(function() {
9844 var offsetParent = this.offsetParent || document.body;
9845 while ( offsetParent && (!rroot.test(offsetParent.nodeName) && jQuery.css(offsetParent, "position") === "static") ) {
9846 offsetParent = offsetParent.offsetParent;
9847 }
9848 return offsetParent;
9849 });
9850 }
9851});
9852
9853
9854// Create scrollLeft and scrollTop methods
9855jQuery.each( ["Left", "Top"], function( i, name ) {
9856 var method = "scroll" + name;
9857
9858 jQuery.fn[ method ] = function( val ) {
9859 var elem, win;
9860
9861 if ( val === undefined ) {
9862 elem = this[ 0 ];
9863
9864 if ( !elem ) {
9865 return null;
9866 }
9867
9868 win = getWindow( elem );
9869
9870 // Return the scroll offset
9871 return win ? ("pageXOffset" in win) ? win[ i ? "pageYOffset" : "pageXOffset" ] :
9872 jQuery.support.boxModel && win.document.documentElement[ method ] ||
9873 win.document.body[ method ] :
9874 elem[ method ];
9875 }
9876
9877 // Set the scroll offset
9878 return this.each(function() {
9879 win = getWindow( this );
9880
9881 if ( win ) {
9882 win.scrollTo(
9883 !i ? val : jQuery( win ).scrollLeft(),
9884 i ? val : jQuery( win ).scrollTop()
9885 );
9886
9887 } else {
9888 this[ method ] = val;
9889 }
9890 });
9891 };
9892});
9893
9894function getWindow( elem ) {
9895 return jQuery.isWindow( elem ) ?
9896 elem :
9897 elem.nodeType === 9 ?
9898 elem.defaultView || elem.parentWindow :
9899 false;
9900}
9901
9902})( jQuery );
9903(function( jQuery ) {
9904
9905// Create width, height, innerHeight, innerWidth, outerHeight and outerWidth methods
9906jQuery.each([ "Height", "Width" ], function( i, name ) {
9907
9908 var type = name.toLowerCase();
9909
9910 // innerHeight and innerWidth
9911 jQuery.fn[ "inner" + name ] = function() {
9912 var elem = this[0];
9913 return elem ?
9914 elem.style ?
9915 parseFloat( jQuery.css( elem, type, "padding" ) ) :
9916 this[ type ]() :
9917 null;
9918 };
9919
9920 // outerHeight and outerWidth
9921 jQuery.fn[ "outer" + name ] = function( margin ) {
9922 var elem = this[0];
9923 return elem ?
9924 elem.style ?
9925 parseFloat( jQuery.css( elem, type, margin ? "margin" : "border" ) ) :
9926 this[ type ]() :
9927 null;
9928 };
9929
9930 jQuery.fn[ type ] = function( size ) {
9931 // Get window width or height
9932 var elem = this[0];
9933 if ( !elem ) {
9934 return size == null ? null : this;
9935 }
9936
9937 if ( jQuery.isFunction( size ) ) {
9938 return this.each(function( i ) {
9939 var self = jQuery( this );
9940 self[ type ]( size.call( this, i, self[ type ]() ) );
9941 });
9942 }
9943
9944 if ( jQuery.isWindow( elem ) ) {
9945 // Everyone else use document.documentElement or document.body depending on Quirks vs Standards mode
9946 // 3rd condition allows Nokia support, as it supports the docElem prop but not CSS1Compat
9947 var docElemProp = elem.document.documentElement[ "client" + name ],
9948 body = elem.document.body;
9949 return elem.document.compatMode === "CSS1Compat" && docElemProp ||
9950 body && body[ "client" + name ] || docElemProp;
9951
9952 // Get document width or height
9953 } else if ( elem.nodeType === 9 ) {
9954 // Either scroll[Width/Height] or offset[Width/Height], whichever is greater
9955 return Math.max(
9956 elem.documentElement["client" + name],
9957 elem.body["scroll" + name], elem.documentElement["scroll" + name],
9958 elem.body["offset" + name], elem.documentElement["offset" + name]
9959 );
9960
9961 // Get or set width or height on the element
9962 } else if ( size === undefined ) {
9963 var orig = jQuery.css( elem, type ),
9964 ret = parseFloat( orig );
9965
9966 return jQuery.isNumeric( ret ) ? ret : orig;
9967
9968 // Set the width or height on the element (default to pixels if value is unitless)
9969 } else {
9970 return this.css( type, typeof size === "string" ? size : size + "px" );
9971 }
9972 };
9973
9974});
9975
9976})( jQuery );
9977(function(jQuery) {
9978 if (typeof(Array.prototype.indexOf) == "undefined")
9979 Array.prototype.indexOf = function(value) {
9980 return jQuery.inArray(value, this);
9981 };
9982
9983 if (typeof(Array.prototype.map) == "undefined")
9984 Array.prototype.map = function(callback) {
9985 return jQuery.map(this, callback);
9986 };
9987
9988 if (typeof(Array.prototype.forEach) == "undefined")
9989 Array.prototype.forEach = function(callback) {
9990 jQuery.each(this, function() {
9991 callback(this);
9992 });
9993 };
9994})(jQuery);
9995var Webxray = (function() {
9996 "use strict";
9997
9998 var GLOBAL_GOGGLES_LOAD_CB = 'webxrayWhenGogglesLoad';
9999
10000 return {
10001 _getBaseURI: function() {
10002 // We would use document.baseURI, but it's not supported on IE9.
10003 var a = document.createElement("a");
10004 a.setAttribute("href", "./");
10005 return a.href;
10006 },
10007 getBookmarkletURL: function getBookmarkletURL(baseURI, lang) {
10008 baseURI = baseURI || this._getBaseURI();
10009
10010 var baseCode = "(function(){var script=document.createElement('script');script.src='-baseuri-/"+lang+"/webxray.js';script.className='webxray';script.setAttribute('data-lang','"+lang+"');script.setAttribute('data-baseuri','-baseuri-/"+lang+"');document.body.appendChild(script);})();";
10011 var code = baseCode.replace( /-baseuri-/g, baseURI );
10012
10013 return 'javascript:' + code;
10014 },
10015 whenLoaded: function whenLoaded(cb, global) {
10016 global = global || window;
10017 global[GLOBAL_GOGGLES_LOAD_CB] = cb;
10018 },
10019 triggerWhenLoaded: function triggerWhenLoaded(ui, global) {
10020 global = global || window;
10021 if (GLOBAL_GOGGLES_LOAD_CB in global &&
10022 typeof(global[GLOBAL_GOGGLES_LOAD_CB]) == 'function')
10023 global[GLOBAL_GOGGLES_LOAD_CB](ui);
10024 }
10025 };
10026})();
10027(function(jQuery) {
10028 "use strict";
10029
10030 function makeAbsoluteURL(baseURI, url) {
10031 if (url.match(/^https?:/))
10032 return url;
10033 return baseURI + url;
10034 }
10035
10036 jQuery.webxraySettings = {
10037 extend: jQuery.extend,
10038 url: function(name) {
10039 if (jQuery.isArray(this[name])) {
10040 var self = this;
10041 return jQuery.map(this[name], function(url) {
10042 return makeAbsoluteURL(self.baseURI, url);
10043 });
10044 }
10045 return makeAbsoluteURL(this.baseURI, this[name]);
10046 },
10047 baseURI: "",
10048 cssURL: "webxray.css",
10049 preferencesURL: "preferences.html",
10050 easyRemixDialogURL: "https://goggles.mozilla.org/" + xray.lang + "/easy-remix-dialog/index.html",
10051 uprootDialogURL: "https://goggles.mozilla.org/" + xray.lang + "/uproot-dialog.html",
10052 helpDialogURL: "https://goggles.mozilla.org/" + xray.lang + "/help.html",
10053 hackpubInjectionURL: "published-hack/injector.js",
10054 pluginURLs: [],
10055 hackpubURL: "",
10056 idwmoURL: "https://id.webmaker.org",
10057 publishwmoURL: "https://publish-webmaker-org-prod.herokuapp.com"
10058 };
10059})(jQuery);
10060(function(jQuery) {
10061 "use strict";
10062
10063 var $ = jQuery,
10064 locale = Localized.get;
10065
10066 function createLocalizedHelp(keys, platform) {
10067 platform = platform || navigator.platform;
10068
10069 var localizedKeys = [];
10070 keys.forEach(function(info) {
10071 var localizedInfo = {key: null, desc: null};
10072 localizedInfo.key = jQuery.nameForKey(info.key, platform);
10073 localizedInfo.desc = locale(info.cmd);
10074 localizedKeys.push(localizedInfo);
10075 });
10076 return localizedKeys;
10077 }
10078
10079 jQuery.extend({
10080 nameForKey: function(key, platform) {
10081 platform = platform || navigator.platform;
10082
10083 var normalKey = "key-names:" + key;
10084 var osKey = normalKey + "-" + platform;
10085 return locale(osKey) ||
10086 locale(normalKey) ||
10087 key;
10088 },
10089 createKeyboardHelpReference: function(keyboardHelp, platform) {
10090 var keys = createLocalizedHelp(keyboardHelp, platform);
10091 var table = $('<div class="webxray-help-box"></div>');
10092 keys.forEach(function(info) {
10093 var row = $('<div class="webxray-help-row"></div>');
10094 var keyCell = $('<div class="webxray-help-key"></div>');
10095 var keyValue = $('<div class="webxray-help-desc"></div>');
10096
10097 keyCell.append($('<div class="webxray-kbd"></div>').text(info.key));
10098 keyValue.text(info.desc);
10099 row.append(keyCell).append(keyValue);
10100 table.append(row);
10101 });
10102 return table;
10103 }
10104 });
10105})(jQuery);
10106(function(jQuery) {
10107 "use strict";
10108
10109 var $ = jQuery;
10110 var HEX_REGEXP = /#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})/i;
10111 var RGB_REGEXP = /rgb\((\d+),\s*(\d+),\s*(\d+)\)/;
10112
10113 jQuery.extend({
10114 // Load the given script. Returns a jQuery deferred that resolves
10115 // when the script is loaded. Nothing happens if the
10116 // script fails to load.
10117 loadScript: function loadScript(url) {
10118 var script = document.createElement('script');
10119 var deferred = jQuery.Deferred();
10120 script.setAttribute('src', url);
10121 script.addEventListener("load", function() {
10122 document.head.removeChild(script);
10123 deferred.resolve();
10124 }, false);
10125 document.head.appendChild(script);
10126 return deferred;
10127 },
10128 // Return a string that is shortened to be the given maximum
10129 // length, with a trailing ellipsis at the end. If the string
10130 // isn't longer than the maximum length, the string is returned
10131 // unaltered.
10132 shortenText: function shortenText(text, maxLength) {
10133 if (text.length > maxLength)
10134 return text.substring(0, maxLength) + '\u2026';
10135 return text;
10136 },
10137 // Return an rgba()-style CSS color string given a color and an
10138 // alpha value.
10139 makeRGBA: function makeRGBA(color, alpha) {
10140 // WebKit and Gecko use this.
10141 var match = color.match(RGB_REGEXP);
10142 if (!match) {
10143 // This is what Opera uses.
10144 var hexMatch = color.match(HEX_REGEXP);
10145 if (hexMatch) {
10146 match = [null];
10147 for (var i = 1; i <= 3; i++)
10148 match.push(parseInt(hexMatch[i], 16));
10149 } else
10150 throw new Error("Couldn't parse " + color);
10151 }
10152 return "rgba(" +
10153 match[1] + ", " +
10154 match[2] + ", " +
10155 match[3] + ", " +
10156 alpha + ")";
10157 },
10158 // Like console.warn(), but only does anything if console exists.
10159 warn: function warn() {
10160 if (window.console && window.console.warn) {
10161 if (window.console.warn.apply)
10162 window.console.warn.apply(window.console, arguments);
10163 else
10164 // IE9's console.warn doesn't have an apply method...
10165 window.console.warn(arguments[0] + " " + arguments[1]);
10166 }
10167 }
10168 });
10169
10170 jQuery.fn.extend({
10171 // Turns all URLs in src and href attributes into absolute URLs
10172 // if they're not already.
10173 absolutifyURLs: function() {
10174 var URL_PROPS = ['href', 'src'];
10175 this.find('*').andSelf().each(function() {
10176 var self = this;
10177 URL_PROPS.forEach(function(name) {
10178 if (name in self && self[name]) {
10179 $(self).attr(name, self[name]);
10180 }
10181 });
10182 });
10183 return this;
10184 },
10185 // returns whether at least one of the matched elements is a
10186 // void element (i.e., has no closing tag).
10187 isVoidElement: function() {
10188 // Taken from:
10189 // http://www.w3.org/TR/html-markup/syntax.html#syntax-elements
10190 return this.is("area, base, br, col, command, embed, hr, img, " +
10191 "input, keygen, link, meta, param, source, " +
10192 "track, wbr");
10193 },
10194 // works much like jQuery's html() with no arguments, but
10195 // includes HTML code for the matched elements themselves.
10196 // unlike jQuery, this will include all matched elements.
10197 outerHtml: function outerHtml() {
10198 var clonedElement = this.clone();
10199 var trivialParent = $('<div></div>').append(clonedElement);
10200 return trivialParent.html();
10201 },
10202 // Given a descendant on the first matched element, returns a CSS
10203 // selector that uniquely selects only the descendant from the
10204 // first matched element.
10205 pathTo: function pathTo(descendant) {
10206 var root = this[0];
10207 var target = $(descendant).get(0);
10208 var parts = [];
10209
10210 for (var node = target; node && node != root; node = node.parentNode) {
10211 var n = $(node).prevAll(node.nodeName.toLowerCase()).length + 1;
10212 var id = $(node).attr("id");
10213 var className = $(node).attr("class");
10214 var classNames = [];
10215 var selector = node.nodeName.toLowerCase();
10216
10217 // Class and id parts are based on jQuery-GetPath code.
10218 if (typeof(id) != "undefined" && id.length)
10219 selector += "#" + id;
10220
10221 if (typeof(className) != "undefined" && className.length)
10222 jQuery.each(jQuery.trim(className).split(/[\s\n]+/), function() {
10223 // Only keep the sane-looking class names. The CSS standard
10224 // does prescribe escape patterns for odd characters in
10225 // selectors, but jQuery's selector parser isn't completely
10226 // standards-compliant, so we'll stick with the safe ones.
10227 if (/^[A-Za-z0-9_\-]+$/.test(this))
10228 classNames.push(this);
10229 });
10230
10231 if (classNames.length)
10232 selector += "." + classNames.join('.');
10233
10234 selector += ':nth-of-type(' + n + ')';
10235 parts.push(selector);
10236 }
10237
10238 parts.reverse();
10239 return ' > ' + parts.join(' > ');
10240 },
10241
10242 // Temporarily remove the set of matched elements,
10243 // returning a removal object with one method,
10244 // undo(), that can be used to undo the removal.
10245 temporarilyRemove: function temporarilyRemove() {
10246 var undoers = [];
10247 jQuery.each(this, function(i, element) {
10248 var document = element.ownerDocument;
10249 var replacer = document.createTextNode('');
10250 if (!element.parentNode) {
10251 // Windows + Blink will have the overlay div outside
10252 // the <body>, thus it will not have a .parentNode.
10253 // This makes sure we don't throw when that happens.
10254 return;
10255 }
10256 element.parentNode.replaceChild(replacer, element);
10257 undoers.push(function() {
10258 replacer.parentNode.replaceChild(element, replacer);
10259 });
10260 });
10261 return {
10262 undo: function undo() {
10263 jQuery.each(undoers, function(i, undoer) {
10264 undoer();
10265 });
10266 undoers = null;
10267 }
10268 };
10269 },
10270
10271 // Return the nth ancestor of the first matched element.
10272 ancestor: function ancestor(generation) {
10273 var ancestor = this[0];
10274
10275 for (var i = 0; i < generation; i++)
10276 if (ancestor.parentNode)
10277 ancestor = ancestor.parentNode;
10278 else
10279 return null;
10280
10281 return $(ancestor);
10282 },
10283 // Return the bounding client rectangle of the first element
10284 // in the selection, taking CSS transforms into account if
10285 // possible.
10286 //
10287 // The returned object has top/left/height/width properties.
10288 bounds: function bounds() {
10289 try {
10290 var rect = this.get(0).getBoundingClientRect();
10291 var window = this.get(0).ownerDocument.defaultView;
10292 return {
10293 top: rect.top + window.pageYOffset,
10294 left: rect.left + window.pageXOffset,
10295 height: rect.height,
10296 width: rect.width
10297 };
10298 } catch (e) {
10299 // Not sure if this will ever get called, but there's code in
10300 // Tilt that deals with this kind of situation, and we'd like to
10301 // gracefully fallback to code that we know works if the above
10302 // fails. For more discussion, see bug #98:
10303 //
10304 // http://hackasaurus.lighthouseapp.com/projects/81472/tickets/98
10305
10306 var pos = this.offset();
10307 return {
10308 top: pos.top,
10309 left: pos.left,
10310 height: this.outerHeight(),
10311 width: this.outerWidth()
10312 };
10313 }
10314 },
10315 // Create and return a div that floats above the first
10316 // matched element.
10317 overlay: function overlay() {
10318 var html = this.get(0).ownerDocument.documentElement;
10319 var overlay = $('<div class="webxray-base webxray-overlay">' +
10320 ' </div>');
10321
10322 overlay.css(this.bounds());
10323 $(html).append(overlay);
10324 return overlay;
10325 },
10326 // Like jQuery.append(), but accepts an arbitrary number of arguments,
10327 // and automatically converts string arguments into text nodes.
10328 emit: function emit() {
10329 for (var i = 0; i < arguments.length; i++) {
10330 var arg = arguments[i];
10331 if (typeof(arg) == "string")
10332 arg = document.createTextNode(arg);
10333 this.append(arg);
10334 }
10335 },
10336 // Resizes and repositions the currently matched element to
10337 // match the size and position of the given target by animating
10338 // it and then executing the given callback.
10339 resizeTo: function resizeTo(target, cb) {
10340 var overlay = this;
10341
10342 var hasNoStyle = $(target).attr('style') === undefined;
10343 overlay.animate($(target).bounds(), cb);
10344 if (hasNoStyle && $(target).attr('style') == '')
10345 $(target).removeAttr('style');
10346 },
10347 // Resizes and repositions the currently matched element to
10348 // match the size and position of the given target by animating
10349 // it, then fades out the currently matched element and
10350 // removes it from the DOM.
10351 resizeToAndFadeOut: function resizeToAndFadeOut(target) {
10352 this.resizeTo(target, function() {
10353 $(this).fadeOut(function() { $(this).remove(); });
10354 });
10355 },
10356 // Removes the class and, if the class attribute is now empty,
10357 // removes the attribute as well (jQuery remove class does not)..
10358 reallyRemoveClass: function reallyRemoveClass(classname) {
10359 this.removeClass(classname).filter('[class=""]').removeAttr('class');
10360 return this;
10361 }
10362 });
10363})(jQuery);
10364(function(jQuery) {
10365 "use strict";
10366
10367 var $ = jQuery;
10368
10369 function makeDoctypeTag(doctype) {
10370 if (!doctype)
10371 return '';
10372 var tag = '<!DOCTYPE ' + doctype.name;
10373 if (doctype.publicId && doctype.publicId.length)
10374 tag += ' PUBLIC "' + doctype.publicId + '"';
10375 if (doctype.systemId && doctype.systemId.length)
10376 tag += ' "' + doctype.systemId + '"';
10377 return tag += '>';
10378 }
10379
10380 jQuery.extend({
10381 openUprootDialog: function(input) {
10382 window.postMessage("goggles-publish-initiated", "*");
10383 $(document).uprootIgnoringWebxray(function(html) {
10384 var injectURL = jQuery.webxraySettings.url("hackpubInjectionURL");
10385 var hackpubInfo = {
10386 injectURL: injectURL,
10387 originalURL: window.location.href,
10388 submissionDate: (new Date()).toString()
10389 };
10390
10391 jQuery.simpleModalDialog({
10392 input: input,
10393 url: jQuery.webxraySettings.url("uprootDialogURL"),
10394 classes: "webxray-publish-dialog",
10395 payload: JSON.stringify({
10396 html: html,
10397 hackpubURL: jQuery.webxraySettings.url("hackpubURL"),
10398 originalURL: hackpubInfo.originalURL
10399 })
10400 });
10401 });
10402 }
10403 });
10404
10405 jQuery.fn.extend({
10406 uprootIgnoringWebxray: function(cb) {
10407 $(document).uproot({
10408 success: cb,
10409 ignore: $([
10410 ".webxray-hud-box",
10411 ".webxray-overlay",
10412 ".webxray-dialog-overlay",
10413 "link.webxray",
10414 "#webxray-is-active",
10415 ".webxray-toolbar",
10416 ".webxray-style-info",
10417 ".webxray-tmsg-overlay",
10418 ".webxray-msg-dialog"
10419 ].join(", "))
10420 });
10421 },
10422 uproot: function(cb) {
10423 var options = {
10424 ignore: $()
10425 };
10426 if (typeof(cb) == 'object') {
10427 options = cb;
10428 cb = options.success;
10429 }
10430 var elem = this[0];
10431 var document = elem.contentDocument || elem;
10432 if (document.nodeName != "#document")
10433 throw new Error("first item of query must be a document or iframe");
10434 var base = document.createElement('base');
10435 if ($('base', document).length === 0) {
10436 $(base).attr('href', document.location.href);
10437 $(document.head).prepend(base);
10438 }
10439 if (cb)
10440 setTimeout(function() {
10441 var ignore = options.ignore.add('script', document);
10442 var removal = ignore.temporarilyRemove();
10443 var doctype = makeDoctypeTag(document.doctype);
10444 var html = doctype + document.querySelector("html").outerHTML;
10445 removal.undo();
10446 $(base).remove();
10447 cb.call(elem, html);
10448 }, 0);
10449 }
10450 });
10451})(jQuery);
10452(function(jQuery) {
10453 "use strict";
10454
10455 var $ = jQuery;
10456
10457 var TAG_COLORS = [
10458 "#C60C46",
10459 "#00AEEF",
10460 "#F3739B",
10461 "#FF66FF",
10462 "#E66124",
10463 "#FFC328",
10464 "#B2E725",
10465 "#660066",
10466 "#FF9900"
10467 ];
10468
10469 var NUM_TAG_COLORS = TAG_COLORS.length;
10470
10471 var TAG_COLOR_MAP = {
10472 img: 0,
10473 p: 1,
10474 div: 2,
10475 a: 3,
10476 span: 4,
10477 body: 5,
10478 h1: 6,
10479 html: 7,
10480 footer: 8
10481 };
10482
10483 var DEFAULT_OVERLAY_OPACITY = 0.7;
10484
10485 function tagNameToNumber(tagName) {
10486 var total = 0;
10487 for (var i = 0; i < tagName.length; i++)
10488 total += tagName.charCodeAt(i);
10489 return total;
10490 }
10491
10492 jQuery.extend({
10493 // This is only really exported so unit tests can use it.
10494 NUM_TAG_COLORS: NUM_TAG_COLORS,
10495
10496 // Returns the color hex for the "official" Web X-Ray color
10497 // for the given tag name, excluding angled brackets.
10498 colorForTag: function colorForTag(tagName) {
10499 var colorNumber;
10500
10501 tagName = tagName.toLowerCase();
10502 if (tagName in TAG_COLOR_MAP)
10503 colorNumber = TAG_COLOR_MAP[tagName];
10504 else
10505 colorNumber = (tagNameToNumber(tagName) % NUM_TAG_COLORS);
10506
10507 return TAG_COLORS[colorNumber];
10508 }
10509 });
10510
10511 jQuery.fn.extend({
10512 // Applies the "official" Web X-Ray color for fromElement to
10513 // the current set of matched elements with the given
10514 // optional opacity. Returns the current set of matched
10515 // elements to support chaining.
10516 applyTagColor: function applyTagColor(fromElement, opacity) {
10517 var bgColor;
10518 var baseColor = $.colorForTag($(fromElement).get(0).nodeName);
10519
10520 if (opacity === undefined)
10521 opacity = DEFAULT_OVERLAY_OPACITY;
10522
10523 bgColor = $.makeRGBA(baseColor, opacity);
10524
10525 this.css({backgroundColor: bgColor});
10526 return this;
10527 },
10528 // Like $.overlay(), but applies the "official" Web X-Ray color
10529 // for the element type being overlaid, with the given opacity.
10530 // A default opacity is used if none is provided.
10531 overlayWithTagColor: function overlayWithTagColor(opacity) {
10532 return $(this).overlay().applyTagColor(this, opacity);
10533 }
10534 });
10535})(jQuery);
10536(function(jQuery) {
10537 "use strict";
10538
10539 jQuery.eventEmitter = function eventEmitter(object) {
10540 var handlers = {};
10541
10542 object.emit = function emit(event, data) {
10543 if (event in handlers)
10544 handlers[event].forEach(function(handler) {
10545 handler(data);
10546 });
10547 };
10548
10549 object.on = object.addListener = function on(event, handler) {
10550 if (!(event in handlers))
10551 handlers[event] = [];
10552 handlers[event].push(handler);
10553 };
10554
10555 object.removeListener = function removeListener(event, handler) {
10556 if (event in handlers) {
10557 var index = handlers[event].indexOf(handler);
10558 if (index != -1)
10559 handlers[event].splice(index, 1);
10560 }
10561 };
10562
10563 object.removeAllListeners = function removeAllListeners(type) {
10564 if (type in handlers)
10565 delete handlers[type];
10566 };
10567
10568 return object;
10569 };
10570})(jQuery);
10571(function(jQuery) {
10572 "use strict";
10573
10574 var $ = jQuery;
10575
10576 jQuery.focusedOverlay = function focusedOverlay(options) {
10577 if (!options)
10578 options = {};
10579
10580 var useAnimation = options.useAnimation;
10581 var ancestorIndex = 0;
10582 var ancestorOverlay = null;
10583 var overlay = null;
10584 var element = null;
10585
10586 function labelOverlay(overlay, target, finalSize) {
10587 var parts = ["top", "bottom"];
10588
10589 if ($(target).isVoidElement())
10590 parts = ["top"];
10591
10592 finalSize = finalSize || overlay;
10593 parts.forEach(function(className) {
10594 var part = $('<div class="webxray-base webxray-overlay-label">' +
10595 '</div>');
10596 var tag = target.nodeName.toLowerCase();
10597 part.addClass("webxray-overlay-label-" + className);
10598 part.text("<" + (className == "bottom" ? "/" : "") +
10599 tag + ">");
10600 overlay.append(part);
10601 if (part.width() > $(finalSize).width() ||
10602 part.height() > $(finalSize).height())
10603 part.hide();
10604 });
10605 }
10606
10607 function setAncestorOverlay(ancestor, useAnimation) {
10608 if (ancestorOverlay) {
10609 ancestorOverlay.remove();
10610 ancestorOverlay = null;
10611 }
10612 if (ancestor) {
10613 if (useAnimation) {
10614 var fromElement = instance.getPrimaryElement();
10615 ancestorOverlay = $(fromElement).overlay();
10616 ancestorOverlay.resizeTo(ancestor);
10617 } else
10618 ancestorOverlay = ancestor.overlay();
10619 ancestorOverlay.addClass("webxray-ancestor");
10620 labelOverlay(ancestorOverlay, ancestor[0], ancestor[0]);
10621 instance.ancestor = ancestor[0];
10622 } else {
10623 if (useAnimation && instance.ancestor) {
10624 ancestorOverlay = $(instance.ancestor).overlay();
10625 ancestorOverlay.addClass("webxray-ancestor");
10626 labelOverlay(ancestorOverlay, instance.element, instance.element);
10627 ancestorOverlay.resizeToAndFadeOut(instance.element);
10628 }
10629 instance.ancestor = null;
10630 }
10631 }
10632
10633 var instance = jQuery.eventEmitter({
10634 element: null,
10635 ancestor: null,
10636 getPrimaryElement: function getPrimaryElement() {
10637 return this.ancestor || this.element;
10638 },
10639 upfocus: function upfocus() {
10640 if (!element)
10641 return;
10642 var ancestor = $(element).ancestor(ancestorIndex + 1);
10643
10644 if (ancestor.length && ancestor[0] != document) {
10645 ancestorIndex++;
10646 setAncestorOverlay(ancestor, useAnimation);
10647 }
10648 this.emit('change', this);
10649 },
10650 downfocus: function downfocus() {
10651 if (!element)
10652 return;
10653 if (ancestorOverlay) {
10654 ancestorOverlay.remove();
10655 ancestorOverlay = null;
10656 }
10657 if (ancestorIndex > 0 && --ancestorIndex > 0) {
10658 var ancestor = $(element).ancestor(ancestorIndex);
10659 setAncestorOverlay(ancestor, useAnimation);
10660 } else
10661 setAncestorOverlay(null, useAnimation);
10662 this.emit('change', this);
10663 },
10664 unfocus: function unfocus() {
10665 if (!element)
10666 return;
10667 overlay.remove();
10668 overlay = null;
10669 element = this.element = null;
10670 setAncestorOverlay(null);
10671 ancestorIndex = 0;
10672 this.emit('change', this);
10673 },
10674 set: function set(newElement) {
10675 this.unfocus();
10676 element = this.element = newElement;
10677 overlay = $(element).overlayWithTagColor();
10678 labelOverlay(overlay, element);
10679 this.emit('change', this);
10680 },
10681 destroy: function destroy() {
10682 this.unfocus();
10683 this.removeAllListeners('change');
10684 }
10685 });
10686
10687 return instance;
10688 }
10689})(jQuery);
10690(function(jQuery) {
10691 "use strict";
10692
10693 var $ = jQuery;
10694 var MAX_URL_LENGTH = 35;
10695
10696 jQuery.hudOverlay = function hudOverlay(options) {
10697 if (options === undefined)
10698 options = {};
10699
10700 var hudContainer = $('<div class="webxray-base webxray-hud-box"></div>');
10701 var hud = $('<div class="webxray-base webxray-hud"></div>');
10702 var l10n = Localized.get;
10703
10704 hudContainer.append(hud);
10705
10706 function showDefaultContent() {
10707 hud.html(options.defaultContent || l10n("default-html"));
10708 }
10709
10710 showDefaultContent();
10711
10712 return {
10713 overlayContainer: hudContainer[0],
10714 overlay: hud[0],
10715 destroy: function destroy() {
10716 this.overlay = null;
10717 hudContainer.remove();
10718 hudContainer = null;
10719 hud = null;
10720 },
10721 onFocusChange: function handleEvent(focused) {
10722 function code(string) {
10723 return $("<code></code>").text(string);
10724 }
10725
10726 function elementInfo(element) {
10727 var info = {
10728 tagName: "<" + element.nodeName.toLowerCase() + ">",
10729 id: element.id,
10730 className: element.className,
10731 url: element.href || element.src || element.action ||
10732 element.currentSrc
10733 };
10734
10735 if (info.url && info.url.length)
10736 info.url = $.shortenText(info.url, MAX_URL_LENGTH);
10737 else
10738 info.url = null;
10739
10740 return info;
10741 }
10742
10743 function elementDesc(element) {
10744 var span = $("<span></span>");
10745 var info = elementInfo(element);
10746 var shortDescKey = "short-element-descriptions:" +
10747 element.nodeName.toLowerCase();
10748
10749 if (l10n(shortDescKey))
10750 span.emit(code(info.tagName),
10751 " (" + l10n(shortDescKey) + ") ",
10752 l10n("element"));
10753 else
10754 span.emit(code(info.tagName), " ", l10n("element"));
10755 if (info.id)
10756 span.emit(" ", l10n("with"), " ", l10n("id"), " ",
10757 code(info.id));
10758 if (info.className)
10759 span.emit(" " + (info.id ? l10n("and") : l10n("with")),
10760 " ", l10n("class"), " ",
10761 code(info.className));
10762 if (info.url) {
10763 span.emit((info.id || info.className) ? "," : "",
10764 " ", l10n("pointing-at"), " ",
10765 $('<span class="webxray-url"></span>').text(info.url));
10766 }
10767 return span;
10768 }
10769
10770 if (focused.element) {
10771 var span = $("<span></span>");
10772 span.emit(l10n("focused-intro"), " ",
10773 elementDesc(focused.element), ".");
10774 if (focused.ancestor)
10775 span.emit(" ", l10n("ancestor-intro"), " ",
10776 elementDesc(focused.ancestor), ".");
10777 hud.empty().append(span);
10778 } else
10779 showDefaultContent();
10780 }
10781 };
10782 };
10783})(jQuery);
10784(function(jQuery) {
10785 "use strict";
10786
10787 var $ = jQuery;
10788
10789 function getContentSize(content) {
10790 var staged = $('<div class="webxray-base"></div>');
10791 staged.append(content.clone());
10792 staged.css({float: 'left'});
10793 $(document.body).append(staged);
10794 var width = staged.width();
10795 staged.remove();
10796 return width;
10797 }
10798
10799 function onUserActivity(cb, bindTarget) {
10800 setTimeout(function() {
10801 var events = ['keydown', 'mousemove', 'touchstart'];
10802 function onEvent() {
10803 events.forEach(function(e) { $(bindTarget).unbind(e, onEvent); });
10804 cb();
10805 }
10806 events.forEach(function(e) { $(bindTarget).bind(e, onEvent); });
10807 }, jQuery.USER_ACTIVITY_DELAY);
10808 }
10809
10810 jQuery.extend({
10811 USER_ACTIVITY_DELAY: 100,
10812 transparentMessage: function(content, duration, cb, parent, bindTarget) {
10813 var div = $('<div class="webxray-base webxray-tmsg-overlay">' +
10814 '<div class="webxray-base webxray-tmsg-outer">' +
10815 '<div class="webxray-base webxray-tmsg-middle">' +
10816 '<div class="webxray-base webxray-tmsg-inner">' +
10817 '</div></div></div></div>');
10818
10819 var inner = div.find('.webxray-tmsg-inner');
10820 inner.append(content);
10821 inner.width(getContentSize(content));
10822 parent = parent || document.body;
10823 $(parent).append(div);
10824
10825 function remove() {
10826 div.fadeOut(function() {
10827 div.remove();
10828 if (cb)
10829 cb();
10830 });
10831 }
10832
10833 if (duration)
10834 setTimeout(remove, duration);
10835 else
10836 onUserActivity(remove, bindTarget || window);
10837
10838 return div;
10839 }
10840 });
10841})(jQuery);
10842(function(jQuery) {
10843 "use strict";
10844
10845 var $ = jQuery;
10846
10847 var DEFAULT_PROPERTIES = [
10848 "background-attachment",
10849 "background-clip",
10850 "background-color",
10851 "background-image",
10852 "background-origin",
10853 "background-position",
10854 "background-repeat",
10855 "background-size",
10856 "font-family",
10857 "font-size",
10858 "font-style",
10859 "font-variant",
10860 "font-weight",
10861 "height",
10862 "list-style-image",
10863 "list-style-position",
10864 "list-style-type",
10865 "min-height",
10866 "min-width",
10867 "text-align",
10868 "text-anchor",
10869 "text-decoration",
10870 "text-indent",
10871 "text-overflow",
10872 "text-rendering",
10873 "text-shadow",
10874 "text-transform",
10875 "top",
10876 "left",
10877 "bottom",
10878 "right",
10879 "color",
10880 "clear",
10881 "cursor",
10882 "direction",
10883 "display",
10884 "position",
10885 "float",
10886 "letter-spacing",
10887 "line-height",
10888 "opacity",
10889 "visibility",
10890 "white-space",
10891 "width",
10892 "vertical-align",
10893 "word-spacing",
10894 "word-wrap",
10895 "z-index"
10896 ].sort(),
10897 l10n = Localized.get;
10898
10899 DEFAULT_PROPERTIES.forEach(function(name) {
10900 if (name.match(/image$/))
10901 jQuery.cssHooks[jQuery.camelCase(name)] = {
10902 set: function(elem, value) {
10903 if (value != "none" && !value.match(/^\s*url\(.*\)/))
10904 return "url(" + value + ")";
10905 return value;
10906 }
10907 };
10908 });
10909
10910 function makeCssValueEditable(event) {
10911 var row = $(this);
10912 var widget = row.data("propertyWidget");
10913
10914 if (event.shiftKey) {
10915 open('https://developer.mozilla.org/en/CSS/' + widget.name, 'info');
10916 return;
10917 }
10918
10919 if (widget.isBeingEdited())
10920 return;
10921
10922 var nameCell = $(this).find('.webxray-name');
10923 var valueCell = $(this).find('.webxray-value');
10924 var originalValue = valueCell.text();
10925 var form = $('<form><input type="text"></input></form>');
10926 var textField = form.find("input");
10927
10928 valueCell.empty().append(form);
10929 textField.val(originalValue).select().focus();
10930
10931 // The -1 is needed on Firefox, or else the whole field will
10932 // wrap to the next line.
10933 textField.width(row.width() - nameCell.outerWidth() - 1);
10934
10935 function revertToOriginal() {
10936 form.remove();
10937 valueCell.text(originalValue);
10938 widget.clearPreview();
10939 }
10940
10941 function confirmChange() {
10942 var newValue = textField.val();
10943 revertToOriginal();
10944 widget.changeValue(newValue);
10945 }
10946
10947 textField.blur(confirmChange);
10948 textField.keydown(function(event) {
10949 if (event.keyCode == $.keys.ESC) {
10950 revertToOriginal();
10951 return false;
10952 }
10953 });
10954 textField.keyup(function(event) {
10955 widget.previewValue(textField.val());
10956 });
10957
10958 form.submit(function() {
10959 confirmChange();
10960 return false;
10961 });
10962 }
10963
10964 function buildPropertyWidget(element, row, style, parentStyle, name, hud) {
10965 var nameCell = $('<div class="webxray-name"></div>');
10966 var valueCell = $('<div class="webxray-value"></div>');
10967
10968 // Replace hyphens with non-breaking ones to keep
10969 // the presentation looking nice.
10970 nameCell.text(name.replace(/-/g, '\u2011'));
10971 row.append(nameCell);
10972 row.append(valueCell);
10973
10974 var lastPreviewValue = null;
10975
10976 var self = {
10977 name: name,
10978 getValue: function() {
10979 return valueCell.text();
10980 },
10981 isBeingEdited: function() {
10982 return (row.find('form').length != 0);
10983 },
10984 refresh: function() {
10985 var value = $.normalizeStyleProperty(style, name);
10986
10987 // TODO: It might be possible for us to return from this
10988 // function when in fact we need to change class information.
10989 // Need to think about this more.
10990 if (valueCell.text() == value)
10991 return;
10992
10993 valueCell.text(value);
10994 valueCell.attr("class", "webxray-value");
10995 if (parentStyle &&
10996 $.normalizeStyleProperty(parentStyle, name) != value)
10997 valueCell.addClass("webxray-value-different-from-parent");
10998 if ($.normalizeStyleProperty(element.style, name) == value)
10999 valueCell.addClass("webxray-value-matches-inline-style");
11000 if (name.match(/color$/)) {
11001 var colorBlock = $('<div class="webxray-color-block"></div>');
11002 colorBlock.css('background-color', value);
11003 valueCell.append(colorBlock);
11004 }
11005 },
11006 clearPreview: function() {
11007 if (lastPreviewValue !== null) {
11008 jQuery.style(element, name, lastPreviewValue);
11009 lastPreviewValue = null;
11010 }
11011 },
11012 previewValue: function(newValue) {
11013 self.clearPreview();
11014 lastPreviewValue = jQuery.style(element, name);
11015 jQuery.style(element, name, newValue);
11016 },
11017 changeValue: function(newValue) {
11018 var originalValue = valueCell.text();
11019 if (newValue != originalValue) {
11020 $(element).css(name, newValue);
11021 self.refresh();
11022 row.trigger('css-property-change');
11023 }
11024 }
11025 };
11026
11027 row.data("propertyWidget", self);
11028 row.mouseover(function() {
11029 if (l10n(name)) {
11030 var moreInfo = $('<span class="webxray-more-info"></span>')
11031 .text(l10n("more-info"));
11032 $(hud.overlay).html(l10n(name))
11033 .append(moreInfo)
11034 .find("a").css({textDecoration: "none"});
11035 }
11036 });
11037 self.refresh();
11038 }
11039
11040 function PrimaryTranslucentOverlay(overlay, primary) {
11041 var tOverlay = $(primary).overlayWithTagColor(0.2);
11042
11043 function onCssPropertyChange() {
11044 tOverlay.show();
11045 tOverlay.resizeTo(primary, function() {
11046 tOverlay.fadeOut();
11047 });
11048 }
11049
11050 overlay.bind('css-property-change', onCssPropertyChange);
11051 tOverlay.hide();
11052
11053 return {
11054 destroy: function() {
11055 overlay.unbind('css-property-change', onCssPropertyChange);
11056 tOverlay.remove();
11057 }
11058 };
11059 }
11060
11061 function ModalOverlay(overlay, primary, input) {
11062 var startStyle = $(primary).attr("style");
11063 var translucentOverlay = PrimaryTranslucentOverlay(overlay, primary);
11064
11065 function handleKeyDown(event) {
11066 if (self.isBeingEdited())
11067 return;
11068 switch (event.keyCode) {
11069 case $.keys.ESC:
11070 event.preventDefault();
11071 event.stopPropagation();
11072 self.close();
11073 break;
11074
11075 case $.keys.LEFT:
11076 case $.keys.RIGHT:
11077 input.handleEvent(event);
11078 if (primary.parentNode) {
11079 startStyle = $(primary).attr("style");
11080 overlay.show().find('.webxray-row').each(function() {
11081 $(this).data("propertyWidget").refresh();
11082 });
11083 } else {
11084 // Um, our target element is no longer attached to
11085 // the document. Just exit the style editing mode.
11086
11087 // TODO: Is this the most humane behavior?
11088 self.close();
11089 }
11090 break;
11091 }
11092 }
11093
11094 function recordChanges() {
11095 var endStyle = $(primary).attr("style");
11096 if (startStyle != endStyle) {
11097 if (typeof(startStyle) == 'undefined')
11098 $(primary).removeAttr("style")
11099 else
11100 $(primary).attr("style", startStyle);
11101 startStyle = endStyle;
11102 self.emit('change-style', endStyle);
11103 }
11104 }
11105
11106 overlay.addClass("webxray-style-info-locked");
11107 overlay.bind('css-property-change', recordChanges);
11108 overlay.find('.webxray-row').bind('click', makeCssValueEditable);
11109 window.addEventListener("keydown", handleKeyDown, true);
11110
11111 var self = jQuery.eventEmitter({
11112 isBeingEdited: function() {
11113 return (overlay.find('form').length != 0);
11114 },
11115 close: function() {
11116 overlay.removeClass("webxray-style-info-locked");
11117 overlay.unbind('css-property-change', recordChanges);
11118 overlay.find('.webxray-row').unbind('click', makeCssValueEditable);
11119 overlay.find('.webxray-close-button').unbind('click', self.close);
11120 window.removeEventListener("keydown", handleKeyDown, true);
11121 translucentOverlay.destroy();
11122 self.emit('close');
11123 }
11124 });
11125
11126 overlay.find('.webxray-close-button').bind('click', self.close);
11127
11128 return self;
11129 }
11130
11131 jQuery.extend({
11132 normalizeStyleProperty: function normalizeStyleProperty(style, name) {
11133 var value = style.getPropertyValue(name);
11134
11135 if (name.match(/image$/) && value) {
11136 var urlMatch = value.match(/url\("?([^"]*)"?\)/);
11137
11138 if (urlMatch)
11139 value = urlMatch[1];
11140 }
11141 return value;
11142 },
11143 styleInfoOverlay: function styleInfoOverlay(options) {
11144 var focused = options.focused;
11145 var commandManager = options.commandManager;
11146 var propertyNames = options.propertyNames;
11147 var mouseMonitor = options.mouseMonitor;
11148 var hud = options.hud;
11149 var body = options.body || document.body;
11150 var isVisible = false;
11151 var modalOverlay = null;
11152
11153 var overlay = $('<div class="webxray-base webxray-style-info"></div>');
11154 $(body).append(overlay);
11155 overlay.hide();
11156
11157 focused.on('change', refresh);
11158
11159 function refresh() {
11160 if (!isVisible || modalOverlay)
11161 return;
11162
11163 var primary = focused.getPrimaryElement();
11164 overlay.empty();
11165
11166 if (primary) {
11167 var info = $(primary).getStyleInfo(propertyNames, hud);
11168 var instructions = $('<div class="webxray-instructions"></div>');
11169 var close = $('<div class="webxray-close-button"></div>');
11170 instructions.html(l10n("tap-space-html"));
11171 close.text(l10n("dialog-common:ok"));
11172 overlay.append(info).append(instructions).append(close);
11173 overlay.show();
11174 } else {
11175 overlay.hide();
11176 }
11177 }
11178
11179 function isMouseInOverlay() {
11180 var mouse = mouseMonitor.lastPosition;
11181 var pos = overlay.offset();
11182 var width = overlay.width();
11183 var height = overlay.height();
11184 var xDiff = mouse.pageX - pos.left;
11185 var yDiff = mouse.pageY - pos.top;
11186 var isInOverlay = (xDiff > 0 && xDiff < width) &&
11187 (yDiff > 0 && yDiff < height);
11188
11189 return isInOverlay;
11190 }
11191
11192 function maybeSwitchSides() {
11193 if (isMouseInOverlay())
11194 overlay.toggleClass('webxray-on-other-side');
11195 // The overlay switched sides; now see if we're in the
11196 // overlay on the other side.
11197 if (isMouseInOverlay())
11198 // We're on the overlay on the other side too, so we're
11199 // just going to annoy the user if we switch its side.
11200 // So, we'll restore the overlay to its original position.
11201 overlay.toggleClass('webxray-on-other-side');
11202 }
11203
11204 var self = jQuery.eventEmitter({
11205 isVisible: function() {
11206 return isVisible;
11207 },
11208 isLocked: function() {
11209 return (modalOverlay !== null);
11210 },
11211 setPropertyNames: function(newPropertyNames) {
11212 propertyNames = newPropertyNames;
11213 },
11214 lock: function(input) {
11215 var primary = focused.getPrimaryElement();
11216
11217 if (primary) {
11218 input.deactivate();
11219 mouseMonitor.removeListener('move', maybeSwitchSides);
11220 modalOverlay = ModalOverlay(overlay, primary, input);
11221 modalOverlay.on('change-style', function(style) {
11222 commandManager.run("ChangeAttributeCmd", {
11223 name: l10n("style-change"),
11224 attribute: "style",
11225 value: style,
11226 element: primary
11227 });
11228 });
11229 modalOverlay.on('close', function() {
11230 modalOverlay = null;
11231 self.hide();
11232 input.activate();
11233 self.emit('unlock');
11234 });
11235 focused.unfocus();
11236 self.emit('lock', {
11237 element: primary
11238 });
11239 }
11240 },
11241 show: function() {
11242 isVisible = true;
11243 overlay.show();
11244 refresh();
11245 mouseMonitor.on('move', maybeSwitchSides);
11246 maybeSwitchSides();
11247 self.emit('show');
11248 },
11249 hide: function() {
11250 mouseMonitor.removeListener('move', maybeSwitchSides);
11251 isVisible = false;
11252 overlay.hide();
11253 self.emit('hide');
11254 },
11255 destroy: function() {
11256 if (modalOverlay)
11257 modalOverlay.close();
11258 focused.removeListener('change', refresh);
11259 overlay.remove();
11260 }
11261 });
11262
11263 return self;
11264 }
11265 });
11266
11267 jQuery.fn.extend({
11268 getStyleInfo: function getStyleInfo(propertyNames, hud) {
11269 var names = propertyNames || DEFAULT_PROPERTIES;
11270 var element = this.get(0);
11271 var window = element.ownerDocument.defaultView;
11272 var style = window.getComputedStyle(element);
11273 var parentStyle = null;
11274
11275 if (element.nodeName != "HTML")
11276 parentStyle = window.getComputedStyle(element.parentNode);
11277
11278 var info = $('<div class="webxray-rows"></div>');
11279 var NUM_COLS = 1;
11280
11281 for (var i = 0; i < names.length + (NUM_COLS-1); i += NUM_COLS) {
11282 var row = $('<div class="webxray-row"></div>');
11283 for (var j = 0; j < NUM_COLS; j++)
11284 buildPropertyWidget(element, row, style, parentStyle, names[i+j], hud);
11285 info.append(row);
11286 }
11287
11288 return info;
11289 }
11290 });
11291})(jQuery);
11292(function(jQuery) {
11293 "use strict";
11294
11295 var $ = jQuery;
11296
11297 var uprootableClass = "webxray-uprootable-element";
11298
11299 function NullTransitionEffectManager() {
11300 return {
11301 enableDuring: function enableDuring(fn) { fn(); }
11302 };
11303 }
11304
11305 function TransitionEffectManager(commandManager) {
11306 var isEnabled = false;
11307
11308 commandManager.on('command-created', function(cmd) {
11309 cmd.on('before-replace', function before(elementToReplace) {
11310 if (!isEnabled)
11311 return;
11312 var overlay = $(elementToReplace).overlay();
11313 cmd.on('after-replace', function after(newContent) {
11314 cmd.removeListener('after-replace', after);
11315 overlay.applyTagColor(newContent, 0.25)
11316 .resizeToAndFadeOut(newContent);
11317 });
11318 });
11319 });
11320
11321 return {
11322 enableDuring: function enableDuring(fn) {
11323 if (!isEnabled) {
11324 isEnabled = true;
11325 fn();
11326 isEnabled = false;
11327 } else
11328 fn();
11329 }
11330 };
11331 }
11332
11333 function MixMaster(options) {
11334 var hud = options.hud;
11335 var focused = options.focusedOverlay;
11336 var commandManager = options.commandManager;
11337 var l10n = Localized.get;
11338 var dialogPageMods = null;
11339 var transitionEffects;
11340
11341 if (options.disableTransitionEffects)
11342 transitionEffects = new NullTransitionEffectManager();
11343 else
11344 transitionEffects = new TransitionEffectManager(commandManager);
11345
11346 function updateStatus(verb, command) {
11347 var span = $('<span></span>');
11348 span.text(verb + ' ' + command.name + '.');
11349 $(hud.overlay).empty().append(span);
11350 }
11351
11352 function runCommand(name, options) {
11353 focused.unfocus();
11354 var command = commandManager.run(name, options);
11355 updateStatus(l10n('command-manager:executed'), command);
11356 }
11357
11358 var self = {
11359 undo: function() {
11360 if (commandManager.canUndo()) {
11361 focused.unfocus();
11362 transitionEffects.enableDuring(function() {
11363 updateStatus(l10n('command-manager:undid'),
11364 commandManager.undo());
11365 });
11366 } else {
11367 var msg = l10n('cannot-undo-html');
11368 $(hud.overlay).html(msg);
11369 }
11370 },
11371 redo: function() {
11372 if (commandManager.canRedo()) {
11373 focused.unfocus();
11374 transitionEffects.enableDuring(function() {
11375 updateStatus(l10n('command-manager:redid'),
11376 commandManager.redo());
11377 });
11378 } else {
11379 var msg = l10n('cannot-redo-html');
11380 $(hud.overlay).html(msg);
11381 }
11382 },
11383 htmlToJQuery: function htmlToJQuery(html) {
11384 if (html === '' || typeof(html) != 'string')
11385 return $('<span></span>');
11386 if (html[0] != '<')
11387 html = '<span>' + html + '</span>';
11388 return $(html);
11389 },
11390 deleteFocusedElement: function deleteFocusedElement() {
11391 var elementToDelete = focused.getPrimaryElement();
11392 if (elementToDelete) {
11393 if ($(elementToDelete).is('html, body')) {
11394 var msg = l10n('too-big-to-change');
11395 jQuery.transparentMessage($('<div></div>').text(msg));
11396 return;
11397 }
11398 // Replacing the element with a zero-length invisible
11399 // span is a lot easier than actually deleting the element,
11400 // since it allows us to place a "bookmark" in the DOM
11401 // that can easily be undone if the user wishes.
11402 var placeholder = $('<span class="webxray-deleted"></span>');
11403 transitionEffects.enableDuring(function() {
11404 runCommand("ReplaceWithCmd", {
11405 name: l10n('deletion'),
11406 elementToReplace: elementToDelete,
11407 newContent: placeholder
11408 });
11409 });
11410 }
11411 },
11412 infoForFocusedElement: function infoForFocusedElement(open) {
11413 var element = focused.getPrimaryElement();
11414 open = open || window.open;
11415 if (element) {
11416 var url = 'https://developer.mozilla.org/en/HTML/Element/' +
11417 element.nodeName.toLowerCase();
11418 open(url, 'info');
11419 }
11420 },
11421 replaceElement: function(originalElement, elementToReplace, html, saveState) {
11422 var newContent = self.htmlToJQuery(html);
11423
11424 // Use saveState to determine whether or not this action should be put on the
11425 // undo/redo stack.
11426 if (saveState) {
11427
11428 // To avoid tapping too far down the Command rabbit-hole, just put the
11429 // original element back, and apply new changes on top of it.
11430 $(elementToReplace).replaceWith(originalElement);
11431
11432 runCommand("ReplaceWithCmd", {
11433 name: l10n('replacement'),
11434 elementToReplace: originalElement,
11435 newContent: newContent
11436 });
11437 }
11438 else {
11439 $(elementToReplace).replaceWith(newContent);
11440 }
11441 return newContent;
11442 },
11443 setDialogPageMods: function(mods) {
11444 dialogPageMods = mods;
11445 },
11446 replaceFocusedElementWithDialog: function(options) {
11447 var input = options.input;
11448 var dialogURL = options.dialogURL;
11449 var sendFullDocument = options.sendFullDocument;
11450 var MAX_HTML_LENGTH = 5000;
11451 var focusedElement = focused.getPrimaryElement();
11452 if (!focusedElement)
11453 return;
11454
11455 // We need to remove any script tags in the element now, or else
11456 // we'll likely re-execute them.
11457 $(focusedElement).find("script").remove();
11458
11459 var focusedHTML = $(focusedElement).outerHtml();
11460
11461 if ($(focusedElement).is('html, body')) {
11462 var msg = l10n("too-big-to-change");
11463 jQuery.transparentMessage($('<div></div>').text(msg));
11464 return;
11465 }
11466
11467 if (focusedHTML.length === 0 ||
11468 focusedHTML.length > MAX_HTML_LENGTH) {
11469 var tagName = focusedElement.nodeName.toLowerCase();
11470 var nmsg = l10n("too-big-to-remix-html").replace("${tagName}",
11471 tagName);
11472 jQuery.transparentMessage($(nmsg));
11473 return;
11474 }
11475
11476 if (sendFullDocument) {
11477 $(focusedElement).addClass(uprootableClass);
11478 $(document).uprootIgnoringWebxray(function (html) {
11479 begin({
11480 html: html,
11481 selector: "."+uprootableClass
11482 });
11483 });
11484 } else {
11485 begin(focusedHTML);
11486 }
11487
11488 function begin(startHTML) {
11489 focused.unfocus();
11490
11491 var originalElement = focusedElement;
11492
11493 jQuery.morphElementIntoDialog({
11494 input: input,
11495 body: options.body,
11496 url: dialogURL,
11497 element: focusedElement,
11498 onLoad: function(dialog) {
11499 dialog.iframe.postMessage(JSON.stringify({
11500 startHTML: startHTML,
11501 mods: dialogPageMods,
11502 baseURI: document.location.href
11503 }), "*");
11504 dialog.iframe.fadeIn();
11505 dialog.iframe.bind("message", function onMessage(event, data) {
11506 try {
11507 data = JSON.parse(data);
11508
11509 if (data.msg === "ok") {
11510 // The dialog may have decided to replace all our spaces
11511 // with non-breaking ones, so we'll undo that.
11512 var html = data.endHTML.replace(/\u00a0/g, " ");
11513 var newContent = self.replaceElement(originalElement, focusedElement, html, data.finished);
11514 focusedElement = newContent[0];
11515
11516 if(data.finished) {
11517 newContent.addClass(uprootableClass);
11518 jQuery.morphDialogIntoElement({
11519 dialog: dialog,
11520 input: input,
11521 element: newContent,
11522 finished: data.finished,
11523 canceled: data.canceled,
11524 onDone: function() {
11525 newContent.reallyRemoveClass(uprootableClass);
11526 window.postMessage("goggles-edit-finished", "*");
11527 }
11528 });
11529 } else {
11530 window.postMessage("goggles-edit-start", "*");
11531 }
11532 } else {
11533 // TODO: Re-focus previously focused elements?
11534 $(focusedElement).reallyRemoveClass(uprootableClass);
11535 dialog.close();
11536 }
11537 } catch (e) {
11538 console.error("postmessage was not valid JSON");
11539 }
11540 });
11541 }
11542 });
11543 }
11544 }
11545 };
11546 return self;
11547 }
11548
11549 jQuery.extend({mixMaster: MixMaster});
11550})(jQuery);
11551(function(jQuery) {
11552 "use strict";
11553
11554 var $ = jQuery;
11555
11556 function CommandManager() {
11557 var undoStack = [];
11558 var redoStack = [];
11559
11560 function serializeCommand(cmd) {
11561 var state = cmd.serialize();
11562 state.__cmd__ = cmd.registeredName;
11563 return state;
11564 }
11565
11566 function createCommand(name, options) {
11567 var constructor = registry[name];
11568 var command = constructor(options);
11569 command.registeredName = name;
11570 self.emit('command-created', command);
11571 return command;
11572 }
11573
11574 function deserializeCommand(state) {
11575 // The fallback here is just for backwards compatibility
11576 // with old-style serializations.
11577 var name = state.__cmd__ || "ReplaceWithCmd";
11578 return createCommand(name, {state: state});
11579 }
11580
11581 var registry = {};
11582
11583 var self = jQuery.eventEmitter({
11584 register: function(constructor, name) {
11585 registry[name] = constructor;
11586 },
11587 run: function(name, options) {
11588 var command = createCommand(name, options);
11589 undoStack.push(command);
11590 redoStack.splice(0);
11591 command.execute();
11592 self.emit('state-change');
11593 return command;
11594 },
11595 canUndo: function() {
11596 return (undoStack.length > 0);
11597 },
11598 canRedo: function() {
11599 return (redoStack.length > 0);
11600 },
11601 undo: function() {
11602 var command = undoStack.pop();
11603 redoStack.push(command);
11604 command.undo();
11605 self.emit('state-change');
11606 return command;
11607 },
11608 redo: function() {
11609 var command = redoStack.pop();
11610 undoStack.push(command);
11611 command.execute();
11612 self.emit('state-change');
11613 return command;
11614 },
11615 getRecording: function() {
11616 var recording = [];
11617 var timesUndone = 0;
11618 while (undoStack.length) {
11619 var cmd = undoStack[undoStack.length - 1];
11620 self.undo();
11621 recording.splice(0, 0, serializeCommand(cmd));
11622 timesUndone++;
11623 }
11624 for (var i = 0; i < timesUndone; i++)
11625 self.redo();
11626 return JSON.stringify(recording);
11627 },
11628 playRecording: function(recording) {
11629 recording = JSON.parse(recording);
11630 undoStack.splice(0);
11631 redoStack.splice(0);
11632 for (var i = 0; i < recording.length; i++) {
11633 var cmd = deserializeCommand(recording[i]);
11634 undoStack.push(cmd);
11635 cmd.execute();
11636 }
11637 },
11638 serializeUndoStack: function() {
11639 var commands = [];
11640 var timesUndone = 0;
11641 while (undoStack.length) {
11642 var cmd = undoStack[undoStack.length - 1];
11643 commands.push(serializeCommand(cmd));
11644 self.undo();
11645 timesUndone++;
11646 }
11647 for (var i = 0; i < timesUndone; i++)
11648 self.redo();
11649 return JSON.stringify(commands);
11650 },
11651 deserializeUndoStack: function(commands) {
11652 commands = JSON.parse(commands);
11653 undoStack.splice(0);
11654 redoStack.splice(0);
11655 for (var i = 0; i < commands.length; i++) {
11656 var cmd = deserializeCommand(commands[i]);
11657 undoStack.push(cmd);
11658 self.undo();
11659 }
11660 for (var i = 0; i < commands.length; i++)
11661 self.redo();
11662 }
11663 });
11664
11665 self.register(ReplaceWithCmd, "ReplaceWithCmd");
11666 self.register(ChangeAttributeCmd, "ChangeAttributeCmd");
11667
11668 return self;
11669 }
11670
11671 function ChangeAttributeCmd(options) {
11672 var name = options.name,
11673 element = options.element,
11674 attribute = options.attribute,
11675 value = options.value;
11676
11677 function deserialize(state) {
11678 name = state.name;
11679 attribute = state.attribute;
11680 value = state.value;
11681 element = $(document.documentElement).find(state.selector);
11682 }
11683
11684 if (options.state)
11685 deserialize(options.state);
11686
11687 function applyValue() {
11688 this.emit('before-replace', element);
11689 var oldValue = $(element).attr(attribute);
11690 if (typeof(value) == 'undefined')
11691 $(element).removeAttr(attribute);
11692 else
11693 $(element).attr(attribute, value);
11694 value = oldValue;
11695 this.emit('after-replace', element);
11696 }
11697
11698 return jQuery.eventEmitter({
11699 name: name,
11700 execute: applyValue,
11701 undo: applyValue,
11702 serialize: function() {
11703 var selector = $(document.documentElement).pathTo(element);
11704
11705 return {
11706 name: name,
11707 selector: selector,
11708 attribute: attribute,
11709 value: value
11710 };
11711 }
11712 });
11713 }
11714
11715 function ReplaceWithCmd(options) {
11716 var name = options.name,
11717 elementToReplace = options.elementToReplace,
11718 newContent = options.newContent,
11719 isExecuted = false;
11720
11721 function deserialize(state) {
11722 if (typeof(state.isExecuted) == 'undefined')
11723 isExecuted = true; // support legacy serializations
11724 else
11725 isExecuted = state.isExecuted;
11726 name = state.name;
11727 if (isExecuted) {
11728 newContent = $(document.documentElement).find(state.selector);
11729 elementToReplace = $(state.html);
11730 if (newContent.length != 1)
11731 throw new Error("selector '" + state.selector + "' matches " +
11732 newContent.length + " elements");
11733 } else {
11734 newContent = $(state.html);
11735 elementToReplace = $(document.documentElement).find(state.selector);
11736 if (elementToReplace.length != 1)
11737 throw new Error("selector '" + state.selector + "' matches " +
11738 elementToReplace.length + " elements");
11739 }
11740 }
11741
11742 if (options.state)
11743 deserialize(options.state);
11744
11745 return jQuery.eventEmitter({
11746 name: name,
11747 execute: function() {
11748 if (isExecuted)
11749 throw new Error("command already executed");
11750 this.emit('before-replace', elementToReplace);
11751 $(elementToReplace).replaceWith(newContent);
11752 this.emit('after-replace', newContent);
11753 isExecuted = true;
11754 },
11755 undo: function() {
11756 if (!isExecuted)
11757 throw new Error("command not yet executed");
11758 this.emit('before-replace', newContent);
11759 $(newContent).replaceWith(elementToReplace);
11760 this.emit('after-replace', elementToReplace);
11761 isExecuted = false;
11762 },
11763 serialize: function() {
11764 var selector;
11765 var html;
11766 if (isExecuted) {
11767 selector = $(document.documentElement).pathTo(newContent);
11768 html = $(elementToReplace).outerHtml();
11769 } else {
11770 selector = $(document.documentElement).pathTo(elementToReplace);
11771 html = $(newContent).outerHtml();
11772 }
11773 return {
11774 isExecuted: isExecuted,
11775 name: name,
11776 selector: selector,
11777 html: html
11778 };
11779 }
11780 });
11781 }
11782
11783 jQuery.extend({commandManager: CommandManager});
11784})(jQuery);
11785(function(jQuery) {
11786 "use strict";
11787
11788 var $ = jQuery;
11789
11790 jQuery.extend({
11791 commandManagerPersistence: function CMPersistence(commandManager) {
11792 return {
11793 saveHistoryToDOM: function saveHistoryToDOM() {
11794 // this history isn't used by our interface, as we do cannot
11795 // "load" goggles publications after the fact
11796 $('#webxray-serialized-history-v1').remove();
11797 },
11798 loadHistoryFromDOM: function loadHistoryFromDOM() {
11799 // see above
11800 $('#webxray-serialized-history-v1').remove();
11801 }
11802 };
11803 }
11804 });
11805})(jQuery);
11806(function(jQuery) {
11807 "use strict";
11808
11809 var $ = jQuery;
11810
11811 jQuery.fn.extend({
11812 postMessage: function(message, targetOrigin) {
11813 if ((jQuery.browser.mozilla && typeof(self) == "object" &&
11814 self.port && self.port.emit) ||
11815 (typeof(chrome) == "object" && chrome.extension)) {
11816 // We're most likely in a Jetpack, and need to work around
11817 // bug 666547. Or, we're in a Chrome extension and are
11818 // stymied by http://stackoverflow.com/q/4062879.
11819
11820 if (!this.attr("id"))
11821 // Likelyhood of a naming collision here is very low,
11822 // and it's only a temporary workaround anyways.
11823 this.attr("id", "webxray-iframe-" + Math.random());
11824
11825 var script = document.createElement("script");
11826
11827 script.text = "(" + (function(id, message) {
11828 var iframe = document.getElementById(id);
11829 iframe.contentWindow.postMessage(message, "*");
11830 }).toString() + ")(" + JSON.stringify(this.attr("id")) + ", " +
11831 JSON.stringify(message) + ");";
11832
11833 document.body.appendChild(script);
11834 document.body.removeChild(script);
11835 } else
11836 this[0].contentWindow.postMessage(message, targetOrigin);
11837 }
11838 });
11839
11840 jQuery.extend({
11841 getModalDialogDimensions: function() {
11842 var div = $('<div class="webxray-base webxray-dialog-overlay">' +
11843 '<div class="webxray-base webxray-dialog-outer">' +
11844 '<div class="webxray-base webxray-dialog-middle">' +
11845 '<div class="webxray-base webxray-dialog-inner">' +
11846 '<div class="webxray-base webxray-dialog-content">' +
11847 '</div></div></div></div></div>');
11848 $(document.body).append(div);
11849
11850 var content = div.find('.webxray-dialog-content');
11851 var pos = content.offset();
11852 var dimensions = {
11853 top: pos.top,
11854 left: pos.left,
11855 width: content.outerWidth(),
11856 height: content.outerHeight()
11857 };
11858
11859 div.remove();
11860 return dimensions;
11861 },
11862 simpleModalDialog: function(options) {
11863 var dialog = jQuery.modalDialog({
11864 input: options.input,
11865 url: options.url,
11866 classes: options.classes
11867 });
11868 dialog.iframe.one("load", function() {
11869 $(this).postMessage(options.payload, "*");
11870 $(this).show().bind("message", function(event, data) {
11871 if (data == "close")
11872 dialog.close();
11873 });
11874 });
11875 return dialog;
11876 },
11877 modalDialog: function(options) {
11878 var input = options.input;
11879 var body = options.body || document.body;
11880 var url = options.url;
11881 var classes = options.classes ? " " + options.classes : '';
11882 var div = $('<div class="webxray-base webxray-dialog-overlay">' +
11883 '<div class="webxray-base webxray-dialog-outer">' +
11884 '<div class="webxray-base webxray-dialog-middle">' +
11885 '<div class="webxray-base webxray-dialog-inner">' +
11886 '<iframe class="webxray-base'+classes+'" src="' + url + '"></iframe>' +
11887 '</div></div></div></div>');
11888 var iframe = div.find("iframe");
11889
11890 function onMessage(event) {
11891 if (event.source == self.iframe.get(0).contentWindow) {
11892 iframe.trigger("message", [event.data]);
11893 }
11894 }
11895
11896 window.addEventListener("message", onMessage, false);
11897 iframe.hide();
11898
11899 var self = {
11900 iframe: iframe,
11901 close: function close(cb) {
11902 div.fadeOut(function() {
11903 window.removeEventListener("message", onMessage, false);
11904 div.remove();
11905 div = null;
11906
11907 // Firefox seems to trigger a mouseout/mouseover event
11908 // when we remove the dialog div, so we'll wait a moment
11909 // before re-activating input so that we don't distract
11910 // the user by focusing on whatever their mouse happens
11911 // to be over when the dialog closes.
11912 setTimeout(function() {
11913 input.activate();
11914 input = null;
11915 window.focus();
11916 if (cb)
11917 cb();
11918 }, 50);
11919 });
11920 }
11921 };
11922
11923 input.deactivate();
11924 $(body).append(div);
11925
11926 return self;
11927 },
11928 morphElementIntoDialog: function(options) {
11929 var input = options.input;
11930 var element = options.element;
11931 var body = options.body || document.body;
11932 var url = options.url;
11933 var overlay = $(element).overlayWithTagColor(1.0);
11934 var backdrop = $('<div class="webxray-base webxray-dialog-overlay">' +
11935 '</div>');
11936
11937 document.body.classList.add("webxray-padded");
11938
11939 // Closing the dialog we make later will re-activate this for us.
11940 input.deactivate();
11941
11942 $(body).append(backdrop);
11943 overlay.addClass('webxray-topmost');
11944 overlay.animate(jQuery.getModalDialogDimensions(), function() {
11945 var dialog = jQuery.modalDialog({
11946 input: input,
11947 body: body,
11948 url: url
11949 });
11950
11951 backdrop.remove();
11952
11953 dialog.iframe.one("load", function onLoad() {
11954 overlay.fadeOut(function() {
11955 overlay.remove();
11956 options.onLoad(dialog);
11957 });
11958 });
11959 });
11960 },
11961 morphDialogIntoElement: function(options) {
11962 var element = options.element;
11963 var dialog = options.dialog;
11964 var input = options.input;
11965 var finished = options.finished;
11966 var canceled = options.canceled;
11967 var overlay = dialog.iframe.overlay();
11968
11969 document.body.classList.remove("webxray-padded");
11970
11971 overlay.applyTagColor(element, 1.0);
11972 overlay.hide();
11973 overlay.fadeIn(function() {
11974 dialog.close(function() {
11975 // input was just re-activated when the dialog closed, but
11976 // we want to deactivate it again because we're not actually
11977 // done with our transition.
11978 input.deactivate();
11979 overlay.resizeTo(element, function() {
11980 $(this).fadeOut(function() {
11981 $(this).remove();
11982 input.activate();
11983 if(finished && !canceled) {
11984 document.dispatchEvent(new CustomEvent("webxray-element-modified"))
11985 }
11986 });
11987 options.onDone();
11988 });
11989 });
11990 });
11991 }
11992 });
11993})(jQuery);
11994
11995(function(jQuery) {
11996 "use strict";
11997
11998 var $ = jQuery;
11999
12000 var keys = {
12001 DELETE: 8,
12002 LEFT: 37,
12003 UP: 38,
12004 RIGHT: 39,
12005 DOWN: 40,
12006 ESC: 27,
12007 SPACE: 32
12008 };
12009
12010 var alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
12011
12012 for (var i = 0; i < alphabet.length; i++)
12013 keys[alphabet[i]] = alphabet.charCodeAt(i);
12014
12015 function isValidFocusTarget(target) {
12016 if ($(target).hasClass('webxray-base')) {
12017 return false;
12018 }
12019 while(target) {
12020 if ($(target).hasClass('webxray-msg-dialog')) {
12021 return false;
12022 }
12023 target = target.parentNode;
12024 }
12025 return true;
12026 }
12027
12028 // This function attempts to compensate for a browser's lack of support
12029 // for the 'pointer-events' CSS feature.
12030 var maybePassThroughEvent = (function() {
12031 function topmostNoPointerEvents(element) {
12032 var topmost = null;
12033 while (element &&
12034 getComputedStyle(element).pointerEvents == 'none') {
12035 topmost = element;
12036 element = element.parentNode;
12037 }
12038 return topmost;
12039 }
12040
12041 // Annoying that we have to do browser detection here, but unfortunately
12042 // we can't simply test for support of the 'pointer-events' CSS feature,
12043 // as Opera and IE9 support it but only for SVG.
12044 if (jQuery.browser.opera || jQuery.browser.msie){
12045 return function(event) {
12046 if (topmostNoPointerEvents(event.relatedTarget))
12047 return null;
12048
12049 var target = topmostNoPointerEvents(event.target);
12050
12051 if (target) {
12052 $(target).hide();
12053 event = {
12054 target: document.elementFromPoint(event.clientX, event.clientY)
12055 };
12056 $(target).show();
12057 }
12058 return event;
12059 };
12060 }
12061 else
12062 return function(event) { return event; };
12063 })();
12064
12065 function styleOverlayInputHandlers(options) {
12066 var styleInfo = options.styleInfoOverlay;
12067 var quasimodeKeycode = keys[options.quasimodeKey];
12068 var lockForEditingKeycode = keys[options.lockForEditingKey];
12069 var isQuasimodeActive = false;
12070
12071 return {
12072 keyup: function(event) {
12073 if (event.keyCode == quasimodeKeycode) {
12074 isQuasimodeActive = false;
12075 styleInfo.hide();
12076 return true;
12077 }
12078 return false;
12079 },
12080 keydown: function(event) {
12081 if (event.altKey || event.ctrlKey ||
12082 event.altGraphKey || event.metaKey) {
12083 return false;
12084 }
12085
12086 switch (event.keyCode) {
12087 case lockForEditingKeycode:
12088 if (isQuasimodeActive) {
12089 isQuasimodeActive = false;
12090 styleInfo.lock(this);
12091 }
12092 return true;
12093
12094 case quasimodeKeycode:
12095 if (!isQuasimodeActive) {
12096 isQuasimodeActive = true;
12097 styleInfo.show();
12098 }
12099 return true;
12100 }
12101 return false;
12102 }
12103 };
12104 }
12105
12106 function touchInputHandlers(focused) {
12107 var lastTouch = null;
12108
12109 function onTouchMove(event) {
12110 var touches = event.changedTouches;
12111 var touch = touches[0];
12112 var element = document.elementFromPoint(touch.clientX,
12113 touch.clientY);
12114
12115 if (element == lastTouch)
12116 return false;
12117 lastTouch = element;
12118
12119 if (!isValidFocusTarget(element))
12120 return false;
12121
12122 if (isValidFocusTarget(element))
12123 focused.set(element);
12124 }
12125
12126 return {
12127 touchstart: onTouchMove,
12128 touchmove: onTouchMove,
12129 touchend: function(event) {
12130 lastTouch = null;
12131 }
12132 };
12133 }
12134
12135 jQuery.extend({
12136 keys: keys,
12137 mouseMonitor: function mouseMonitor() {
12138 function onMouseMove(event) {
12139 self.lastPosition.pageX = event.pageX;
12140 self.lastPosition.pageY = event.pageY;
12141 self.emit('move', self);
12142 }
12143 $(document).mousemove(onMouseMove);
12144
12145 var self = jQuery.eventEmitter({
12146 lastPosition: {
12147 pageX: 0,
12148 pageY: 0
12149 },
12150 unload: function() {
12151 $(document).unbind('mousemove', onMouseMove);
12152 self.removeAllListeners();
12153 }
12154 });
12155
12156 return self;
12157 },
12158 inputHandlerChain: function inputHandlerChain(eventTypes, eventSource) {
12159 var handlerChains = {};
12160 var listeners = {};
12161
12162 /*jshint validthis: true */
12163 function eventListener(event) {
12164 for (var i = 0; i < handlerChains[event.type].length; i++) {
12165 if (handlerChains[event.type][i].call(this, event)) {
12166 event.preventDefault();
12167 event.stopPropagation();
12168 return;
12169 }
12170 }
12171 }
12172
12173 eventTypes.forEach(function(eventName) {
12174 handlerChains[eventName] = [];
12175 listeners[eventName] = eventListener;
12176 });
12177
12178 var self = jQuery.inputManager(listeners, eventSource).extend({
12179 add: function(handlers) {
12180 for (var name in handlers)
12181 handlerChains[name].push(handlers[name]);
12182 }
12183 });
12184
12185 return self;
12186 },
12187 inputManager: function inputManager(listeners, eventSource) {
12188 var isActive = false;
12189
12190 var self = jQuery.eventEmitter({
12191 extend: jQuery.extend,
12192 handleEvent: function handleEvent(event) {
12193 if (event.type in listeners)
12194 listeners[event.type].call(self, event);
12195 else
12196 throw new Error("Unexpected event type: " + event.type);
12197 },
12198 activate: function() {
12199 // We're listening during the capture phase to intercept
12200 // any events at the earliest point before they're
12201 // handled by the page itself. Because JQuery's bind() doesn't
12202 // appear to allow for listening during the capture phase,
12203 // we're using document.addEventListener() directly.
12204 if (!isActive) {
12205 isActive = true;
12206 for (var name in listeners)
12207 eventSource.addEventListener(name, self.handleEvent, true);
12208 self.emit('activate');
12209 }
12210 },
12211 deactivate: function() {
12212 if (isActive) {
12213 isActive = false;
12214 for (var name in listeners)
12215 eventSource.removeEventListener(name, self.handleEvent, true);
12216 self.emit('deactivate');
12217 }
12218 }
12219 });
12220
12221 return self;
12222 },
12223 simpleKeyBindings: function simpleKeyBindings() {
12224 var bindings = {};
12225 return {
12226 set: function(keycodes) {
12227 for (var keycode in keycodes) {
12228 if (!(keycode in keys))
12229 throw new Error('unknown key: ' + keycode);
12230 bindings[keys[keycode]] = keycodes[keycode];
12231 }
12232 },
12233 handlers: {
12234 keydown: function(event) {
12235 if (event.altKey || event.ctrlKey ||
12236 event.altGraphKey || event.metaKey)
12237 return false;
12238
12239 if (typeof(bindings[event.keyCode]) == 'function') {
12240 bindings[event.keyCode].call(this, event);
12241 return true;
12242 }
12243 return false;
12244 }
12245 }
12246 };
12247 },
12248 xRayInput: function xRayInput(options) {
12249 var focused = options.focusedOverlay;
12250 var mixMaster = options.mixMaster;
12251 var commandManager = options.commandManager;
12252 var eventSource = options.eventSource;
12253 var onQuit = options.onQuit;
12254 var persistence = options.persistence;
12255 var styleInfo = options.styleInfoOverlay;
12256 var touchesReceived = false;
12257 var self = jQuery.inputHandlerChain([
12258 'keydown',
12259 'keyup',
12260 'click',
12261 'mouseout',
12262 'mouseover',
12263 'touchstart',
12264 'touchmove',
12265 'touchend'
12266 ], eventSource);
12267
12268 self.add({
12269 click: function(event) {
12270 if (isValidFocusTarget(event.target)) {
12271 self.commandBindings.remix.execute();
12272 return true;
12273 }
12274 },
12275 touchmove: function(event) {
12276 touchesReceived = true;
12277 return false;
12278 },
12279 mouseout: function(event) {
12280 if (touchesReceived)
12281 // We're likely on a tablet, so this is probably a simulated
12282 // mouse event that we want to ignore.
12283 return false;
12284 if ((event = maybePassThroughEvent(event)) === null)
12285 return false;
12286
12287 if (isValidFocusTarget(event.target)) {
12288 focused.unfocus();
12289 return true;
12290 }
12291 },
12292 mouseover: function(event) {
12293 if (touchesReceived)
12294 // We're likely on a tablet, so this is probably a simulated
12295 // mouse event that we want to ignore.
12296 return false;
12297 if ((event = maybePassThroughEvent(event)) === null)
12298 return false;
12299
12300 if (isValidFocusTarget(event.target)) {
12301 focused.set(event.target);
12302 return true;
12303 }
12304 }
12305 });
12306
12307 self.extend({
12308 simpleKeyBindings: jQuery.simpleKeyBindings(),
12309 keyboardHelp: [],
12310 commandBindings: {},
12311 showKeyboardHelp: function() {
12312 jQuery.simpleModalDialog({
12313 input: self,
12314 url: jQuery.webxraySettings.url("helpDialogURL"),
12315 classes: "webxray-publish-dialog"
12316 });
12317 },
12318 addSimpleKeyBindings: function(bindings) {
12319 bindings.forEach(function(binding) {
12320 if (binding.cmd) {
12321 self.keyboardHelp.push(binding);
12322 self.commandBindings[binding.cmd] = binding;
12323 }
12324 if (binding.execute) {
12325 var simpleBinding = {};
12326 simpleBinding[binding.key] = binding.execute;
12327 self.simpleKeyBindings.set(simpleBinding);
12328 }
12329 });
12330 }
12331 });
12332
12333 self.addSimpleKeyBindings([
12334 {
12335 key: 'P',
12336 cmd: 'uproot',
12337 alwaysInToolbar: true,
12338 execute: function() {
12339 persistence.saveHistoryToDOM();
12340 jQuery.openUprootDialog(self);
12341 }
12342 },
12343 {
12344 key: 'ESC',
12345 cmd: 'quit',
12346 alwaysInToolbar: true,
12347 execute: function() {
12348 if (onQuit) onQuit();
12349 }
12350 },
12351 {
12352 key: 'LEFT',
12353 cmd: 'undo',
12354 alwaysInToolbar: true,
12355 execute: function() { mixMaster.undo(); }
12356 },
12357 {
12358 key: 'RIGHT',
12359 cmd: 'redo',
12360 alwaysInToolbar: true,
12361 execute: function() { mixMaster.redo(); }
12362 },
12363 {
12364 key: 'H',
12365 cmd: 'help',
12366 alwaysInToolbar: true,
12367 execute: function() {
12368 self.showKeyboardHelp();
12369 }
12370 },
12371 {
12372 key: 'R',
12373 cmd: 'remix',
12374 execute: function() {
12375 mixMaster.replaceFocusedElementWithDialog({
12376 input: self,
12377 dialogURL: jQuery.webxraySettings.url("easyRemixDialogURL"),
12378 sendFullDocument: true
12379 });
12380 }
12381 },
12382 {
12383 key: 'C',
12384 cmd: 'css-quasimode'
12385 },
12386 {
12387 key: 'DELETE',
12388 cmd: 'remove',
12389 execute: function() {
12390 mixMaster.deleteFocusedElement();
12391 }
12392 },
12393 {
12394 key: 'UP',
12395 cmd: 'dom-ascend',
12396 execute: function() { focused.upfocus(); }
12397 },
12398 {
12399 key: 'DOWN',
12400 cmd: 'dom-descend',
12401 execute: function() {
12402 focused.downfocus();
12403 }
12404 },
12405 {
12406 key: 'I',
12407 execute: function() {
12408 mixMaster.infoForFocusedElement();
12409 }
12410 }
12411 ]);
12412
12413 self.add(self.simpleKeyBindings.handlers);
12414 self.add(touchInputHandlers(focused));
12415 self.add(styleOverlayInputHandlers({
12416 styleInfoOverlay: styleInfo,
12417 lockForEditingKey: 'SPACE',
12418 quasimodeKey: 'C'
12419 }));
12420
12421 return self;
12422 }
12423 });
12424})(jQuery);
12425(function(jQuery) {
12426 "use strict";
12427
12428 var $ = jQuery;
12429
12430 function canBeTouched() {
12431 return ('ontouchstart' in window);
12432 }
12433
12434 function makeButton(glyph, text, cb) {
12435 var button = $(
12436 '<div class="webxray-toolbar-button">' +
12437 '<div class="webxray-toolbar-button-glyph"></div>' +
12438 '<div class="webxray-toolbar-button-text"></div>' +
12439 '</div>'
12440 );
12441 button.addClass("glyph-"+glyph);
12442 var glyphDiv = $('.webxray-toolbar-button-glyph', button);
12443 glyphDiv.text(glyph);
12444 if (glyph.length != 1)
12445 glyphDiv.addClass('webxray-toolbar-button-glyph-tiny');
12446 $('.webxray-toolbar-button-text', button).text(text);
12447 button.find('*').andSelf().addClass('webxray-base');
12448 button.bind('touchstart touchmove click', function(event) {
12449 event.preventDefault();
12450 cb.call(this);
12451 });
12452 return button;
12453 }
12454
12455 jQuery.extend({
12456 touchToolbar: function(input, locale, platform) {
12457 locale = locale || jQuery.locale;
12458 platform = platform || navigator.platform;
12459
12460 var toolbar = $('<div class="webxray-base webxray-toolbar"></div>');
12461
12462 input.keyboardHelp.forEach(function(binding) {
12463 if (binding.execute && (canBeTouched() || binding.alwaysInToolbar))
12464 makeButton(jQuery.nameForKey(binding.key, locale, platform),
12465 Localized.get("short-command-descriptions:" + binding.cmd), function() {
12466 binding.execute();
12467 }).appendTo(toolbar);
12468 });
12469
12470 toolbar.appendTo(document.body);
12471
12472 input.on('activate', function() { toolbar.fadeIn(); });
12473 input.on('deactivate', function() { toolbar.fadeOut(); });
12474
12475 return {
12476 unload: function() {
12477 toolbar.remove();
12478 toolbar = null;
12479 }
12480 };
12481 }
12482 });
12483})(jQuery);
12484(function(jQuery) {
12485 "use strict";
12486
12487 var $ = jQuery;
12488
12489 jQuery.extend({
12490 blurIndicator: function(input, focusable, body) {
12491 body = body || document.body;
12492
12493 function showBlurIndicator() {
12494 var blurIndicator = $('<div class="webxray-base ' +
12495 'webxray-dialog-overlay"></div>');
12496 $(body).append(blurIndicator);
12497 $(focusable).one('focus', function() {
12498 // If we wait a moment before removing the indicator, it'll receive
12499 // any click events instead of elements underneath it. We can
12500 // safely assume that any click events made immediately after
12501 // focus are really just intended to focus the page rather
12502 // than click on a specific element, so we want to swallow
12503 // such events rather than e.g. take the user to a new page.
12504 setTimeout(function() {
12505 blurIndicator.remove();
12506 blurIndicator = null;
12507 }, 10);
12508 input.activate();
12509 });
12510 input.deactivate();
12511 }
12512
12513 input.on('activate', function() {
12514 $(focusable).bind('blur', showBlurIndicator);
12515 });
12516 input.on('deactivate', function() {
12517 $(focusable).unbind('blur', showBlurIndicator);
12518 });
12519 }
12520 });
12521})(jQuery);
12522(function(jQuery) {
12523 "use strict";
12524
12525 var $ = jQuery;
12526
12527 function addHelpButton(hud, input) {
12528 var help = $('<div class="webxray-base webxray-help">?</div>');
12529 help.click(input.showKeyboardHelp);
12530 $(hud.overlayContainer).append(help);
12531 }
12532
12533 // If the user has made changes to the page, we don't want them
12534 // to be able to navigate away from it without facing a modal
12535 // dialog.
12536 function ModalUnloadBlocker(commandManager) {
12537 function beforeUnload(event) {
12538 if (commandManager.canUndo()) {
12539 event.preventDefault();
12540 return Localized.get("unload-blocked");
12541 }
12542 }
12543
12544 window.addEventListener("beforeunload", beforeUnload, true);
12545
12546 return {
12547 unload: function() {
12548 window.removeEventListener("beforeunload", beforeUnload, true);
12549 }
12550 };
12551 }
12552
12553 jQuery.extend({
12554 xRayUI: function xRayUI(options) {
12555 var isUnloaded = false;
12556 var hud = jQuery.hudOverlay();
12557 var focused = jQuery.focusedOverlay({
12558 useAnimation: true
12559 });
12560 var commandManager = jQuery.commandManager();
12561 var mixMaster = jQuery.mixMaster({
12562 hud: hud,
12563 focusedOverlay: focused,
12564 commandManager: commandManager
12565 });
12566 var persistence = jQuery.commandManagerPersistence(commandManager);
12567 var mouseMonitor = jQuery.mouseMonitor();
12568 var styleInfo = jQuery.styleInfoOverlay({
12569 focused: focused,
12570 commandManager: commandManager,
12571 mouseMonitor: mouseMonitor,
12572 hud: hud
12573 });
12574 var input = jQuery.xRayInput({
12575 focusedOverlay: focused,
12576 styleInfoOverlay: styleInfo,
12577 mixMaster: mixMaster,
12578 commandManager: commandManager,
12579 persistence: persistence,
12580 eventSource: options.eventSource,
12581 onQuit: function() {
12582 self.emit('quit');
12583 }
12584 });
12585 var touchToolbar = jQuery.touchToolbar(input);
12586 var indicator = jQuery.blurIndicator(input, window);
12587 var modalUnloadBlocker = new ModalUnloadBlocker(commandManager);
12588
12589 var self = jQuery.eventEmitter({
12590 persistence: persistence,
12591 start: function() {
12592 persistence.loadHistoryFromDOM();
12593 addHelpButton(hud, input);
12594 $(document.body).append(hud.overlayContainer);
12595 focused.on('change', hud.onFocusChange);
12596 input.activate();
12597 $(window).focus();
12598 window.parent.postMessage("goggles-start", "*");
12599 },
12600 unload: function() {
12601 if (!isUnloaded) {
12602 isUnloaded = true;
12603 focused.destroy();
12604 focused = null;
12605 input.deactivate();
12606 input = null;
12607 touchToolbar.unload();
12608 touchToolbar = null;
12609 hud.destroy();
12610 hud = null;
12611 styleInfo.destroy();
12612 styleInfo = null;
12613 indicator = null;
12614 mouseMonitor.unload();
12615 mouseMonitor = null;
12616 modalUnloadBlocker.unload();
12617 modalUnloadBlocker = null;
12618 window.parent.postMessage("goggles-end", "*");
12619 }
12620 },
12621
12622 // These exports are primarily for use by third-party code.
12623 jQuery: jQuery,
12624 focusedOverlay: focused,
12625 hudOverlay: hud,
12626 mixMaster: mixMaster,
12627 styleInfoOverlay: styleInfo,
12628 commandManager: commandManager,
12629 input: input,
12630 modalUnloadBlocker: modalUnloadBlocker
12631 });
12632
12633 return self;
12634 }
12635 });
12636})(jQuery);(function(jQuery) {
12637 "use strict";
12638
12639 var $ = jQuery;
12640 var removeOnUnload = $();
12641
12642 function getMyScript() {
12643 return $('script.webxray, script[src$="webxray.js"]');
12644 }
12645
12646 // If the goggles are already active on this page, just exit.
12647 if ($("#webxray-is-active").length) {
12648 getMyScript().remove();
12649 return;
12650 }
12651
12652 function waitForCSSToLoad() {
12653 // Sadly, link elements don't fire load events on most/all browsers,
12654 // so we'll define a special style in our stylesheet and keep
12655 // polling an element with that style until it has what we've
12656 // defined in the stylesheet.
12657 var div = $('<div id="webxray-wait-for-css-to-load"></div>');
12658 var deferred = jQuery.Deferred();
12659
12660 div.hide();
12661 $(document.body).append(div);
12662
12663 function checkIfLoaded() {
12664 // This works on most browsers.
12665 var content = div.css('content');
12666
12667 // This works on Safari.
12668 var bgColor = div.css('background-color');
12669
12670 if ((content && content.match(/CSS\ is\ loaded/)) ||
12671 (bgColor && bgColor.match(/rgb\(0,\s*1,\s*2\)/))) {
12672 div.remove();
12673 clearInterval(intervalID);
12674 deferred.resolve();
12675 }
12676 }
12677
12678 var intervalID = setInterval(checkIfLoaded, 10);
12679 checkIfLoaded();
12680 return deferred;
12681 }
12682
12683 function waitForPreferencesToLoad() {
12684 var deferred = jQuery.Deferred();
12685
12686 var iframe = document.createElement('iframe');
12687 iframe.src = jQuery.webxraySettings.url('preferencesURL');
12688 $(document.body).append(iframe);
12689 $(iframe).hide();
12690 window.addEventListener('message', function onMessage(event) {
12691 if (event.source == iframe.contentWindow) {
12692 window.removeEventListener('message', onMessage, false);
12693 $(iframe).remove();
12694 try {
12695 var prefs = JSON.parse(event.data);
12696 jQuery.webxraySettings.extend(prefs);
12697 } catch (e) {
12698 jQuery.warn("loading preferences failed");
12699 jQuery.warn("preference data is", event.data);
12700 jQuery.warn("exception thrown is", e);
12701 }
12702 deferred.resolve();
12703 }
12704 }, false);
12705 return deferred;
12706 }
12707
12708 function loadPrerequisites(cb) {
12709 var script = getMyScript();
12710
12711 if (jQuery.webxraySettings.baseURI.length == 0) {
12712 var baseURI = script.attr("src").match(/(.*)webxray\.js$/)[1];
12713 jQuery.webxraySettings.baseURI = baseURI;
12714 }
12715
12716 var cssURL = jQuery.webxraySettings.url("cssURL");
12717 var cssLink = $('link[href="' + cssURL + '"]');
12718 var active = $('<div id="webxray-is-active"></div>');
12719
12720 script.remove();
12721 active.hide();
12722 $(document.body).append(active);
12723
12724 // This is a test to see if we're using legacy bookmarklet code,
12725 // which inserts the link tag itself.
12726 if (cssLink.length == 0) {
12727 cssLink = $('<link rel="stylesheet" class="webxray"></link>');
12728 $(document.head).append(cssLink.attr("href", cssURL));
12729 }
12730
12731 removeOnUnload = removeOnUnload.add([cssLink.get(0), active.get(0)]);
12732
12733 var cssLoaded = waitForCSSToLoad();
12734 var prefsLoaded = waitForPreferencesToLoad();
12735
12736 jQuery.when(prefsLoaded, cssLoaded).done(cb);
12737 }
12738
12739 function loadPlugins(cb) {
12740 var pluginsToLoad = [];
12741
12742 jQuery.webxraySettings.url("pluginURLs").forEach(function(plugin) {
12743 pluginsToLoad.push(jQuery.loadScript(plugin));
12744 });
12745 jQuery.when.apply(jQuery.when, pluginsToLoad).done(cb);
12746 }
12747
12748 jQuery.extend({webxrayBuildMetadata: buildMetadata});
12749
12750 Localized.ready({url: xray.url}, function() {
12751 if (window.console && console.log) {
12752 console.log("Initializing Web X-Ray Goggles built on " +
12753 buildMetadata.date + " (commit " +
12754 buildMetadata.commit + ").");
12755 }
12756
12757 loadPrerequisites(function() {
12758 var ui = jQuery.xRayUI({eventSource: document});
12759 window.webxrayUI = ui;
12760 loadPlugins(function() {
12761 var welcomeMsg = $("<div></div>");
12762 welcomeMsg.html(Localized.get("default-html"));
12763 jQuery.transparentMessage(welcomeMsg);
12764
12765 ui.start();
12766 Webxray.triggerWhenLoaded(ui);
12767 ui.on('quit', function() {
12768 ui.persistence.saveHistoryToDOM();
12769 $(document).trigger('unload');
12770 delete window.webxrayUI;
12771 });
12772 $(document).unload(function() {
12773 ui.unload();
12774 removeOnUnload.remove();
12775 });
12776 });
12777 });
12778 });
12779})(jQuery);
12780// Make sure we don't conflict in any way with our parent window.
12781jQuery.noConflict(true);
12782})(window);