PageRenderTime 132ms CodeModel.GetById 2ms RepoModel.GetById 1ms app.codeStats 3ms

/lib/infusion/MyInfusion.js

https://bitbucket.org/cindyli/decapod-0.7-ui-iteration3
JavaScript | 15897 lines | 11361 code | 2225 blank | 2311 comment | 2751 complexity | a7d596364914612aa7a0c2b292b87087 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, Apache-2.0, LGPL-2.0
  1. /*!
  2. * jQuery JavaScript Library v1.7.2
  3. * http://jquery.com/
  4. *
  5. * Copyright 2011, John Resig
  6. * Dual licensed under the MIT or GPL Version 2 licenses.
  7. * http://jquery.org/license
  8. *
  9. * Includes Sizzle.js
  10. * http://sizzlejs.com/
  11. * Copyright 2011, The Dojo Foundation
  12. * Released under the MIT, BSD, and GPL Licenses.
  13. *
  14. * Date: Wed Mar 21 12:46:34 2012 -0700
  15. */
  16. (function( window, undefined ) {
  17. // Use the correct document accordingly with window argument (sandbox)
  18. var document = window.document,
  19. navigator = window.navigator,
  20. location = window.location;
  21. var jQuery = (function() {
  22. // Define a local copy of jQuery
  23. var jQuery = function( selector, context ) {
  24. // The jQuery object is actually just the init constructor 'enhanced'
  25. return new jQuery.fn.init( selector, context, rootjQuery );
  26. },
  27. // Map over jQuery in case of overwrite
  28. _jQuery = window.jQuery,
  29. // Map over the $ in case of overwrite
  30. _$ = window.$,
  31. // A central reference to the root jQuery(document)
  32. rootjQuery,
  33. // A simple way to check for HTML strings or ID strings
  34. // Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
  35. quickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,
  36. // Check if a string has a non-whitespace character in it
  37. rnotwhite = /\S/,
  38. // Used for trimming whitespace
  39. trimLeft = /^\s+/,
  40. trimRight = /\s+$/,
  41. // Match a standalone tag
  42. rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/,
  43. // JSON RegExp
  44. rvalidchars = /^[\],:{}\s]*$/,
  45. rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,
  46. rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,
  47. rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g,
  48. // Useragent RegExp
  49. rwebkit = /(webkit)[ \/]([\w.]+)/,
  50. ropera = /(opera)(?:.*version)?[ \/]([\w.]+)/,
  51. rmsie = /(msie) ([\w.]+)/,
  52. rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/,
  53. // Matches dashed string for camelizing
  54. rdashAlpha = /-([a-z]|[0-9])/ig,
  55. rmsPrefix = /^-ms-/,
  56. // Used by jQuery.camelCase as callback to replace()
  57. fcamelCase = function( all, letter ) {
  58. return ( letter + "" ).toUpperCase();
  59. },
  60. // Keep a UserAgent string for use with jQuery.browser
  61. userAgent = navigator.userAgent,
  62. // For matching the engine and version of the browser
  63. browserMatch,
  64. // The deferred used on DOM ready
  65. readyList,
  66. // The ready event handler
  67. DOMContentLoaded,
  68. // Save a reference to some core methods
  69. toString = Object.prototype.toString,
  70. hasOwn = Object.prototype.hasOwnProperty,
  71. push = Array.prototype.push,
  72. slice = Array.prototype.slice,
  73. trim = String.prototype.trim,
  74. indexOf = Array.prototype.indexOf,
  75. // [[Class]] -> type pairs
  76. class2type = {};
  77. jQuery.fn = jQuery.prototype = {
  78. constructor: jQuery,
  79. init: function( selector, context, rootjQuery ) {
  80. var match, elem, ret, doc;
  81. // Handle $(""), $(null), or $(undefined)
  82. if ( !selector ) {
  83. return this;
  84. }
  85. // Handle $(DOMElement)
  86. if ( selector.nodeType ) {
  87. this.context = this[0] = selector;
  88. this.length = 1;
  89. return this;
  90. }
  91. // The body element only exists once, optimize finding it
  92. if ( selector === "body" && !context && document.body ) {
  93. this.context = document;
  94. this[0] = document.body;
  95. this.selector = selector;
  96. this.length = 1;
  97. return this;
  98. }
  99. // Handle HTML strings
  100. if ( typeof selector === "string" ) {
  101. // Are we dealing with HTML string or an ID?
  102. if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
  103. // Assume that strings that start and end with <> are HTML and skip the regex check
  104. match = [ null, selector, null ];
  105. } else {
  106. match = quickExpr.exec( selector );
  107. }
  108. // Verify a match, and that no context was specified for #id
  109. if ( match && (match[1] || !context) ) {
  110. // HANDLE: $(html) -> $(array)
  111. if ( match[1] ) {
  112. context = context instanceof jQuery ? context[0] : context;
  113. doc = ( context ? context.ownerDocument || context : document );
  114. // If a single string is passed in and it's a single tag
  115. // just do a createElement and skip the rest
  116. ret = rsingleTag.exec( selector );
  117. if ( ret ) {
  118. if ( jQuery.isPlainObject( context ) ) {
  119. selector = [ document.createElement( ret[1] ) ];
  120. jQuery.fn.attr.call( selector, context, true );
  121. } else {
  122. selector = [ doc.createElement( ret[1] ) ];
  123. }
  124. } else {
  125. ret = jQuery.buildFragment( [ match[1] ], [ doc ] );
  126. selector = ( ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment ).childNodes;
  127. }
  128. return jQuery.merge( this, selector );
  129. // HANDLE: $("#id")
  130. } else {
  131. elem = document.getElementById( match[2] );
  132. // Check parentNode to catch when Blackberry 4.6 returns
  133. // nodes that are no longer in the document #6963
  134. if ( elem && elem.parentNode ) {
  135. // Handle the case where IE and Opera return items
  136. // by name instead of ID
  137. if ( elem.id !== match[2] ) {
  138. return rootjQuery.find( selector );
  139. }
  140. // Otherwise, we inject the element directly into the jQuery object
  141. this.length = 1;
  142. this[0] = elem;
  143. }
  144. this.context = document;
  145. this.selector = selector;
  146. return this;
  147. }
  148. // HANDLE: $(expr, $(...))
  149. } else if ( !context || context.jquery ) {
  150. return ( context || rootjQuery ).find( selector );
  151. // HANDLE: $(expr, context)
  152. // (which is just equivalent to: $(context).find(expr)
  153. } else {
  154. return this.constructor( context ).find( selector );
  155. }
  156. // HANDLE: $(function)
  157. // Shortcut for document ready
  158. } else if ( jQuery.isFunction( selector ) ) {
  159. return rootjQuery.ready( selector );
  160. }
  161. if ( selector.selector !== undefined ) {
  162. this.selector = selector.selector;
  163. this.context = selector.context;
  164. }
  165. return jQuery.makeArray( selector, this );
  166. },
  167. // Start with an empty selector
  168. selector: "",
  169. // The current version of jQuery being used
  170. jquery: "1.7.2",
  171. // The default length of a jQuery object is 0
  172. length: 0,
  173. // The number of elements contained in the matched element set
  174. size: function() {
  175. return this.length;
  176. },
  177. toArray: function() {
  178. return slice.call( this, 0 );
  179. },
  180. // Get the Nth element in the matched element set OR
  181. // Get the whole matched element set as a clean array
  182. get: function( num ) {
  183. return num == null ?
  184. // Return a 'clean' array
  185. this.toArray() :
  186. // Return just the object
  187. ( num < 0 ? this[ this.length + num ] : this[ num ] );
  188. },
  189. // Take an array of elements and push it onto the stack
  190. // (returning the new matched element set)
  191. pushStack: function( elems, name, selector ) {
  192. // Build a new jQuery matched element set
  193. var ret = this.constructor();
  194. if ( jQuery.isArray( elems ) ) {
  195. push.apply( ret, elems );
  196. } else {
  197. jQuery.merge( ret, elems );
  198. }
  199. // Add the old object onto the stack (as a reference)
  200. ret.prevObject = this;
  201. ret.context = this.context;
  202. if ( name === "find" ) {
  203. ret.selector = this.selector + ( this.selector ? " " : "" ) + selector;
  204. } else if ( name ) {
  205. ret.selector = this.selector + "." + name + "(" + selector + ")";
  206. }
  207. // Return the newly-formed element set
  208. return ret;
  209. },
  210. // Execute a callback for every element in the matched set.
  211. // (You can seed the arguments with an array of args, but this is
  212. // only used internally.)
  213. each: function( callback, args ) {
  214. return jQuery.each( this, callback, args );
  215. },
  216. ready: function( fn ) {
  217. // Attach the listeners
  218. jQuery.bindReady();
  219. // Add the callback
  220. readyList.add( fn );
  221. return this;
  222. },
  223. eq: function( i ) {
  224. i = +i;
  225. return i === -1 ?
  226. this.slice( i ) :
  227. this.slice( i, i + 1 );
  228. },
  229. first: function() {
  230. return this.eq( 0 );
  231. },
  232. last: function() {
  233. return this.eq( -1 );
  234. },
  235. slice: function() {
  236. return this.pushStack( slice.apply( this, arguments ),
  237. "slice", slice.call(arguments).join(",") );
  238. },
  239. map: function( callback ) {
  240. return this.pushStack( jQuery.map(this, function( elem, i ) {
  241. return callback.call( elem, i, elem );
  242. }));
  243. },
  244. end: function() {
  245. return this.prevObject || this.constructor(null);
  246. },
  247. // For internal use only.
  248. // Behaves like an Array's method, not like a jQuery method.
  249. push: push,
  250. sort: [].sort,
  251. splice: [].splice
  252. };
  253. // Give the init function the jQuery prototype for later instantiation
  254. jQuery.fn.init.prototype = jQuery.fn;
  255. jQuery.extend = jQuery.fn.extend = function() {
  256. var options, name, src, copy, copyIsArray, clone,
  257. target = arguments[0] || {},
  258. i = 1,
  259. length = arguments.length,
  260. deep = false;
  261. // Handle a deep copy situation
  262. if ( typeof target === "boolean" ) {
  263. deep = target;
  264. target = arguments[1] || {};
  265. // skip the boolean and the target
  266. i = 2;
  267. }
  268. // Handle case when target is a string or something (possible in deep copy)
  269. if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
  270. target = {};
  271. }
  272. // extend jQuery itself if only one argument is passed
  273. if ( length === i ) {
  274. target = this;
  275. --i;
  276. }
  277. for ( ; i < length; i++ ) {
  278. // Only deal with non-null/undefined values
  279. if ( (options = arguments[ i ]) != null ) {
  280. // Extend the base object
  281. for ( name in options ) {
  282. src = target[ name ];
  283. copy = options[ name ];
  284. // Prevent never-ending loop
  285. if ( target === copy ) {
  286. continue;
  287. }
  288. // Recurse if we're merging plain objects or arrays
  289. if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
  290. if ( copyIsArray ) {
  291. copyIsArray = false;
  292. clone = src && jQuery.isArray(src) ? src : [];
  293. } else {
  294. clone = src && jQuery.isPlainObject(src) ? src : {};
  295. }
  296. // Never move original objects, clone them
  297. target[ name ] = jQuery.extend( deep, clone, copy );
  298. // Don't bring in undefined values
  299. } else if ( copy !== undefined ) {
  300. target[ name ] = copy;
  301. }
  302. }
  303. }
  304. }
  305. // Return the modified object
  306. return target;
  307. };
  308. jQuery.extend({
  309. noConflict: function( deep ) {
  310. if ( window.$ === jQuery ) {
  311. window.$ = _$;
  312. }
  313. if ( deep && window.jQuery === jQuery ) {
  314. window.jQuery = _jQuery;
  315. }
  316. return jQuery;
  317. },
  318. // Is the DOM ready to be used? Set to true once it occurs.
  319. isReady: false,
  320. // A counter to track how many items to wait for before
  321. // the ready event fires. See #6781
  322. readyWait: 1,
  323. // Hold (or release) the ready event
  324. holdReady: function( hold ) {
  325. if ( hold ) {
  326. jQuery.readyWait++;
  327. } else {
  328. jQuery.ready( true );
  329. }
  330. },
  331. // Handle when the DOM is ready
  332. ready: function( wait ) {
  333. // Either a released hold or an DOMready/load event and not yet ready
  334. if ( (wait === true && !--jQuery.readyWait) || (wait !== true && !jQuery.isReady) ) {
  335. // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
  336. if ( !document.body ) {
  337. return setTimeout( jQuery.ready, 1 );
  338. }
  339. // Remember that the DOM is ready
  340. jQuery.isReady = true;
  341. // If a normal DOM Ready event fired, decrement, and wait if need be
  342. if ( wait !== true && --jQuery.readyWait > 0 ) {
  343. return;
  344. }
  345. // If there are functions bound, to execute
  346. readyList.fireWith( document, [ jQuery ] );
  347. // Trigger any bound ready events
  348. if ( jQuery.fn.trigger ) {
  349. jQuery( document ).trigger( "ready" ).off( "ready" );
  350. }
  351. }
  352. },
  353. bindReady: function() {
  354. if ( readyList ) {
  355. return;
  356. }
  357. readyList = jQuery.Callbacks( "once memory" );
  358. // Catch cases where $(document).ready() is called after the
  359. // browser event has already occurred.
  360. if ( document.readyState === "complete" ) {
  361. // Handle it asynchronously to allow scripts the opportunity to delay ready
  362. return setTimeout( jQuery.ready, 1 );
  363. }
  364. // Mozilla, Opera and webkit nightlies currently support this event
  365. if ( document.addEventListener ) {
  366. // Use the handy event callback
  367. document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
  368. // A fallback to window.onload, that will always work
  369. window.addEventListener( "load", jQuery.ready, false );
  370. // If IE event model is used
  371. } else if ( document.attachEvent ) {
  372. // ensure firing before onload,
  373. // maybe late but safe also for iframes
  374. document.attachEvent( "onreadystatechange", DOMContentLoaded );
  375. // A fallback to window.onload, that will always work
  376. window.attachEvent( "onload", jQuery.ready );
  377. // If IE and not a frame
  378. // continually check to see if the document is ready
  379. var toplevel = false;
  380. try {
  381. toplevel = window.frameElement == null;
  382. } catch(e) {}
  383. if ( document.documentElement.doScroll && toplevel ) {
  384. doScrollCheck();
  385. }
  386. }
  387. },
  388. // See test/unit/core.js for details concerning isFunction.
  389. // Since version 1.3, DOM methods and functions like alert
  390. // aren't supported. They return false on IE (#2968).
  391. isFunction: function( obj ) {
  392. return jQuery.type(obj) === "function";
  393. },
  394. isArray: Array.isArray || function( obj ) {
  395. return jQuery.type(obj) === "array";
  396. },
  397. isWindow: function( obj ) {
  398. return obj != null && obj == obj.window;
  399. },
  400. isNumeric: function( obj ) {
  401. return !isNaN( parseFloat(obj) ) && isFinite( obj );
  402. },
  403. type: function( obj ) {
  404. return obj == null ?
  405. String( obj ) :
  406. class2type[ toString.call(obj) ] || "object";
  407. },
  408. isPlainObject: function( obj ) {
  409. // Must be an Object.
  410. // Because of IE, we also have to check the presence of the constructor property.
  411. // Make sure that DOM nodes and window objects don't pass through, as well
  412. if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
  413. return false;
  414. }
  415. try {
  416. // Not own constructor property must be Object
  417. if ( obj.constructor &&
  418. !hasOwn.call(obj, "constructor") &&
  419. !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
  420. return false;
  421. }
  422. } catch ( e ) {
  423. // IE8,9 Will throw exceptions on certain host objects #9897
  424. return false;
  425. }
  426. // Own properties are enumerated firstly, so to speed up,
  427. // if last one is own, then all properties are own.
  428. var key;
  429. for ( key in obj ) {}
  430. return key === undefined || hasOwn.call( obj, key );
  431. },
  432. isEmptyObject: function( obj ) {
  433. for ( var name in obj ) {
  434. return false;
  435. }
  436. return true;
  437. },
  438. error: function( msg ) {
  439. throw new Error( msg );
  440. },
  441. parseJSON: function( data ) {
  442. if ( typeof data !== "string" || !data ) {
  443. return null;
  444. }
  445. // Make sure leading/trailing whitespace is removed (IE can't handle it)
  446. data = jQuery.trim( data );
  447. // Attempt to parse using the native JSON parser first
  448. if ( window.JSON && window.JSON.parse ) {
  449. return window.JSON.parse( data );
  450. }
  451. // Make sure the incoming data is actual JSON
  452. // Logic borrowed from http://json.org/json2.js
  453. if ( rvalidchars.test( data.replace( rvalidescape, "@" )
  454. .replace( rvalidtokens, "]" )
  455. .replace( rvalidbraces, "")) ) {
  456. return ( new Function( "return " + data ) )();
  457. }
  458. jQuery.error( "Invalid JSON: " + data );
  459. },
  460. // Cross-browser xml parsing
  461. parseXML: function( data ) {
  462. if ( typeof data !== "string" || !data ) {
  463. return null;
  464. }
  465. var xml, tmp;
  466. try {
  467. if ( window.DOMParser ) { // Standard
  468. tmp = new DOMParser();
  469. xml = tmp.parseFromString( data , "text/xml" );
  470. } else { // IE
  471. xml = new ActiveXObject( "Microsoft.XMLDOM" );
  472. xml.async = "false";
  473. xml.loadXML( data );
  474. }
  475. } catch( e ) {
  476. xml = undefined;
  477. }
  478. if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) {
  479. jQuery.error( "Invalid XML: " + data );
  480. }
  481. return xml;
  482. },
  483. noop: function() {},
  484. // Evaluates a script in a global context
  485. // Workarounds based on findings by Jim Driscoll
  486. // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context
  487. globalEval: function( data ) {
  488. if ( data && rnotwhite.test( data ) ) {
  489. // We use execScript on Internet Explorer
  490. // We use an anonymous function so that context is window
  491. // rather than jQuery in Firefox
  492. ( window.execScript || function( data ) {
  493. window[ "eval" ].call( window, data );
  494. } )( data );
  495. }
  496. },
  497. // Convert dashed to camelCase; used by the css and data modules
  498. // Microsoft forgot to hump their vendor prefix (#9572)
  499. camelCase: function( string ) {
  500. return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
  501. },
  502. nodeName: function( elem, name ) {
  503. return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase();
  504. },
  505. // args is for internal usage only
  506. each: function( object, callback, args ) {
  507. var name, i = 0,
  508. length = object.length,
  509. isObj = length === undefined || jQuery.isFunction( object );
  510. if ( args ) {
  511. if ( isObj ) {
  512. for ( name in object ) {
  513. if ( callback.apply( object[ name ], args ) === false ) {
  514. break;
  515. }
  516. }
  517. } else {
  518. for ( ; i < length; ) {
  519. if ( callback.apply( object[ i++ ], args ) === false ) {
  520. break;
  521. }
  522. }
  523. }
  524. // A special, fast, case for the most common use of each
  525. } else {
  526. if ( isObj ) {
  527. for ( name in object ) {
  528. if ( callback.call( object[ name ], name, object[ name ] ) === false ) {
  529. break;
  530. }
  531. }
  532. } else {
  533. for ( ; i < length; ) {
  534. if ( callback.call( object[ i ], i, object[ i++ ] ) === false ) {
  535. break;
  536. }
  537. }
  538. }
  539. }
  540. return object;
  541. },
  542. // Use native String.trim function wherever possible
  543. trim: trim ?
  544. function( text ) {
  545. return text == null ?
  546. "" :
  547. trim.call( text );
  548. } :
  549. // Otherwise use our own trimming functionality
  550. function( text ) {
  551. return text == null ?
  552. "" :
  553. text.toString().replace( trimLeft, "" ).replace( trimRight, "" );
  554. },
  555. // results is for internal usage only
  556. makeArray: function( array, results ) {
  557. var ret = results || [];
  558. if ( array != null ) {
  559. // The window, strings (and functions) also have 'length'
  560. // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930
  561. var type = jQuery.type( array );
  562. if ( array.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( array ) ) {
  563. push.call( ret, array );
  564. } else {
  565. jQuery.merge( ret, array );
  566. }
  567. }
  568. return ret;
  569. },
  570. inArray: function( elem, array, i ) {
  571. var len;
  572. if ( array ) {
  573. if ( indexOf ) {
  574. return indexOf.call( array, elem, i );
  575. }
  576. len = array.length;
  577. i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0;
  578. for ( ; i < len; i++ ) {
  579. // Skip accessing in sparse arrays
  580. if ( i in array && array[ i ] === elem ) {
  581. return i;
  582. }
  583. }
  584. }
  585. return -1;
  586. },
  587. merge: function( first, second ) {
  588. var i = first.length,
  589. j = 0;
  590. if ( typeof second.length === "number" ) {
  591. for ( var l = second.length; j < l; j++ ) {
  592. first[ i++ ] = second[ j ];
  593. }
  594. } else {
  595. while ( second[j] !== undefined ) {
  596. first[ i++ ] = second[ j++ ];
  597. }
  598. }
  599. first.length = i;
  600. return first;
  601. },
  602. grep: function( elems, callback, inv ) {
  603. var ret = [], retVal;
  604. inv = !!inv;
  605. // Go through the array, only saving the items
  606. // that pass the validator function
  607. for ( var i = 0, length = elems.length; i < length; i++ ) {
  608. retVal = !!callback( elems[ i ], i );
  609. if ( inv !== retVal ) {
  610. ret.push( elems[ i ] );
  611. }
  612. }
  613. return ret;
  614. },
  615. // arg is for internal usage only
  616. map: function( elems, callback, arg ) {
  617. var value, key, ret = [],
  618. i = 0,
  619. length = elems.length,
  620. // jquery objects are treated as arrays
  621. isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ;
  622. // Go through the array, translating each of the items to their
  623. if ( isArray ) {
  624. for ( ; i < length; i++ ) {
  625. value = callback( elems[ i ], i, arg );
  626. if ( value != null ) {
  627. ret[ ret.length ] = value;
  628. }
  629. }
  630. // Go through every key on the object,
  631. } else {
  632. for ( key in elems ) {
  633. value = callback( elems[ key ], key, arg );
  634. if ( value != null ) {
  635. ret[ ret.length ] = value;
  636. }
  637. }
  638. }
  639. // Flatten any nested arrays
  640. return ret.concat.apply( [], ret );
  641. },
  642. // A global GUID counter for objects
  643. guid: 1,
  644. // Bind a function to a context, optionally partially applying any
  645. // arguments.
  646. proxy: function( fn, context ) {
  647. if ( typeof context === "string" ) {
  648. var tmp = fn[ context ];
  649. context = fn;
  650. fn = tmp;
  651. }
  652. // Quick check to determine if target is callable, in the spec
  653. // this throws a TypeError, but we will just return undefined.
  654. if ( !jQuery.isFunction( fn ) ) {
  655. return undefined;
  656. }
  657. // Simulated bind
  658. var args = slice.call( arguments, 2 ),
  659. proxy = function() {
  660. return fn.apply( context, args.concat( slice.call( arguments ) ) );
  661. };
  662. // Set the guid of unique handler to the same of original handler, so it can be removed
  663. proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++;
  664. return proxy;
  665. },
  666. // Mutifunctional method to get and set values to a collection
  667. // The value/s can optionally be executed if it's a function
  668. access: function( elems, fn, key, value, chainable, emptyGet, pass ) {
  669. var exec,
  670. bulk = key == null,
  671. i = 0,
  672. length = elems.length;
  673. // Sets many values
  674. if ( key && typeof key === "object" ) {
  675. for ( i in key ) {
  676. jQuery.access( elems, fn, i, key[i], 1, emptyGet, value );
  677. }
  678. chainable = 1;
  679. // Sets one value
  680. } else if ( value !== undefined ) {
  681. // Optionally, function values get executed if exec is true
  682. exec = pass === undefined && jQuery.isFunction( value );
  683. if ( bulk ) {
  684. // Bulk operations only iterate when executing function values
  685. if ( exec ) {
  686. exec = fn;
  687. fn = function( elem, key, value ) {
  688. return exec.call( jQuery( elem ), value );
  689. };
  690. // Otherwise they run against the entire set
  691. } else {
  692. fn.call( elems, value );
  693. fn = null;
  694. }
  695. }
  696. if ( fn ) {
  697. for (; i < length; i++ ) {
  698. fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass );
  699. }
  700. }
  701. chainable = 1;
  702. }
  703. return chainable ?
  704. elems :
  705. // Gets
  706. bulk ?
  707. fn.call( elems ) :
  708. length ? fn( elems[0], key ) : emptyGet;
  709. },
  710. now: function() {
  711. return ( new Date() ).getTime();
  712. },
  713. // Use of jQuery.browser is frowned upon.
  714. // More details: http://docs.jquery.com/Utilities/jQuery.browser
  715. uaMatch: function( ua ) {
  716. ua = ua.toLowerCase();
  717. var match = rwebkit.exec( ua ) ||
  718. ropera.exec( ua ) ||
  719. rmsie.exec( ua ) ||
  720. ua.indexOf("compatible") < 0 && rmozilla.exec( ua ) ||
  721. [];
  722. return { browser: match[1] || "", version: match[2] || "0" };
  723. },
  724. sub: function() {
  725. function jQuerySub( selector, context ) {
  726. return new jQuerySub.fn.init( selector, context );
  727. }
  728. jQuery.extend( true, jQuerySub, this );
  729. jQuerySub.superclass = this;
  730. jQuerySub.fn = jQuerySub.prototype = this();
  731. jQuerySub.fn.constructor = jQuerySub;
  732. jQuerySub.sub = this.sub;
  733. jQuerySub.fn.init = function init( selector, context ) {
  734. if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) {
  735. context = jQuerySub( context );
  736. }
  737. return jQuery.fn.init.call( this, selector, context, rootjQuerySub );
  738. };
  739. jQuerySub.fn.init.prototype = jQuerySub.fn;
  740. var rootjQuerySub = jQuerySub(document);
  741. return jQuerySub;
  742. },
  743. browser: {}
  744. });
  745. // Populate the class2type map
  746. jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) {
  747. class2type[ "[object " + name + "]" ] = name.toLowerCase();
  748. });
  749. browserMatch = jQuery.uaMatch( userAgent );
  750. if ( browserMatch.browser ) {
  751. jQuery.browser[ browserMatch.browser ] = true;
  752. jQuery.browser.version = browserMatch.version;
  753. }
  754. // Deprecated, use jQuery.browser.webkit instead
  755. if ( jQuery.browser.webkit ) {
  756. jQuery.browser.safari = true;
  757. }
  758. // IE doesn't match non-breaking spaces with \s
  759. if ( rnotwhite.test( "\xA0" ) ) {
  760. trimLeft = /^[\s\xA0]+/;
  761. trimRight = /[\s\xA0]+$/;
  762. }
  763. // All jQuery objects should point back to these
  764. rootjQuery = jQuery(document);
  765. // Cleanup functions for the document ready method
  766. if ( document.addEventListener ) {
  767. DOMContentLoaded = function() {
  768. document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false );
  769. jQuery.ready();
  770. };
  771. } else if ( document.attachEvent ) {
  772. DOMContentLoaded = function() {
  773. // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
  774. if ( document.readyState === "complete" ) {
  775. document.detachEvent( "onreadystatechange", DOMContentLoaded );
  776. jQuery.ready();
  777. }
  778. };
  779. }
  780. // The DOM ready check for Internet Explorer
  781. function doScrollCheck() {
  782. if ( jQuery.isReady ) {
  783. return;
  784. }
  785. try {
  786. // If IE is used, use the trick by Diego Perini
  787. // http://javascript.nwbox.com/IEContentLoaded/
  788. document.documentElement.doScroll("left");
  789. } catch(e) {
  790. setTimeout( doScrollCheck, 1 );
  791. return;
  792. }
  793. // and execute any waiting functions
  794. jQuery.ready();
  795. }
  796. return jQuery;
  797. })();
  798. // String to Object flags format cache
  799. var flagsCache = {};
  800. // Convert String-formatted flags into Object-formatted ones and store in cache
  801. function createFlags( flags ) {
  802. var object = flagsCache[ flags ] = {},
  803. i, length;
  804. flags = flags.split( /\s+/ );
  805. for ( i = 0, length = flags.length; i < length; i++ ) {
  806. object[ flags[i] ] = true;
  807. }
  808. return object;
  809. }
  810. /*
  811. * Create a callback list using the following parameters:
  812. *
  813. * flags: an optional list of space-separated flags that will change how
  814. * the callback list behaves
  815. *
  816. * By default a callback list will act like an event callback list and can be
  817. * "fired" multiple times.
  818. *
  819. * Possible flags:
  820. *
  821. * once: will ensure the callback list can only be fired once (like a Deferred)
  822. *
  823. * memory: will keep track of previous values and will call any callback added
  824. * after the list has been fired right away with the latest "memorized"
  825. * values (like a Deferred)
  826. *
  827. * unique: will ensure a callback can only be added once (no duplicate in the list)
  828. *
  829. * stopOnFalse: interrupt callings when a callback returns false
  830. *
  831. */
  832. jQuery.Callbacks = function( flags ) {
  833. // Convert flags from String-formatted to Object-formatted
  834. // (we check in cache first)
  835. flags = flags ? ( flagsCache[ flags ] || createFlags( flags ) ) : {};
  836. var // Actual callback list
  837. list = [],
  838. // Stack of fire calls for repeatable lists
  839. stack = [],
  840. // Last fire value (for non-forgettable lists)
  841. memory,
  842. // Flag to know if list was already fired
  843. fired,
  844. // Flag to know if list is currently firing
  845. firing,
  846. // First callback to fire (used internally by add and fireWith)
  847. firingStart,
  848. // End of the loop when firing
  849. firingLength,
  850. // Index of currently firing callback (modified by remove if needed)
  851. firingIndex,
  852. // Add one or several callbacks to the list
  853. add = function( args ) {
  854. var i,
  855. length,
  856. elem,
  857. type,
  858. actual;
  859. for ( i = 0, length = args.length; i < length; i++ ) {
  860. elem = args[ i ];
  861. type = jQuery.type( elem );
  862. if ( type === "array" ) {
  863. // Inspect recursively
  864. add( elem );
  865. } else if ( type === "function" ) {
  866. // Add if not in unique mode and callback is not in
  867. if ( !flags.unique || !self.has( elem ) ) {
  868. list.push( elem );
  869. }
  870. }
  871. }
  872. },
  873. // Fire callbacks
  874. fire = function( context, args ) {
  875. args = args || [];
  876. memory = !flags.memory || [ context, args ];
  877. fired = true;
  878. firing = true;
  879. firingIndex = firingStart || 0;
  880. firingStart = 0;
  881. firingLength = list.length;
  882. for ( ; list && firingIndex < firingLength; firingIndex++ ) {
  883. if ( list[ firingIndex ].apply( context, args ) === false && flags.stopOnFalse ) {
  884. memory = true; // Mark as halted
  885. break;
  886. }
  887. }
  888. firing = false;
  889. if ( list ) {
  890. if ( !flags.once ) {
  891. if ( stack && stack.length ) {
  892. memory = stack.shift();
  893. self.fireWith( memory[ 0 ], memory[ 1 ] );
  894. }
  895. } else if ( memory === true ) {
  896. self.disable();
  897. } else {
  898. list = [];
  899. }
  900. }
  901. },
  902. // Actual Callbacks object
  903. self = {
  904. // Add a callback or a collection of callbacks to the list
  905. add: function() {
  906. if ( list ) {
  907. var length = list.length;
  908. add( arguments );
  909. // Do we need to add the callbacks to the
  910. // current firing batch?
  911. if ( firing ) {
  912. firingLength = list.length;
  913. // With memory, if we're not firing then
  914. // we should call right away, unless previous
  915. // firing was halted (stopOnFalse)
  916. } else if ( memory && memory !== true ) {
  917. firingStart = length;
  918. fire( memory[ 0 ], memory[ 1 ] );
  919. }
  920. }
  921. return this;
  922. },
  923. // Remove a callback from the list
  924. remove: function() {
  925. if ( list ) {
  926. var args = arguments,
  927. argIndex = 0,
  928. argLength = args.length;
  929. for ( ; argIndex < argLength ; argIndex++ ) {
  930. for ( var i = 0; i < list.length; i++ ) {
  931. if ( args[ argIndex ] === list[ i ] ) {
  932. // Handle firingIndex and firingLength
  933. if ( firing ) {
  934. if ( i <= firingLength ) {
  935. firingLength--;
  936. if ( i <= firingIndex ) {
  937. firingIndex--;
  938. }
  939. }
  940. }
  941. // Remove the element
  942. list.splice( i--, 1 );
  943. // If we have some unicity property then
  944. // we only need to do this once
  945. if ( flags.unique ) {
  946. break;
  947. }
  948. }
  949. }
  950. }
  951. }
  952. return this;
  953. },
  954. // Control if a given callback is in the list
  955. has: function( fn ) {
  956. if ( list ) {
  957. var i = 0,
  958. length = list.length;
  959. for ( ; i < length; i++ ) {
  960. if ( fn === list[ i ] ) {
  961. return true;
  962. }
  963. }
  964. }
  965. return false;
  966. },
  967. // Remove all callbacks from the list
  968. empty: function() {
  969. list = [];
  970. return this;
  971. },
  972. // Have the list do nothing anymore
  973. disable: function() {
  974. list = stack = memory = undefined;
  975. return this;
  976. },
  977. // Is it disabled?
  978. disabled: function() {
  979. return !list;
  980. },
  981. // Lock the list in its current state
  982. lock: function() {
  983. stack = undefined;
  984. if ( !memory || memory === true ) {
  985. self.disable();
  986. }
  987. return this;
  988. },
  989. // Is it locked?
  990. locked: function() {
  991. return !stack;
  992. },
  993. // Call all callbacks with the given context and arguments
  994. fireWith: function( context, args ) {
  995. if ( stack ) {
  996. if ( firing ) {
  997. if ( !flags.once ) {
  998. stack.push( [ context, args ] );
  999. }
  1000. } else if ( !( flags.once && memory ) ) {
  1001. fire( context, args );
  1002. }
  1003. }
  1004. return this;
  1005. },
  1006. // Call all the callbacks with the given arguments
  1007. fire: function() {
  1008. self.fireWith( this, arguments );
  1009. return this;
  1010. },
  1011. // To know if the callbacks have already been called at least once
  1012. fired: function() {
  1013. return !!fired;
  1014. }
  1015. };
  1016. return self;
  1017. };
  1018. var // Static reference to slice
  1019. sliceDeferred = [].slice;
  1020. jQuery.extend({
  1021. Deferred: function( func ) {
  1022. var doneList = jQuery.Callbacks( "once memory" ),
  1023. failList = jQuery.Callbacks( "once memory" ),
  1024. progressList = jQuery.Callbacks( "memory" ),
  1025. state = "pending",
  1026. lists = {
  1027. resolve: doneList,
  1028. reject: failList,
  1029. notify: progressList
  1030. },
  1031. promise = {
  1032. done: doneList.add,
  1033. fail: failList.add,
  1034. progress: progressList.add,
  1035. state: function() {
  1036. return state;
  1037. },
  1038. // Deprecated
  1039. isResolved: doneList.fired,
  1040. isRejected: failList.fired,
  1041. then: function( doneCallbacks, failCallbacks, progressCallbacks ) {
  1042. deferred.done( doneCallbacks ).fail( failCallbacks ).progress( progressCallbacks );
  1043. return this;
  1044. },
  1045. always: function() {
  1046. deferred.done.apply( deferred, arguments ).fail.apply( deferred, arguments );
  1047. return this;
  1048. },
  1049. pipe: function( fnDone, fnFail, fnProgress ) {
  1050. return jQuery.Deferred(function( newDefer ) {
  1051. jQuery.each( {
  1052. done: [ fnDone, "resolve" ],
  1053. fail: [ fnFail, "reject" ],
  1054. progress: [ fnProgress, "notify" ]
  1055. }, function( handler, data ) {
  1056. var fn = data[ 0 ],
  1057. action = data[ 1 ],
  1058. returned;
  1059. if ( jQuery.isFunction( fn ) ) {
  1060. deferred[ handler ](function() {
  1061. returned = fn.apply( this, arguments );
  1062. if ( returned && jQuery.isFunction( returned.promise ) ) {
  1063. returned.promise().then( newDefer.resolve, newDefer.reject, newDefer.notify );
  1064. } else {
  1065. newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] );
  1066. }
  1067. });
  1068. } else {
  1069. deferred[ handler ]( newDefer[ action ] );
  1070. }
  1071. });
  1072. }).promise();
  1073. },
  1074. // Get a promise for this deferred
  1075. // If obj is provided, the promise aspect is added to the object
  1076. promise: function( obj ) {
  1077. if ( obj == null ) {
  1078. obj = promise;
  1079. } else {
  1080. for ( var key in promise ) {
  1081. obj[ key ] = promise[ key ];
  1082. }
  1083. }
  1084. return obj;
  1085. }
  1086. },
  1087. deferred = promise.promise({}),
  1088. key;
  1089. for ( key in lists ) {
  1090. deferred[ key ] = lists[ key ].fire;
  1091. deferred[ key + "With" ] = lists[ key ].fireWith;
  1092. }
  1093. // Handle state
  1094. deferred.done( function() {
  1095. state = "resolved";
  1096. }, failList.disable, progressList.lock ).fail( function() {
  1097. state = "rejected";
  1098. }, doneList.disable, progressList.lock );
  1099. // Call given func if any
  1100. if ( func ) {
  1101. func.call( deferred, deferred );
  1102. }
  1103. // All done!
  1104. return deferred;
  1105. },
  1106. // Deferred helper
  1107. when: function( firstParam ) {
  1108. var args = sliceDeferred.call( arguments, 0 ),
  1109. i = 0,
  1110. length = args.length,
  1111. pValues = new Array( length ),
  1112. count = length,
  1113. pCount = length,
  1114. deferred = length <= 1 && firstParam && jQuery.isFunction( firstParam.promise ) ?
  1115. firstParam :
  1116. jQuery.Deferred(),
  1117. promise = deferred.promise();
  1118. function resolveFunc( i ) {
  1119. return function( value ) {
  1120. args[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value;
  1121. if ( !( --count ) ) {
  1122. deferred.resolveWith( deferred, args );
  1123. }
  1124. };
  1125. }
  1126. function progressFunc( i ) {
  1127. return function( value ) {
  1128. pValues[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value;
  1129. deferred.notifyWith( promise, pValues );
  1130. };
  1131. }
  1132. if ( length > 1 ) {
  1133. for ( ; i < length; i++ ) {
  1134. if ( args[ i ] && args[ i ].promise && jQuery.isFunction( args[ i ].promise ) ) {
  1135. args[ i ].promise().then( resolveFunc(i), deferred.reject, progressFunc(i) );
  1136. } else {
  1137. --count;
  1138. }
  1139. }
  1140. if ( !count ) {
  1141. deferred.resolveWith( deferred, args );
  1142. }
  1143. } else if ( deferred !== firstParam ) {
  1144. deferred.resolveWith( deferred, length ? [ firstParam ] : [] );
  1145. }
  1146. return promise;
  1147. }
  1148. });
  1149. jQuery.support = (function() {
  1150. var support,
  1151. all,
  1152. a,
  1153. select,
  1154. opt,
  1155. input,
  1156. fragment,
  1157. tds,
  1158. events,
  1159. eventName,
  1160. i,
  1161. isSupported,
  1162. div = document.createElement( "div" ),
  1163. documentElement = document.documentElement;
  1164. // Preliminary tests
  1165. div.setAttribute("className", "t");
  1166. div.innerHTML = " <link/><table></table><a href='/a' style='top:1px;float:left;opacity:.55;'>a</a><input type='checkbox'/>";
  1167. all = div.getElementsByTagName( "*" );
  1168. a = div.getElementsByTagName( "a" )[ 0 ];
  1169. // Can't get basic test support
  1170. if ( !all || !all.length || !a ) {
  1171. return {};
  1172. }
  1173. // First batch of supports tests
  1174. select = document.createElement( "select" );
  1175. opt = select.appendChild( document.createElement("option") );
  1176. input = div.getElementsByTagName( "input" )[ 0 ];
  1177. support = {
  1178. // IE strips leading whitespace when .innerHTML is used
  1179. leadingWhitespace: ( div.firstChild.nodeType === 3 ),
  1180. // Make sure that tbody elements aren't automatically inserted
  1181. // IE will insert them into empty tables
  1182. tbody: !div.getElementsByTagName("tbody").length,
  1183. // Make sure that link elements get serialized correctly by innerHTML
  1184. // This requires a wrapper element in IE
  1185. htmlSerialize: !!div.getElementsByTagName("link").length,
  1186. // Get the style information from getAttribute
  1187. // (IE uses .cssText instead)
  1188. style: /top/.test( a.getAttribute("style") ),
  1189. // Make sure that URLs aren't manipulated
  1190. // (IE normalizes it by default)
  1191. hrefNormalized: ( a.getAttribute("href") === "/a" ),
  1192. // Make sure that element opacity exists
  1193. // (IE uses filter instead)
  1194. // Use a regex to work around a WebKit issue. See #5145
  1195. opacity: /^0.55/.test( a.style.opacity ),
  1196. // Verify style float existence
  1197. // (IE uses styleFloat instead of cssFloat)
  1198. cssFloat: !!a.style.cssFloat,
  1199. // Make sure that if no value is specified for a checkbox
  1200. // that it defaults to "on".
  1201. // (WebKit defaults to "" instead)
  1202. checkOn: ( input.value === "on" ),
  1203. // Make sure that a selected-by-default option has a working selected property.
  1204. // (WebKit defaults to false instead of true, IE too, if it's in an optgroup)
  1205. optSelected: opt.selected,
  1206. // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7)
  1207. getSetAttribute: div.className !== "t",
  1208. // Tests for enctype support on a form(#6743)
  1209. enctype: !!document.createElement("form").enctype,
  1210. // Makes sure cloning an html5 element does not cause problems
  1211. // Where outerHTML is undefined, this still works
  1212. html5Clone: document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav></:nav>",
  1213. // Will be defined later
  1214. submitBubbles: true,
  1215. changeBubbles: true,
  1216. focusinBubbles: false,
  1217. deleteExpando: true,
  1218. noCloneEvent: true,
  1219. inlineBlockNeedsLayout: false,
  1220. shrinkWrapBlocks: false,
  1221. reliableMarginRight: true,
  1222. pixelMargin: true
  1223. };
  1224. // jQuery.boxModel DEPRECATED in 1.3, use jQuery.support.boxModel instead
  1225. jQuery.boxModel = support.boxModel = (document.compatMode === "CSS1Compat");
  1226. // Make sure checked status is properly cloned
  1227. input.checked = true;
  1228. support.noCloneChecked = input.cloneNode( true ).checked;
  1229. // Make sure that the options inside disabled selects aren't marked as disabled
  1230. // (WebKit marks them as disabled)
  1231. select.disabled = true;
  1232. support.optDisabled = !opt.disabled;
  1233. // Test to see if it's possible to delete an expando from an element
  1234. // Fails in Internet Explorer
  1235. try {
  1236. delete div.test;
  1237. } catch( e ) {
  1238. support.deleteExpando = false;
  1239. }
  1240. if ( !div.addEventListener && div.attachEvent && div.fireEvent ) {
  1241. div.attachEvent( "onclick", function() {
  1242. // Cloning a node shouldn't copy over any
  1243. // bound event handlers (IE does this)
  1244. support.noCloneEvent = false;
  1245. });
  1246. div.cloneNode( true ).fireEvent( "onclick" );
  1247. }
  1248. // Check if a radio maintains its value
  1249. // after being appended to the DOM
  1250. input = document.createElement("input");
  1251. input.value = "t";
  1252. input.setAttribute("type", "radio");
  1253. support.radioValue = input.value === "t";
  1254. input.setAttribute("checked", "checked");
  1255. // #11217 - WebKit loses check when the name is after the checked attribute
  1256. input.setAttribute( "name", "t" );
  1257. div.appendChild( input );
  1258. fragment = document.createDocumentFragment();
  1259. fragment.appendChild( div.lastChild );
  1260. // WebKit doesn't clone checked state correctly in fragments
  1261. support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked;
  1262. // Check if a disconnected checkbox will retain its checked
  1263. // value of true after appended to the DOM (IE6/7)
  1264. support.appendChecked = input.checked;
  1265. fragment.removeChild( input );
  1266. fragment.appendChild( div );
  1267. // Technique from Juriy Zaytsev
  1268. // http://perfectionkills.com/detecting-event-support-without-browser-sniffing/
  1269. // We only care about the case where non-standard event systems
  1270. // are used, namely in IE. Short-circuiting here helps us to
  1271. // avoid an eval call (in setAttribute) which can cause CSP
  1272. // to go haywire. See: https://developer.mozilla.org/en/Security/CSP
  1273. if ( div.attachEvent ) {
  1274. for ( i in {
  1275. submit: 1,
  1276. change: 1,
  1277. focusin: 1
  1278. }) {
  1279. eventName = "on" + i;
  1280. isSupported = ( eventName in div );
  1281. if ( !isSupported ) {
  1282. div.setAttribute( eventName, "return;" );
  1283. isSupported = ( typeof div[ eventName ] === "function" );
  1284. }
  1285. support[ i + "Bubbles" ] = isSupported;
  1286. }
  1287. }
  1288. fragment.removeChild( div );
  1289. // Null elements to avoid leaks in IE
  1290. fragment = select = opt = div = input = null;
  1291. // Run tests that need a body at doc ready
  1292. jQuery(function() {
  1293. var container, outer, inner, table, td, offsetSupport,
  1294. marginDiv, conMarginTop, style, html, positionTopLeftWidthHeight,
  1295. paddingMarginBorderVisibility, paddingMarginBorder,
  1296. body = document.getElementsByTagName("body")[0];
  1297. if ( !body ) {
  1298. // Return for frameset docs that don't have a body
  1299. return;
  1300. }
  1301. conMarginTop = 1;
  1302. paddingMarginBorder = "padding:0;margin:0;border:";
  1303. positionTopLeftWidthHeight = "position:absolute;top:0;left:0;width:1px;height:1px;";
  1304. paddingMarginBorderVisibility = paddingMarginBorder + "0;visibility:hidden;";
  1305. style = "style='" + positionTopLeftWidthHeight + paddingMarginBorder + "5px solid #000;";
  1306. html = "<div " + style + "display:block;'><div style='" + paddingMarginBorder + "0;display:block;overflow:hidden;'></div></div>" +
  1307. "<table " + style + "' cellpadding='0' cellspacing='0'>" +
  1308. "<tr><td></td></tr></table>";
  1309. container = document.createElement("div");
  1310. container.style.cssText = paddingMarginBorderVisibility + "width:0;height:0;position:static;top:0;margin-top:" + conMarginTop + "px";
  1311. body.insertBefore( container, body.firstChild );
  1312. // Construct the test element
  1313. div = document.createElement("div");
  1314. container.appendChild( div );
  1315. // Check if table cells still have offsetWidth/Height when they are set
  1316. // to display:none and there are still other visible table cells in a
  1317. // table row; if so, offsetWidth/Height are not reliable for use when
  1318. // determining if an element has been hidden directly using
  1319. // display:none (it is still safe to use offsets if a parent element is
  1320. // hidden; don safety goggles and see bug #4512 for more information).
  1321. // (only IE 8 fails this test)
  1322. div.innerHTML = "<table><tr><td style='" + paddingMarginBorder + "0;display:none'></td><td>t</td></tr></table>";
  1323. tds = div.getElementsByTagName( "td" );
  1324. isSupported = ( tds[ 0 ].offsetHeight === 0 );
  1325. tds[ 0 ].style.display = "";
  1326. tds[ 1 ].style.display = "none";
  1327. // Check if empty table cells still have offsetWidth/Height
  1328. // (IE <= 8 fail this test)
  1329. support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 );
  1330. // Check if div with explicit width and no margin-right incorrectly
  1331. // gets computed margin-right based on width of container. For more
  1332. // info see bug #3333
  1333. // Fails in WebKit before Feb 2011 nightlies
  1334. // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
  1335. if ( window.getComputedStyle ) {
  1336. div.innerHTML = "";
  1337. marginDiv = document.createElement( "div" );
  1338. marginDiv.style.width = "0";
  1339. marginDiv.style.marginRight = "0";
  1340. div.style.width = "2px";
  1341. div.appendChild( marginDiv );
  1342. support.reliableMarginRight =
  1343. ( parseInt( ( window.getComputedStyle( marginDiv, null ) || { marginRight: 0 } ).marginRight, 10 ) || 0 ) === 0;
  1344. }
  1345. if ( typeof div.style.zoom !== "undefined" ) {
  1346. // Check if natively block-level elements act like inline-block
  1347. // elements when setting their display to 'inline' and giving
  1348. // them layout
  1349. // (IE < 8 does this)
  1350. div.innerHTML = "";
  1351. div.style.width = div.style.padding = "1px";
  1352. div.style.border = 0;
  1353. div.style.overflow = "hidden";
  1354. div.style.display = "inline";
  1355. div.style.zoom = 1;
  1356. support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 );
  1357. // Check if elements with layout shrink-wrap their children
  1358. // (IE 6 does this)
  1359. div.style.display = "block";
  1360. div.style.overflow = "visible";
  1361. div.innerHTML = "<div style='width:5px;'></div>";
  1362. support.shrinkWrapBlocks = ( div.offsetWidth !== 3 );
  1363. }
  1364. div.style.cssText = positionTopLeftWidthHeight + paddingMarginBorderVisibility;
  1365. div.innerHTML = html;
  1366. outer = div.firstChild;
  1367. inner = outer.firstChild;
  1368. td = outer.nextSibling.firstChild.firstChild;
  1369. offsetSupport = {
  1370. doesNotAddBorder: ( inner.offsetTop !== 5 ),
  1371. doesAddBorderForTableAndCells: ( td.offsetTop === 5 )
  1372. };
  1373. inner.style.position = "fixed";
  1374. inner.style.top = "20px";
  1375. // safari subtracts parent border width here which is 5px
  1376. offsetSupport.fixedPosition = ( inner.offsetTop === 20 || inner.offsetTop === 15 );
  1377. inner.style.position = inner.style.top = "";
  1378. outer.style.overflow = "hidden";
  1379. outer.style.position = "relative";
  1380. offsetSupport.subtractsBorderForOverflowNotVisible = ( inner.offsetTop === -5 );
  1381. offsetSupport.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== conMarginTop );
  1382. if ( window.getComputedStyle ) {
  1383. div.style.marginTop = "1%";
  1384. support.pixelMargin = ( window.getComputedStyle( div, null ) || { marginTop: 0 } ).marginTop !== "1%";
  1385. }
  1386. if ( typeof container.style.zoom !== "undefined" ) {
  1387. container.style.zoom = 1;
  1388. }
  1389. body.removeChild( container );
  1390. marginDiv = div = container = null;
  1391. jQuery.extend( support, offsetSupport );
  1392. });
  1393. return support;
  1394. })();
  1395. var rbrace = /^(?:\{.*\}|\[.*\])$/,
  1396. rmultiDash = /([A-Z])/g;
  1397. jQuery.extend({
  1398. cache: {},
  1399. // Please use with caution
  1400. uuid: 0,
  1401. // Unique for each copy of jQuery on the page
  1402. // Non-digits removed to match rinlinejQuery
  1403. expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ),
  1404. // The following elements throw uncatchable exceptions if you
  1405. // attempt to add expando properties to them.
  1406. noData: {
  1407. "embed": true,
  1408. // Ban all objects except for Flash (which handle expandos)
  1409. "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",
  1410. "applet": true
  1411. },
  1412. hasData: function( elem ) {
  1413. elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];
  1414. return !!elem && !isEmptyDataObject( elem );
  1415. },
  1416. data: function( elem, name, data, pvt /* Internal Use Only */ ) {
  1417. if ( !jQuery.acceptData( elem ) ) {
  1418. return;
  1419. }
  1420. var privateCache, thisCache, ret,
  1421. internalKey = jQuery.expando,
  1422. getByName = typeof name === "string",
  1423. // We have to handle DOM nodes and JS objects differently because IE6-7
  1424. // can't GC object references properly across the DOM-JS boundary
  1425. isNode = elem.nodeType,
  1426. // Only DOM nodes need the global jQuery cache; JS object data is
  1427. // attached directly to the object so GC can occur automatically
  1428. cache = isNode ? jQuery.cache : elem,
  1429. // Only defining an ID for JS objects if its cache already exists allows
  1430. // the code to shortcut on the same path as a DOM node with no cache
  1431. id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey,
  1432. isEvents = name === "events";
  1433. // Avoid doing any more work than we need to when trying to get data on an
  1434. // object that has no data at all
  1435. if ( (!id || !cache[id] || (!isEvents && !pvt && !cache[id].data)) && getByName && data === undefined ) {
  1436. return;
  1437. }
  1438. if ( !id ) {
  1439. // Only DOM nodes need a new unique ID for each element since their data
  1440. // ends up in the global cache
  1441. if ( isNode ) {
  1442. elem[ internalKey ] = id = ++jQuery.uuid;
  1443. } else {
  1444. id = internalKey;
  1445. }
  1446. }
  1447. if ( !cache[ id ] ) {
  1448. cache[ id ] = {};
  1449. // Avoids exposing jQuery metadata on plain JS objects when the object
  1450. // is serialized using JSON.stringify
  1451. if ( !isNode ) {
  1452. cache[ id ].toJSON = jQuery.noop;
  1453. }
  1454. }
  1455. // An object can be passed to jQuery.data instead of a key/value pair; this gets
  1456. // shallow copied over onto the existing cache
  1457. if ( typeof name === "object" || typeof name === "function" ) {
  1458. if ( pvt ) {
  1459. cache[ id ] = jQuery.extend( cache[ id ], name );
  1460. } else {
  1461. cache[ id ].data = jQuery.extend( cache[ id ].data, name );
  1462. }
  1463. }
  1464. privateCache = thisCache = cache[ id ];
  1465. // jQuery data() is stored in a separate object inside the object's internal data
  1466. // cache in order to avoid key collisions between internal data and user-defined
  1467. // data.
  1468. if ( !pvt ) {
  1469. if ( !thisCache.data ) {
  1470. thisCache.data = {};
  1471. }
  1472. thisCache = thisCache.data;
  1473. }
  1474. if ( data !== undefined ) {
  1475. thisCache[ jQuery.camelCase( name ) ] = data;
  1476. }
  1477. // Users should not attempt to inspect the internal events object using jQuery.data,
  1478. // it is undocumented and subject to change. But does anyone listen? No.
  1479. if ( isEvents && !thisCache[ name ] ) {
  1480. return privateCache.events;
  1481. }
  1482. // Check for both converted-to-camel and non-converted data property names
  1483. // If a data property was specified
  1484. if ( getByName ) {
  1485. // First Try to find as-is property data
  1486. ret = thisCache[ name ];
  1487. // Test for null|undefined property data
  1488. if ( ret == null ) {
  1489. // Try to find the camelCased property
  1490. ret = thisCache[ jQuery.camelCase( name ) ];
  1491. }
  1492. } else {
  1493. ret = thisCache;
  1494. }
  1495. return ret;
  1496. },
  1497. removeData: function( elem, name, pvt /* Internal Use Only */ ) {
  1498. if ( !jQuery.acceptData( elem ) ) {
  1499. return;
  1500. }
  1501. var thisCache, i, l,
  1502. // Reference to internal data cache key
  1503. internalKey = jQuery.expando,
  1504. isNode = elem.nodeType,
  1505. // See jQuery.data for more information
  1506. cache = isNode ? jQuery.cache : elem,
  1507. // See jQuery.data for more information
  1508. id = isNode ? elem[ internalKey ] : internalKey;
  1509. // If there is already no cache entry for this object, there is no
  1510. // purpose in continuing
  1511. if ( !cache[ id ] ) {
  1512. return;
  1513. }
  1514. if ( name ) {
  1515. thisCache = pvt ? cache[ id ] : cache[ id ].data;
  1516. if ( thisCache ) {
  1517. // Support array or space separated string names for data keys
  1518. if ( !jQuery.isArray( name ) ) {
  1519. // try the string as a key before any manipulation
  1520. if ( name in thisCache ) {
  1521. name = [ name ];
  1522. } else {
  1523. // split the camel cased version by spaces unless a key with the spaces exists
  1524. name = jQuery.camelCase( name );
  1525. if ( name in thisCache ) {
  1526. name = [ name ];
  1527. } else {
  1528. name = name.split( " " );
  1529. }
  1530. }
  1531. }
  1532. for ( i = 0, l = name.length; i < l; i++ ) {
  1533. delete thisCache[ name[i] ];
  1534. }
  1535. // If there is no data left in the cache, we want to continue
  1536. // and let the cache object itself get destroyed
  1537. if ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) {
  1538. return;
  1539. }
  1540. }
  1541. }
  1542. // See jQuery.data for more information
  1543. if ( !pvt ) {
  1544. delete cache[ id ].data;
  1545. // Don't destroy the parent cache unless the internal data object
  1546. // had been the only thing left in it
  1547. if ( !isEmptyDataObject(cache[ id ]) ) {
  1548. return;
  1549. }
  1550. }
  1551. // Browsers that fail expando deletion also refuse to delete expandos on
  1552. // the window, but it will allow it on all other JS objects; other browsers
  1553. // don't care
  1554. // Ensure that `cache` is not a window object #10080
  1555. if ( jQuery.support.deleteExpando || !cache.setInterval ) {
  1556. delete cache[ id ];
  1557. } else {
  1558. cache[ id ] = null;
  1559. }
  1560. // We destroyed the cache and need to eliminate the expando on the node to avoid
  1561. // false lookups in the cache for entries that no longer exist
  1562. if ( isNode ) {
  1563. // IE does not allow us to delete expando properties from nodes,
  1564. // nor does it have a removeAttribute function on Document nodes;
  1565. // we must handle all of these cases
  1566. if ( jQuery.support.deleteExpando ) {
  1567. delete elem[ internalKey ];
  1568. } else if ( elem.removeAttribute ) {
  1569. elem.removeAttribute( internalKey );
  1570. } else {
  1571. elem[ internalKey ] = null;
  1572. }
  1573. }
  1574. },
  1575. // For internal use only.
  1576. _data: function( elem, name, data ) {
  1577. return jQuery.data( elem, name, data, true );
  1578. },
  1579. // A method for determining if a DOM node can handle the data expando
  1580. acceptData: function( elem ) {
  1581. if ( elem.nodeName ) {
  1582. var match = jQuery.noData[ elem.nodeName.toLowerCase() ];
  1583. if ( match ) {
  1584. return !(match === true || elem.getAttribute("classid") !== match);
  1585. }
  1586. }
  1587. return true;
  1588. }
  1589. });
  1590. jQuery.fn.extend({
  1591. data: function( key, value ) {
  1592. var parts, part, attr, name, l,
  1593. elem = this[0],
  1594. i = 0,
  1595. data = null;
  1596. // Gets all values
  1597. if ( key === undefined ) {
  1598. if ( this.length ) {
  1599. data = jQuery.data( elem );
  1600. if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) {
  1601. attr = elem.attributes;
  1602. for ( l = attr.length; i < l; i++ ) {
  1603. name = attr[i].name;
  1604. if ( name.indexOf( "data-" ) === 0 ) {
  1605. name = jQuery.camelCase( name.substring(5) );
  1606. dataAttr( elem, name, data[ name ] );
  1607. }
  1608. }
  1609. jQuery._data( elem, "parsedAttrs", true );
  1610. }
  1611. }
  1612. return data;
  1613. }
  1614. // Sets multiple values
  1615. if ( typeof key === "object" ) {
  1616. return this.each(function() {
  1617. jQuery.data( this, key );
  1618. });
  1619. }
  1620. parts = key.split( ".", 2 );
  1621. parts[1] = parts[1] ? "." + parts[1] : "";
  1622. part = parts[1] + "!";
  1623. return jQuery.access( this, function( value ) {
  1624. if ( value === undefined ) {
  1625. data = this.triggerHandler( "getData" + part, [ parts[0] ] );
  1626. // Try to fetch any internally stored data first
  1627. if ( data === undefined && elem ) {
  1628. data = jQuery.data( elem, key );
  1629. data = dataAttr( elem, key, data );
  1630. }
  1631. return data === undefined && parts[1] ?
  1632. this.data( parts[0] ) :
  1633. data;
  1634. }
  1635. parts[1] = value;
  1636. this.each(function() {
  1637. var self = jQuery( this );
  1638. self.triggerHandler( "setData" + part, parts );
  1639. jQuery.data( this, key, value );
  1640. self.triggerHandler( "changeData" + part, parts );
  1641. });
  1642. }, null, value, arguments.length > 1, null, false );
  1643. },
  1644. removeData: function( key ) {
  1645. return this.each(function() {
  1646. jQuery.removeData( this, key );
  1647. });
  1648. }
  1649. });
  1650. function dataAttr( elem, key, data ) {
  1651. // If nothing was found internally, try to fetch any
  1652. // data from the HTML5 data-* attribute
  1653. if ( data === undefined && elem.nodeType === 1 ) {
  1654. var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase();
  1655. data = elem.getAttribute( name );
  1656. if ( typeof data === "string" ) {
  1657. try {
  1658. data = data === "true" ? true :
  1659. data === "false" ? false :
  1660. data === "null" ? null :
  1661. jQuery.isNumeric( data ) ? +data :
  1662. rbrace.test( data ) ? jQuery.parseJSON( data ) :
  1663. data;
  1664. } catch( e ) {}
  1665. // Make sure we set the data so it isn't changed later
  1666. jQuery.data( elem, key, data );
  1667. } else {
  1668. data = undefined;
  1669. }
  1670. }
  1671. return data;
  1672. }
  1673. // checks a cache object for emptiness
  1674. function isEmptyDataObject( obj ) {
  1675. for ( var name in obj ) {
  1676. // if the public data object is empty, the private is still empty
  1677. if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) {
  1678. continue;
  1679. }
  1680. if ( name !== "toJSON" ) {
  1681. return false;
  1682. }
  1683. }
  1684. return true;
  1685. }
  1686. function handleQueueMarkDefer( elem, type, src ) {
  1687. var deferDataKey = type + "defer",
  1688. queueDataKey = type + "queue",
  1689. markDataKey = type + "mark",
  1690. defer = jQuery._data( elem, deferDataKey );
  1691. if ( defer &&
  1692. ( src === "queue" || !jQuery._data(elem, queueDataKey) ) &&
  1693. ( src === "mark" || !jQuery._data(elem, markDataKey) ) ) {
  1694. // Give room for hard-coded callbacks to fire first
  1695. // and eventually mark/queue something else on the element
  1696. setTimeout( function() {
  1697. if ( !jQuery._data( elem, queueDataKey ) &&
  1698. !jQuery._data( elem, markDataKey ) ) {
  1699. jQuery.removeData( elem, deferDataKey, true );
  1700. defer.fire();
  1701. }
  1702. }, 0 );
  1703. }
  1704. }
  1705. jQuery.extend({
  1706. _mark: function( elem, type ) {
  1707. if ( elem ) {
  1708. type = ( type || "fx" ) + "mark";
  1709. jQuery._data( elem, type, (jQuery._data( elem, type ) || 0) + 1 );
  1710. }
  1711. },
  1712. _unmark: function( force, elem, type ) {
  1713. if ( force !== true ) {
  1714. type = elem;
  1715. elem = force;
  1716. force = false;
  1717. }
  1718. if ( elem ) {
  1719. type = type || "fx";
  1720. var key = type + "mark",
  1721. count = force ? 0 : ( (jQuery._data( elem, key ) || 1) - 1 );
  1722. if ( count ) {
  1723. jQuery._data( elem, key, count );
  1724. } else {
  1725. jQuery.removeData( elem, key, true );
  1726. handleQueueMarkDefer( elem, type, "mark" );
  1727. }
  1728. }
  1729. },
  1730. queue: function( elem, type, data ) {
  1731. var q;
  1732. if ( elem ) {
  1733. type = ( type || "fx" ) + "queue";
  1734. q = jQuery._data( elem, type );
  1735. // Speed up dequeue by getting out quickly if this is just a lookup
  1736. if ( data ) {
  1737. if ( !q || jQuery.isArray(data) ) {
  1738. q = jQuery._data( elem, type, jQuery.makeArray(data) );
  1739. } else {
  1740. q.push( data );
  1741. }
  1742. }
  1743. return q || [];
  1744. }
  1745. },
  1746. dequeue: function( elem, type ) {
  1747. type = type || "fx";
  1748. var queue = jQuery.queue( elem, type ),
  1749. fn = queue.shift(),
  1750. hooks = {};
  1751. // If the fx queue is dequeued, always remove the progress sentinel
  1752. if ( fn === "inprogress" ) {
  1753. fn = queue.shift();
  1754. }
  1755. if ( fn ) {
  1756. // Add a progress sentinel to prevent the fx queue from being
  1757. // automatically dequeued
  1758. if ( type === "fx" ) {
  1759. queue.unshift( "inprogress" );
  1760. }
  1761. jQuery._data( elem, type + ".run", hooks );
  1762. fn.call( elem, function() {
  1763. jQuery.dequeue( elem, type );
  1764. }, hooks );
  1765. }
  1766. if ( !queue.length ) {
  1767. jQuery.removeData( elem, type + "queue " + type + ".run", true );
  1768. handleQueueMarkDefer( elem, type, "queue" );
  1769. }
  1770. }
  1771. });
  1772. jQuery.fn.extend({
  1773. queue: function( type, data ) {
  1774. var setter = 2;
  1775. if ( typeof type !== "string" ) {
  1776. data = type;
  1777. type = "fx";
  1778. setter--;
  1779. }
  1780. if ( arguments.length < setter ) {
  1781. return jQuery.queue( this[0], type );
  1782. }
  1783. return data === undefined ?
  1784. this :
  1785. this.each(function() {
  1786. var queue = jQuery.queue( this, type, data );
  1787. if ( type === "fx" && queue[0] !== "inprogress" ) {
  1788. jQuery.dequeue( this, type );
  1789. }
  1790. });
  1791. },
  1792. dequeue: function( type ) {
  1793. return this.each(function() {
  1794. jQuery.dequeue( this, type );
  1795. });
  1796. },
  1797. // Based off of the plugin by Clint Helfers, with permission.
  1798. // http://blindsignals.com/index.php/2009/07/jquery-delay/
  1799. delay: function( time, type ) {
  1800. time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
  1801. type = type || "fx";
  1802. return this.queue( type, function( next, hooks ) {
  1803. var timeout = setTimeout( next, time );
  1804. hooks.stop = function() {
  1805. clearTimeout( timeout );
  1806. };
  1807. });
  1808. },
  1809. clearQueue: function( type ) {
  1810. return this.queue( type || "fx", [] );
  1811. },
  1812. // Get a promise resolved when queues of a certain type
  1813. // are emptied (fx is the type by default)
  1814. promise: function( type, object ) {
  1815. if ( typeof type !== "string" ) {
  1816. object = type;
  1817. type = undefined;
  1818. }
  1819. type = type || "fx";
  1820. var defer = jQuery.Deferred(),
  1821. elements = this,
  1822. i = elements.length,
  1823. count = 1,
  1824. deferDataKey = type + "defer",
  1825. queueDataKey = type + "queue",
  1826. markDataKey = type + "mark",
  1827. tmp;
  1828. function resolve() {
  1829. if ( !( --count ) ) {
  1830. defer.resolveWith( elements, [ elements ] );
  1831. }
  1832. }
  1833. while( i-- ) {
  1834. if (( tmp = jQuery.data( elements[ i ], deferDataKey, undefined, true ) ||
  1835. ( jQuery.data( elements[ i ], queueDataKey, undefined, true ) ||
  1836. jQuery.data( elements[ i ], markDataKey, undefined, true ) ) &&
  1837. jQuery.data( elements[ i ], deferDataKey, jQuery.Callbacks( "once memory" ), true ) )) {
  1838. count++;
  1839. tmp.add( resolve );
  1840. }
  1841. }
  1842. resolve();
  1843. return defer.promise( object );
  1844. }
  1845. });
  1846. var rclass = /[\n\t\r]/g,
  1847. rspace = /\s+/,
  1848. rreturn = /\r/g,
  1849. rtype = /^(?:button|input)$/i,
  1850. rfocusable = /^(?:button|input|object|select|textarea)$/i,
  1851. rclickable = /^a(?:rea)?$/i,
  1852. rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,
  1853. getSetAttribute = jQuery.support.getSetAttribute,
  1854. nodeHook, boolHook, fixSpecified;
  1855. jQuery.fn.extend({
  1856. attr: function( name, value ) {
  1857. return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 );
  1858. },
  1859. removeAttr: function( name ) {
  1860. return this.each(function() {
  1861. jQuery.removeAttr( this, name );
  1862. });
  1863. },
  1864. prop: function( name, value ) {
  1865. return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 );
  1866. },
  1867. removeProp: function( name ) {
  1868. name = jQuery.propFix[ name ] || name;
  1869. return this.each(function() {
  1870. // try/catch handles cases where IE balks (such as removing a property on window)
  1871. try {
  1872. this[ name ] = undefined;
  1873. delete this[ name ];
  1874. } catch( e ) {}
  1875. });
  1876. },
  1877. addClass: function( value ) {
  1878. var classNames, i, l, elem,
  1879. setClass, c, cl;
  1880. if ( jQuery.isFunction( value ) ) {
  1881. return this.each(function( j ) {
  1882. jQuery( this ).addClass( value.call(this, j, this.className) );
  1883. });
  1884. }
  1885. if ( value && typeof value === "string" ) {
  1886. classNames = value.split( rspace );
  1887. for ( i = 0, l = this.length; i < l; i++ ) {
  1888. elem = this[ i ];
  1889. if ( elem.nodeType === 1 ) {
  1890. if ( !elem.className && classNames.length === 1 ) {
  1891. elem.className = value;
  1892. } else {
  1893. setClass = " " + elem.className + " ";
  1894. for ( c = 0, cl = classNames.length; c < cl; c++ ) {
  1895. if ( !~setClass.indexOf( " " + classNames[ c ] + " " ) ) {
  1896. setClass += classNames[ c ] + " ";
  1897. }
  1898. }
  1899. elem.className = jQuery.trim( setClass );
  1900. }
  1901. }
  1902. }
  1903. }
  1904. return this;
  1905. },
  1906. removeClass: function( value ) {
  1907. var classNames, i, l, elem, className, c, cl;
  1908. if ( jQuery.isFunction( value ) ) {
  1909. return this.each(function( j ) {
  1910. jQuery( this ).removeClass( value.call(this, j, this.className) );
  1911. });
  1912. }
  1913. if ( (value && typeof value === "string") || value === undefined ) {
  1914. classNames = ( value || "" ).split( rspace );
  1915. for ( i = 0, l = this.length; i < l; i++ ) {
  1916. elem = this[ i ];
  1917. if ( elem.nodeType === 1 && elem.className ) {
  1918. if ( value ) {
  1919. className = (" " + elem.className + " ").replace( rclass, " " );
  1920. for ( c = 0, cl = classNames.length; c < cl; c++ ) {
  1921. className = className.replace(" " + classNames[ c ] + " ", " ");
  1922. }
  1923. elem.className = jQuery.trim( className );
  1924. } else {
  1925. elem.className = "";
  1926. }
  1927. }
  1928. }
  1929. }
  1930. return this;
  1931. },
  1932. toggleClass: function( value, stateVal ) {
  1933. var type = typeof value,
  1934. isBool = typeof stateVal === "boolean";
  1935. if ( jQuery.isFunction( value ) ) {
  1936. return this.each(function( i ) {
  1937. jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );
  1938. });
  1939. }
  1940. return this.each(function() {
  1941. if ( type === "string" ) {
  1942. // toggle individual class names
  1943. var className,
  1944. i = 0,
  1945. self = jQuery( this ),
  1946. state = stateVal,
  1947. classNames = value.split( rspace );
  1948. while ( (className = classNames[ i++ ]) ) {
  1949. // check each className given, space seperated list
  1950. state = isBool ? state : !self.hasClass( className );
  1951. self[ state ? "addClass" : "removeClass" ]( className );
  1952. }
  1953. } else if ( type === "undefined" || type === "boolean" ) {
  1954. if ( this.className ) {
  1955. // store className if set
  1956. jQuery._data( this, "__className__", this.className );
  1957. }
  1958. // toggle whole className
  1959. this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || "";
  1960. }
  1961. });
  1962. },
  1963. hasClass: function( selector ) {
  1964. var className = " " + selector + " ",
  1965. i = 0,
  1966. l = this.length;
  1967. for ( ; i < l; i++ ) {
  1968. if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) {
  1969. return true;
  1970. }
  1971. }
  1972. return false;
  1973. },
  1974. val: function( value ) {
  1975. var hooks, ret, isFunction,
  1976. elem = this[0];
  1977. if ( !arguments.length ) {
  1978. if ( elem ) {
  1979. hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ];
  1980. if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) {
  1981. return ret;
  1982. }
  1983. ret = elem.value;
  1984. return typeof ret === "string" ?
  1985. // handle most common string cases
  1986. ret.replace(rreturn, "") :
  1987. // handle cases where value is null/undef or number
  1988. ret == null ? "" : ret;
  1989. }
  1990. return;
  1991. }
  1992. isFunction = jQuery.isFunction( value );
  1993. return this.each(function( i ) {
  1994. var self = jQuery(this), val;
  1995. if ( this.nodeType !== 1 ) {
  1996. return;
  1997. }
  1998. if ( isFunction ) {
  1999. val = value.call( this, i, self.val() );
  2000. } else {
  2001. val = value;
  2002. }
  2003. // Treat null/undefined as ""; convert numbers to string
  2004. if ( val == null ) {
  2005. val = "";
  2006. } else if ( typeof val === "number" ) {
  2007. val += "";
  2008. } else if ( jQuery.isArray( val ) ) {
  2009. val = jQuery.map(val, function ( value ) {
  2010. return value == null ? "" : value + "";
  2011. });
  2012. }
  2013. hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];
  2014. // If set returns undefined, fall back to normal setting
  2015. if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) {
  2016. this.value = val;
  2017. }
  2018. });
  2019. }
  2020. });
  2021. jQuery.extend({
  2022. valHooks: {
  2023. option: {
  2024. get: function( elem ) {
  2025. // attributes.value is undefined in Blackberry 4.7 but
  2026. // uses .value. See #6932
  2027. var val = elem.attributes.value;
  2028. return !val || val.specified ? elem.value : elem.text;
  2029. }
  2030. },
  2031. select: {
  2032. get: function( elem ) {
  2033. var value, i, max, option,
  2034. index = elem.selectedIndex,
  2035. values = [],
  2036. options = elem.options,
  2037. one = elem.type === "select-one";
  2038. // Nothing was selected
  2039. if ( index < 0 ) {
  2040. return null;
  2041. }
  2042. // Loop through all the selected options
  2043. i = one ? index : 0;
  2044. max = one ? index + 1 : options.length;
  2045. for ( ; i < max; i++ ) {
  2046. option = options[ i ];
  2047. // Don't return options that are disabled or in a disabled optgroup
  2048. if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) &&
  2049. (!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) {
  2050. // Get the specific value for the option
  2051. value = jQuery( option ).val();
  2052. // We don't need an array for one selects
  2053. if ( one ) {
  2054. return value;
  2055. }
  2056. // Multi-Selects return an array
  2057. values.push( value );
  2058. }
  2059. }
  2060. // Fixes Bug #2551 -- select.val() broken in IE after form.reset()
  2061. if ( one && !values.length && options.length ) {
  2062. return jQuery( options[ index ] ).val();
  2063. }
  2064. return values;
  2065. },
  2066. set: function( elem, value ) {
  2067. var values = jQuery.makeArray( value );
  2068. jQuery(elem).find("option").each(function() {
  2069. this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0;
  2070. });
  2071. if ( !values.length ) {
  2072. elem.selectedIndex = -1;
  2073. }
  2074. return values;
  2075. }
  2076. }
  2077. },
  2078. attrFn: {
  2079. val: true,
  2080. css: true,
  2081. html: true,
  2082. text: true,
  2083. data: true,
  2084. width: true,
  2085. height: true,
  2086. offset: true
  2087. },
  2088. attr: function( elem, name, value, pass ) {
  2089. var ret, hooks, notxml,
  2090. nType = elem.nodeType;
  2091. // don't get/set attributes on text, comment and attribute nodes
  2092. if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
  2093. return;
  2094. }
  2095. if ( pass && name in jQuery.attrFn ) {
  2096. return jQuery( elem )[ name ]( value );
  2097. }
  2098. // Fallback to prop when attributes are not supported
  2099. if ( typeof elem.getAttribute === "undefined" ) {
  2100. return jQuery.prop( elem, name, value );
  2101. }
  2102. notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
  2103. // All attributes are lowercase
  2104. // Grab necessary hook if one is defined
  2105. if ( notxml ) {
  2106. name = name.toLowerCase();
  2107. hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook );
  2108. }
  2109. if ( value !== undefined ) {
  2110. if ( value === null ) {
  2111. jQuery.removeAttr( elem, name );
  2112. return;
  2113. } else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) {
  2114. return ret;
  2115. } else {
  2116. elem.setAttribute( name, "" + value );
  2117. return value;
  2118. }
  2119. } else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) {
  2120. return ret;
  2121. } else {
  2122. ret = elem.getAttribute( name );
  2123. // Non-existent attributes return null, we normalize to undefined
  2124. return ret === null ?
  2125. undefined :
  2126. ret;
  2127. }
  2128. },
  2129. removeAttr: function( elem, value ) {
  2130. var propName, attrNames, name, l, isBool,
  2131. i = 0;
  2132. if ( value && elem.nodeType === 1 ) {
  2133. attrNames = value.toLowerCase().split( rspace );
  2134. l = attrNames.length;
  2135. for ( ; i < l; i++ ) {
  2136. name = attrNames[ i ];
  2137. if ( name ) {
  2138. propName = jQuery.propFix[ name ] || name;
  2139. isBool = rboolean.test( name );
  2140. // See #9699 for explanation of this approach (setting first, then removal)
  2141. // Do not do this for boolean attributes (see #10870)
  2142. if ( !isBool ) {
  2143. jQuery.attr( elem, name, "" );
  2144. }
  2145. elem.removeAttribute( getSetAttribute ? name : propName );
  2146. // Set corresponding property to false for boolean attributes
  2147. if ( isBool && propName in elem ) {
  2148. elem[ propName ] = false;
  2149. }
  2150. }
  2151. }
  2152. }
  2153. },
  2154. attrHooks: {
  2155. type: {
  2156. set: function( elem, value ) {
  2157. // We can't allow the type property to be changed (since it causes problems in IE)
  2158. if ( rtype.test( elem.nodeName ) && elem.parentNode ) {
  2159. jQuery.error( "type property can't be changed" );
  2160. } else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) {
  2161. // Setting the type on a radio button after the value resets the value in IE6-9
  2162. // Reset value to it's default in case type is set after value
  2163. // This is for element creation
  2164. var val = elem.value;
  2165. elem.setAttribute( "type", value );
  2166. if ( val ) {
  2167. elem.value = val;
  2168. }
  2169. return value;
  2170. }
  2171. }
  2172. },
  2173. // Use the value property for back compat
  2174. // Use the nodeHook for button elements in IE6/7 (#1954)
  2175. value: {
  2176. get: function( elem, name ) {
  2177. if ( nodeHook && jQuery.nodeName( elem, "button" ) ) {
  2178. return nodeHook.get( elem, name );
  2179. }
  2180. return name in elem ?
  2181. elem.value :
  2182. null;
  2183. },
  2184. set: function( elem, value, name ) {
  2185. if ( nodeHook && jQuery.nodeName( elem, "button" ) ) {
  2186. return nodeHook.set( elem, value, name );
  2187. }
  2188. // Does not return so that setAttribute is also used
  2189. elem.value = value;
  2190. }
  2191. }
  2192. },
  2193. propFix: {
  2194. tabindex: "tabIndex",
  2195. readonly: "readOnly",
  2196. "for": "htmlFor",
  2197. "class": "className",
  2198. maxlength: "maxLength",
  2199. cellspacing: "cellSpacing",
  2200. cellpadding: "cellPadding",
  2201. rowspan: "rowSpan",
  2202. colspan: "colSpan",
  2203. usemap: "useMap",
  2204. frameborder: "frameBorder",
  2205. contenteditable: "contentEditable"
  2206. },
  2207. prop: function( elem, name, value ) {
  2208. var ret, hooks, notxml,
  2209. nType = elem.nodeType;
  2210. // don't get/set properties on text, comment and attribute nodes
  2211. if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
  2212. return;
  2213. }
  2214. notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
  2215. if ( notxml ) {
  2216. // Fix name and attach hooks
  2217. name = jQuery.propFix[ name ] || name;
  2218. hooks = jQuery.propHooks[ name ];
  2219. }
  2220. if ( value !== undefined ) {
  2221. if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
  2222. return ret;
  2223. } else {
  2224. return ( elem[ name ] = value );
  2225. }
  2226. } else {
  2227. if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
  2228. return ret;
  2229. } else {
  2230. return elem[ name ];
  2231. }
  2232. }
  2233. },
  2234. propHooks: {
  2235. tabIndex: {
  2236. get: function( elem ) {
  2237. // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set
  2238. // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
  2239. var attributeNode = elem.getAttributeNode("tabindex");
  2240. return attributeNode && attributeNode.specified ?
  2241. parseInt( attributeNode.value, 10 ) :
  2242. rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?
  2243. 0 :
  2244. undefined;
  2245. }
  2246. }
  2247. }
  2248. });
  2249. // Add the tabIndex propHook to attrHooks for back-compat (different case is intentional)
  2250. jQuery.attrHooks.tabindex = jQuery.propHooks.tabIndex;
  2251. // Hook for boolean attributes
  2252. boolHook = {
  2253. get: function( elem, name ) {
  2254. // Align boolean attributes with corresponding properties
  2255. // Fall back to attribute presence where some booleans are not supported
  2256. var attrNode,
  2257. property = jQuery.prop( elem, name );
  2258. return property === true || typeof property !== "boolean" && ( attrNode = elem.getAttributeNode(name) ) && attrNode.nodeValue !== false ?
  2259. name.toLowerCase() :
  2260. undefined;
  2261. },
  2262. set: function( elem, value, name ) {
  2263. var propName;
  2264. if ( value === false ) {
  2265. // Remove boolean attributes when set to false
  2266. jQuery.removeAttr( elem, name );
  2267. } else {
  2268. // value is true since we know at this point it's type boolean and not false
  2269. // Set boolean attributes to the same name and set the DOM property
  2270. propName = jQuery.propFix[ name ] || name;
  2271. if ( propName in elem ) {
  2272. // Only set the IDL specifically if it already exists on the element
  2273. elem[ propName ] = true;
  2274. }
  2275. elem.setAttribute( name, name.toLowerCase() );
  2276. }
  2277. return name;
  2278. }
  2279. };
  2280. // IE6/7 do not support getting/setting some attributes with get/setAttribute
  2281. if ( !getSetAttribute ) {
  2282. fixSpecified = {
  2283. name: true,
  2284. id: true,
  2285. coords: true
  2286. };
  2287. // Use this for any attribute in IE6/7
  2288. // This fixes almost every IE6/7 issue
  2289. nodeHook = jQuery.valHooks.button = {
  2290. get: function( elem, name ) {
  2291. var ret;
  2292. ret = elem.getAttributeNode( name );
  2293. return ret && ( fixSpecified[ name ] ? ret.nodeValue !== "" : ret.specified ) ?
  2294. ret.nodeValue :
  2295. undefined;
  2296. },
  2297. set: function( elem, value, name ) {
  2298. // Set the existing or create a new attribute node
  2299. var ret = elem.getAttributeNode( name );
  2300. if ( !ret ) {
  2301. ret = document.createAttribute( name );
  2302. elem.setAttributeNode( ret );
  2303. }
  2304. return ( ret.nodeValue = value + "" );
  2305. }
  2306. };
  2307. // Apply the nodeHook to tabindex
  2308. jQuery.attrHooks.tabindex.set = nodeHook.set;
  2309. // Set width and height to auto instead of 0 on empty string( Bug #8150 )
  2310. // This is for removals
  2311. jQuery.each([ "width", "height" ], function( i, name ) {
  2312. jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {
  2313. set: function( elem, value ) {
  2314. if ( value === "" ) {
  2315. elem.setAttribute( name, "auto" );
  2316. return value;
  2317. }
  2318. }
  2319. });
  2320. });
  2321. // Set contenteditable to false on removals(#10429)
  2322. // Setting to empty string throws an error as an invalid value
  2323. jQuery.attrHooks.contenteditable = {
  2324. get: nodeHook.get,
  2325. set: function( elem, value, name ) {
  2326. if ( value === "" ) {
  2327. value = "false";
  2328. }
  2329. nodeHook.set( elem, value, name );
  2330. }
  2331. };
  2332. }
  2333. // Some attributes require a special call on IE
  2334. if ( !jQuery.support.hrefNormalized ) {
  2335. jQuery.each([ "href", "src", "width", "height" ], function( i, name ) {
  2336. jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {
  2337. get: function( elem ) {
  2338. var ret = elem.getAttribute( name, 2 );
  2339. return ret === null ? undefined : ret;
  2340. }
  2341. });
  2342. });
  2343. }
  2344. if ( !jQuery.support.style ) {
  2345. jQuery.attrHooks.style = {
  2346. get: function( elem ) {
  2347. // Return undefined in the case of empty string
  2348. // Normalize to lowercase since IE uppercases css property names
  2349. return elem.style.cssText.toLowerCase() || undefined;
  2350. },
  2351. set: function( elem, value ) {
  2352. return ( elem.style.cssText = "" + value );
  2353. }
  2354. };
  2355. }
  2356. // Safari mis-reports the default selected property of an option
  2357. // Accessing the parent's selectedIndex property fixes it
  2358. if ( !jQuery.support.optSelected ) {
  2359. jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, {
  2360. get: function( elem ) {
  2361. var parent = elem.parentNode;
  2362. if ( parent ) {
  2363. parent.selectedIndex;
  2364. // Make sure that it also works with optgroups, see #5701
  2365. if ( parent.parentNode ) {
  2366. parent.parentNode.selectedIndex;
  2367. }
  2368. }
  2369. return null;
  2370. }
  2371. });
  2372. }
  2373. // IE6/7 call enctype encoding
  2374. if ( !jQuery.support.enctype ) {
  2375. jQuery.propFix.enctype = "encoding";
  2376. }
  2377. // Radios and checkboxes getter/setter
  2378. if ( !jQuery.support.checkOn ) {
  2379. jQuery.each([ "radio", "checkbox" ], function() {
  2380. jQuery.valHooks[ this ] = {
  2381. get: function( elem ) {
  2382. // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified
  2383. return elem.getAttribute("value") === null ? "on" : elem.value;
  2384. }
  2385. };
  2386. });
  2387. }
  2388. jQuery.each([ "radio", "checkbox" ], function() {
  2389. jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], {
  2390. set: function( elem, value ) {
  2391. if ( jQuery.isArray( value ) ) {
  2392. return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 );
  2393. }
  2394. }
  2395. });
  2396. });
  2397. var rformElems = /^(?:textarea|input|select)$/i,
  2398. rtypenamespace = /^([^\.]*)?(?:\.(.+))?$/,
  2399. rhoverHack = /(?:^|\s)hover(\.\S+)?\b/,
  2400. rkeyEvent = /^key/,
  2401. rmouseEvent = /^(?:mouse|contextmenu)|click/,
  2402. rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
  2403. rquickIs = /^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/,
  2404. quickParse = function( selector ) {
  2405. var quick = rquickIs.exec( selector );
  2406. if ( quick ) {
  2407. // 0 1 2 3
  2408. // [ _, tag, id, class ]
  2409. quick[1] = ( quick[1] || "" ).toLowerCase();
  2410. quick[3] = quick[3] && new RegExp( "(?:^|\\s)" + quick[3] + "(?:\\s|$)" );
  2411. }
  2412. return quick;
  2413. },
  2414. quickIs = function( elem, m ) {
  2415. var attrs = elem.attributes || {};
  2416. return (
  2417. (!m[1] || elem.nodeName.toLowerCase() === m[1]) &&
  2418. (!m[2] || (attrs.id || {}).value === m[2]) &&
  2419. (!m[3] || m[3].test( (attrs[ "class" ] || {}).value ))
  2420. );
  2421. },
  2422. hoverHack = function( events ) {
  2423. return jQuery.event.special.hover ? events : events.replace( rhoverHack, "mouseenter$1 mouseleave$1" );
  2424. };
  2425. /*
  2426. * Helper functions for managing events -- not part of the public interface.
  2427. * Props to Dean Edwards' addEvent library for many of the ideas.
  2428. */
  2429. jQuery.event = {
  2430. add: function( elem, types, handler, data, selector ) {
  2431. var elemData, eventHandle, events,
  2432. t, tns, type, namespaces, handleObj,
  2433. handleObjIn, quick, handlers, special;
  2434. // Don't attach events to noData or text/comment nodes (allow plain objects tho)
  2435. if ( elem.nodeType === 3 || elem.nodeType === 8 || !types || !handler || !(elemData = jQuery._data( elem )) ) {
  2436. return;
  2437. }
  2438. // Caller can pass in an object of custom data in lieu of the handler
  2439. if ( handler.handler ) {
  2440. handleObjIn = handler;
  2441. handler = handleObjIn.handler;
  2442. selector = handleObjIn.selector;
  2443. }
  2444. // Make sure that the handler has a unique ID, used to find/remove it later
  2445. if ( !handler.guid ) {
  2446. handler.guid = jQuery.guid++;
  2447. }
  2448. // Init the element's event structure and main handler, if this is the first
  2449. events = elemData.events;
  2450. if ( !events ) {
  2451. elemData.events = events = {};
  2452. }
  2453. eventHandle = elemData.handle;
  2454. if ( !eventHandle ) {
  2455. elemData.handle = eventHandle = function( e ) {
  2456. // Discard the second event of a jQuery.event.trigger() and
  2457. // when an event is called after a page has unloaded
  2458. return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ?
  2459. jQuery.event.dispatch.apply( eventHandle.elem, arguments ) :
  2460. undefined;
  2461. };
  2462. // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events
  2463. eventHandle.elem = elem;
  2464. }
  2465. // Handle multiple events separated by a space
  2466. // jQuery(...).bind("mouseover mouseout", fn);
  2467. types = jQuery.trim( hoverHack(types) ).split( " " );
  2468. for ( t = 0; t < types.length; t++ ) {
  2469. tns = rtypenamespace.exec( types[t] ) || [];
  2470. type = tns[1];
  2471. namespaces = ( tns[2] || "" ).split( "." ).sort();
  2472. // If event changes its type, use the special event handlers for the changed type
  2473. special = jQuery.event.special[ type ] || {};
  2474. // If selector defined, determine special event api type, otherwise given type
  2475. type = ( selector ? special.delegateType : special.bindType ) || type;
  2476. // Update special based on newly reset type
  2477. special = jQuery.event.special[ type ] || {};
  2478. // handleObj is passed to all event handlers
  2479. handleObj = jQuery.extend({
  2480. type: type,
  2481. origType: tns[1],
  2482. data: data,
  2483. handler: handler,
  2484. guid: handler.guid,
  2485. selector: selector,
  2486. quick: selector && quickParse( selector ),
  2487. namespace: namespaces.join(".")
  2488. }, handleObjIn );
  2489. // Init the event handler queue if we're the first
  2490. handlers = events[ type ];
  2491. if ( !handlers ) {
  2492. handlers = events[ type ] = [];
  2493. handlers.delegateCount = 0;
  2494. // Only use addEventListener/attachEvent if the special events handler returns false
  2495. if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
  2496. // Bind the global event handler to the element
  2497. if ( elem.addEventListener ) {
  2498. elem.addEventListener( type, eventHandle, false );
  2499. } else if ( elem.attachEvent ) {
  2500. elem.attachEvent( "on" + type, eventHandle );
  2501. }
  2502. }
  2503. }
  2504. if ( special.add ) {
  2505. special.add.call( elem, handleObj );
  2506. if ( !handleObj.handler.guid ) {
  2507. handleObj.handler.guid = handler.guid;
  2508. }
  2509. }
  2510. // Add to the element's handler list, delegates in front
  2511. if ( selector ) {
  2512. handlers.splice( handlers.delegateCount++, 0, handleObj );
  2513. } else {
  2514. handlers.push( handleObj );
  2515. }
  2516. // Keep track of which events have ever been used, for event optimization
  2517. jQuery.event.global[ type ] = true;
  2518. }
  2519. // Nullify elem to prevent memory leaks in IE
  2520. elem = null;
  2521. },
  2522. global: {},
  2523. // Detach an event or set of events from an element
  2524. remove: function( elem, types, handler, selector, mappedTypes ) {
  2525. var elemData = jQuery.hasData( elem ) && jQuery._data( elem ),
  2526. t, tns, type, origType, namespaces, origCount,
  2527. j, events, special, handle, eventType, handleObj;
  2528. if ( !elemData || !(events = elemData.events) ) {
  2529. return;
  2530. }
  2531. // Once for each type.namespace in types; type may be omitted
  2532. types = jQuery.trim( hoverHack( types || "" ) ).split(" ");
  2533. for ( t = 0; t < types.length; t++ ) {
  2534. tns = rtypenamespace.exec( types[t] ) || [];
  2535. type = origType = tns[1];
  2536. namespaces = tns[2];
  2537. // Unbind all events (on this namespace, if provided) for the element
  2538. if ( !type ) {
  2539. for ( type in events ) {
  2540. jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
  2541. }
  2542. continue;
  2543. }
  2544. special = jQuery.event.special[ type ] || {};
  2545. type = ( selector? special.delegateType : special.bindType ) || type;
  2546. eventType = events[ type ] || [];
  2547. origCount = eventType.length;
  2548. namespaces = namespaces ? new RegExp("(^|\\.)" + namespaces.split(".").sort().join("\\.(?:.*\\.)?") + "(\\.|$)") : null;
  2549. // Remove matching events
  2550. for ( j = 0; j < eventType.length; j++ ) {
  2551. handleObj = eventType[ j ];
  2552. if ( ( mappedTypes || origType === handleObj.origType ) &&
  2553. ( !handler || handler.guid === handleObj.guid ) &&
  2554. ( !namespaces || namespaces.test( handleObj.namespace ) ) &&
  2555. ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) {
  2556. eventType.splice( j--, 1 );
  2557. if ( handleObj.selector ) {
  2558. eventType.delegateCount--;
  2559. }
  2560. if ( special.remove ) {
  2561. special.remove.call( elem, handleObj );
  2562. }
  2563. }
  2564. }
  2565. // Remove generic event handler if we removed something and no more handlers exist
  2566. // (avoids potential for endless recursion during removal of special event handlers)
  2567. if ( eventType.length === 0 && origCount !== eventType.length ) {
  2568. if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) {
  2569. jQuery.removeEvent( elem, type, elemData.handle );
  2570. }
  2571. delete events[ type ];
  2572. }
  2573. }
  2574. // Remove the expando if it's no longer used
  2575. if ( jQuery.isEmptyObject( events ) ) {
  2576. handle = elemData.handle;
  2577. if ( handle ) {
  2578. handle.elem = null;
  2579. }
  2580. // removeData also checks for emptiness and clears the expando if empty
  2581. // so use it instead of delete
  2582. jQuery.removeData( elem, [ "events", "handle" ], true );
  2583. }
  2584. },
  2585. // Events that are safe to short-circuit if no handlers are attached.
  2586. // Native DOM events should not be added, they may have inline handlers.
  2587. customEvent: {
  2588. "getData": true,
  2589. "setData": true,
  2590. "changeData": true
  2591. },
  2592. trigger: function( event, data, elem, onlyHandlers ) {
  2593. // Don't do events on text and comment nodes
  2594. if ( elem && (elem.nodeType === 3 || elem.nodeType === 8) ) {
  2595. return;
  2596. }
  2597. // Event object or event type
  2598. var type = event.type || event,
  2599. namespaces = [],
  2600. cache, exclusive, i, cur, old, ontype, special, handle, eventPath, bubbleType;
  2601. // focus/blur morphs to focusin/out; ensure we're not firing them right now
  2602. if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
  2603. return;
  2604. }
  2605. if ( type.indexOf( "!" ) >= 0 ) {
  2606. // Exclusive events trigger only for the exact event (no namespaces)
  2607. type = type.slice(0, -1);
  2608. exclusive = true;
  2609. }
  2610. if ( type.indexOf( "." ) >= 0 ) {
  2611. // Namespaced trigger; create a regexp to match event type in handle()
  2612. namespaces = type.split(".");
  2613. type = namespaces.shift();
  2614. namespaces.sort();
  2615. }
  2616. if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) {
  2617. // No jQuery handlers for this event type, and it can't have inline handlers
  2618. return;
  2619. }
  2620. // Caller can pass in an Event, Object, or just an event type string
  2621. event = typeof event === "object" ?
  2622. // jQuery.Event object
  2623. event[ jQuery.expando ] ? event :
  2624. // Object literal
  2625. new jQuery.Event( type, event ) :
  2626. // Just the event type (string)
  2627. new jQuery.Event( type );
  2628. event.type = type;
  2629. event.isTrigger = true;
  2630. event.exclusive = exclusive;
  2631. event.namespace = namespaces.join( "." );
  2632. event.namespace_re = event.namespace? new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.)?") + "(\\.|$)") : null;
  2633. ontype = type.indexOf( ":" ) < 0 ? "on" + type : "";
  2634. // Handle a global trigger
  2635. if ( !elem ) {
  2636. // TODO: Stop taunting the data cache; remove global events and always attach to document
  2637. cache = jQuery.cache;
  2638. for ( i in cache ) {
  2639. if ( cache[ i ].events && cache[ i ].events[ type ] ) {
  2640. jQuery.event.trigger( event, data, cache[ i ].handle.elem, true );
  2641. }
  2642. }
  2643. return;
  2644. }
  2645. // Clean up the event in case it is being reused
  2646. event.result = undefined;
  2647. if ( !event.target ) {
  2648. event.target = elem;
  2649. }
  2650. // Clone any incoming data and prepend the event, creating the handler arg list
  2651. data = data != null ? jQuery.makeArray( data ) : [];
  2652. data.unshift( event );
  2653. // Allow special events to draw outside the lines
  2654. special = jQuery.event.special[ type ] || {};
  2655. if ( special.trigger && special.trigger.apply( elem, data ) === false ) {
  2656. return;
  2657. }
  2658. // Determine event propagation path in advance, per W3C events spec (#9951)
  2659. // Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
  2660. eventPath = [[ elem, special.bindType || type ]];
  2661. if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {
  2662. bubbleType = special.delegateType || type;
  2663. cur = rfocusMorph.test( bubbleType + type ) ? elem : elem.parentNode;
  2664. old = null;
  2665. for ( ; cur; cur = cur.parentNode ) {
  2666. eventPath.push([ cur, bubbleType ]);
  2667. old = cur;
  2668. }
  2669. // Only add window if we got to document (e.g., not plain obj or detached DOM)
  2670. if ( old && old === elem.ownerDocument ) {
  2671. eventPath.push([ old.defaultView || old.parentWindow || window, bubbleType ]);
  2672. }
  2673. }
  2674. // Fire handlers on the event path
  2675. for ( i = 0; i < eventPath.length && !event.isPropagationStopped(); i++ ) {
  2676. cur = eventPath[i][0];
  2677. event.type = eventPath[i][1];
  2678. handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" );
  2679. if ( handle ) {
  2680. handle.apply( cur, data );
  2681. }
  2682. // Note that this is a bare JS function and not a jQuery handler
  2683. handle = ontype && cur[ ontype ];
  2684. if ( handle && jQuery.acceptData( cur ) && handle.apply( cur, data ) === false ) {
  2685. event.preventDefault();
  2686. }
  2687. }
  2688. event.type = type;
  2689. // If nobody prevented the default action, do it now
  2690. if ( !onlyHandlers && !event.isDefaultPrevented() ) {
  2691. if ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) &&
  2692. !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) {
  2693. // Call a native DOM method on the target with the same name name as the event.
  2694. // Can't use an .isFunction() check here because IE6/7 fails that test.
  2695. // Don't do default actions on window, that's where global variables be (#6170)
  2696. // IE<9 dies on focus/blur to hidden element (#1486)
  2697. if ( ontype && elem[ type ] && ((type !== "focus" && type !== "blur") || event.target.offsetWidth !== 0) && !jQuery.isWindow( elem ) ) {
  2698. // Don't re-trigger an onFOO event when we call its FOO() method
  2699. old = elem[ ontype ];
  2700. if ( old ) {
  2701. elem[ ontype ] = null;
  2702. }
  2703. // Prevent re-triggering of the same event, since we already bubbled it above
  2704. jQuery.event.triggered = type;
  2705. elem[ type ]();
  2706. jQuery.event.triggered = undefined;
  2707. if ( old ) {
  2708. elem[ ontype ] = old;
  2709. }
  2710. }
  2711. }
  2712. }
  2713. return event.result;
  2714. },
  2715. dispatch: function( event ) {
  2716. // Make a writable jQuery.Event from the native event object
  2717. event = jQuery.event.fix( event || window.event );
  2718. var handlers = ( (jQuery._data( this, "events" ) || {} )[ event.type ] || []),
  2719. delegateCount = handlers.delegateCount,
  2720. args = [].slice.call( arguments, 0 ),
  2721. run_all = !event.exclusive && !event.namespace,
  2722. special = jQuery.event.special[ event.type ] || {},
  2723. handlerQueue = [],
  2724. i, j, cur, jqcur, ret, selMatch, matched, matches, handleObj, sel, related;
  2725. // Use the fix-ed jQuery.Event rather than the (read-only) native event
  2726. args[0] = event;
  2727. event.delegateTarget = this;
  2728. // Call the preDispatch hook for the mapped type, and let it bail if desired
  2729. if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
  2730. return;
  2731. }
  2732. // Determine handlers that should run if there are delegated events
  2733. // Avoid non-left-click bubbling in Firefox (#3861)
  2734. if ( delegateCount && !(event.button && event.type === "click") ) {
  2735. // Pregenerate a single jQuery object for reuse with .is()
  2736. jqcur = jQuery(this);
  2737. jqcur.context = this.ownerDocument || this;
  2738. for ( cur = event.target; cur != this; cur = cur.parentNode || this ) {
  2739. // Don't process events on disabled elements (#6911, #8165)
  2740. if ( cur.disabled !== true ) {
  2741. selMatch = {};
  2742. matches = [];
  2743. jqcur[0] = cur;
  2744. for ( i = 0; i < delegateCount; i++ ) {
  2745. handleObj = handlers[ i ];
  2746. sel = handleObj.selector;
  2747. if ( selMatch[ sel ] === undefined ) {
  2748. selMatch[ sel ] = (
  2749. handleObj.quick ? quickIs( cur, handleObj.quick ) : jqcur.is( sel )
  2750. );
  2751. }
  2752. if ( selMatch[ sel ] ) {
  2753. matches.push( handleObj );
  2754. }
  2755. }
  2756. if ( matches.length ) {
  2757. handlerQueue.push({ elem: cur, matches: matches });
  2758. }
  2759. }
  2760. }
  2761. }
  2762. // Add the remaining (directly-bound) handlers
  2763. if ( handlers.length > delegateCount ) {
  2764. handlerQueue.push({ elem: this, matches: handlers.slice( delegateCount ) });
  2765. }
  2766. // Run delegates first; they may want to stop propagation beneath us
  2767. for ( i = 0; i < handlerQueue.length && !event.isPropagationStopped(); i++ ) {
  2768. matched = handlerQueue[ i ];
  2769. event.currentTarget = matched.elem;
  2770. for ( j = 0; j < matched.matches.length && !event.isImmediatePropagationStopped(); j++ ) {
  2771. handleObj = matched.matches[ j ];
  2772. // Triggered event must either 1) be non-exclusive and have no namespace, or
  2773. // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace).
  2774. if ( run_all || (!event.namespace && !handleObj.namespace) || event.namespace_re && event.namespace_re.test( handleObj.namespace ) ) {
  2775. event.data = handleObj.data;
  2776. event.handleObj = handleObj;
  2777. ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )
  2778. .apply( matched.elem, args );
  2779. if ( ret !== undefined ) {
  2780. event.result = ret;
  2781. if ( ret === false ) {
  2782. event.preventDefault();
  2783. event.stopPropagation();
  2784. }
  2785. }
  2786. }
  2787. }
  2788. }
  2789. // Call the postDispatch hook for the mapped type
  2790. if ( special.postDispatch ) {
  2791. special.postDispatch.call( this, event );
  2792. }
  2793. return event.result;
  2794. },
  2795. // Includes some event props shared by KeyEvent and MouseEvent
  2796. // *** attrChange attrName relatedNode srcElement are not normalized, non-W3C, deprecated, will be removed in 1.8 ***
  2797. props: "attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),
  2798. fixHooks: {},
  2799. keyHooks: {
  2800. props: "char charCode key keyCode".split(" "),
  2801. filter: function( event, original ) {
  2802. // Add which for key events
  2803. if ( event.which == null ) {
  2804. event.which = original.charCode != null ? original.charCode : original.keyCode;
  2805. }
  2806. return event;
  2807. }
  2808. },
  2809. mouseHooks: {
  2810. props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),
  2811. filter: function( event, original ) {
  2812. var eventDoc, doc, body,
  2813. button = original.button,
  2814. fromElement = original.fromElement;
  2815. // Calculate pageX/Y if missing and clientX/Y available
  2816. if ( event.pageX == null && original.clientX != null ) {
  2817. eventDoc = event.target.ownerDocument || document;
  2818. doc = eventDoc.documentElement;
  2819. body = eventDoc.body;
  2820. event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 );
  2821. event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 );
  2822. }
  2823. // Add relatedTarget, if necessary
  2824. if ( !event.relatedTarget && fromElement ) {
  2825. event.relatedTarget = fromElement === event.target ? original.toElement : fromElement;
  2826. }
  2827. // Add which for click: 1 === left; 2 === middle; 3 === right
  2828. // Note: button is not normalized, so don't use it
  2829. if ( !event.which && button !== undefined ) {
  2830. event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );
  2831. }
  2832. return event;
  2833. }
  2834. },
  2835. fix: function( event ) {
  2836. if ( event[ jQuery.expando ] ) {
  2837. return event;
  2838. }
  2839. // Create a writable copy of the event object and normalize some properties
  2840. var i, prop,
  2841. originalEvent = event,
  2842. fixHook = jQuery.event.fixHooks[ event.type ] || {},
  2843. copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props;
  2844. event = jQuery.Event( originalEvent );
  2845. for ( i = copy.length; i; ) {
  2846. prop = copy[ --i ];
  2847. event[ prop ] = originalEvent[ prop ];
  2848. }
  2849. // Fix target property, if necessary (#1925, IE 6/7/8 & Safari2)
  2850. if ( !event.target ) {
  2851. event.target = originalEvent.srcElement || document;
  2852. }
  2853. // Target should not be a text node (#504, Safari)
  2854. if ( event.target.nodeType === 3 ) {
  2855. event.target = event.target.parentNode;
  2856. }
  2857. // For mouse/key events; add metaKey if it's not there (#3368, IE6/7/8)
  2858. if ( event.metaKey === undefined ) {
  2859. event.metaKey = event.ctrlKey;
  2860. }
  2861. return fixHook.filter? fixHook.filter( event, originalEvent ) : event;
  2862. },
  2863. special: {
  2864. ready: {
  2865. // Make sure the ready event is setup
  2866. setup: jQuery.bindReady
  2867. },
  2868. load: {
  2869. // Prevent triggered image.load events from bubbling to window.load
  2870. noBubble: true
  2871. },
  2872. focus: {
  2873. delegateType: "focusin"
  2874. },
  2875. blur: {
  2876. delegateType: "focusout"
  2877. },
  2878. beforeunload: {
  2879. setup: function( data, namespaces, eventHandle ) {
  2880. // We only want to do this special case on windows
  2881. if ( jQuery.isWindow( this ) ) {
  2882. this.onbeforeunload = eventHandle;
  2883. }
  2884. },
  2885. teardown: function( namespaces, eventHandle ) {
  2886. if ( this.onbeforeunload === eventHandle ) {
  2887. this.onbeforeunload = null;
  2888. }
  2889. }
  2890. }
  2891. },
  2892. simulate: function( type, elem, event, bubble ) {
  2893. // Piggyback on a donor event to simulate a different one.
  2894. // Fake originalEvent to avoid donor's stopPropagation, but if the
  2895. // simulated event prevents default then we do the same on the donor.
  2896. var e = jQuery.extend(
  2897. new jQuery.Event(),
  2898. event,
  2899. { type: type,
  2900. isSimulated: true,
  2901. originalEvent: {}
  2902. }
  2903. );
  2904. if ( bubble ) {
  2905. jQuery.event.trigger( e, null, elem );
  2906. } else {
  2907. jQuery.event.dispatch.call( elem, e );
  2908. }
  2909. if ( e.isDefaultPrevented() ) {
  2910. event.preventDefault();
  2911. }
  2912. }
  2913. };
  2914. // Some plugins are using, but it's undocumented/deprecated and will be removed.
  2915. // The 1.7 special event interface should provide all the hooks needed now.
  2916. jQuery.event.handle = jQuery.event.dispatch;
  2917. jQuery.removeEvent = document.removeEventListener ?
  2918. function( elem, type, handle ) {
  2919. if ( elem.removeEventListener ) {
  2920. elem.removeEventListener( type, handle, false );
  2921. }
  2922. } :
  2923. function( elem, type, handle ) {
  2924. if ( elem.detachEvent ) {
  2925. elem.detachEvent( "on" + type, handle );
  2926. }
  2927. };
  2928. jQuery.Event = function( src, props ) {
  2929. // Allow instantiation without the 'new' keyword
  2930. if ( !(this instanceof jQuery.Event) ) {
  2931. return new jQuery.Event( src, props );
  2932. }
  2933. // Event object
  2934. if ( src && src.type ) {
  2935. this.originalEvent = src;
  2936. this.type = src.type;
  2937. // Events bubbling up the document may have been marked as prevented
  2938. // by a handler lower down the tree; reflect the correct value.
  2939. this.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false ||
  2940. src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse;
  2941. // Event type
  2942. } else {
  2943. this.type = src;
  2944. }
  2945. // Put explicitly provided properties onto the event object
  2946. if ( props ) {
  2947. jQuery.extend( this, props );
  2948. }
  2949. // Create a timestamp if incoming event doesn't have one
  2950. this.timeStamp = src && src.timeStamp || jQuery.now();
  2951. // Mark it as fixed
  2952. this[ jQuery.expando ] = true;
  2953. };
  2954. function returnFalse() {
  2955. return false;
  2956. }
  2957. function returnTrue() {
  2958. return true;
  2959. }
  2960. // jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
  2961. // http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
  2962. jQuery.Event.prototype = {
  2963. preventDefault: function() {
  2964. this.isDefaultPrevented = returnTrue;
  2965. var e = this.originalEvent;
  2966. if ( !e ) {
  2967. return;
  2968. }
  2969. // if preventDefault exists run it on the original event
  2970. if ( e.preventDefault ) {
  2971. e.preventDefault();
  2972. // otherwise set the returnValue property of the original event to false (IE)
  2973. } else {
  2974. e.returnValue = false;
  2975. }
  2976. },
  2977. stopPropagation: function() {
  2978. this.isPropagationStopped = returnTrue;
  2979. var e = this.originalEvent;
  2980. if ( !e ) {
  2981. return;
  2982. }
  2983. // if stopPropagation exists run it on the original event
  2984. if ( e.stopPropagation ) {
  2985. e.stopPropagation();
  2986. }
  2987. // otherwise set the cancelBubble property of the original event to true (IE)
  2988. e.cancelBubble = true;
  2989. },
  2990. stopImmediatePropagation: function() {
  2991. this.isImmediatePropagationStopped = returnTrue;
  2992. this.stopPropagation();
  2993. },
  2994. isDefaultPrevented: returnFalse,
  2995. isPropagationStopped: returnFalse,
  2996. isImmediatePropagationStopped: returnFalse
  2997. };
  2998. // Create mouseenter/leave events using mouseover/out and event-time checks
  2999. jQuery.each({
  3000. mouseenter: "mouseover",
  3001. mouseleave: "mouseout"
  3002. }, function( orig, fix ) {
  3003. jQuery.event.special[ orig ] = {
  3004. delegateType: fix,
  3005. bindType: fix,
  3006. handle: function( event ) {
  3007. var target = this,
  3008. related = event.relatedTarget,
  3009. handleObj = event.handleObj,
  3010. selector = handleObj.selector,
  3011. ret;
  3012. // For mousenter/leave call the handler if related is outside the target.
  3013. // NB: No relatedTarget if the mouse left/entered the browser window
  3014. if ( !related || (related !== target && !jQuery.contains( target, related )) ) {
  3015. event.type = handleObj.origType;
  3016. ret = handleObj.handler.apply( this, arguments );
  3017. event.type = fix;
  3018. }
  3019. return ret;
  3020. }
  3021. };
  3022. });
  3023. // IE submit delegation
  3024. if ( !jQuery.support.submitBubbles ) {
  3025. jQuery.event.special.submit = {
  3026. setup: function() {
  3027. // Only need this for delegated form submit events
  3028. if ( jQuery.nodeName( this, "form" ) ) {
  3029. return false;
  3030. }
  3031. // Lazy-add a submit handler when a descendant form may potentially be submitted
  3032. jQuery.event.add( this, "click._submit keypress._submit", function( e ) {
  3033. // Node name check avoids a VML-related crash in IE (#9807)
  3034. var elem = e.target,
  3035. form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined;
  3036. if ( form && !form._submit_attached ) {
  3037. jQuery.event.add( form, "submit._submit", function( event ) {
  3038. event._submit_bubble = true;
  3039. });
  3040. form._submit_attached = true;
  3041. }
  3042. });
  3043. // return undefined since we don't need an event listener
  3044. },
  3045. postDispatch: function( event ) {
  3046. // If form was submitted by the user, bubble the event up the tree
  3047. if ( event._submit_bubble ) {
  3048. delete event._submit_bubble;
  3049. if ( this.parentNode && !event.isTrigger ) {
  3050. jQuery.event.simulate( "submit", this.parentNode, event, true );
  3051. }
  3052. }
  3053. },
  3054. teardown: function() {
  3055. // Only need this for delegated form submit events
  3056. if ( jQuery.nodeName( this, "form" ) ) {
  3057. return false;
  3058. }
  3059. // Remove delegated handlers; cleanData eventually reaps submit handlers attached above
  3060. jQuery.event.remove( this, "._submit" );
  3061. }
  3062. };
  3063. }
  3064. // IE change delegation and checkbox/radio fix
  3065. if ( !jQuery.support.changeBubbles ) {
  3066. jQuery.event.special.change = {
  3067. setup: function() {
  3068. if ( rformElems.test( this.nodeName ) ) {
  3069. // IE doesn't fire change on a check/radio until blur; trigger it on click
  3070. // after a propertychange. Eat the blur-change in special.change.handle.
  3071. // This still fires onchange a second time for check/radio after blur.
  3072. if ( this.type === "checkbox" || this.type === "radio" ) {
  3073. jQuery.event.add( this, "propertychange._change", function( event ) {
  3074. if ( event.originalEvent.propertyName === "checked" ) {
  3075. this._just_changed = true;
  3076. }
  3077. });
  3078. jQuery.event.add( this, "click._change", function( event ) {
  3079. if ( this._just_changed && !event.isTrigger ) {
  3080. this._just_changed = false;
  3081. jQuery.event.simulate( "change", this, event, true );
  3082. }
  3083. });
  3084. }
  3085. return false;
  3086. }
  3087. // Delegated event; lazy-add a change handler on descendant inputs
  3088. jQuery.event.add( this, "beforeactivate._change", function( e ) {
  3089. var elem = e.target;
  3090. if ( rformElems.test( elem.nodeName ) && !elem._change_attached ) {
  3091. jQuery.event.add( elem, "change._change", function( event ) {
  3092. if ( this.parentNode && !event.isSimulated && !event.isTrigger ) {
  3093. jQuery.event.simulate( "change", this.parentNode, event, true );
  3094. }
  3095. });
  3096. elem._change_attached = true;
  3097. }
  3098. });
  3099. },
  3100. handle: function( event ) {
  3101. var elem = event.target;
  3102. // Swallow native change events from checkbox/radio, we already triggered them above
  3103. if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) {
  3104. return event.handleObj.handler.apply( this, arguments );
  3105. }
  3106. },
  3107. teardown: function() {
  3108. jQuery.event.remove( this, "._change" );
  3109. return rformElems.test( this.nodeName );
  3110. }
  3111. };
  3112. }
  3113. // Create "bubbling" focus and blur events
  3114. if ( !jQuery.support.focusinBubbles ) {
  3115. jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
  3116. // Attach a single capturing handler while someone wants focusin/focusout
  3117. var attaches = 0,
  3118. handler = function( event ) {
  3119. jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true );
  3120. };
  3121. jQuery.event.special[ fix ] = {
  3122. setup: function() {
  3123. if ( attaches++ === 0 ) {
  3124. document.addEventListener( orig, handler, true );
  3125. }
  3126. },
  3127. teardown: function() {
  3128. if ( --attaches === 0 ) {
  3129. document.removeEventListener( orig, handler, true );
  3130. }
  3131. }
  3132. };
  3133. });
  3134. }
  3135. jQuery.fn.extend({
  3136. on: function( types, selector, data, fn, /*INTERNAL*/ one ) {
  3137. var origFn, type;
  3138. // Types can be a map of types/handlers
  3139. if ( typeof types === "object" ) {
  3140. // ( types-Object, selector, data )
  3141. if ( typeof selector !== "string" ) { // && selector != null
  3142. // ( types-Object, data )
  3143. data = data || selector;
  3144. selector = undefined;
  3145. }
  3146. for ( type in types ) {
  3147. this.on( type, selector, data, types[ type ], one );
  3148. }
  3149. return this;
  3150. }
  3151. if ( data == null && fn == null ) {
  3152. // ( types, fn )
  3153. fn = selector;
  3154. data = selector = undefined;
  3155. } else if ( fn == null ) {
  3156. if ( typeof selector === "string" ) {
  3157. // ( types, selector, fn )
  3158. fn = data;
  3159. data = undefined;
  3160. } else {
  3161. // ( types, data, fn )
  3162. fn = data;
  3163. data = selector;
  3164. selector = undefined;
  3165. }
  3166. }
  3167. if ( fn === false ) {
  3168. fn = returnFalse;
  3169. } else if ( !fn ) {
  3170. return this;
  3171. }
  3172. if ( one === 1 ) {
  3173. origFn = fn;
  3174. fn = function( event ) {
  3175. // Can use an empty set, since event contains the info
  3176. jQuery().off( event );
  3177. return origFn.apply( this, arguments );
  3178. };
  3179. // Use same guid so caller can remove using origFn
  3180. fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
  3181. }
  3182. return this.each( function() {
  3183. jQuery.event.add( this, types, fn, data, selector );
  3184. });
  3185. },
  3186. one: function( types, selector, data, fn ) {
  3187. return this.on( types, selector, data, fn, 1 );
  3188. },
  3189. off: function( types, selector, fn ) {
  3190. if ( types && types.preventDefault && types.handleObj ) {
  3191. // ( event ) dispatched jQuery.Event
  3192. var handleObj = types.handleObj;
  3193. jQuery( types.delegateTarget ).off(
  3194. handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType,
  3195. handleObj.selector,
  3196. handleObj.handler
  3197. );
  3198. return this;
  3199. }
  3200. if ( typeof types === "object" ) {
  3201. // ( types-object [, selector] )
  3202. for ( var type in types ) {
  3203. this.off( type, selector, types[ type ] );
  3204. }
  3205. return this;
  3206. }
  3207. if ( selector === false || typeof selector === "function" ) {
  3208. // ( types [, fn] )
  3209. fn = selector;
  3210. selector = undefined;
  3211. }
  3212. if ( fn === false ) {
  3213. fn = returnFalse;
  3214. }
  3215. return this.each(function() {
  3216. jQuery.event.remove( this, types, fn, selector );
  3217. });
  3218. },
  3219. bind: function( types, data, fn ) {
  3220. return this.on( types, null, data, fn );
  3221. },
  3222. unbind: function( types, fn ) {
  3223. return this.off( types, null, fn );
  3224. },
  3225. live: function( types, data, fn ) {
  3226. jQuery( this.context ).on( types, this.selector, data, fn );
  3227. return this;
  3228. },
  3229. die: function( types, fn ) {
  3230. jQuery( this.context ).off( types, this.selector || "**", fn );
  3231. return this;
  3232. },
  3233. delegate: function( selector, types, data, fn ) {
  3234. return this.on( types, selector, data, fn );
  3235. },
  3236. undelegate: function( selector, types, fn ) {
  3237. // ( namespace ) or ( selector, types [, fn] )
  3238. return arguments.length == 1? this.off( selector, "**" ) : this.off( types, selector, fn );
  3239. },
  3240. trigger: function( type, data ) {
  3241. return this.each(function() {
  3242. jQuery.event.trigger( type, data, this );
  3243. });
  3244. },
  3245. triggerHandler: function( type, data ) {
  3246. if ( this[0] ) {
  3247. return jQuery.event.trigger( type, data, this[0], true );
  3248. }
  3249. },
  3250. toggle: function( fn ) {
  3251. // Save reference to arguments for access in closure
  3252. var args = arguments,
  3253. guid = fn.guid || jQuery.guid++,
  3254. i = 0,
  3255. toggler = function( event ) {
  3256. // Figure out which function to execute
  3257. var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i;
  3258. jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 );
  3259. // Make sure that clicks stop
  3260. event.preventDefault();
  3261. // and execute the function
  3262. return args[ lastToggle ].apply( this, arguments ) || false;
  3263. };
  3264. // link all the functions, so any of them can unbind this click handler
  3265. toggler.guid = guid;
  3266. while ( i < args.length ) {
  3267. args[ i++ ].guid = guid;
  3268. }
  3269. return this.click( toggler );
  3270. },
  3271. hover: function( fnOver, fnOut ) {
  3272. return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
  3273. }
  3274. });
  3275. jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
  3276. "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
  3277. "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) {
  3278. // Handle event binding
  3279. jQuery.fn[ name ] = function( data, fn ) {
  3280. if ( fn == null ) {
  3281. fn = data;
  3282. data = null;
  3283. }
  3284. return arguments.length > 0 ?
  3285. this.on( name, null, data, fn ) :
  3286. this.trigger( name );
  3287. };
  3288. if ( jQuery.attrFn ) {
  3289. jQuery.attrFn[ name ] = true;
  3290. }
  3291. if ( rkeyEvent.test( name ) ) {
  3292. jQuery.event.fixHooks[ name ] = jQuery.event.keyHooks;
  3293. }
  3294. if ( rmouseEvent.test( name ) ) {
  3295. jQuery.event.fixHooks[ name ] = jQuery.event.mouseHooks;
  3296. }
  3297. });
  3298. /*!
  3299. * Sizzle CSS Selector Engine
  3300. * Copyright 2011, The Dojo Foundation
  3301. * Released under the MIT, BSD, and GPL Licenses.
  3302. * More information: http://sizzlejs.com/
  3303. */
  3304. (function(){
  3305. var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
  3306. expando = "sizcache" + (Math.random() + '').replace('.', ''),
  3307. done = 0,
  3308. toString = Object.prototype.toString,
  3309. hasDuplicate = false,
  3310. baseHasDuplicate = true,
  3311. rBackslash = /\\/g,
  3312. rReturn = /\r\n/g,
  3313. rNonWord = /\W/;
  3314. // Here we check if the JavaScript engine is using some sort of
  3315. // optimization where it does not always call our comparision
  3316. // function. If that is the case, discard the hasDuplicate value.
  3317. // Thus far that includes Google Chrome.
  3318. [0, 0].sort(function() {
  3319. baseHasDuplicate = false;
  3320. return 0;
  3321. });
  3322. var Sizzle = function( selector, context, results, seed ) {
  3323. results = results || [];
  3324. context = context || document;
  3325. var origContext = context;
  3326. if ( context.nodeType !== 1 && context.nodeType !== 9 ) {
  3327. return [];
  3328. }
  3329. if ( !selector || typeof selector !== "string" ) {
  3330. return results;
  3331. }
  3332. var m, set, checkSet, extra, ret, cur, pop, i,
  3333. prune = true,
  3334. contextXML = Sizzle.isXML( context ),
  3335. parts = [],
  3336. soFar = selector;
  3337. // Reset the position of the chunker regexp (start from head)
  3338. do {
  3339. chunker.exec( "" );
  3340. m = chunker.exec( soFar );
  3341. if ( m ) {
  3342. soFar = m[3];
  3343. parts.push( m[1] );
  3344. if ( m[2] ) {
  3345. extra = m[3];
  3346. break;
  3347. }
  3348. }
  3349. } while ( m );
  3350. if ( parts.length > 1 && origPOS.exec( selector ) ) {
  3351. if ( parts.length === 2 && Expr.relative[ parts[0] ] ) {
  3352. set = posProcess( parts[0] + parts[1], context, seed );
  3353. } else {
  3354. set = Expr.relative[ parts[0] ] ?
  3355. [ context ] :
  3356. Sizzle( parts.shift(), context );
  3357. while ( parts.length ) {
  3358. selector = parts.shift();
  3359. if ( Expr.relative[ selector ] ) {
  3360. selector += parts.shift();
  3361. }
  3362. set = posProcess( selector, set, seed );
  3363. }
  3364. }
  3365. } else {
  3366. // Take a shortcut and set the context if the root selector is an ID
  3367. // (but not if it'll be faster if the inner selector is an ID)
  3368. if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML &&
  3369. Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) {
  3370. ret = Sizzle.find( parts.shift(), context, contextXML );
  3371. context = ret.expr ?
  3372. Sizzle.filter( ret.expr, ret.set )[0] :
  3373. ret.set[0];
  3374. }
  3375. if ( context ) {
  3376. ret = seed ?
  3377. { expr: parts.pop(), set: makeArray(seed) } :
  3378. Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML );
  3379. set = ret.expr ?
  3380. Sizzle.filter( ret.expr, ret.set ) :
  3381. ret.set;
  3382. if ( parts.length > 0 ) {
  3383. checkSet = makeArray( set );
  3384. } else {
  3385. prune = false;
  3386. }
  3387. while ( parts.length ) {
  3388. cur = parts.pop();
  3389. pop = cur;
  3390. if ( !Expr.relative[ cur ] ) {
  3391. cur = "";
  3392. } else {
  3393. pop = parts.pop();
  3394. }
  3395. if ( pop == null ) {
  3396. pop = context;
  3397. }
  3398. Expr.relative[ cur ]( checkSet, pop, contextXML );
  3399. }
  3400. } else {
  3401. checkSet = parts = [];
  3402. }
  3403. }
  3404. if ( !checkSet ) {
  3405. checkSet = set;
  3406. }
  3407. if ( !checkSet ) {
  3408. Sizzle.error( cur || selector );
  3409. }
  3410. if ( toString.call(checkSet) === "[object Array]" ) {
  3411. if ( !prune ) {
  3412. results.push.apply( results, checkSet );
  3413. } else if ( context && context.nodeType === 1 ) {
  3414. for ( i = 0; checkSet[i] != null; i++ ) {
  3415. if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && Sizzle.contains(context, checkSet[i])) ) {
  3416. results.push( set[i] );
  3417. }
  3418. }
  3419. } else {
  3420. for ( i = 0; checkSet[i] != null; i++ ) {
  3421. if ( checkSet[i] && checkSet[i].nodeType === 1 ) {
  3422. results.push( set[i] );
  3423. }
  3424. }
  3425. }
  3426. } else {
  3427. makeArray( checkSet, results );
  3428. }
  3429. if ( extra ) {
  3430. Sizzle( extra, origContext, results, seed );
  3431. Sizzle.uniqueSort( results );
  3432. }
  3433. return results;
  3434. };
  3435. Sizzle.uniqueSort = function( results ) {
  3436. if ( sortOrder ) {
  3437. hasDuplicate = baseHasDuplicate;
  3438. results.sort( sortOrder );
  3439. if ( hasDuplicate ) {
  3440. for ( var i = 1; i < results.length; i++ ) {
  3441. if ( results[i] === results[ i - 1 ] ) {
  3442. results.splice( i--, 1 );
  3443. }
  3444. }
  3445. }
  3446. }
  3447. return results;
  3448. };
  3449. Sizzle.matches = function( expr, set ) {
  3450. return Sizzle( expr, null, null, set );
  3451. };
  3452. Sizzle.matchesSelector = function( node, expr ) {
  3453. return Sizzle( expr, null, null, [node] ).length > 0;
  3454. };
  3455. Sizzle.find = function( expr, context, isXML ) {
  3456. var set, i, len, match, type, left;
  3457. if ( !expr ) {
  3458. return [];
  3459. }
  3460. for ( i = 0, len = Expr.order.length; i < len; i++ ) {
  3461. type = Expr.order[i];
  3462. if ( (match = Expr.leftMatch[ type ].exec( expr )) ) {
  3463. left = match[1];
  3464. match.splice( 1, 1 );
  3465. if ( left.substr( left.length - 1 ) !== "\\" ) {
  3466. match[1] = (match[1] || "").replace( rBackslash, "" );
  3467. set = Expr.find[ type ]( match, context, isXML );
  3468. if ( set != null ) {
  3469. expr = expr.replace( Expr.match[ type ], "" );
  3470. break;
  3471. }
  3472. }
  3473. }
  3474. }
  3475. if ( !set ) {
  3476. set = typeof context.getElementsByTagName !== "undefined" ?
  3477. context.getElementsByTagName( "*" ) :
  3478. [];
  3479. }
  3480. return { set: set, expr: expr };
  3481. };
  3482. Sizzle.filter = function( expr, set, inplace, not ) {
  3483. var match, anyFound,
  3484. type, found, item, filter, left,
  3485. i, pass,
  3486. old = expr,
  3487. result = [],
  3488. curLoop = set,
  3489. isXMLFilter = set && set[0] && Sizzle.isXML( set[0] );
  3490. while ( expr && set.length ) {
  3491. for ( type in Expr.filter ) {
  3492. if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) {
  3493. filter = Expr.filter[ type ];
  3494. left = match[1];
  3495. anyFound = false;
  3496. match.splice(1,1);
  3497. if ( left.substr( left.length - 1 ) === "\\" ) {
  3498. continue;
  3499. }
  3500. if ( curLoop === result ) {
  3501. result = [];
  3502. }
  3503. if ( Expr.preFilter[ type ] ) {
  3504. match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter );
  3505. if ( !match ) {
  3506. anyFound = found = true;
  3507. } else if ( match === true ) {
  3508. continue;
  3509. }
  3510. }
  3511. if ( match ) {
  3512. for ( i = 0; (item = curLoop[i]) != null; i++ ) {
  3513. if ( item ) {
  3514. found = filter( item, match, i, curLoop );
  3515. pass = not ^ found;
  3516. if ( inplace && found != null ) {
  3517. if ( pass ) {
  3518. anyFound = true;
  3519. } else {
  3520. curLoop[i] = false;
  3521. }
  3522. } else if ( pass ) {
  3523. result.push( item );
  3524. anyFound = true;
  3525. }
  3526. }
  3527. }
  3528. }
  3529. if ( found !== undefined ) {
  3530. if ( !inplace ) {
  3531. curLoop = result;
  3532. }
  3533. expr = expr.replace( Expr.match[ type ], "" );
  3534. if ( !anyFound ) {
  3535. return [];
  3536. }
  3537. break;
  3538. }
  3539. }
  3540. }
  3541. // Improper expression
  3542. if ( expr === old ) {
  3543. if ( anyFound == null ) {
  3544. Sizzle.error( expr );
  3545. } else {
  3546. break;
  3547. }
  3548. }
  3549. old = expr;
  3550. }
  3551. return curLoop;
  3552. };
  3553. Sizzle.error = function( msg ) {
  3554. throw new Error( "Syntax error, unrecognized expression: " + msg );
  3555. };
  3556. /**
  3557. * Utility function for retreiving the text value of an array of DOM nodes
  3558. * @param {Array|Element} elem
  3559. */
  3560. var getText = Sizzle.getText = function( elem ) {
  3561. var i, node,
  3562. nodeType = elem.nodeType,
  3563. ret = "";
  3564. if ( nodeType ) {
  3565. if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
  3566. // Use textContent || innerText for elements
  3567. if ( typeof elem.textContent === 'string' ) {
  3568. return elem.textContent;
  3569. } else if ( typeof elem.innerText === 'string' ) {
  3570. // Replace IE's carriage returns
  3571. return elem.innerText.replace( rReturn, '' );
  3572. } else {
  3573. // Traverse it's children
  3574. for ( elem = elem.firstChild; elem; elem = elem.nextSibling) {
  3575. ret += getText( elem );
  3576. }
  3577. }
  3578. } else if ( nodeType === 3 || nodeType === 4 ) {
  3579. return elem.nodeValue;
  3580. }
  3581. } else {
  3582. // If no nodeType, this is expected to be an array
  3583. for ( i = 0; (node = elem[i]); i++ ) {
  3584. // Do not traverse comment nodes
  3585. if ( node.nodeType !== 8 ) {
  3586. ret += getText( node );
  3587. }
  3588. }
  3589. }
  3590. return ret;
  3591. };
  3592. var Expr = Sizzle.selectors = {
  3593. order: [ "ID", "NAME", "TAG" ],
  3594. match: {
  3595. ID: /#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,
  3596. CLASS: /\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,
  3597. NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,
  3598. ATTR: /\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/,
  3599. TAG: /^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,
  3600. CHILD: /:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/,
  3601. POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,
  3602. PSEUDO: /:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/
  3603. },
  3604. leftMatch: {},
  3605. attrMap: {
  3606. "class": "className",
  3607. "for": "htmlFor"
  3608. },
  3609. attrHandle: {
  3610. href: function( elem ) {
  3611. return elem.getAttribute( "href" );
  3612. },
  3613. type: function( elem ) {
  3614. return elem.getAttribute( "type" );
  3615. }
  3616. },
  3617. relative: {
  3618. "+": function(checkSet, part){
  3619. var isPartStr = typeof part === "string",
  3620. isTag = isPartStr && !rNonWord.test( part ),
  3621. isPartStrNotTag = isPartStr && !isTag;
  3622. if ( isTag ) {
  3623. part = part.toLowerCase();
  3624. }
  3625. for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) {
  3626. if ( (elem = checkSet[i]) ) {
  3627. while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {}
  3628. checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ?
  3629. elem || false :
  3630. elem === part;
  3631. }
  3632. }
  3633. if ( isPartStrNotTag ) {
  3634. Sizzle.filter( part, checkSet, true );
  3635. }
  3636. },
  3637. ">": function( checkSet, part ) {
  3638. var elem,
  3639. isPartStr = typeof part === "string",
  3640. i = 0,
  3641. l = checkSet.length;
  3642. if ( isPartStr && !rNonWord.test( part ) ) {
  3643. part = part.toLowerCase();
  3644. for ( ; i < l; i++ ) {
  3645. elem = checkSet[i];
  3646. if ( elem ) {
  3647. var parent = elem.parentNode;
  3648. checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false;
  3649. }
  3650. }
  3651. } else {
  3652. for ( ; i < l; i++ ) {
  3653. elem = checkSet[i];
  3654. if ( elem ) {
  3655. checkSet[i] = isPartStr ?
  3656. elem.parentNode :
  3657. elem.parentNode === part;
  3658. }
  3659. }
  3660. if ( isPartStr ) {
  3661. Sizzle.filter( part, checkSet, true );
  3662. }
  3663. }
  3664. },
  3665. "": function(checkSet, part, isXML){
  3666. var nodeCheck,
  3667. doneName = done++,
  3668. checkFn = dirCheck;
  3669. if ( typeof part === "string" && !rNonWord.test( part ) ) {
  3670. part = part.toLowerCase();
  3671. nodeCheck = part;
  3672. checkFn = dirNodeCheck;
  3673. }
  3674. checkFn( "parentNode", part, doneName, checkSet, nodeCheck, isXML );
  3675. },
  3676. "~": function( checkSet, part, isXML ) {
  3677. var nodeCheck,
  3678. doneName = done++,
  3679. checkFn = dirCheck;
  3680. if ( typeof part === "string" && !rNonWord.test( part ) ) {
  3681. part = part.toLowerCase();
  3682. nodeCheck = part;
  3683. checkFn = dirNodeCheck;
  3684. }
  3685. checkFn( "previousSibling", part, doneName, checkSet, nodeCheck, isXML );
  3686. }
  3687. },
  3688. find: {
  3689. ID: function( match, context, isXML ) {
  3690. if ( typeof context.getElementById !== "undefined" && !isXML ) {
  3691. var m = context.getElementById(match[1]);
  3692. // Check parentNode to catch when Blackberry 4.6 returns
  3693. // nodes that are no longer in the document #6963
  3694. return m && m.parentNode ? [m] : [];
  3695. }
  3696. },
  3697. NAME: function( match, context ) {
  3698. if ( typeof context.getElementsByName !== "undefined" ) {
  3699. var ret = [],
  3700. results = context.getElementsByName( match[1] );
  3701. for ( var i = 0, l = results.length; i < l; i++ ) {
  3702. if ( results[i].getAttribute("name") === match[1] ) {
  3703. ret.push( results[i] );
  3704. }
  3705. }
  3706. return ret.length === 0 ? null : ret;
  3707. }
  3708. },
  3709. TAG: function( match, context ) {
  3710. if ( typeof context.getElementsByTagName !== "undefined" ) {
  3711. return context.getElementsByTagName( match[1] );
  3712. }
  3713. }
  3714. },
  3715. preFilter: {
  3716. CLASS: function( match, curLoop, inplace, result, not, isXML ) {
  3717. match = " " + match[1].replace( rBackslash, "" ) + " ";
  3718. if ( isXML ) {
  3719. return match;
  3720. }
  3721. for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) {
  3722. if ( elem ) {
  3723. if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n\r]/g, " ").indexOf(match) >= 0) ) {
  3724. if ( !inplace ) {
  3725. result.push( elem );
  3726. }
  3727. } else if ( inplace ) {
  3728. curLoop[i] = false;
  3729. }
  3730. }
  3731. }
  3732. return false;
  3733. },
  3734. ID: function( match ) {
  3735. return match[1].replace( rBackslash, "" );
  3736. },
  3737. TAG: function( match, curLoop ) {
  3738. return match[1].replace( rBackslash, "" ).toLowerCase();
  3739. },
  3740. CHILD: function( match ) {
  3741. if ( match[1] === "nth" ) {
  3742. if ( !match[2] ) {
  3743. Sizzle.error( match[0] );
  3744. }
  3745. match[2] = match[2].replace(/^\+|\s*/g, '');
  3746. // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'
  3747. var test = /(-?)(\d*)(?:n([+\-]?\d*))?/.exec(
  3748. match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" ||
  3749. !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]);
  3750. // calculate the numbers (first)n+(last) including if they are negative
  3751. match[2] = (test[1] + (test[2] || 1)) - 0;
  3752. match[3] = test[3] - 0;
  3753. }
  3754. else if ( match[2] ) {
  3755. Sizzle.error( match[0] );
  3756. }
  3757. // TODO: Move to normal caching system
  3758. match[0] = done++;
  3759. return match;
  3760. },
  3761. ATTR: function( match, curLoop, inplace, result, not, isXML ) {
  3762. var name = match[1] = match[1].replace( rBackslash, "" );
  3763. if ( !isXML && Expr.attrMap[name] ) {
  3764. match[1] = Expr.attrMap[name];
  3765. }
  3766. // Handle if an un-quoted value was used
  3767. match[4] = ( match[4] || match[5] || "" ).replace( rBackslash, "" );
  3768. if ( match[2] === "~=" ) {
  3769. match[4] = " " + match[4] + " ";
  3770. }
  3771. return match;
  3772. },
  3773. PSEUDO: function( match, curLoop, inplace, result, not ) {
  3774. if ( match[1] === "not" ) {
  3775. // If we're dealing with a complex expression, or a simple one
  3776. if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) {
  3777. match[3] = Sizzle(match[3], null, null, curLoop);
  3778. } else {
  3779. var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not);
  3780. if ( !inplace ) {
  3781. result.push.apply( result, ret );
  3782. }
  3783. return false;
  3784. }
  3785. } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) {
  3786. return true;
  3787. }
  3788. return match;
  3789. },
  3790. POS: function( match ) {
  3791. match.unshift( true );
  3792. return match;
  3793. }
  3794. },
  3795. filters: {
  3796. enabled: function( elem ) {
  3797. return elem.disabled === false && elem.type !== "hidden";
  3798. },
  3799. disabled: function( elem ) {
  3800. return elem.disabled === true;
  3801. },
  3802. checked: function( elem ) {
  3803. return elem.checked === true;
  3804. },
  3805. selected: function( elem ) {
  3806. // Accessing this property makes selected-by-default
  3807. // options in Safari work properly
  3808. if ( elem.parentNode ) {
  3809. elem.parentNode.selectedIndex;
  3810. }
  3811. return elem.selected === true;
  3812. },
  3813. parent: function( elem ) {
  3814. return !!elem.firstChild;
  3815. },
  3816. empty: function( elem ) {
  3817. return !elem.firstChild;
  3818. },
  3819. has: function( elem, i, match ) {
  3820. return !!Sizzle( match[3], elem ).length;
  3821. },
  3822. header: function( elem ) {
  3823. return (/h\d/i).test( elem.nodeName );
  3824. },
  3825. text: function( elem ) {
  3826. var attr = elem.getAttribute( "type" ), type = elem.type;
  3827. // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc)
  3828. // use getAttribute instead to test this case
  3829. return elem.nodeName.toLowerCase() === "input" && "text" === type && ( attr === type || attr === null );
  3830. },
  3831. radio: function( elem ) {
  3832. return elem.nodeName.toLowerCase() === "input" && "radio" === elem.type;
  3833. },
  3834. checkbox: function( elem ) {
  3835. return elem.nodeName.toLowerCase() === "input" && "checkbox" === elem.type;
  3836. },
  3837. file: function( elem ) {
  3838. return elem.nodeName.toLowerCase() === "input" && "file" === elem.type;
  3839. },
  3840. password: function( elem ) {
  3841. return elem.nodeName.toLowerCase() === "input" && "password" === elem.type;
  3842. },
  3843. submit: function( elem ) {
  3844. var name = elem.nodeName.toLowerCase();
  3845. return (name === "input" || name === "button") && "submit" === elem.type;
  3846. },
  3847. image: function( elem ) {
  3848. return elem.nodeName.toLowerCase() === "input" && "image" === elem.type;
  3849. },
  3850. reset: function( elem ) {
  3851. var name = elem.nodeName.toLowerCase();
  3852. return (name === "input" || name === "button") && "reset" === elem.type;
  3853. },
  3854. button: function( elem ) {
  3855. var name = elem.nodeName.toLowerCase();
  3856. return name === "input" && "button" === elem.type || name === "button";
  3857. },
  3858. input: function( elem ) {
  3859. return (/input|select|textarea|button/i).test( elem.nodeName );
  3860. },
  3861. focus: function( elem ) {
  3862. return elem === elem.ownerDocument.activeElement;
  3863. }
  3864. },
  3865. setFilters: {
  3866. first: function( elem, i ) {
  3867. return i === 0;
  3868. },
  3869. last: function( elem, i, match, array ) {
  3870. return i === array.length - 1;
  3871. },
  3872. even: function( elem, i ) {
  3873. return i % 2 === 0;
  3874. },
  3875. odd: function( elem, i ) {
  3876. return i % 2 === 1;
  3877. },
  3878. lt: function( elem, i, match ) {
  3879. return i < match[3] - 0;
  3880. },
  3881. gt: function( elem, i, match ) {
  3882. return i > match[3] - 0;
  3883. },
  3884. nth: function( elem, i, match ) {
  3885. return match[3] - 0 === i;
  3886. },
  3887. eq: function( elem, i, match ) {
  3888. return match[3] - 0 === i;
  3889. }
  3890. },
  3891. filter: {
  3892. PSEUDO: function( elem, match, i, array ) {
  3893. var name = match[1],
  3894. filter = Expr.filters[ name ];
  3895. if ( filter ) {
  3896. return filter( elem, i, match, array );
  3897. } else if ( name === "contains" ) {
  3898. return (elem.textContent || elem.innerText || getText([ elem ]) || "").indexOf(match[3]) >= 0;
  3899. } else if ( name === "not" ) {
  3900. var not = match[3];
  3901. for ( var j = 0, l = not.length; j < l; j++ ) {
  3902. if ( not[j] === elem ) {
  3903. return false;
  3904. }
  3905. }
  3906. return true;
  3907. } else {
  3908. Sizzle.error( name );
  3909. }
  3910. },
  3911. CHILD: function( elem, match ) {
  3912. var first, last,
  3913. doneName, parent, cache,
  3914. count, diff,
  3915. type = match[1],
  3916. node = elem;
  3917. switch ( type ) {
  3918. case "only":
  3919. case "first":
  3920. while ( (node = node.previousSibling) ) {
  3921. if ( node.nodeType === 1 ) {
  3922. return false;
  3923. }
  3924. }
  3925. if ( type === "first" ) {
  3926. return true;
  3927. }
  3928. node = elem;
  3929. /* falls through */
  3930. case "last":
  3931. while ( (node = node.nextSibling) ) {
  3932. if ( node.nodeType === 1 ) {
  3933. return false;
  3934. }
  3935. }
  3936. return true;
  3937. case "nth":
  3938. first = match[2];
  3939. last = match[3];
  3940. if ( first === 1 && last === 0 ) {
  3941. return true;
  3942. }
  3943. doneName = match[0];
  3944. parent = elem.parentNode;
  3945. if ( parent && (parent[ expando ] !== doneName || !elem.nodeIndex) ) {
  3946. count = 0;
  3947. for ( node = parent.firstChild; node; node = node.nextSibling ) {
  3948. if ( node.nodeType === 1 ) {
  3949. node.nodeIndex = ++count;
  3950. }
  3951. }
  3952. parent[ expando ] = doneName;
  3953. }
  3954. diff = elem.nodeIndex - last;
  3955. if ( first === 0 ) {
  3956. return diff === 0;
  3957. } else {
  3958. return ( diff % first === 0 && diff / first >= 0 );
  3959. }
  3960. }
  3961. },
  3962. ID: function( elem, match ) {
  3963. return elem.nodeType === 1 && elem.getAttribute("id") === match;
  3964. },
  3965. TAG: function( elem, match ) {
  3966. return (match === "*" && elem.nodeType === 1) || !!elem.nodeName && elem.nodeName.toLowerCase() === match;
  3967. },
  3968. CLASS: function( elem, match ) {
  3969. return (" " + (elem.className || elem.getAttribute("class")) + " ")
  3970. .indexOf( match ) > -1;
  3971. },
  3972. ATTR: function( elem, match ) {
  3973. var name = match[1],
  3974. result = Sizzle.attr ?
  3975. Sizzle.attr( elem, name ) :
  3976. Expr.attrHandle[ name ] ?
  3977. Expr.attrHandle[ name ]( elem ) :
  3978. elem[ name ] != null ?
  3979. elem[ name ] :
  3980. elem.getAttribute( name ),
  3981. value = result + "",
  3982. type = match[2],
  3983. check = match[4];
  3984. return result == null ?
  3985. type === "!=" :
  3986. !type && Sizzle.attr ?
  3987. result != null :
  3988. type === "=" ?
  3989. value === check :
  3990. type === "*=" ?
  3991. value.indexOf(check) >= 0 :
  3992. type === "~=" ?
  3993. (" " + value + " ").indexOf(check) >= 0 :
  3994. !check ?
  3995. value && result !== false :
  3996. type === "!=" ?
  3997. value !== check :
  3998. type === "^=" ?
  3999. value.indexOf(check) === 0 :
  4000. type === "$=" ?
  4001. value.substr(value.length - check.length) === check :
  4002. type === "|=" ?
  4003. value === check || value.substr(0, check.length + 1) === check + "-" :
  4004. false;
  4005. },
  4006. POS: function( elem, match, i, array ) {
  4007. var name = match[2],
  4008. filter = Expr.setFilters[ name ];
  4009. if ( filter ) {
  4010. return filter( elem, i, match, array );
  4011. }
  4012. }
  4013. }
  4014. };
  4015. var origPOS = Expr.match.POS,
  4016. fescape = function(all, num){
  4017. return "\\" + (num - 0 + 1);
  4018. };
  4019. for ( var type in Expr.match ) {
  4020. Expr.match[ type ] = new RegExp( Expr.match[ type ].source + (/(?![^\[]*\])(?![^\(]*\))/.source) );
  4021. Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, fescape) );
  4022. }
  4023. // Expose origPOS
  4024. // "global" as in regardless of relation to brackets/parens
  4025. Expr.match.globalPOS = origPOS;
  4026. var makeArray = function( array, results ) {
  4027. array = Array.prototype.slice.call( array, 0 );
  4028. if ( results ) {
  4029. results.push.apply( results, array );
  4030. return results;
  4031. }
  4032. return array;
  4033. };
  4034. // Perform a simple check to determine if the browser is capable of
  4035. // converting a NodeList to an array using builtin methods.
  4036. // Also verifies that the returned array holds DOM nodes
  4037. // (which is not the case in the Blackberry browser)
  4038. try {
  4039. Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType;
  4040. // Provide a fallback method if it does not work
  4041. } catch( e ) {
  4042. makeArray = function( array, results ) {
  4043. var i = 0,
  4044. ret = results || [];
  4045. if ( toString.call(array) === "[object Array]" ) {
  4046. Array.prototype.push.apply( ret, array );
  4047. } else {
  4048. if ( typeof array.length === "number" ) {
  4049. for ( var l = array.length; i < l; i++ ) {
  4050. ret.push( array[i] );
  4051. }
  4052. } else {
  4053. for ( ; array[i]; i++ ) {
  4054. ret.push( array[i] );
  4055. }
  4056. }
  4057. }
  4058. return ret;
  4059. };
  4060. }
  4061. var sortOrder, siblingCheck;
  4062. if ( document.documentElement.compareDocumentPosition ) {
  4063. sortOrder = function( a, b ) {
  4064. if ( a === b ) {
  4065. hasDuplicate = true;
  4066. return 0;
  4067. }
  4068. if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) {
  4069. return a.compareDocumentPosition ? -1 : 1;
  4070. }
  4071. return a.compareDocumentPosition(b) & 4 ? -1 : 1;
  4072. };
  4073. } else {
  4074. sortOrder = function( a, b ) {
  4075. // The nodes are identical, we can exit early
  4076. if ( a === b ) {
  4077. hasDuplicate = true;
  4078. return 0;
  4079. // Fallback to using sourceIndex (in IE) if it's available on both nodes
  4080. } else if ( a.sourceIndex && b.sourceIndex ) {
  4081. return a.sourceIndex - b.sourceIndex;
  4082. }
  4083. var al, bl,
  4084. ap = [],
  4085. bp = [],
  4086. aup = a.parentNode,
  4087. bup = b.parentNode,
  4088. cur = aup;
  4089. // If the nodes are siblings (or identical) we can do a quick check
  4090. if ( aup === bup ) {
  4091. return siblingCheck( a, b );
  4092. // If no parents were found then the nodes are disconnected
  4093. } else if ( !aup ) {
  4094. return -1;
  4095. } else if ( !bup ) {
  4096. return 1;
  4097. }
  4098. // Otherwise they're somewhere else in the tree so we need
  4099. // to build up a full list of the parentNodes for comparison
  4100. while ( cur ) {
  4101. ap.unshift( cur );
  4102. cur = cur.parentNode;
  4103. }
  4104. cur = bup;
  4105. while ( cur ) {
  4106. bp.unshift( cur );
  4107. cur = cur.parentNode;
  4108. }
  4109. al = ap.length;
  4110. bl = bp.length;
  4111. // Start walking down the tree looking for a discrepancy
  4112. for ( var i = 0; i < al && i < bl; i++ ) {
  4113. if ( ap[i] !== bp[i] ) {
  4114. return siblingCheck( ap[i], bp[i] );
  4115. }
  4116. }
  4117. // We ended someplace up the tree so do a sibling check
  4118. return i === al ?
  4119. siblingCheck( a, bp[i], -1 ) :
  4120. siblingCheck( ap[i], b, 1 );
  4121. };
  4122. siblingCheck = function( a, b, ret ) {
  4123. if ( a === b ) {
  4124. return ret;
  4125. }
  4126. var cur = a.nextSibling;
  4127. while ( cur ) {
  4128. if ( cur === b ) {
  4129. return -1;
  4130. }
  4131. cur = cur.nextSibling;
  4132. }
  4133. return 1;
  4134. };
  4135. }
  4136. // Check to see if the browser returns elements by name when
  4137. // querying by getElementById (and provide a workaround)
  4138. (function(){
  4139. // We're going to inject a fake input element with a specified name
  4140. var form = document.createElement("div"),
  4141. id = "script" + (new Date()).getTime(),
  4142. root = document.documentElement;
  4143. form.innerHTML = "<a name='" + id + "'/>";
  4144. // Inject it into the root element, check its status, and remove it quickly
  4145. root.insertBefore( form, root.firstChild );
  4146. // The workaround has to do additional checks after a getElementById
  4147. // Which slows things down for other browsers (hence the branching)
  4148. if ( document.getElementById( id ) ) {
  4149. Expr.find.ID = function( match, context, isXML ) {
  4150. if ( typeof context.getElementById !== "undefined" && !isXML ) {
  4151. var m = context.getElementById(match[1]);
  4152. return m ?
  4153. m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ?
  4154. [m] :
  4155. undefined :
  4156. [];
  4157. }
  4158. };
  4159. Expr.filter.ID = function( elem, match ) {
  4160. var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id");
  4161. return elem.nodeType === 1 && node && node.nodeValue === match;
  4162. };
  4163. }
  4164. root.removeChild( form );
  4165. // release memory in IE
  4166. root = form = null;
  4167. })();
  4168. (function(){
  4169. // Check to see if the browser returns only elements
  4170. // when doing getElementsByTagName("*")
  4171. // Create a fake element
  4172. var div = document.createElement("div");
  4173. div.appendChild( document.createComment("") );
  4174. // Make sure no comments are found
  4175. if ( div.getElementsByTagName("*").length > 0 ) {
  4176. Expr.find.TAG = function( match, context ) {
  4177. var results = context.getElementsByTagName( match[1] );
  4178. // Filter out possible comments
  4179. if ( match[1] === "*" ) {
  4180. var tmp = [];
  4181. for ( var i = 0; results[i]; i++ ) {
  4182. if ( results[i].nodeType === 1 ) {
  4183. tmp.push( results[i] );
  4184. }
  4185. }
  4186. results = tmp;
  4187. }
  4188. return results;
  4189. };
  4190. }
  4191. // Check to see if an attribute returns normalized href attributes
  4192. div.innerHTML = "<a href='#'></a>";
  4193. if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" &&
  4194. div.firstChild.getAttribute("href") !== "#" ) {
  4195. Expr.attrHandle.href = function( elem ) {
  4196. return elem.getAttribute( "href", 2 );
  4197. };
  4198. }
  4199. // release memory in IE
  4200. div = null;
  4201. })();
  4202. if ( document.querySelectorAll ) {
  4203. (function(){
  4204. var oldSizzle = Sizzle,
  4205. div = document.createElement("div"),
  4206. id = "__sizzle__";
  4207. div.innerHTML = "<p class='TEST'></p>";
  4208. // Safari can't handle uppercase or unicode characters when
  4209. // in quirks mode.
  4210. if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) {
  4211. return;
  4212. }
  4213. Sizzle = function( query, context, extra, seed ) {
  4214. context = context || document;
  4215. // Only use querySelectorAll on non-XML documents
  4216. // (ID selectors don't work in non-HTML documents)
  4217. if ( !seed && !Sizzle.isXML(context) ) {
  4218. // See if we find a selector to speed up
  4219. var match = /^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec( query );
  4220. if ( match && (context.nodeType === 1 || context.nodeType === 9) ) {
  4221. // Speed-up: Sizzle("TAG")
  4222. if ( match[1] ) {
  4223. return makeArray( context.getElementsByTagName( query ), extra );
  4224. // Speed-up: Sizzle(".CLASS")
  4225. } else if ( match[2] && Expr.find.CLASS && context.getElementsByClassName ) {
  4226. return makeArray( context.getElementsByClassName( match[2] ), extra );
  4227. }
  4228. }
  4229. if ( context.nodeType === 9 ) {
  4230. // Speed-up: Sizzle("body")
  4231. // The body element only exists once, optimize finding it
  4232. if ( query === "body" && context.body ) {
  4233. return makeArray( [ context.body ], extra );
  4234. // Speed-up: Sizzle("#ID")
  4235. } else if ( match && match[3] ) {
  4236. var elem = context.getElementById( match[3] );
  4237. // Check parentNode to catch when Blackberry 4.6 returns
  4238. // nodes that are no longer in the document #6963
  4239. if ( elem && elem.parentNode ) {
  4240. // Handle the case where IE and Opera return items
  4241. // by name instead of ID
  4242. if ( elem.id === match[3] ) {
  4243. return makeArray( [ elem ], extra );
  4244. }
  4245. } else {
  4246. return makeArray( [], extra );
  4247. }
  4248. }
  4249. try {
  4250. return makeArray( context.querySelectorAll(query), extra );
  4251. } catch(qsaError) {}
  4252. // qSA works strangely on Element-rooted queries
  4253. // We can work around this by specifying an extra ID on the root
  4254. // and working up from there (Thanks to Andrew Dupont for the technique)
  4255. // IE 8 doesn't work on object elements
  4256. } else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
  4257. var oldContext = context,
  4258. old = context.getAttribute( "id" ),
  4259. nid = old || id,
  4260. hasParent = context.parentNode,
  4261. relativeHierarchySelector = /^\s*[+~]/.test( query );
  4262. if ( !old ) {
  4263. context.setAttribute( "id", nid );
  4264. } else {
  4265. nid = nid.replace( /'/g, "\\$&" );
  4266. }
  4267. if ( relativeHierarchySelector && hasParent ) {
  4268. context = context.parentNode;
  4269. }
  4270. try {
  4271. if ( !relativeHierarchySelector || hasParent ) {
  4272. return makeArray( context.querySelectorAll( "[id='" + nid + "'] " + query ), extra );
  4273. }
  4274. } catch(pseudoError) {
  4275. } finally {
  4276. if ( !old ) {
  4277. oldContext.removeAttribute( "id" );
  4278. }
  4279. }
  4280. }
  4281. }
  4282. return oldSizzle(query, context, extra, seed);
  4283. };
  4284. for ( var prop in oldSizzle ) {
  4285. Sizzle[ prop ] = oldSizzle[ prop ];
  4286. }
  4287. // release memory in IE
  4288. div = null;
  4289. })();
  4290. }
  4291. (function(){
  4292. var html = document.documentElement,
  4293. matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector;
  4294. if ( matches ) {
  4295. // Check to see if it's possible to do matchesSelector
  4296. // on a disconnected node (IE 9 fails this)
  4297. var disconnectedMatch = !matches.call( document.createElement( "div" ), "div" ),
  4298. pseudoWorks = false;
  4299. try {
  4300. // This should fail with an exception
  4301. // Gecko does not error, returns false instead
  4302. matches.call( document.documentElement, "[test!='']:sizzle" );
  4303. } catch( pseudoError ) {
  4304. pseudoWorks = true;
  4305. }
  4306. Sizzle.matchesSelector = function( node, expr ) {
  4307. // Make sure that attribute selectors are quoted
  4308. expr = expr.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']");
  4309. if ( !Sizzle.isXML( node ) ) {
  4310. try {
  4311. if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) {
  4312. var ret = matches.call( node, expr );
  4313. // IE 9's matchesSelector returns false on disconnected nodes
  4314. if ( ret || !disconnectedMatch ||
  4315. // As well, disconnected nodes are said to be in a document
  4316. // fragment in IE 9, so check for that
  4317. node.document && node.document.nodeType !== 11 ) {
  4318. return ret;
  4319. }
  4320. }
  4321. } catch(e) {}
  4322. }
  4323. return Sizzle(expr, null, null, [node]).length > 0;
  4324. };
  4325. }
  4326. })();
  4327. (function(){
  4328. var div = document.createElement("div");
  4329. div.innerHTML = "<div class='test e'></div><div class='test'></div>";
  4330. // Opera can't find a second classname (in 9.6)
  4331. // Also, make sure that getElementsByClassName actually exists
  4332. if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) {
  4333. return;
  4334. }
  4335. // Safari caches class attributes, doesn't catch changes (in 3.2)
  4336. div.lastChild.className = "e";
  4337. if ( div.getElementsByClassName("e").length === 1 ) {
  4338. return;
  4339. }
  4340. Expr.order.splice(1, 0, "CLASS");
  4341. Expr.find.CLASS = function( match, context, isXML ) {
  4342. if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) {
  4343. return context.getElementsByClassName(match[1]);
  4344. }
  4345. };
  4346. // release memory in IE
  4347. div = null;
  4348. })();
  4349. function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
  4350. for ( var i = 0, l = checkSet.length; i < l; i++ ) {
  4351. var elem = checkSet[i];
  4352. if ( elem ) {
  4353. var match = false;
  4354. elem = elem[dir];
  4355. while ( elem ) {
  4356. if ( elem[ expando ] === doneName ) {
  4357. match = checkSet[elem.sizset];
  4358. break;
  4359. }
  4360. if ( elem.nodeType === 1 && !isXML ){
  4361. elem[ expando ] = doneName;
  4362. elem.sizset = i;
  4363. }
  4364. if ( elem.nodeName.toLowerCase() === cur ) {
  4365. match = elem;
  4366. break;
  4367. }
  4368. elem = elem[dir];
  4369. }
  4370. checkSet[i] = match;
  4371. }
  4372. }
  4373. }
  4374. function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
  4375. for ( var i = 0, l = checkSet.length; i < l; i++ ) {
  4376. var elem = checkSet[i];
  4377. if ( elem ) {
  4378. var match = false;
  4379. elem = elem[dir];
  4380. while ( elem ) {
  4381. if ( elem[ expando ] === doneName ) {
  4382. match = checkSet[elem.sizset];
  4383. break;
  4384. }
  4385. if ( elem.nodeType === 1 ) {
  4386. if ( !isXML ) {
  4387. elem[ expando ] = doneName;
  4388. elem.sizset = i;
  4389. }
  4390. if ( typeof cur !== "string" ) {
  4391. if ( elem === cur ) {
  4392. match = true;
  4393. break;
  4394. }
  4395. } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) {
  4396. match = elem;
  4397. break;
  4398. }
  4399. }
  4400. elem = elem[dir];
  4401. }
  4402. checkSet[i] = match;
  4403. }
  4404. }
  4405. }
  4406. if ( document.documentElement.contains ) {
  4407. Sizzle.contains = function( a, b ) {
  4408. return a !== b && (a.contains ? a.contains(b) : true);
  4409. };
  4410. } else if ( document.documentElement.compareDocumentPosition ) {
  4411. Sizzle.contains = function( a, b ) {
  4412. return !!(a.compareDocumentPosition(b) & 16);
  4413. };
  4414. } else {
  4415. Sizzle.contains = function() {
  4416. return false;
  4417. };
  4418. }
  4419. Sizzle.isXML = function( elem ) {
  4420. // documentElement is verified for cases where it doesn't yet exist
  4421. // (such as loading iframes in IE - #4833)
  4422. var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement;
  4423. return documentElement ? documentElement.nodeName !== "HTML" : false;
  4424. };
  4425. var posProcess = function( selector, context, seed ) {
  4426. var match,
  4427. tmpSet = [],
  4428. later = "",
  4429. root = context.nodeType ? [context] : context;
  4430. // Position selectors must be done after the filter
  4431. // And so must :not(positional) so we move all PSEUDOs to the end
  4432. while ( (match = Expr.match.PSEUDO.exec( selector )) ) {
  4433. later += match[0];
  4434. selector = selector.replace( Expr.match.PSEUDO, "" );
  4435. }
  4436. selector = Expr.relative[selector] ? selector + "*" : selector;
  4437. for ( var i = 0, l = root.length; i < l; i++ ) {
  4438. Sizzle( selector, root[i], tmpSet, seed );
  4439. }
  4440. return Sizzle.filter( later, tmpSet );
  4441. };
  4442. // EXPOSE
  4443. // Override sizzle attribute retrieval
  4444. Sizzle.attr = jQuery.attr;
  4445. Sizzle.selectors.attrMap = {};
  4446. jQuery.find = Sizzle;
  4447. jQuery.expr = Sizzle.selectors;
  4448. jQuery.expr[":"] = jQuery.expr.filters;
  4449. jQuery.unique = Sizzle.uniqueSort;
  4450. jQuery.text = Sizzle.getText;
  4451. jQuery.isXMLDoc = Sizzle.isXML;
  4452. jQuery.contains = Sizzle.contains;
  4453. })();
  4454. var runtil = /Until$/,
  4455. rparentsprev = /^(?:parents|prevUntil|prevAll)/,
  4456. // Note: This RegExp should be improved, or likely pulled from Sizzle
  4457. rmultiselector = /,/,
  4458. isSimple = /^.[^:#\[\.,]*$/,
  4459. slice = Array.prototype.slice,
  4460. POS = jQuery.expr.match.globalPOS,
  4461. // methods guaranteed to produce a unique set when starting from a unique set
  4462. guaranteedUnique = {
  4463. children: true,
  4464. contents: true,
  4465. next: true,
  4466. prev: true
  4467. };
  4468. jQuery.fn.extend({
  4469. find: function( selector ) {
  4470. var self = this,
  4471. i, l;
  4472. if ( typeof selector !== "string" ) {
  4473. return jQuery( selector ).filter(function() {
  4474. for ( i = 0, l = self.length; i < l; i++ ) {
  4475. if ( jQuery.contains( self[ i ], this ) ) {
  4476. return true;
  4477. }
  4478. }
  4479. });
  4480. }
  4481. var ret = this.pushStack( "", "find", selector ),
  4482. length, n, r;
  4483. for ( i = 0, l = this.length; i < l; i++ ) {
  4484. length = ret.length;
  4485. jQuery.find( selector, this[i], ret );
  4486. if ( i > 0 ) {
  4487. // Make sure that the results are unique
  4488. for ( n = length; n < ret.length; n++ ) {
  4489. for ( r = 0; r < length; r++ ) {
  4490. if ( ret[r] === ret[n] ) {
  4491. ret.splice(n--, 1);
  4492. break;
  4493. }
  4494. }
  4495. }
  4496. }
  4497. }
  4498. return ret;
  4499. },
  4500. has: function( target ) {
  4501. var targets = jQuery( target );
  4502. return this.filter(function() {
  4503. for ( var i = 0, l = targets.length; i < l; i++ ) {
  4504. if ( jQuery.contains( this, targets[i] ) ) {
  4505. return true;
  4506. }
  4507. }
  4508. });
  4509. },
  4510. not: function( selector ) {
  4511. return this.pushStack( winnow(this, selector, false), "not", selector);
  4512. },
  4513. filter: function( selector ) {
  4514. return this.pushStack( winnow(this, selector, true), "filter", selector );
  4515. },
  4516. is: function( selector ) {
  4517. return !!selector && (
  4518. typeof selector === "string" ?
  4519. // If this is a positional selector, check membership in the returned set
  4520. // so $("p:first").is("p:last") won't return true for a doc with two "p".
  4521. POS.test( selector ) ?
  4522. jQuery( selector, this.context ).index( this[0] ) >= 0 :
  4523. jQuery.filter( selector, this ).length > 0 :
  4524. this.filter( selector ).length > 0 );
  4525. },
  4526. closest: function( selectors, context ) {
  4527. var ret = [], i, l, cur = this[0];
  4528. // Array (deprecated as of jQuery 1.7)
  4529. if ( jQuery.isArray( selectors ) ) {
  4530. var level = 1;
  4531. while ( cur && cur.ownerDocument && cur !== context ) {
  4532. for ( i = 0; i < selectors.length; i++ ) {
  4533. if ( jQuery( cur ).is( selectors[ i ] ) ) {
  4534. ret.push({ selector: selectors[ i ], elem: cur, level: level });
  4535. }
  4536. }
  4537. cur = cur.parentNode;
  4538. level++;
  4539. }
  4540. return ret;
  4541. }
  4542. // String
  4543. var pos = POS.test( selectors ) || typeof selectors !== "string" ?
  4544. jQuery( selectors, context || this.context ) :
  4545. 0;
  4546. for ( i = 0, l = this.length; i < l; i++ ) {
  4547. cur = this[i];
  4548. while ( cur ) {
  4549. if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) {
  4550. ret.push( cur );
  4551. break;
  4552. } else {
  4553. cur = cur.parentNode;
  4554. if ( !cur || !cur.ownerDocument || cur === context || cur.nodeType === 11 ) {
  4555. break;
  4556. }
  4557. }
  4558. }
  4559. }
  4560. ret = ret.length > 1 ? jQuery.unique( ret ) : ret;
  4561. return this.pushStack( ret, "closest", selectors );
  4562. },
  4563. // Determine the position of an element within
  4564. // the matched set of elements
  4565. index: function( elem ) {
  4566. // No argument, return index in parent
  4567. if ( !elem ) {
  4568. return ( this[0] && this[0].parentNode ) ? this.prevAll().length : -1;
  4569. }
  4570. // index in selector
  4571. if ( typeof elem === "string" ) {
  4572. return jQuery.inArray( this[0], jQuery( elem ) );
  4573. }
  4574. // Locate the position of the desired element
  4575. return jQuery.inArray(
  4576. // If it receives a jQuery object, the first element is used
  4577. elem.jquery ? elem[0] : elem, this );
  4578. },
  4579. add: function( selector, context ) {
  4580. var set = typeof selector === "string" ?
  4581. jQuery( selector, context ) :
  4582. jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ),
  4583. all = jQuery.merge( this.get(), set );
  4584. return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ?
  4585. all :
  4586. jQuery.unique( all ) );
  4587. },
  4588. andSelf: function() {
  4589. return this.add( this.prevObject );
  4590. }
  4591. });
  4592. // A painfully simple check to see if an element is disconnected
  4593. // from a document (should be improved, where feasible).
  4594. function isDisconnected( node ) {
  4595. return !node || !node.parentNode || node.parentNode.nodeType === 11;
  4596. }
  4597. jQuery.each({
  4598. parent: function( elem ) {
  4599. var parent = elem.parentNode;
  4600. return parent && parent.nodeType !== 11 ? parent : null;
  4601. },
  4602. parents: function( elem ) {
  4603. return jQuery.dir( elem, "parentNode" );
  4604. },
  4605. parentsUntil: function( elem, i, until ) {
  4606. return jQuery.dir( elem, "parentNode", until );
  4607. },
  4608. next: function( elem ) {
  4609. return jQuery.nth( elem, 2, "nextSibling" );
  4610. },
  4611. prev: function( elem ) {
  4612. return jQuery.nth( elem, 2, "previousSibling" );
  4613. },
  4614. nextAll: function( elem ) {
  4615. return jQuery.dir( elem, "nextSibling" );
  4616. },
  4617. prevAll: function( elem ) {
  4618. return jQuery.dir( elem, "previousSibling" );
  4619. },
  4620. nextUntil: function( elem, i, until ) {
  4621. return jQuery.dir( elem, "nextSibling", until );
  4622. },
  4623. prevUntil: function( elem, i, until ) {
  4624. return jQuery.dir( elem, "previousSibling", until );
  4625. },
  4626. siblings: function( elem ) {
  4627. return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem );
  4628. },
  4629. children: function( elem ) {
  4630. return jQuery.sibling( elem.firstChild );
  4631. },
  4632. contents: function( elem ) {
  4633. return jQuery.nodeName( elem, "iframe" ) ?
  4634. elem.contentDocument || elem.contentWindow.document :
  4635. jQuery.makeArray( elem.childNodes );
  4636. }
  4637. }, function( name, fn ) {
  4638. jQuery.fn[ name ] = function( until, selector ) {
  4639. var ret = jQuery.map( this, fn, until );
  4640. if ( !runtil.test( name ) ) {
  4641. selector = until;
  4642. }
  4643. if ( selector && typeof selector === "string" ) {
  4644. ret = jQuery.filter( selector, ret );
  4645. }
  4646. ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret;
  4647. if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) {
  4648. ret = ret.reverse();
  4649. }
  4650. return this.pushStack( ret, name, slice.call( arguments ).join(",") );
  4651. };
  4652. });
  4653. jQuery.extend({
  4654. filter: function( expr, elems, not ) {
  4655. if ( not ) {
  4656. expr = ":not(" + expr + ")";
  4657. }
  4658. return elems.length === 1 ?
  4659. jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] :
  4660. jQuery.find.matches(expr, elems);
  4661. },
  4662. dir: function( elem, dir, until ) {
  4663. var matched = [],
  4664. cur = elem[ dir ];
  4665. while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {
  4666. if ( cur.nodeType === 1 ) {
  4667. matched.push( cur );
  4668. }
  4669. cur = cur[dir];
  4670. }
  4671. return matched;
  4672. },
  4673. nth: function( cur, result, dir, elem ) {
  4674. result = result || 1;
  4675. var num = 0;
  4676. for ( ; cur; cur = cur[dir] ) {
  4677. if ( cur.nodeType === 1 && ++num === result ) {
  4678. break;
  4679. }
  4680. }
  4681. return cur;
  4682. },
  4683. sibling: function( n, elem ) {
  4684. var r = [];
  4685. for ( ; n; n = n.nextSibling ) {
  4686. if ( n.nodeType === 1 && n !== elem ) {
  4687. r.push( n );
  4688. }
  4689. }
  4690. return r;
  4691. }
  4692. });
  4693. // Implement the identical functionality for filter and not
  4694. function winnow( elements, qualifier, keep ) {
  4695. // Can't pass null or undefined to indexOf in Firefox 4
  4696. // Set to 0 to skip string check
  4697. qualifier = qualifier || 0;
  4698. if ( jQuery.isFunction( qualifier ) ) {
  4699. return jQuery.grep(elements, function( elem, i ) {
  4700. var retVal = !!qualifier.call( elem, i, elem );
  4701. return retVal === keep;
  4702. });
  4703. } else if ( qualifier.nodeType ) {
  4704. return jQuery.grep(elements, function( elem, i ) {
  4705. return ( elem === qualifier ) === keep;
  4706. });
  4707. } else if ( typeof qualifier === "string" ) {
  4708. var filtered = jQuery.grep(elements, function( elem ) {
  4709. return elem.nodeType === 1;
  4710. });
  4711. if ( isSimple.test( qualifier ) ) {
  4712. return jQuery.filter(qualifier, filtered, !keep);
  4713. } else {
  4714. qualifier = jQuery.filter( qualifier, filtered );
  4715. }
  4716. }
  4717. return jQuery.grep(elements, function( elem, i ) {
  4718. return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep;
  4719. });
  4720. }
  4721. function createSafeFragment( document ) {
  4722. var list = nodeNames.split( "|" ),
  4723. safeFrag = document.createDocumentFragment();
  4724. if ( safeFrag.createElement ) {
  4725. while ( list.length ) {
  4726. safeFrag.createElement(
  4727. list.pop()
  4728. );
  4729. }
  4730. }
  4731. return safeFrag;
  4732. }
  4733. var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" +
  4734. "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",
  4735. rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g,
  4736. rleadingWhitespace = /^\s+/,
  4737. rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,
  4738. rtagName = /<([\w:]+)/,
  4739. rtbody = /<tbody/i,
  4740. rhtml = /<|&#?\w+;/,
  4741. rnoInnerhtml = /<(?:script|style)/i,
  4742. rnocache = /<(?:script|object|embed|option|style)/i,
  4743. rnoshimcache = new RegExp("<(?:" + nodeNames + ")[\\s/>]", "i"),
  4744. // checked="checked" or checked
  4745. rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
  4746. rscriptType = /\/(java|ecma)script/i,
  4747. rcleanScript = /^\s*<!(?:\[CDATA\[|\-\-)/,
  4748. wrapMap = {
  4749. option: [ 1, "<select multiple='multiple'>", "</select>" ],
  4750. legend: [ 1, "<fieldset>", "</fieldset>" ],
  4751. thead: [ 1, "<table>", "</table>" ],
  4752. tr: [ 2, "<table><tbody>", "</tbody></table>" ],
  4753. td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
  4754. col: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ],
  4755. area: [ 1, "<map>", "</map>" ],
  4756. _default: [ 0, "", "" ]
  4757. },
  4758. safeFragment = createSafeFragment( document );
  4759. wrapMap.optgroup = wrapMap.option;
  4760. wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
  4761. wrapMap.th = wrapMap.td;
  4762. // IE can't serialize <link> and <script> tags normally
  4763. if ( !jQuery.support.htmlSerialize ) {
  4764. wrapMap._default = [ 1, "div<div>", "</div>" ];
  4765. }
  4766. jQuery.fn.extend({
  4767. text: function( value ) {
  4768. return jQuery.access( this, function( value ) {
  4769. return value === undefined ?
  4770. jQuery.text( this ) :
  4771. this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) );
  4772. }, null, value, arguments.length );
  4773. },
  4774. wrapAll: function( html ) {
  4775. if ( jQuery.isFunction( html ) ) {
  4776. return this.each(function(i) {
  4777. jQuery(this).wrapAll( html.call(this, i) );
  4778. });
  4779. }
  4780. if ( this[0] ) {
  4781. // The elements to wrap the target around
  4782. var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true);
  4783. if ( this[0].parentNode ) {
  4784. wrap.insertBefore( this[0] );
  4785. }
  4786. wrap.map(function() {
  4787. var elem = this;
  4788. while ( elem.firstChild && elem.firstChild.nodeType === 1 ) {
  4789. elem = elem.firstChild;
  4790. }
  4791. return elem;
  4792. }).append( this );
  4793. }
  4794. return this;
  4795. },
  4796. wrapInner: function( html ) {
  4797. if ( jQuery.isFunction( html ) ) {
  4798. return this.each(function(i) {
  4799. jQuery(this).wrapInner( html.call(this, i) );
  4800. });
  4801. }
  4802. return this.each(function() {
  4803. var self = jQuery( this ),
  4804. contents = self.contents();
  4805. if ( contents.length ) {
  4806. contents.wrapAll( html );
  4807. } else {
  4808. self.append( html );
  4809. }
  4810. });
  4811. },
  4812. wrap: function( html ) {
  4813. var isFunction = jQuery.isFunction( html );
  4814. return this.each(function(i) {
  4815. jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html );
  4816. });
  4817. },
  4818. unwrap: function() {
  4819. return this.parent().each(function() {
  4820. if ( !jQuery.nodeName( this, "body" ) ) {
  4821. jQuery( this ).replaceWith( this.childNodes );
  4822. }
  4823. }).end();
  4824. },
  4825. append: function() {
  4826. return this.domManip(arguments, true, function( elem ) {
  4827. if ( this.nodeType === 1 ) {
  4828. this.appendChild( elem );
  4829. }
  4830. });
  4831. },
  4832. prepend: function() {
  4833. return this.domManip(arguments, true, function( elem ) {
  4834. if ( this.nodeType === 1 ) {
  4835. this.insertBefore( elem, this.firstChild );
  4836. }
  4837. });
  4838. },
  4839. before: function() {
  4840. if ( this[0] && this[0].parentNode ) {
  4841. return this.domManip(arguments, false, function( elem ) {
  4842. this.parentNode.insertBefore( elem, this );
  4843. });
  4844. } else if ( arguments.length ) {
  4845. var set = jQuery.clean( arguments );
  4846. set.push.apply( set, this.toArray() );
  4847. return this.pushStack( set, "before", arguments );
  4848. }
  4849. },
  4850. after: function() {
  4851. if ( this[0] && this[0].parentNode ) {
  4852. return this.domManip(arguments, false, function( elem ) {
  4853. this.parentNode.insertBefore( elem, this.nextSibling );
  4854. });
  4855. } else if ( arguments.length ) {
  4856. var set = this.pushStack( this, "after", arguments );
  4857. set.push.apply( set, jQuery.clean(arguments) );
  4858. return set;
  4859. }
  4860. },
  4861. // keepData is for internal use only--do not document
  4862. remove: function( selector, keepData ) {
  4863. for ( var i = 0, elem; (elem = this[i]) != null; i++ ) {
  4864. if ( !selector || jQuery.filter( selector, [ elem ] ).length ) {
  4865. if ( !keepData && elem.nodeType === 1 ) {
  4866. jQuery.cleanData( elem.getElementsByTagName("*") );
  4867. jQuery.cleanData( [ elem ] );
  4868. }
  4869. if ( elem.parentNode ) {
  4870. elem.parentNode.removeChild( elem );
  4871. }
  4872. }
  4873. }
  4874. return this;
  4875. },
  4876. empty: function() {
  4877. for ( var i = 0, elem; (elem = this[i]) != null; i++ ) {
  4878. // Remove element nodes and prevent memory leaks
  4879. if ( elem.nodeType === 1 ) {
  4880. jQuery.cleanData( elem.getElementsByTagName("*") );
  4881. }
  4882. // Remove any remaining nodes
  4883. while ( elem.firstChild ) {
  4884. elem.removeChild( elem.firstChild );
  4885. }
  4886. }
  4887. return this;
  4888. },
  4889. clone: function( dataAndEvents, deepDataAndEvents ) {
  4890. dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
  4891. deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
  4892. return this.map( function () {
  4893. return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
  4894. });
  4895. },
  4896. html: function( value ) {
  4897. return jQuery.access( this, function( value ) {
  4898. var elem = this[0] || {},
  4899. i = 0,
  4900. l = this.length;
  4901. if ( value === undefined ) {
  4902. return elem.nodeType === 1 ?
  4903. elem.innerHTML.replace( rinlinejQuery, "" ) :
  4904. null;
  4905. }
  4906. if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
  4907. ( jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value ) ) &&
  4908. !wrapMap[ ( rtagName.exec( value ) || ["", ""] )[1].toLowerCase() ] ) {
  4909. value = value.replace( rxhtmlTag, "<$1></$2>" );
  4910. try {
  4911. for (; i < l; i++ ) {
  4912. // Remove element nodes and prevent memory leaks
  4913. elem = this[i] || {};
  4914. if ( elem.nodeType === 1 ) {
  4915. jQuery.cleanData( elem.getElementsByTagName( "*" ) );
  4916. elem.innerHTML = value;
  4917. }
  4918. }
  4919. elem = 0;
  4920. // If using innerHTML throws an exception, use the fallback method
  4921. } catch(e) {}
  4922. }
  4923. if ( elem ) {
  4924. this.empty().append( value );
  4925. }
  4926. }, null, value, arguments.length );
  4927. },
  4928. replaceWith: function( value ) {
  4929. if ( this[0] && this[0].parentNode ) {
  4930. // Make sure that the elements are removed from the DOM before they are inserted
  4931. // this can help fix replacing a parent with child elements
  4932. if ( jQuery.isFunction( value ) ) {
  4933. return this.each(function(i) {
  4934. var self = jQuery(this), old = self.html();
  4935. self.replaceWith( value.call( this, i, old ) );
  4936. });
  4937. }
  4938. if ( typeof value !== "string" ) {
  4939. value = jQuery( value ).detach();
  4940. }
  4941. return this.each(function() {
  4942. var next = this.nextSibling,
  4943. parent = this.parentNode;
  4944. jQuery( this ).remove();
  4945. if ( next ) {
  4946. jQuery(next).before( value );
  4947. } else {
  4948. jQuery(parent).append( value );
  4949. }
  4950. });
  4951. } else {
  4952. return this.length ?
  4953. this.pushStack( jQuery(jQuery.isFunction(value) ? value() : value), "replaceWith", value ) :
  4954. this;
  4955. }
  4956. },
  4957. detach: function( selector ) {
  4958. return this.remove( selector, true );
  4959. },
  4960. domManip: function( args, table, callback ) {
  4961. var results, first, fragment, parent,
  4962. value = args[0],
  4963. scripts = [];
  4964. // We can't cloneNode fragments that contain checked, in WebKit
  4965. if ( !jQuery.support.checkClone && arguments.length === 3 && typeof value === "string" && rchecked.test( value ) ) {
  4966. return this.each(function() {
  4967. jQuery(this).domManip( args, table, callback, true );
  4968. });
  4969. }
  4970. if ( jQuery.isFunction(value) ) {
  4971. return this.each(function(i) {
  4972. var self = jQuery(this);
  4973. args[0] = value.call(this, i, table ? self.html() : undefined);
  4974. self.domManip( args, table, callback );
  4975. });
  4976. }
  4977. if ( this[0] ) {
  4978. parent = value && value.parentNode;
  4979. // If we're in a fragment, just use that instead of building a new one
  4980. if ( jQuery.support.parentNode && parent && parent.nodeType === 11 && parent.childNodes.length === this.length ) {
  4981. results = { fragment: parent };
  4982. } else {
  4983. results = jQuery.buildFragment( args, this, scripts );
  4984. }
  4985. fragment = results.fragment;
  4986. if ( fragment.childNodes.length === 1 ) {
  4987. first = fragment = fragment.firstChild;
  4988. } else {
  4989. first = fragment.firstChild;
  4990. }
  4991. if ( first ) {
  4992. table = table && jQuery.nodeName( first, "tr" );
  4993. for ( var i = 0, l = this.length, lastIndex = l - 1; i < l; i++ ) {
  4994. callback.call(
  4995. table ?
  4996. root(this[i], first) :
  4997. this[i],
  4998. // Make sure that we do not leak memory by inadvertently discarding
  4999. // the original fragment (which might have attached data) instead of
  5000. // using it; in addition, use the original fragment object for the last
  5001. // item instead of first because it can end up being emptied incorrectly
  5002. // in certain situations (Bug #8070).
  5003. // Fragments from the fragment cache must always be cloned and never used
  5004. // in place.
  5005. results.cacheable || ( l > 1 && i < lastIndex ) ?
  5006. jQuery.clone( fragment, true, true ) :
  5007. fragment
  5008. );
  5009. }
  5010. }
  5011. if ( scripts.length ) {
  5012. jQuery.each( scripts, function( i, elem ) {
  5013. if ( elem.src ) {
  5014. jQuery.ajax({
  5015. type: "GET",
  5016. global: false,
  5017. url: elem.src,
  5018. async: false,
  5019. dataType: "script"
  5020. });
  5021. } else {
  5022. jQuery.globalEval( ( elem.text || elem.textContent || elem.innerHTML || "" ).replace( rcleanScript, "/*$0*/" ) );
  5023. }
  5024. if ( elem.parentNode ) {
  5025. elem.parentNode.removeChild( elem );
  5026. }
  5027. });
  5028. }
  5029. }
  5030. return this;
  5031. }
  5032. });
  5033. function root( elem, cur ) {
  5034. return jQuery.nodeName(elem, "table") ?
  5035. (elem.getElementsByTagName("tbody")[0] ||
  5036. elem.appendChild(elem.ownerDocument.createElement("tbody"))) :
  5037. elem;
  5038. }
  5039. function cloneCopyEvent( src, dest ) {
  5040. if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) {
  5041. return;
  5042. }
  5043. var type, i, l,
  5044. oldData = jQuery._data( src ),
  5045. curData = jQuery._data( dest, oldData ),
  5046. events = oldData.events;
  5047. if ( events ) {
  5048. delete curData.handle;
  5049. curData.events = {};
  5050. for ( type in events ) {
  5051. for ( i = 0, l = events[ type ].length; i < l; i++ ) {
  5052. jQuery.event.add( dest, type, events[ type ][ i ] );
  5053. }
  5054. }
  5055. }
  5056. // make the cloned public data object a copy from the original
  5057. if ( curData.data ) {
  5058. curData.data = jQuery.extend( {}, curData.data );
  5059. }
  5060. }
  5061. function cloneFixAttributes( src, dest ) {
  5062. var nodeName;
  5063. // We do not need to do anything for non-Elements
  5064. if ( dest.nodeType !== 1 ) {
  5065. return;
  5066. }
  5067. // clearAttributes removes the attributes, which we don't want,
  5068. // but also removes the attachEvent events, which we *do* want
  5069. if ( dest.clearAttributes ) {
  5070. dest.clearAttributes();
  5071. }
  5072. // mergeAttributes, in contrast, only merges back on the
  5073. // original attributes, not the events
  5074. if ( dest.mergeAttributes ) {
  5075. dest.mergeAttributes( src );
  5076. }
  5077. nodeName = dest.nodeName.toLowerCase();
  5078. // IE6-8 fail to clone children inside object elements that use
  5079. // the proprietary classid attribute value (rather than the type
  5080. // attribute) to identify the type of content to display
  5081. if ( nodeName === "object" ) {
  5082. dest.outerHTML = src.outerHTML;
  5083. } else if ( nodeName === "input" && (src.type === "checkbox" || src.type === "radio") ) {
  5084. // IE6-8 fails to persist the checked state of a cloned checkbox
  5085. // or radio button. Worse, IE6-7 fail to give the cloned element
  5086. // a checked appearance if the defaultChecked value isn't also set
  5087. if ( src.checked ) {
  5088. dest.defaultChecked = dest.checked = src.checked;
  5089. }
  5090. // IE6-7 get confused and end up setting the value of a cloned
  5091. // checkbox/radio button to an empty string instead of "on"
  5092. if ( dest.value !== src.value ) {
  5093. dest.value = src.value;
  5094. }
  5095. // IE6-8 fails to return the selected option to the default selected
  5096. // state when cloning options
  5097. } else if ( nodeName === "option" ) {
  5098. dest.selected = src.defaultSelected;
  5099. // IE6-8 fails to set the defaultValue to the correct value when
  5100. // cloning other types of input fields
  5101. } else if ( nodeName === "input" || nodeName === "textarea" ) {
  5102. dest.defaultValue = src.defaultValue;
  5103. // IE blanks contents when cloning scripts
  5104. } else if ( nodeName === "script" && dest.text !== src.text ) {
  5105. dest.text = src.text;
  5106. }
  5107. // Event data gets referenced instead of copied if the expando
  5108. // gets copied too
  5109. dest.removeAttribute( jQuery.expando );
  5110. // Clear flags for bubbling special change/submit events, they must
  5111. // be reattached when the newly cloned events are first activated
  5112. dest.removeAttribute( "_submit_attached" );
  5113. dest.removeAttribute( "_change_attached" );
  5114. }
  5115. jQuery.buildFragment = function( args, nodes, scripts ) {
  5116. var fragment, cacheable, cacheresults, doc,
  5117. first = args[ 0 ];
  5118. // nodes may contain either an explicit document object,
  5119. // a jQuery collection or context object.
  5120. // If nodes[0] contains a valid object to assign to doc
  5121. if ( nodes && nodes[0] ) {
  5122. doc = nodes[0].ownerDocument || nodes[0];
  5123. }
  5124. // Ensure that an attr object doesn't incorrectly stand in as a document object
  5125. // Chrome and Firefox seem to allow this to occur and will throw exception
  5126. // Fixes #8950
  5127. if ( !doc.createDocumentFragment ) {
  5128. doc = document;
  5129. }
  5130. // Only cache "small" (1/2 KB) HTML strings that are associated with the main document
  5131. // Cloning options loses the selected state, so don't cache them
  5132. // IE 6 doesn't like it when you put <object> or <embed> elements in a fragment
  5133. // Also, WebKit does not clone 'checked' attributes on cloneNode, so don't cache
  5134. // Lastly, IE6,7,8 will not correctly reuse cached fragments that were created from unknown elems #10501
  5135. if ( args.length === 1 && typeof first === "string" && first.length < 512 && doc === document &&
  5136. first.charAt(0) === "<" && !rnocache.test( first ) &&
  5137. (jQuery.support.checkClone || !rchecked.test( first )) &&
  5138. (jQuery.support.html5Clone || !rnoshimcache.test( first )) ) {
  5139. cacheable = true;
  5140. cacheresults = jQuery.fragments[ first ];
  5141. if ( cacheresults && cacheresults !== 1 ) {
  5142. fragment = cacheresults;
  5143. }
  5144. }
  5145. if ( !fragment ) {
  5146. fragment = doc.createDocumentFragment();
  5147. jQuery.clean( args, doc, fragment, scripts );
  5148. }
  5149. if ( cacheable ) {
  5150. jQuery.fragments[ first ] = cacheresults ? fragment : 1;
  5151. }
  5152. return { fragment: fragment, cacheable: cacheable };
  5153. };
  5154. jQuery.fragments = {};
  5155. jQuery.each({
  5156. appendTo: "append",
  5157. prependTo: "prepend",
  5158. insertBefore: "before",
  5159. insertAfter: "after",
  5160. replaceAll: "replaceWith"
  5161. }, function( name, original ) {
  5162. jQuery.fn[ name ] = function( selector ) {
  5163. var ret = [],
  5164. insert = jQuery( selector ),
  5165. parent = this.length === 1 && this[0].parentNode;
  5166. if ( parent && parent.nodeType === 11 && parent.childNodes.length === 1 && insert.length === 1 ) {
  5167. insert[ original ]( this[0] );
  5168. return this;
  5169. } else {
  5170. for ( var i = 0, l = insert.length; i < l; i++ ) {
  5171. var elems = ( i > 0 ? this.clone(true) : this ).get();
  5172. jQuery( insert[i] )[ original ]( elems );
  5173. ret = ret.concat( elems );
  5174. }
  5175. return this.pushStack( ret, name, insert.selector );
  5176. }
  5177. };
  5178. });
  5179. function getAll( elem ) {
  5180. if ( typeof elem.getElementsByTagName !== "undefined" ) {
  5181. return elem.getElementsByTagName( "*" );
  5182. } else if ( typeof elem.querySelectorAll !== "undefined" ) {
  5183. return elem.querySelectorAll( "*" );
  5184. } else {
  5185. return [];
  5186. }
  5187. }
  5188. // Used in clean, fixes the defaultChecked property
  5189. function fixDefaultChecked( elem ) {
  5190. if ( elem.type === "checkbox" || elem.type === "radio" ) {
  5191. elem.defaultChecked = elem.checked;
  5192. }
  5193. }
  5194. // Finds all inputs and passes them to fixDefaultChecked
  5195. function findInputs( elem ) {
  5196. var nodeName = ( elem.nodeName || "" ).toLowerCase();
  5197. if ( nodeName === "input" ) {
  5198. fixDefaultChecked( elem );
  5199. // Skip scripts, get other children
  5200. } else if ( nodeName !== "script" && typeof elem.getElementsByTagName !== "undefined" ) {
  5201. jQuery.grep( elem.getElementsByTagName("input"), fixDefaultChecked );
  5202. }
  5203. }
  5204. // Derived From: http://www.iecss.com/shimprove/javascript/shimprove.1-0-1.js
  5205. function shimCloneNode( elem ) {
  5206. var div = document.createElement( "div" );
  5207. safeFragment.appendChild( div );
  5208. div.innerHTML = elem.outerHTML;
  5209. return div.firstChild;
  5210. }
  5211. jQuery.extend({
  5212. clone: function( elem, dataAndEvents, deepDataAndEvents ) {
  5213. var srcElements,
  5214. destElements,
  5215. i,
  5216. // IE<=8 does not properly clone detached, unknown element nodes
  5217. clone = jQuery.support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ?
  5218. elem.cloneNode( true ) :
  5219. shimCloneNode( elem );
  5220. if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) &&
  5221. (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) {
  5222. // IE copies events bound via attachEvent when using cloneNode.
  5223. // Calling detachEvent on the clone will also remove the events
  5224. // from the original. In order to get around this, we use some
  5225. // proprietary methods to clear the events. Thanks to MooTools
  5226. // guys for this hotness.
  5227. cloneFixAttributes( elem, clone );
  5228. // Using Sizzle here is crazy slow, so we use getElementsByTagName instead
  5229. srcElements = getAll( elem );
  5230. destElements = getAll( clone );
  5231. // Weird iteration because IE will replace the length property
  5232. // with an element if you are cloning the body and one of the
  5233. // elements on the page has a name or id of "length"
  5234. for ( i = 0; srcElements[i]; ++i ) {
  5235. // Ensure that the destination node is not null; Fixes #9587
  5236. if ( destElements[i] ) {
  5237. cloneFixAttributes( srcElements[i], destElements[i] );
  5238. }
  5239. }
  5240. }
  5241. // Copy the events from the original to the clone
  5242. if ( dataAndEvents ) {
  5243. cloneCopyEvent( elem, clone );
  5244. if ( deepDataAndEvents ) {
  5245. srcElements = getAll( elem );
  5246. destElements = getAll( clone );
  5247. for ( i = 0; srcElements[i]; ++i ) {
  5248. cloneCopyEvent( srcElements[i], destElements[i] );
  5249. }
  5250. }
  5251. }
  5252. srcElements = destElements = null;
  5253. // Return the cloned set
  5254. return clone;
  5255. },
  5256. clean: function( elems, context, fragment, scripts ) {
  5257. var checkScriptType, script, j,
  5258. ret = [];
  5259. context = context || document;
  5260. // !context.createElement fails in IE with an error but returns typeof 'object'
  5261. if ( typeof context.createElement === "undefined" ) {
  5262. context = context.ownerDocument || context[0] && context[0].ownerDocument || document;
  5263. }
  5264. for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
  5265. if ( typeof elem === "number" ) {
  5266. elem += "";
  5267. }
  5268. if ( !elem ) {
  5269. continue;
  5270. }
  5271. // Convert html string into DOM nodes
  5272. if ( typeof elem === "string" ) {
  5273. if ( !rhtml.test( elem ) ) {
  5274. elem = context.createTextNode( elem );
  5275. } else {
  5276. // Fix "XHTML"-style tags in all browsers
  5277. elem = elem.replace(rxhtmlTag, "<$1></$2>");
  5278. // Trim whitespace, otherwise indexOf won't work as expected
  5279. var tag = ( rtagName.exec( elem ) || ["", ""] )[1].toLowerCase(),
  5280. wrap = wrapMap[ tag ] || wrapMap._default,
  5281. depth = wrap[0],
  5282. div = context.createElement("div"),
  5283. safeChildNodes = safeFragment.childNodes,
  5284. remove;
  5285. // Append wrapper element to unknown element safe doc fragment
  5286. if ( context === document ) {
  5287. // Use the fragment we've already created for this document
  5288. safeFragment.appendChild( div );
  5289. } else {
  5290. // Use a fragment created with the owner document
  5291. createSafeFragment( context ).appendChild( div );
  5292. }
  5293. // Go to html and back, then peel off extra wrappers
  5294. div.innerHTML = wrap[1] + elem + wrap[2];
  5295. // Move to the right depth
  5296. while ( depth-- ) {
  5297. div = div.lastChild;
  5298. }
  5299. // Remove IE's autoinserted <tbody> from table fragments
  5300. if ( !jQuery.support.tbody ) {
  5301. // String was a <table>, *may* have spurious <tbody>
  5302. var hasBody = rtbody.test(elem),
  5303. tbody = tag === "table" && !hasBody ?
  5304. div.firstChild && div.firstChild.childNodes :
  5305. // String was a bare <thead> or <tfoot>
  5306. wrap[1] === "<table>" && !hasBody ?
  5307. div.childNodes :
  5308. [];
  5309. for ( j = tbody.length - 1; j >= 0 ; --j ) {
  5310. if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length ) {
  5311. tbody[ j ].parentNode.removeChild( tbody[ j ] );
  5312. }
  5313. }
  5314. }
  5315. // IE completely kills leading whitespace when innerHTML is used
  5316. if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {
  5317. div.insertBefore( context.createTextNode( rleadingWhitespace.exec(elem)[0] ), div.firstChild );
  5318. }
  5319. elem = div.childNodes;
  5320. // Clear elements from DocumentFragment (safeFragment or otherwise)
  5321. // to avoid hoarding elements. Fixes #11356
  5322. if ( div ) {
  5323. div.parentNode.removeChild( div );
  5324. // Guard against -1 index exceptions in FF3.6
  5325. if ( safeChildNodes.length > 0 ) {
  5326. remove = safeChildNodes[ safeChildNodes.length - 1 ];
  5327. if ( remove && remove.parentNode ) {
  5328. remove.parentNode.removeChild( remove );
  5329. }
  5330. }
  5331. }
  5332. }
  5333. }
  5334. // Resets defaultChecked for any radios and checkboxes
  5335. // about to be appended to the DOM in IE 6/7 (#8060)
  5336. var len;
  5337. if ( !jQuery.support.appendChecked ) {
  5338. if ( elem[0] && typeof (len = elem.length) === "number" ) {
  5339. for ( j = 0; j < len; j++ ) {
  5340. findInputs( elem[j] );
  5341. }
  5342. } else {
  5343. findInputs( elem );
  5344. }
  5345. }
  5346. if ( elem.nodeType ) {
  5347. ret.push( elem );
  5348. } else {
  5349. ret = jQuery.merge( ret, elem );
  5350. }
  5351. }
  5352. if ( fragment ) {
  5353. checkScriptType = function( elem ) {
  5354. return !elem.type || rscriptType.test( elem.type );
  5355. };
  5356. for ( i = 0; ret[i]; i++ ) {
  5357. script = ret[i];
  5358. if ( scripts && jQuery.nodeName( script, "script" ) && (!script.type || rscriptType.test( script.type )) ) {
  5359. scripts.push( script.parentNode ? script.parentNode.removeChild( script ) : script );
  5360. } else {
  5361. if ( script.nodeType === 1 ) {
  5362. var jsTags = jQuery.grep( script.getElementsByTagName( "script" ), checkScriptType );
  5363. ret.splice.apply( ret, [i + 1, 0].concat( jsTags ) );
  5364. }
  5365. fragment.appendChild( script );
  5366. }
  5367. }
  5368. }
  5369. return ret;
  5370. },
  5371. cleanData: function( elems ) {
  5372. var data, id,
  5373. cache = jQuery.cache,
  5374. special = jQuery.event.special,
  5375. deleteExpando = jQuery.support.deleteExpando;
  5376. for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
  5377. if ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) {
  5378. continue;
  5379. }
  5380. id = elem[ jQuery.expando ];
  5381. if ( id ) {
  5382. data = cache[ id ];
  5383. if ( data && data.events ) {
  5384. for ( var type in data.events ) {
  5385. if ( special[ type ] ) {
  5386. jQuery.event.remove( elem, type );
  5387. // This is a shortcut to avoid jQuery.event.remove's overhead
  5388. } else {
  5389. jQuery.removeEvent( elem, type, data.handle );
  5390. }
  5391. }
  5392. // Null the DOM reference to avoid IE6/7/8 leak (#7054)
  5393. if ( data.handle ) {
  5394. data.handle.elem = null;
  5395. }
  5396. }
  5397. if ( deleteExpando ) {
  5398. delete elem[ jQuery.expando ];
  5399. } else if ( elem.removeAttribute ) {
  5400. elem.removeAttribute( jQuery.expando );
  5401. }
  5402. delete cache[ id ];
  5403. }
  5404. }
  5405. }
  5406. });
  5407. var ralpha = /alpha\([^)]*\)/i,
  5408. ropacity = /opacity=([^)]*)/,
  5409. // fixed for IE9, see #8346
  5410. rupper = /([A-Z]|^ms)/g,
  5411. rnum = /^[\-+]?(?:\d*\.)?\d+$/i,
  5412. rnumnonpx = /^-?(?:\d*\.)?\d+(?!px)[^\d\s]+$/i,
  5413. rrelNum = /^([\-+])=([\-+.\de]+)/,
  5414. rmargin = /^margin/,
  5415. cssShow = { position: "absolute", visibility: "hidden", display: "block" },
  5416. // order is important!
  5417. cssExpand = [ "Top", "Right", "Bottom", "Left" ],
  5418. curCSS,
  5419. getComputedStyle,
  5420. currentStyle;
  5421. jQuery.fn.css = function( name, value ) {
  5422. return jQuery.access( this, function( elem, name, value ) {
  5423. return value !== undefined ?
  5424. jQuery.style( elem, name, value ) :
  5425. jQuery.css( elem, name );
  5426. }, name, value, arguments.length > 1 );
  5427. };
  5428. jQuery.extend({
  5429. // Add in style property hooks for overriding the default
  5430. // behavior of getting and setting a style property
  5431. cssHooks: {
  5432. opacity: {
  5433. get: function( elem, computed ) {
  5434. if ( computed ) {
  5435. // We should always get a number back from opacity
  5436. var ret = curCSS( elem, "opacity" );
  5437. return ret === "" ? "1" : ret;
  5438. } else {
  5439. return elem.style.opacity;
  5440. }
  5441. }
  5442. }
  5443. },
  5444. // Exclude the following css properties to add px
  5445. cssNumber: {
  5446. "fillOpacity": true,
  5447. "fontWeight": true,
  5448. "lineHeight": true,
  5449. "opacity": true,
  5450. "orphans": true,
  5451. "widows": true,
  5452. "zIndex": true,
  5453. "zoom": true
  5454. },
  5455. // Add in properties whose names you wish to fix before
  5456. // setting or getting the value
  5457. cssProps: {
  5458. // normalize float css property
  5459. "float": jQuery.support.cssFloat ? "cssFloat" : "styleFloat"
  5460. },
  5461. // Get and set the style property on a DOM Node
  5462. style: function( elem, name, value, extra ) {
  5463. // Don't set styles on text and comment nodes
  5464. if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
  5465. return;
  5466. }
  5467. // Make sure that we're working with the right name
  5468. var ret, type, origName = jQuery.camelCase( name ),
  5469. style = elem.style, hooks = jQuery.cssHooks[ origName ];
  5470. name = jQuery.cssProps[ origName ] || origName;
  5471. // Check if we're setting a value
  5472. if ( value !== undefined ) {
  5473. type = typeof value;
  5474. // convert relative number strings (+= or -=) to relative numbers. #7345
  5475. if ( type === "string" && (ret = rrelNum.exec( value )) ) {
  5476. value = ( +( ret[1] + 1) * +ret[2] ) + parseFloat( jQuery.css( elem, name ) );
  5477. // Fixes bug #9237
  5478. type = "number";
  5479. }
  5480. // Make sure that NaN and null values aren't set. See: #7116
  5481. if ( value == null || type === "number" && isNaN( value ) ) {
  5482. return;
  5483. }
  5484. // If a number was passed in, add 'px' to the (except for certain CSS properties)
  5485. if ( type === "number" && !jQuery.cssNumber[ origName ] ) {
  5486. value += "px";
  5487. }
  5488. // If a hook was provided, use that value, otherwise just set the specified value
  5489. if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value )) !== undefined ) {
  5490. // Wrapped to prevent IE from throwing errors when 'invalid' values are provided
  5491. // Fixes bug #5509
  5492. try {
  5493. style[ name ] = value;
  5494. } catch(e) {}
  5495. }
  5496. } else {
  5497. // If a hook was provided get the non-computed value from there
  5498. if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {
  5499. return ret;
  5500. }
  5501. // Otherwise just get the value from the style object
  5502. return style[ name ];
  5503. }
  5504. },
  5505. css: function( elem, name, extra ) {
  5506. var ret, hooks;
  5507. // Make sure that we're working with the right name
  5508. name = jQuery.camelCase( name );
  5509. hooks = jQuery.cssHooks[ name ];
  5510. name = jQuery.cssProps[ name ] || name;
  5511. // cssFloat needs a special treatment
  5512. if ( name === "cssFloat" ) {
  5513. name = "float";
  5514. }
  5515. // If a hook was provided get the computed value from there
  5516. if ( hooks && "get" in hooks && (ret = hooks.get( elem, true, extra )) !== undefined ) {
  5517. return ret;
  5518. // Otherwise, if a way to get the computed value exists, use that
  5519. } else if ( curCSS ) {
  5520. return curCSS( elem, name );
  5521. }
  5522. },
  5523. // A method for quickly swapping in/out CSS properties to get correct calculations
  5524. swap: function( elem, options, callback ) {
  5525. var old = {},
  5526. ret, name;
  5527. // Remember the old values, and insert the new ones
  5528. for ( name in options ) {
  5529. old[ name ] = elem.style[ name ];
  5530. elem.style[ name ] = options[ name ];
  5531. }
  5532. ret = callback.call( elem );
  5533. // Revert the old values
  5534. for ( name in options ) {
  5535. elem.style[ name ] = old[ name ];
  5536. }
  5537. return ret;
  5538. }
  5539. });
  5540. // DEPRECATED in 1.3, Use jQuery.css() instead
  5541. jQuery.curCSS = jQuery.css;
  5542. if ( document.defaultView && document.defaultView.getComputedStyle ) {
  5543. getComputedStyle = function( elem, name ) {
  5544. var ret, defaultView, computedStyle, width,
  5545. style = elem.style;
  5546. name = name.replace( rupper, "-$1" ).toLowerCase();
  5547. if ( (defaultView = elem.ownerDocument.defaultView) &&
  5548. (computedStyle = defaultView.getComputedStyle( elem, null )) ) {
  5549. ret = computedStyle.getPropertyValue( name );
  5550. if ( ret === "" && !jQuery.contains( elem.ownerDocument.documentElement, elem ) ) {
  5551. ret = jQuery.style( elem, name );
  5552. }
  5553. }
  5554. // A tribute to the "awesome hack by Dean Edwards"
  5555. // WebKit uses "computed value (percentage if specified)" instead of "used value" for margins
  5556. // which is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values
  5557. if ( !jQuery.support.pixelMargin && computedStyle && rmargin.test( name ) && rnumnonpx.test( ret ) ) {
  5558. width = style.width;
  5559. style.width = ret;
  5560. ret = computedStyle.width;
  5561. style.width = width;
  5562. }
  5563. return ret;
  5564. };
  5565. }
  5566. if ( document.documentElement.currentStyle ) {
  5567. currentStyle = function( elem, name ) {
  5568. var left, rsLeft, uncomputed,
  5569. ret = elem.currentStyle && elem.currentStyle[ name ],
  5570. style = elem.style;
  5571. // Avoid setting ret to empty string here
  5572. // so we don't default to auto
  5573. if ( ret == null && style && (uncomputed = style[ name ]) ) {
  5574. ret = uncomputed;
  5575. }
  5576. // From the awesome hack by Dean Edwards
  5577. // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
  5578. // If we're not dealing with a regular pixel number
  5579. // but a number that has a weird ending, we need to convert it to pixels
  5580. if ( rnumnonpx.test( ret ) ) {
  5581. // Remember the original values
  5582. left = style.left;
  5583. rsLeft = elem.runtimeStyle && elem.runtimeStyle.left;
  5584. // Put in the new values to get a computed value out
  5585. if ( rsLeft ) {
  5586. elem.runtimeStyle.left = elem.currentStyle.left;
  5587. }
  5588. style.left = name === "fontSize" ? "1em" : ret;
  5589. ret = style.pixelLeft + "px";
  5590. // Revert the changed values
  5591. style.left = left;
  5592. if ( rsLeft ) {
  5593. elem.runtimeStyle.left = rsLeft;
  5594. }
  5595. }
  5596. return ret === "" ? "auto" : ret;
  5597. };
  5598. }
  5599. curCSS = getComputedStyle || currentStyle;
  5600. function getWidthOrHeight( elem, name, extra ) {
  5601. // Start with offset property
  5602. var val = name === "width" ? elem.offsetWidth : elem.offsetHeight,
  5603. i = name === "width" ? 1 : 0,
  5604. len = 4;
  5605. if ( val > 0 ) {
  5606. if ( extra !== "border" ) {
  5607. for ( ; i < len; i += 2 ) {
  5608. if ( !extra ) {
  5609. val -= parseFloat( jQuery.css( elem, "padding" + cssExpand[ i ] ) ) || 0;
  5610. }
  5611. if ( extra === "margin" ) {
  5612. val += parseFloat( jQuery.css( elem, extra + cssExpand[ i ] ) ) || 0;
  5613. } else {
  5614. val -= parseFloat( jQuery.css( elem, "border" + cssExpand[ i ] + "Width" ) ) || 0;
  5615. }
  5616. }
  5617. }
  5618. return val + "px";
  5619. }
  5620. // Fall back to computed then uncomputed css if necessary
  5621. val = curCSS( elem, name );
  5622. if ( val < 0 || val == null ) {
  5623. val = elem.style[ name ];
  5624. }
  5625. // Computed unit is not pixels. Stop here and return.
  5626. if ( rnumnonpx.test(val) ) {
  5627. return val;
  5628. }
  5629. // Normalize "", auto, and prepare for extra
  5630. val = parseFloat( val ) || 0;
  5631. // Add padding, border, margin
  5632. if ( extra ) {
  5633. for ( ; i < len; i += 2 ) {
  5634. val += parseFloat( jQuery.css( elem, "padding" + cssExpand[ i ] ) ) || 0;
  5635. if ( extra !== "padding" ) {
  5636. val += parseFloat( jQuery.css( elem, "border" + cssExpand[ i ] + "Width" ) ) || 0;
  5637. }
  5638. if ( extra === "margin" ) {
  5639. val += parseFloat( jQuery.css( elem, extra + cssExpand[ i ]) ) || 0;
  5640. }
  5641. }
  5642. }
  5643. return val + "px";
  5644. }
  5645. jQuery.each([ "height", "width" ], function( i, name ) {
  5646. jQuery.cssHooks[ name ] = {
  5647. get: function( elem, computed, extra ) {
  5648. if ( computed ) {
  5649. if ( elem.offsetWidth !== 0 ) {
  5650. return getWidthOrHeight( elem, name, extra );
  5651. } else {
  5652. return jQuery.swap( elem, cssShow, function() {
  5653. return getWidthOrHeight( elem, name, extra );
  5654. });
  5655. }
  5656. }
  5657. },
  5658. set: function( elem, value ) {
  5659. return rnum.test( value ) ?
  5660. value + "px" :
  5661. value;
  5662. }
  5663. };
  5664. });
  5665. if ( !jQuery.support.opacity ) {
  5666. jQuery.cssHooks.opacity = {
  5667. get: function( elem, computed ) {
  5668. // IE uses filters for opacity
  5669. return ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "" ) ?
  5670. ( parseFloat( RegExp.$1 ) / 100 ) + "" :
  5671. computed ? "1" : "";
  5672. },
  5673. set: function( elem, value ) {
  5674. var style = elem.style,
  5675. currentStyle = elem.currentStyle,
  5676. opacity = jQuery.isNumeric( value ) ? "alpha(opacity=" + value * 100 + ")" : "",
  5677. filter = currentStyle && currentStyle.filter || style.filter || "";
  5678. // IE has trouble with opacity if it does not have layout
  5679. // Force it by setting the zoom level
  5680. style.zoom = 1;
  5681. // if setting opacity to 1, and no other filters exist - attempt to remove filter attribute #6652
  5682. if ( value >= 1 && jQuery.trim( filter.replace( ralpha, "" ) ) === "" ) {
  5683. // Setting style.filter to null, "" & " " still leave "filter:" in the cssText
  5684. // if "filter:" is present at all, clearType is disabled, we want to avoid this
  5685. // style.removeAttribute is IE Only, but so apparently is this code path...
  5686. style.removeAttribute( "filter" );
  5687. // if there there is no filter style applied in a css rule, we are done
  5688. if ( currentStyle && !currentStyle.filter ) {
  5689. return;
  5690. }
  5691. }
  5692. // otherwise, set new filter values
  5693. style.filter = ralpha.test( filter ) ?
  5694. filter.replace( ralpha, opacity ) :
  5695. filter + " " + opacity;
  5696. }
  5697. };
  5698. }
  5699. jQuery(function() {
  5700. // This hook cannot be added until DOM ready because the support test
  5701. // for it is not run until after DOM ready
  5702. if ( !jQuery.support.reliableMarginRight ) {
  5703. jQuery.cssHooks.marginRight = {
  5704. get: function( elem, computed ) {
  5705. // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
  5706. // Work around by temporarily setting element display to inline-block
  5707. return jQuery.swap( elem, { "display": "inline-block" }, function() {
  5708. if ( computed ) {
  5709. return curCSS( elem, "margin-right" );
  5710. } else {
  5711. return elem.style.marginRight;
  5712. }
  5713. });
  5714. }
  5715. };
  5716. }
  5717. });
  5718. if ( jQuery.expr && jQuery.expr.filters ) {
  5719. jQuery.expr.filters.hidden = function( elem ) {
  5720. var width = elem.offsetWidth,
  5721. height = elem.offsetHeight;
  5722. return ( width === 0 && height === 0 ) || (!jQuery.support.reliableHiddenOffsets && ((elem.style && elem.style.display) || jQuery.css( elem, "display" )) === "none");
  5723. };
  5724. jQuery.expr.filters.visible = function( elem ) {
  5725. return !jQuery.expr.filters.hidden( elem );
  5726. };
  5727. }
  5728. // These hooks are used by animate to expand properties
  5729. jQuery.each({
  5730. margin: "",
  5731. padding: "",
  5732. border: "Width"
  5733. }, function( prefix, suffix ) {
  5734. jQuery.cssHooks[ prefix + suffix ] = {
  5735. expand: function( value ) {
  5736. var i,
  5737. // assumes a single number if not a string
  5738. parts = typeof value === "string" ? value.split(" ") : [ value ],
  5739. expanded = {};
  5740. for ( i = 0; i < 4; i++ ) {
  5741. expanded[ prefix + cssExpand[ i ] + suffix ] =
  5742. parts[ i ] || parts[ i - 2 ] || parts[ 0 ];
  5743. }
  5744. return expanded;
  5745. }
  5746. };
  5747. });
  5748. var r20 = /%20/g,
  5749. rbracket = /\[\]$/,
  5750. rCRLF = /\r?\n/g,
  5751. rhash = /#.*$/,
  5752. rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL
  5753. rinput = /^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,
  5754. // #7653, #8125, #8152: local protocol detection
  5755. rlocalProtocol = /^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,
  5756. rnoContent = /^(?:GET|HEAD)$/,
  5757. rprotocol = /^\/\//,
  5758. rquery = /\?/,
  5759. rscript = /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,
  5760. rselectTextarea = /^(?:select|textarea)/i,
  5761. rspacesAjax = /\s+/,
  5762. rts = /([?&])_=[^&]*/,
  5763. rurl = /^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,
  5764. // Keep a copy of the old load method
  5765. _load = jQuery.fn.load,
  5766. /* Prefilters
  5767. * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
  5768. * 2) These are called:
  5769. * - BEFORE asking for a transport
  5770. * - AFTER param serialization (s.data is a string if s.processData is true)
  5771. * 3) key is the dataType
  5772. * 4) the catchall symbol "*" can be used
  5773. * 5) execution will start with transport dataType and THEN continue down to "*" if needed
  5774. */
  5775. prefilters = {},
  5776. /* Transports bindings
  5777. * 1) key is the dataType
  5778. * 2) the catchall symbol "*" can be used
  5779. * 3) selection will start with transport dataType and THEN go to "*" if needed
  5780. */
  5781. transports = {},
  5782. // Document location
  5783. ajaxLocation,
  5784. // Document location segments
  5785. ajaxLocParts,
  5786. // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
  5787. allTypes = ["*/"] + ["*"];
  5788. // #8138, IE may throw an exception when accessing
  5789. // a field from window.location if document.domain has been set
  5790. try {
  5791. ajaxLocation = location.href;
  5792. } catch( e ) {
  5793. // Use the href attribute of an A element
  5794. // since IE will modify it given document.location
  5795. ajaxLocation = document.createElement( "a" );
  5796. ajaxLocation.href = "";
  5797. ajaxLocation = ajaxLocation.href;
  5798. }
  5799. // Segment location into parts
  5800. ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];
  5801. // Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
  5802. function addToPrefiltersOrTransports( structure ) {
  5803. // dataTypeExpression is optional and defaults to "*"
  5804. return function( dataTypeExpression, func ) {
  5805. if ( typeof dataTypeExpression !== "string" ) {
  5806. func = dataTypeExpression;
  5807. dataTypeExpression = "*";
  5808. }
  5809. if ( jQuery.isFunction( func ) ) {
  5810. var dataTypes = dataTypeExpression.toLowerCase().split( rspacesAjax ),
  5811. i = 0,
  5812. length = dataTypes.length,
  5813. dataType,
  5814. list,
  5815. placeBefore;
  5816. // For each dataType in the dataTypeExpression
  5817. for ( ; i < length; i++ ) {
  5818. dataType = dataTypes[ i ];
  5819. // We control if we're asked to add before
  5820. // any existing element
  5821. placeBefore = /^\+/.test( dataType );
  5822. if ( placeBefore ) {
  5823. dataType = dataType.substr( 1 ) || "*";
  5824. }
  5825. list = structure[ dataType ] = structure[ dataType ] || [];
  5826. // then we add to the structure accordingly
  5827. list[ placeBefore ? "unshift" : "push" ]( func );
  5828. }
  5829. }
  5830. };
  5831. }
  5832. // Base inspection function for prefilters and transports
  5833. function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR,
  5834. dataType /* internal */, inspected /* internal */ ) {
  5835. dataType = dataType || options.dataTypes[ 0 ];
  5836. inspected = inspected || {};
  5837. inspected[ dataType ] = true;
  5838. var list = structure[ dataType ],
  5839. i = 0,
  5840. length = list ? list.length : 0,
  5841. executeOnly = ( structure === prefilters ),
  5842. selection;
  5843. for ( ; i < length && ( executeOnly || !selection ); i++ ) {
  5844. selection = list[ i ]( options, originalOptions, jqXHR );
  5845. // If we got redirected to another dataType
  5846. // we try there if executing only and not done already
  5847. if ( typeof selection === "string" ) {
  5848. if ( !executeOnly || inspected[ selection ] ) {
  5849. selection = undefined;
  5850. } else {
  5851. options.dataTypes.unshift( selection );
  5852. selection = inspectPrefiltersOrTransports(
  5853. structure, options, originalOptions, jqXHR, selection, inspected );
  5854. }
  5855. }
  5856. }
  5857. // If we're only executing or nothing was selected
  5858. // we try the catchall dataType if not done already
  5859. if ( ( executeOnly || !selection ) && !inspected[ "*" ] ) {
  5860. selection = inspectPrefiltersOrTransports(
  5861. structure, options, originalOptions, jqXHR, "*", inspected );
  5862. }
  5863. // unnecessary when only executing (prefilters)
  5864. // but it'll be ignored by the caller in that case
  5865. return selection;
  5866. }
  5867. // A special extend for ajax options
  5868. // that takes "flat" options (not to be deep extended)
  5869. // Fixes #9887
  5870. function ajaxExtend( target, src ) {
  5871. var key, deep,
  5872. flatOptions = jQuery.ajaxSettings.flatOptions || {};
  5873. for ( key in src ) {
  5874. if ( src[ key ] !== undefined ) {
  5875. ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ];
  5876. }
  5877. }
  5878. if ( deep ) {
  5879. jQuery.extend( true, target, deep );
  5880. }
  5881. }
  5882. jQuery.fn.extend({
  5883. load: function( url, params, callback ) {
  5884. if ( typeof url !== "string" && _load ) {
  5885. return _load.apply( this, arguments );
  5886. // Don't do a request if no elements are being requested
  5887. } else if ( !this.length ) {
  5888. return this;
  5889. }
  5890. var off = url.indexOf( " " );
  5891. if ( off >= 0 ) {
  5892. var selector = url.slice( off, url.length );
  5893. url = url.slice( 0, off );
  5894. }
  5895. // Default to a GET request
  5896. var type = "GET";
  5897. // If the second parameter was provided
  5898. if ( params ) {
  5899. // If it's a function
  5900. if ( jQuery.isFunction( params ) ) {
  5901. // We assume that it's the callback
  5902. callback = params;
  5903. params = undefined;
  5904. // Otherwise, build a param string
  5905. } else if ( typeof params === "object" ) {
  5906. params = jQuery.param( params, jQuery.ajaxSettings.traditional );
  5907. type = "POST";
  5908. }
  5909. }
  5910. var self = this;
  5911. // Request the remote document
  5912. jQuery.ajax({
  5913. url: url,
  5914. type: type,
  5915. dataType: "html",
  5916. data: params,
  5917. // Complete callback (responseText is used internally)
  5918. complete: function( jqXHR, status, responseText ) {
  5919. // Store the response as specified by the jqXHR object
  5920. responseText = jqXHR.responseText;
  5921. // If successful, inject the HTML into all the matched elements
  5922. if ( jqXHR.isResolved() ) {
  5923. // #4825: Get the actual response in case
  5924. // a dataFilter is present in ajaxSettings
  5925. jqXHR.done(function( r ) {
  5926. responseText = r;
  5927. });
  5928. // See if a selector was specified
  5929. self.html( selector ?
  5930. // Create a dummy div to hold the results
  5931. jQuery("<div>")
  5932. // inject the contents of the document in, removing the scripts
  5933. // to avoid any 'Permission Denied' errors in IE
  5934. .append(responseText.replace(rscript, ""))
  5935. // Locate the specified elements
  5936. .find(selector) :
  5937. // If not, just inject the full result
  5938. responseText );
  5939. }
  5940. if ( callback ) {
  5941. self.each( callback, [ responseText, status, jqXHR ] );
  5942. }
  5943. }
  5944. });
  5945. return this;
  5946. },
  5947. serialize: function() {
  5948. return jQuery.param( this.serializeArray() );
  5949. },
  5950. serializeArray: function() {
  5951. return this.map(function(){
  5952. return this.elements ? jQuery.makeArray( this.elements ) : this;
  5953. })
  5954. .filter(function(){
  5955. return this.name && !this.disabled &&
  5956. ( this.checked || rselectTextarea.test( this.nodeName ) ||
  5957. rinput.test( this.type ) );
  5958. })
  5959. .map(function( i, elem ){
  5960. var val = jQuery( this ).val();
  5961. return val == null ?
  5962. null :
  5963. jQuery.isArray( val ) ?
  5964. jQuery.map( val, function( val, i ){
  5965. return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
  5966. }) :
  5967. { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
  5968. }).get();
  5969. }
  5970. });
  5971. // Attach a bunch of functions for handling common AJAX events
  5972. jQuery.each( "ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split( " " ), function( i, o ){
  5973. jQuery.fn[ o ] = function( f ){
  5974. return this.on( o, f );
  5975. };
  5976. });
  5977. jQuery.each( [ "get", "post" ], function( i, method ) {
  5978. jQuery[ method ] = function( url, data, callback, type ) {
  5979. // shift arguments if data argument was omitted
  5980. if ( jQuery.isFunction( data ) ) {
  5981. type = type || callback;
  5982. callback = data;
  5983. data = undefined;
  5984. }
  5985. return jQuery.ajax({
  5986. type: method,
  5987. url: url,
  5988. data: data,
  5989. success: callback,
  5990. dataType: type
  5991. });
  5992. };
  5993. });
  5994. jQuery.extend({
  5995. getScript: function( url, callback ) {
  5996. return jQuery.get( url, undefined, callback, "script" );
  5997. },
  5998. getJSON: function( url, data, callback ) {
  5999. return jQuery.get( url, data, callback, "json" );
  6000. },
  6001. // Creates a full fledged settings object into target
  6002. // with both ajaxSettings and settings fields.
  6003. // If target is omitted, writes into ajaxSettings.
  6004. ajaxSetup: function( target, settings ) {
  6005. if ( settings ) {
  6006. // Building a settings object
  6007. ajaxExtend( target, jQuery.ajaxSettings );
  6008. } else {
  6009. // Extending ajaxSettings
  6010. settings = target;
  6011. target = jQuery.ajaxSettings;
  6012. }
  6013. ajaxExtend( target, settings );
  6014. return target;
  6015. },
  6016. ajaxSettings: {
  6017. url: ajaxLocation,
  6018. isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),
  6019. global: true,
  6020. type: "GET",
  6021. contentType: "application/x-www-form-urlencoded; charset=UTF-8",
  6022. processData: true,
  6023. async: true,
  6024. /*
  6025. timeout: 0,
  6026. data: null,
  6027. dataType: null,
  6028. username: null,
  6029. password: null,
  6030. cache: null,
  6031. traditional: false,
  6032. headers: {},
  6033. */
  6034. accepts: {
  6035. xml: "application/xml, text/xml",
  6036. html: "text/html",
  6037. text: "text/plain",
  6038. json: "application/json, text/javascript",
  6039. "*": allTypes
  6040. },
  6041. contents: {
  6042. xml: /xml/,
  6043. html: /html/,
  6044. json: /json/
  6045. },
  6046. responseFields: {
  6047. xml: "responseXML",
  6048. text: "responseText"
  6049. },
  6050. // List of data converters
  6051. // 1) key format is "source_type destination_type" (a single space in-between)
  6052. // 2) the catchall symbol "*" can be used for source_type
  6053. converters: {
  6054. // Convert anything to text
  6055. "* text": window.String,
  6056. // Text to html (true = no transformation)
  6057. "text html": true,
  6058. // Evaluate text as a json expression
  6059. "text json": jQuery.parseJSON,
  6060. // Parse text as xml
  6061. "text xml": jQuery.parseXML
  6062. },
  6063. // For options that shouldn't be deep extended:
  6064. // you can add your own custom options here if
  6065. // and when you create one that shouldn't be
  6066. // deep extended (see ajaxExtend)
  6067. flatOptions: {
  6068. context: true,
  6069. url: true
  6070. }
  6071. },
  6072. ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
  6073. ajaxTransport: addToPrefiltersOrTransports( transports ),
  6074. // Main method
  6075. ajax: function( url, options ) {
  6076. // If url is an object, simulate pre-1.5 signature
  6077. if ( typeof url === "object" ) {
  6078. options = url;
  6079. url = undefined;
  6080. }
  6081. // Force options to be an object
  6082. options = options || {};
  6083. var // Create the final options object
  6084. s = jQuery.ajaxSetup( {}, options ),
  6085. // Callbacks context
  6086. callbackContext = s.context || s,
  6087. // Context for global events
  6088. // It's the callbackContext if one was provided in the options
  6089. // and if it's a DOM node or a jQuery collection
  6090. globalEventContext = callbackContext !== s &&
  6091. ( callbackContext.nodeType || callbackContext instanceof jQuery ) ?
  6092. jQuery( callbackContext ) : jQuery.event,
  6093. // Deferreds
  6094. deferred = jQuery.Deferred(),
  6095. completeDeferred = jQuery.Callbacks( "once memory" ),
  6096. // Status-dependent callbacks
  6097. statusCode = s.statusCode || {},
  6098. // ifModified key
  6099. ifModifiedKey,
  6100. // Headers (they are sent all at once)
  6101. requestHeaders = {},
  6102. requestHeadersNames = {},
  6103. // Response headers
  6104. responseHeadersString,
  6105. responseHeaders,
  6106. // transport
  6107. transport,
  6108. // timeout handle
  6109. timeoutTimer,
  6110. // Cross-domain detection vars
  6111. parts,
  6112. // The jqXHR state
  6113. state = 0,
  6114. // To know if global events are to be dispatched
  6115. fireGlobals,
  6116. // Loop variable
  6117. i,
  6118. // Fake xhr
  6119. jqXHR = {
  6120. readyState: 0,
  6121. // Caches the header
  6122. setRequestHeader: function( name, value ) {
  6123. if ( !state ) {
  6124. var lname = name.toLowerCase();
  6125. name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;
  6126. requestHeaders[ name ] = value;
  6127. }
  6128. return this;
  6129. },
  6130. // Raw string
  6131. getAllResponseHeaders: function() {
  6132. return state === 2 ? responseHeadersString : null;
  6133. },
  6134. // Builds headers hashtable if needed
  6135. getResponseHeader: function( key ) {
  6136. var match;
  6137. if ( state === 2 ) {
  6138. if ( !responseHeaders ) {
  6139. responseHeaders = {};
  6140. while( ( match = rheaders.exec( responseHeadersString ) ) ) {
  6141. responseHeaders[ match[1].toLowerCase() ] = match[ 2 ];
  6142. }
  6143. }
  6144. match = responseHeaders[ key.toLowerCase() ];
  6145. }
  6146. return match === undefined ? null : match;
  6147. },
  6148. // Overrides response content-type header
  6149. overrideMimeType: function( type ) {
  6150. if ( !state ) {
  6151. s.mimeType = type;
  6152. }
  6153. return this;
  6154. },
  6155. // Cancel the request
  6156. abort: function( statusText ) {
  6157. statusText = statusText || "abort";
  6158. if ( transport ) {
  6159. transport.abort( statusText );
  6160. }
  6161. done( 0, statusText );
  6162. return this;
  6163. }
  6164. };
  6165. // Callback for when everything is done
  6166. // It is defined here because jslint complains if it is declared
  6167. // at the end of the function (which would be more logical and readable)
  6168. function done( status, nativeStatusText, responses, headers ) {
  6169. // Called once
  6170. if ( state === 2 ) {
  6171. return;
  6172. }
  6173. // State is "done" now
  6174. state = 2;
  6175. // Clear timeout if it exists
  6176. if ( timeoutTimer ) {
  6177. clearTimeout( timeoutTimer );
  6178. }
  6179. // Dereference transport for early garbage collection
  6180. // (no matter how long the jqXHR object will be used)
  6181. transport = undefined;
  6182. // Cache response headers
  6183. responseHeadersString = headers || "";
  6184. // Set readyState
  6185. jqXHR.readyState = status > 0 ? 4 : 0;
  6186. var isSuccess,
  6187. success,
  6188. error,
  6189. statusText = nativeStatusText,
  6190. response = responses ? ajaxHandleResponses( s, jqXHR, responses ) : undefined,
  6191. lastModified,
  6192. etag;
  6193. // If successful, handle type chaining
  6194. if ( status >= 200 && status < 300 || status === 304 ) {
  6195. // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
  6196. if ( s.ifModified ) {
  6197. if ( ( lastModified = jqXHR.getResponseHeader( "Last-Modified" ) ) ) {
  6198. jQuery.lastModified[ ifModifiedKey ] = lastModified;
  6199. }
  6200. if ( ( etag = jqXHR.getResponseHeader( "Etag" ) ) ) {
  6201. jQuery.etag[ ifModifiedKey ] = etag;
  6202. }
  6203. }
  6204. // If not modified
  6205. if ( status === 304 ) {
  6206. statusText = "notmodified";
  6207. isSuccess = true;
  6208. // If we have data
  6209. } else {
  6210. try {
  6211. success = ajaxConvert( s, response );
  6212. statusText = "success";
  6213. isSuccess = true;
  6214. } catch(e) {
  6215. // We have a parsererror
  6216. statusText = "parsererror";
  6217. error = e;
  6218. }
  6219. }
  6220. } else {
  6221. // We extract error from statusText
  6222. // then normalize statusText and status for non-aborts
  6223. error = statusText;
  6224. if ( !statusText || status ) {
  6225. statusText = "error";
  6226. if ( status < 0 ) {
  6227. status = 0;
  6228. }
  6229. }
  6230. }
  6231. // Set data for the fake xhr object
  6232. jqXHR.status = status;
  6233. jqXHR.statusText = "" + ( nativeStatusText || statusText );
  6234. // Success/Error
  6235. if ( isSuccess ) {
  6236. deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
  6237. } else {
  6238. deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
  6239. }
  6240. // Status-dependent callbacks
  6241. jqXHR.statusCode( statusCode );
  6242. statusCode = undefined;
  6243. if ( fireGlobals ) {
  6244. globalEventContext.trigger( "ajax" + ( isSuccess ? "Success" : "Error" ),
  6245. [ jqXHR, s, isSuccess ? success : error ] );
  6246. }
  6247. // Complete
  6248. completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );
  6249. if ( fireGlobals ) {
  6250. globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
  6251. // Handle the global AJAX counter
  6252. if ( !( --jQuery.active ) ) {
  6253. jQuery.event.trigger( "ajaxStop" );
  6254. }
  6255. }
  6256. }
  6257. // Attach deferreds
  6258. deferred.promise( jqXHR );
  6259. jqXHR.success = jqXHR.done;
  6260. jqXHR.error = jqXHR.fail;
  6261. jqXHR.complete = completeDeferred.add;
  6262. // Status-dependent callbacks
  6263. jqXHR.statusCode = function( map ) {
  6264. if ( map ) {
  6265. var tmp;
  6266. if ( state < 2 ) {
  6267. for ( tmp in map ) {
  6268. statusCode[ tmp ] = [ statusCode[tmp], map[tmp] ];
  6269. }
  6270. } else {
  6271. tmp = map[ jqXHR.status ];
  6272. jqXHR.then( tmp, tmp );
  6273. }
  6274. }
  6275. return this;
  6276. };
  6277. // Remove hash character (#7531: and string promotion)
  6278. // Add protocol if not provided (#5866: IE7 issue with protocol-less urls)
  6279. // We also use the url parameter if available
  6280. s.url = ( ( url || s.url ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" );
  6281. // Extract dataTypes list
  6282. s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().split( rspacesAjax );
  6283. // Determine if a cross-domain request is in order
  6284. if ( s.crossDomain == null ) {
  6285. parts = rurl.exec( s.url.toLowerCase() );
  6286. s.crossDomain = !!( parts &&
  6287. ( parts[ 1 ] != ajaxLocParts[ 1 ] || parts[ 2 ] != ajaxLocParts[ 2 ] ||
  6288. ( parts[ 3 ] || ( parts[ 1 ] === "http:" ? 80 : 443 ) ) !=
  6289. ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? 80 : 443 ) ) )
  6290. );
  6291. }
  6292. // Convert data if not already a string
  6293. if ( s.data && s.processData && typeof s.data !== "string" ) {
  6294. s.data = jQuery.param( s.data, s.traditional );
  6295. }
  6296. // Apply prefilters
  6297. inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
  6298. // If request was aborted inside a prefilter, stop there
  6299. if ( state === 2 ) {
  6300. return false;
  6301. }
  6302. // We can fire global events as of now if asked to
  6303. fireGlobals = s.global;
  6304. // Uppercase the type
  6305. s.type = s.type.toUpperCase();
  6306. // Determine if request has content
  6307. s.hasContent = !rnoContent.test( s.type );
  6308. // Watch for a new set of requests
  6309. if ( fireGlobals && jQuery.active++ === 0 ) {
  6310. jQuery.event.trigger( "ajaxStart" );
  6311. }
  6312. // More options handling for requests with no content
  6313. if ( !s.hasContent ) {
  6314. // If data is available, append data to url
  6315. if ( s.data ) {
  6316. s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.data;
  6317. // #9682: remove data so that it's not used in an eventual retry
  6318. delete s.data;
  6319. }
  6320. // Get ifModifiedKey before adding the anti-cache parameter
  6321. ifModifiedKey = s.url;
  6322. // Add anti-cache in url if needed
  6323. if ( s.cache === false ) {
  6324. var ts = jQuery.now(),
  6325. // try replacing _= if it is there
  6326. ret = s.url.replace( rts, "$1_=" + ts );
  6327. // if nothing was replaced, add timestamp to the end
  6328. s.url = ret + ( ( ret === s.url ) ? ( rquery.test( s.url ) ? "&" : "?" ) + "_=" + ts : "" );
  6329. }
  6330. }
  6331. // Set the correct header, if data is being sent
  6332. if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
  6333. jqXHR.setRequestHeader( "Content-Type", s.contentType );
  6334. }
  6335. // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
  6336. if ( s.ifModified ) {
  6337. ifModifiedKey = ifModifiedKey || s.url;
  6338. if ( jQuery.lastModified[ ifModifiedKey ] ) {
  6339. jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ ifModifiedKey ] );
  6340. }
  6341. if ( jQuery.etag[ ifModifiedKey ] ) {
  6342. jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ ifModifiedKey ] );
  6343. }
  6344. }
  6345. // Set the Accepts header for the server, depending on the dataType
  6346. jqXHR.setRequestHeader(
  6347. "Accept",
  6348. s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?
  6349. s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
  6350. s.accepts[ "*" ]
  6351. );
  6352. // Check for headers option
  6353. for ( i in s.headers ) {
  6354. jqXHR.setRequestHeader( i, s.headers[ i ] );
  6355. }
  6356. // Allow custom headers/mimetypes and early abort
  6357. if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {
  6358. // Abort if not done already
  6359. jqXHR.abort();
  6360. return false;
  6361. }
  6362. // Install callbacks on deferreds
  6363. for ( i in { success: 1, error: 1, complete: 1 } ) {
  6364. jqXHR[ i ]( s[ i ] );
  6365. }
  6366. // Get transport
  6367. transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
  6368. // If no transport, we auto-abort
  6369. if ( !transport ) {
  6370. done( -1, "No Transport" );
  6371. } else {
  6372. jqXHR.readyState = 1;
  6373. // Send global event
  6374. if ( fireGlobals ) {
  6375. globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
  6376. }
  6377. // Timeout
  6378. if ( s.async && s.timeout > 0 ) {
  6379. timeoutTimer = setTimeout( function(){
  6380. jqXHR.abort( "timeout" );
  6381. }, s.timeout );
  6382. }
  6383. try {
  6384. state = 1;
  6385. transport.send( requestHeaders, done );
  6386. } catch (e) {
  6387. // Propagate exception as error if not done
  6388. if ( state < 2 ) {
  6389. done( -1, e );
  6390. // Simply rethrow otherwise
  6391. } else {
  6392. throw e;
  6393. }
  6394. }
  6395. }
  6396. return jqXHR;
  6397. },
  6398. // Serialize an array of form elements or a set of
  6399. // key/values into a query string
  6400. param: function( a, traditional ) {
  6401. var s = [],
  6402. add = function( key, value ) {
  6403. // If value is a function, invoke it and return its value
  6404. value = jQuery.isFunction( value ) ? value() : value;
  6405. s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value );
  6406. };
  6407. // Set traditional to true for jQuery <= 1.3.2 behavior.
  6408. if ( traditional === undefined ) {
  6409. traditional = jQuery.ajaxSettings.traditional;
  6410. }
  6411. // If an array was passed in, assume that it is an array of form elements.
  6412. if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
  6413. // Serialize the form elements
  6414. jQuery.each( a, function() {
  6415. add( this.name, this.value );
  6416. });
  6417. } else {
  6418. // If traditional, encode the "old" way (the way 1.3.2 or older
  6419. // did it), otherwise encode params recursively.
  6420. for ( var prefix in a ) {
  6421. buildParams( prefix, a[ prefix ], traditional, add );
  6422. }
  6423. }
  6424. // Return the resulting serialization
  6425. return s.join( "&" ).replace( r20, "+" );
  6426. }
  6427. });
  6428. function buildParams( prefix, obj, traditional, add ) {
  6429. if ( jQuery.isArray( obj ) ) {
  6430. // Serialize array item.
  6431. jQuery.each( obj, function( i, v ) {
  6432. if ( traditional || rbracket.test( prefix ) ) {
  6433. // Treat each array item as a scalar.
  6434. add( prefix, v );
  6435. } else {
  6436. // If array item is non-scalar (array or object), encode its
  6437. // numeric index to resolve deserialization ambiguity issues.
  6438. // Note that rack (as of 1.0.0) can't currently deserialize
  6439. // nested arrays properly, and attempting to do so may cause
  6440. // a server error. Possible fixes are to modify rack's
  6441. // deserialization algorithm or to provide an option or flag
  6442. // to force array serialization to be shallow.
  6443. buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add );
  6444. }
  6445. });
  6446. } else if ( !traditional && jQuery.type( obj ) === "object" ) {
  6447. // Serialize object item.
  6448. for ( var name in obj ) {
  6449. buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
  6450. }
  6451. } else {
  6452. // Serialize scalar item.
  6453. add( prefix, obj );
  6454. }
  6455. }
  6456. // This is still on the jQuery object... for now
  6457. // Want to move this to jQuery.ajax some day
  6458. jQuery.extend({
  6459. // Counter for holding the number of active queries
  6460. active: 0,
  6461. // Last-Modified header cache for next request
  6462. lastModified: {},
  6463. etag: {}
  6464. });
  6465. /* Handles responses to an ajax request:
  6466. * - sets all responseXXX fields accordingly
  6467. * - finds the right dataType (mediates between content-type and expected dataType)
  6468. * - returns the corresponding response
  6469. */
  6470. function ajaxHandleResponses( s, jqXHR, responses ) {
  6471. var contents = s.contents,
  6472. dataTypes = s.dataTypes,
  6473. responseFields = s.responseFields,
  6474. ct,
  6475. type,
  6476. finalDataType,
  6477. firstDataType;
  6478. // Fill responseXXX fields
  6479. for ( type in responseFields ) {
  6480. if ( type in responses ) {
  6481. jqXHR[ responseFields[type] ] = responses[ type ];
  6482. }
  6483. }
  6484. // Remove auto dataType and get content-type in the process
  6485. while( dataTypes[ 0 ] === "*" ) {
  6486. dataTypes.shift();
  6487. if ( ct === undefined ) {
  6488. ct = s.mimeType || jqXHR.getResponseHeader( "content-type" );
  6489. }
  6490. }
  6491. // Check if we're dealing with a known content-type
  6492. if ( ct ) {
  6493. for ( type in contents ) {
  6494. if ( contents[ type ] && contents[ type ].test( ct ) ) {
  6495. dataTypes.unshift( type );
  6496. break;
  6497. }
  6498. }
  6499. }
  6500. // Check to see if we have a response for the expected dataType
  6501. if ( dataTypes[ 0 ] in responses ) {
  6502. finalDataType = dataTypes[ 0 ];
  6503. } else {
  6504. // Try convertible dataTypes
  6505. for ( type in responses ) {
  6506. if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) {
  6507. finalDataType = type;
  6508. break;
  6509. }
  6510. if ( !firstDataType ) {
  6511. firstDataType = type;
  6512. }
  6513. }
  6514. // Or just use first one
  6515. finalDataType = finalDataType || firstDataType;
  6516. }
  6517. // If we found a dataType
  6518. // We add the dataType to the list if needed
  6519. // and return the corresponding response
  6520. if ( finalDataType ) {
  6521. if ( finalDataType !== dataTypes[ 0 ] ) {
  6522. dataTypes.unshift( finalDataType );
  6523. }
  6524. return responses[ finalDataType ];
  6525. }
  6526. }
  6527. // Chain conversions given the request and the original response
  6528. function ajaxConvert( s, response ) {
  6529. // Apply the dataFilter if provided
  6530. if ( s.dataFilter ) {
  6531. response = s.dataFilter( response, s.dataType );
  6532. }
  6533. var dataTypes = s.dataTypes,
  6534. converters = {},
  6535. i,
  6536. key,
  6537. length = dataTypes.length,
  6538. tmp,
  6539. // Current and previous dataTypes
  6540. current = dataTypes[ 0 ],
  6541. prev,
  6542. // Conversion expression
  6543. conversion,
  6544. // Conversion function
  6545. conv,
  6546. // Conversion functions (transitive conversion)
  6547. conv1,
  6548. conv2;
  6549. // For each dataType in the chain
  6550. for ( i = 1; i < length; i++ ) {
  6551. // Create converters map
  6552. // with lowercased keys
  6553. if ( i === 1 ) {
  6554. for ( key in s.converters ) {
  6555. if ( typeof key === "string" ) {
  6556. converters[ key.toLowerCase() ] = s.converters[ key ];
  6557. }
  6558. }
  6559. }
  6560. // Get the dataTypes
  6561. prev = current;
  6562. current = dataTypes[ i ];
  6563. // If current is auto dataType, update it to prev
  6564. if ( current === "*" ) {
  6565. current = prev;
  6566. // If no auto and dataTypes are actually different
  6567. } else if ( prev !== "*" && prev !== current ) {
  6568. // Get the converter
  6569. conversion = prev + " " + current;
  6570. conv = converters[ conversion ] || converters[ "* " + current ];
  6571. // If there is no direct converter, search transitively
  6572. if ( !conv ) {
  6573. conv2 = undefined;
  6574. for ( conv1 in converters ) {
  6575. tmp = conv1.split( " " );
  6576. if ( tmp[ 0 ] === prev || tmp[ 0 ] === "*" ) {
  6577. conv2 = converters[ tmp[1] + " " + current ];
  6578. if ( conv2 ) {
  6579. conv1 = converters[ conv1 ];
  6580. if ( conv1 === true ) {
  6581. conv = conv2;
  6582. } else if ( conv2 === true ) {
  6583. conv = conv1;
  6584. }
  6585. break;
  6586. }
  6587. }
  6588. }
  6589. }
  6590. // If we found no converter, dispatch an error
  6591. if ( !( conv || conv2 ) ) {
  6592. jQuery.error( "No conversion from " + conversion.replace(" "," to ") );
  6593. }
  6594. // If found converter is not an equivalence
  6595. if ( conv !== true ) {
  6596. // Convert with 1 or 2 converters accordingly
  6597. response = conv ? conv( response ) : conv2( conv1(response) );
  6598. }
  6599. }
  6600. }
  6601. return response;
  6602. }
  6603. var jsc = jQuery.now(),
  6604. jsre = /(\=)\?(&|$)|\?\?/i;
  6605. // Default jsonp settings
  6606. jQuery.ajaxSetup({
  6607. jsonp: "callback",
  6608. jsonpCallback: function() {
  6609. return jQuery.expando + "_" + ( jsc++ );
  6610. }
  6611. });
  6612. // Detect, normalize options and install callbacks for jsonp requests
  6613. jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
  6614. var inspectData = ( typeof s.data === "string" ) && /^application\/x\-www\-form\-urlencoded/.test( s.contentType );
  6615. if ( s.dataTypes[ 0 ] === "jsonp" ||
  6616. s.jsonp !== false && ( jsre.test( s.url ) ||
  6617. inspectData && jsre.test( s.data ) ) ) {
  6618. var responseContainer,
  6619. jsonpCallback = s.jsonpCallback =
  6620. jQuery.isFunction( s.jsonpCallback ) ? s.jsonpCallback() : s.jsonpCallback,
  6621. previous = window[ jsonpCallback ],
  6622. url = s.url,
  6623. data = s.data,
  6624. replace = "$1" + jsonpCallback + "$2";
  6625. if ( s.jsonp !== false ) {
  6626. url = url.replace( jsre, replace );
  6627. if ( s.url === url ) {
  6628. if ( inspectData ) {
  6629. data = data.replace( jsre, replace );
  6630. }
  6631. if ( s.data === data ) {
  6632. // Add callback manually
  6633. url += (/\?/.test( url ) ? "&" : "?") + s.jsonp + "=" + jsonpCallback;
  6634. }
  6635. }
  6636. }
  6637. s.url = url;
  6638. s.data = data;
  6639. // Install callback
  6640. window[ jsonpCallback ] = function( response ) {
  6641. responseContainer = [ response ];
  6642. };
  6643. // Clean-up function
  6644. jqXHR.always(function() {
  6645. // Set callback back to previous value
  6646. window[ jsonpCallback ] = previous;
  6647. // Call if it was a function and we have a response
  6648. if ( responseContainer && jQuery.isFunction( previous ) ) {
  6649. window[ jsonpCallback ]( responseContainer[ 0 ] );
  6650. }
  6651. });
  6652. // Use data converter to retrieve json after script execution
  6653. s.converters["script json"] = function() {
  6654. if ( !responseContainer ) {
  6655. jQuery.error( jsonpCallback + " was not called" );
  6656. }
  6657. return responseContainer[ 0 ];
  6658. };
  6659. // force json dataType
  6660. s.dataTypes[ 0 ] = "json";
  6661. // Delegate to script
  6662. return "script";
  6663. }
  6664. });
  6665. // Install script dataType
  6666. jQuery.ajaxSetup({
  6667. accepts: {
  6668. script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
  6669. },
  6670. contents: {
  6671. script: /javascript|ecmascript/
  6672. },
  6673. converters: {
  6674. "text script": function( text ) {
  6675. jQuery.globalEval( text );
  6676. return text;
  6677. }
  6678. }
  6679. });
  6680. // Handle cache's special case and global
  6681. jQuery.ajaxPrefilter( "script", function( s ) {
  6682. if ( s.cache === undefined ) {
  6683. s.cache = false;
  6684. }
  6685. if ( s.crossDomain ) {
  6686. s.type = "GET";
  6687. s.global = false;
  6688. }
  6689. });
  6690. // Bind script tag hack transport
  6691. jQuery.ajaxTransport( "script", function(s) {
  6692. // This transport only deals with cross domain requests
  6693. if ( s.crossDomain ) {
  6694. var script,
  6695. head = document.head || document.getElementsByTagName( "head" )[0] || document.documentElement;
  6696. return {
  6697. send: function( _, callback ) {
  6698. script = document.createElement( "script" );
  6699. script.async = "async";
  6700. if ( s.scriptCharset ) {
  6701. script.charset = s.scriptCharset;
  6702. }
  6703. script.src = s.url;
  6704. // Attach handlers for all browsers
  6705. script.onload = script.onreadystatechange = function( _, isAbort ) {
  6706. if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) {
  6707. // Handle memory leak in IE
  6708. script.onload = script.onreadystatechange = null;
  6709. // Remove the script
  6710. if ( head && script.parentNode ) {
  6711. head.removeChild( script );
  6712. }
  6713. // Dereference the script
  6714. script = undefined;
  6715. // Callback if not abort
  6716. if ( !isAbort ) {
  6717. callback( 200, "success" );
  6718. }
  6719. }
  6720. };
  6721. // Use insertBefore instead of appendChild to circumvent an IE6 bug.
  6722. // This arises when a base node is used (#2709 and #4378).
  6723. head.insertBefore( script, head.firstChild );
  6724. },
  6725. abort: function() {
  6726. if ( script ) {
  6727. script.onload( 0, 1 );
  6728. }
  6729. }
  6730. };
  6731. }
  6732. });
  6733. var // #5280: Internet Explorer will keep connections alive if we don't abort on unload
  6734. xhrOnUnloadAbort = window.ActiveXObject ? function() {
  6735. // Abort all pending requests
  6736. for ( var key in xhrCallbacks ) {
  6737. xhrCallbacks[ key ]( 0, 1 );
  6738. }
  6739. } : false,
  6740. xhrId = 0,
  6741. xhrCallbacks;
  6742. // Functions to create xhrs
  6743. function createStandardXHR() {
  6744. try {
  6745. return new window.XMLHttpRequest();
  6746. } catch( e ) {}
  6747. }
  6748. function createActiveXHR() {
  6749. try {
  6750. return new window.ActiveXObject( "Microsoft.XMLHTTP" );
  6751. } catch( e ) {}
  6752. }
  6753. // Create the request object
  6754. // (This is still attached to ajaxSettings for backward compatibility)
  6755. jQuery.ajaxSettings.xhr = window.ActiveXObject ?
  6756. /* Microsoft failed to properly
  6757. * implement the XMLHttpRequest in IE7 (can't request local files),
  6758. * so we use the ActiveXObject when it is available
  6759. * Additionally XMLHttpRequest can be disabled in IE7/IE8 so
  6760. * we need a fallback.
  6761. */
  6762. function() {
  6763. return !this.isLocal && createStandardXHR() || createActiveXHR();
  6764. } :
  6765. // For all other browsers, use the standard XMLHttpRequest object
  6766. createStandardXHR;
  6767. // Determine support properties
  6768. (function( xhr ) {
  6769. jQuery.extend( jQuery.support, {
  6770. ajax: !!xhr,
  6771. cors: !!xhr && ( "withCredentials" in xhr )
  6772. });
  6773. })( jQuery.ajaxSettings.xhr() );
  6774. // Create transport if the browser can provide an xhr
  6775. if ( jQuery.support.ajax ) {
  6776. jQuery.ajaxTransport(function( s ) {
  6777. // Cross domain only allowed if supported through XMLHttpRequest
  6778. if ( !s.crossDomain || jQuery.support.cors ) {
  6779. var callback;
  6780. return {
  6781. send: function( headers, complete ) {
  6782. // Get a new xhr
  6783. var xhr = s.xhr(),
  6784. handle,
  6785. i;
  6786. // Open the socket
  6787. // Passing null username, generates a login popup on Opera (#2865)
  6788. if ( s.username ) {
  6789. xhr.open( s.type, s.url, s.async, s.username, s.password );
  6790. } else {
  6791. xhr.open( s.type, s.url, s.async );
  6792. }
  6793. // Apply custom fields if provided
  6794. if ( s.xhrFields ) {
  6795. for ( i in s.xhrFields ) {
  6796. xhr[ i ] = s.xhrFields[ i ];
  6797. }
  6798. }
  6799. // Override mime type if needed
  6800. if ( s.mimeType && xhr.overrideMimeType ) {
  6801. xhr.overrideMimeType( s.mimeType );
  6802. }
  6803. // X-Requested-With header
  6804. // For cross-domain requests, seeing as conditions for a preflight are
  6805. // akin to a jigsaw puzzle, we simply never set it to be sure.
  6806. // (it can always be set on a per-request basis or even using ajaxSetup)
  6807. // For same-domain requests, won't change header if already provided.
  6808. if ( !s.crossDomain && !headers["X-Requested-With"] ) {
  6809. headers[ "X-Requested-With" ] = "XMLHttpRequest";
  6810. }
  6811. // Need an extra try/catch for cross domain requests in Firefox 3
  6812. try {
  6813. for ( i in headers ) {
  6814. xhr.setRequestHeader( i, headers[ i ] );
  6815. }
  6816. } catch( _ ) {}
  6817. // Do send the request
  6818. // This may raise an exception which is actually
  6819. // handled in jQuery.ajax (so no try/catch here)
  6820. xhr.send( ( s.hasContent && s.data ) || null );
  6821. // Listener
  6822. callback = function( _, isAbort ) {
  6823. var status,
  6824. statusText,
  6825. responseHeaders,
  6826. responses,
  6827. xml;
  6828. // Firefox throws exceptions when accessing properties
  6829. // of an xhr when a network error occured
  6830. // http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_(NS_ERROR_NOT_AVAILABLE)
  6831. try {
  6832. // Was never called and is aborted or complete
  6833. if ( callback && ( isAbort || xhr.readyState === 4 ) ) {
  6834. // Only called once
  6835. callback = undefined;
  6836. // Do not keep as active anymore
  6837. if ( handle ) {
  6838. xhr.onreadystatechange = jQuery.noop;
  6839. if ( xhrOnUnloadAbort ) {
  6840. delete xhrCallbacks[ handle ];
  6841. }
  6842. }
  6843. // If it's an abort
  6844. if ( isAbort ) {
  6845. // Abort it manually if needed
  6846. if ( xhr.readyState !== 4 ) {
  6847. xhr.abort();
  6848. }
  6849. } else {
  6850. status = xhr.status;
  6851. responseHeaders = xhr.getAllResponseHeaders();
  6852. responses = {};
  6853. xml = xhr.responseXML;
  6854. // Construct response list
  6855. if ( xml && xml.documentElement /* #4958 */ ) {
  6856. responses.xml = xml;
  6857. }
  6858. // When requesting binary data, IE6-9 will throw an exception
  6859. // on any attempt to access responseText (#11426)
  6860. try {
  6861. responses.text = xhr.responseText;
  6862. } catch( _ ) {
  6863. }
  6864. // Firefox throws an exception when accessing
  6865. // statusText for faulty cross-domain requests
  6866. try {
  6867. statusText = xhr.statusText;
  6868. } catch( e ) {
  6869. // We normalize with Webkit giving an empty statusText
  6870. statusText = "";
  6871. }
  6872. // Filter status for non standard behaviors
  6873. // If the request is local and we have data: assume a success
  6874. // (success with no data won't get notified, that's the best we
  6875. // can do given current implementations)
  6876. if ( !status && s.isLocal && !s.crossDomain ) {
  6877. status = responses.text ? 200 : 404;
  6878. // IE - #1450: sometimes returns 1223 when it should be 204
  6879. } else if ( status === 1223 ) {
  6880. status = 204;
  6881. }
  6882. }
  6883. }
  6884. } catch( firefoxAccessException ) {
  6885. if ( !isAbort ) {
  6886. complete( -1, firefoxAccessException );
  6887. }
  6888. }
  6889. // Call complete if needed
  6890. if ( responses ) {
  6891. complete( status, statusText, responses, responseHeaders );
  6892. }
  6893. };
  6894. // if we're in sync mode or it's in cache
  6895. // and has been retrieved directly (IE6 & IE7)
  6896. // we need to manually fire the callback
  6897. if ( !s.async || xhr.readyState === 4 ) {
  6898. callback();
  6899. } else {
  6900. handle = ++xhrId;
  6901. if ( xhrOnUnloadAbort ) {
  6902. // Create the active xhrs callbacks list if needed
  6903. // and attach the unload handler
  6904. if ( !xhrCallbacks ) {
  6905. xhrCallbacks = {};
  6906. jQuery( window ).unload( xhrOnUnloadAbort );
  6907. }
  6908. // Add to list of active xhrs callbacks
  6909. xhrCallbacks[ handle ] = callback;
  6910. }
  6911. xhr.onreadystatechange = callback;
  6912. }
  6913. },
  6914. abort: function() {
  6915. if ( callback ) {
  6916. callback(0,1);
  6917. }
  6918. }
  6919. };
  6920. }
  6921. });
  6922. }
  6923. var elemdisplay = {},
  6924. iframe, iframeDoc,
  6925. rfxtypes = /^(?:toggle|show|hide)$/,
  6926. rfxnum = /^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,
  6927. timerId,
  6928. fxAttrs = [
  6929. // height animations
  6930. [ "height", "marginTop", "marginBottom", "paddingTop", "paddingBottom" ],
  6931. // width animations
  6932. [ "width", "marginLeft", "marginRight", "paddingLeft", "paddingRight" ],
  6933. // opacity animations
  6934. [ "opacity" ]
  6935. ],
  6936. fxNow;
  6937. jQuery.fn.extend({
  6938. show: function( speed, easing, callback ) {
  6939. var elem, display;
  6940. if ( speed || speed === 0 ) {
  6941. return this.animate( genFx("show", 3), speed, easing, callback );
  6942. } else {
  6943. for ( var i = 0, j = this.length; i < j; i++ ) {
  6944. elem = this[ i ];
  6945. if ( elem.style ) {
  6946. display = elem.style.display;
  6947. // Reset the inline display of this element to learn if it is
  6948. // being hidden by cascaded rules or not
  6949. if ( !jQuery._data(elem, "olddisplay") && display === "none" ) {
  6950. display = elem.style.display = "";
  6951. }
  6952. // Set elements which have been overridden with display: none
  6953. // in a stylesheet to whatever the default browser style is
  6954. // for such an element
  6955. if ( (display === "" && jQuery.css(elem, "display") === "none") ||
  6956. !jQuery.contains( elem.ownerDocument.documentElement, elem ) ) {
  6957. jQuery._data( elem, "olddisplay", defaultDisplay(elem.nodeName) );
  6958. }
  6959. }
  6960. }
  6961. // Set the display of most of the elements in a second loop
  6962. // to avoid the constant reflow
  6963. for ( i = 0; i < j; i++ ) {
  6964. elem = this[ i ];
  6965. if ( elem.style ) {
  6966. display = elem.style.display;
  6967. if ( display === "" || display === "none" ) {
  6968. elem.style.display = jQuery._data( elem, "olddisplay" ) || "";
  6969. }
  6970. }
  6971. }
  6972. return this;
  6973. }
  6974. },
  6975. hide: function( speed, easing, callback ) {
  6976. if ( speed || speed === 0 ) {
  6977. return this.animate( genFx("hide", 3), speed, easing, callback);
  6978. } else {
  6979. var elem, display,
  6980. i = 0,
  6981. j = this.length;
  6982. for ( ; i < j; i++ ) {
  6983. elem = this[i];
  6984. if ( elem.style ) {
  6985. display = jQuery.css( elem, "display" );
  6986. if ( display !== "none" && !jQuery._data( elem, "olddisplay" ) ) {
  6987. jQuery._data( elem, "olddisplay", display );
  6988. }
  6989. }
  6990. }
  6991. // Set the display of the elements in a second loop
  6992. // to avoid the constant reflow
  6993. for ( i = 0; i < j; i++ ) {
  6994. if ( this[i].style ) {
  6995. this[i].style.display = "none";
  6996. }
  6997. }
  6998. return this;
  6999. }
  7000. },
  7001. // Save the old toggle function
  7002. _toggle: jQuery.fn.toggle,
  7003. toggle: function( fn, fn2, callback ) {
  7004. var bool = typeof fn === "boolean";
  7005. if ( jQuery.isFunction(fn) && jQuery.isFunction(fn2) ) {
  7006. this._toggle.apply( this, arguments );
  7007. } else if ( fn == null || bool ) {
  7008. this.each(function() {
  7009. var state = bool ? fn : jQuery(this).is(":hidden");
  7010. jQuery(this)[ state ? "show" : "hide" ]();
  7011. });
  7012. } else {
  7013. this.animate(genFx("toggle", 3), fn, fn2, callback);
  7014. }
  7015. return this;
  7016. },
  7017. fadeTo: function( speed, to, easing, callback ) {
  7018. return this.filter(":hidden").css("opacity", 0).show().end()
  7019. .animate({opacity: to}, speed, easing, callback);
  7020. },
  7021. animate: function( prop, speed, easing, callback ) {
  7022. var optall = jQuery.speed( speed, easing, callback );
  7023. if ( jQuery.isEmptyObject( prop ) ) {
  7024. return this.each( optall.complete, [ false ] );
  7025. }
  7026. // Do not change referenced properties as per-property easing will be lost
  7027. prop = jQuery.extend( {}, prop );
  7028. function doAnimation() {
  7029. // XXX 'this' does not always have a nodeName when running the
  7030. // test suite
  7031. if ( optall.queue === false ) {
  7032. jQuery._mark( this );
  7033. }
  7034. var opt = jQuery.extend( {}, optall ),
  7035. isElement = this.nodeType === 1,
  7036. hidden = isElement && jQuery(this).is(":hidden"),
  7037. name, val, p, e, hooks, replace,
  7038. parts, start, end, unit,
  7039. method;
  7040. // will store per property easing and be used to determine when an animation is complete
  7041. opt.animatedProperties = {};
  7042. // first pass over propertys to expand / normalize
  7043. for ( p in prop ) {
  7044. name = jQuery.camelCase( p );
  7045. if ( p !== name ) {
  7046. prop[ name ] = prop[ p ];
  7047. delete prop[ p ];
  7048. }
  7049. if ( ( hooks = jQuery.cssHooks[ name ] ) && "expand" in hooks ) {
  7050. replace = hooks.expand( prop[ name ] );
  7051. delete prop[ name ];
  7052. // not quite $.extend, this wont overwrite keys already present.
  7053. // also - reusing 'p' from above because we have the correct "name"
  7054. for ( p in replace ) {
  7055. if ( ! ( p in prop ) ) {
  7056. prop[ p ] = replace[ p ];
  7057. }
  7058. }
  7059. }
  7060. }
  7061. for ( name in prop ) {
  7062. val = prop[ name ];
  7063. // easing resolution: per property > opt.specialEasing > opt.easing > 'swing' (default)
  7064. if ( jQuery.isArray( val ) ) {
  7065. opt.animatedProperties[ name ] = val[ 1 ];
  7066. val = prop[ name ] = val[ 0 ];
  7067. } else {
  7068. opt.animatedProperties[ name ] = opt.specialEasing && opt.specialEasing[ name ] || opt.easing || 'swing';
  7069. }
  7070. if ( val === "hide" && hidden || val === "show" && !hidden ) {
  7071. return opt.complete.call( this );
  7072. }
  7073. if ( isElement && ( name === "height" || name === "width" ) ) {
  7074. // Make sure that nothing sneaks out
  7075. // Record all 3 overflow attributes because IE does not
  7076. // change the overflow attribute when overflowX and
  7077. // overflowY are set to the same value
  7078. opt.overflow = [ this.style.overflow, this.style.overflowX, this.style.overflowY ];
  7079. // Set display property to inline-block for height/width
  7080. // animations on inline elements that are having width/height animated
  7081. if ( jQuery.css( this, "display" ) === "inline" &&
  7082. jQuery.css( this, "float" ) === "none" ) {
  7083. // inline-level elements accept inline-block;
  7084. // block-level elements need to be inline with layout
  7085. if ( !jQuery.support.inlineBlockNeedsLayout || defaultDisplay( this.nodeName ) === "inline" ) {
  7086. this.style.display = "inline-block";
  7087. } else {
  7088. this.style.zoom = 1;
  7089. }
  7090. }
  7091. }
  7092. }
  7093. if ( opt.overflow != null ) {
  7094. this.style.overflow = "hidden";
  7095. }
  7096. for ( p in prop ) {
  7097. e = new jQuery.fx( this, opt, p );
  7098. val = prop[ p ];
  7099. if ( rfxtypes.test( val ) ) {
  7100. // Tracks whether to show or hide based on private
  7101. // data attached to the element
  7102. method = jQuery._data( this, "toggle" + p ) || ( val === "toggle" ? hidden ? "show" : "hide" : 0 );
  7103. if ( method ) {
  7104. jQuery._data( this, "toggle" + p, method === "show" ? "hide" : "show" );
  7105. e[ method ]();
  7106. } else {
  7107. e[ val ]();
  7108. }
  7109. } else {
  7110. parts = rfxnum.exec( val );
  7111. start = e.cur();
  7112. if ( parts ) {
  7113. end = parseFloat( parts[2] );
  7114. unit = parts[3] || ( jQuery.cssNumber[ p ] ? "" : "px" );
  7115. // We need to compute starting value
  7116. if ( unit !== "px" ) {
  7117. jQuery.style( this, p, (end || 1) + unit);
  7118. start = ( (end || 1) / e.cur() ) * start;
  7119. jQuery.style( this, p, start + unit);
  7120. }
  7121. // If a +=/-= token was provided, we're doing a relative animation
  7122. if ( parts[1] ) {
  7123. end = ( (parts[ 1 ] === "-=" ? -1 : 1) * end ) + start;
  7124. }
  7125. e.custom( start, end, unit );
  7126. } else {
  7127. e.custom( start, val, "" );
  7128. }
  7129. }
  7130. }
  7131. // For JS strict compliance
  7132. return true;
  7133. }
  7134. return optall.queue === false ?
  7135. this.each( doAnimation ) :
  7136. this.queue( optall.queue, doAnimation );
  7137. },
  7138. stop: function( type, clearQueue, gotoEnd ) {
  7139. if ( typeof type !== "string" ) {
  7140. gotoEnd = clearQueue;
  7141. clearQueue = type;
  7142. type = undefined;
  7143. }
  7144. if ( clearQueue && type !== false ) {
  7145. this.queue( type || "fx", [] );
  7146. }
  7147. return this.each(function() {
  7148. var index,
  7149. hadTimers = false,
  7150. timers = jQuery.timers,
  7151. data = jQuery._data( this );
  7152. // clear marker counters if we know they won't be
  7153. if ( !gotoEnd ) {
  7154. jQuery._unmark( true, this );
  7155. }
  7156. function stopQueue( elem, data, index ) {
  7157. var hooks = data[ index ];
  7158. jQuery.removeData( elem, index, true );
  7159. hooks.stop( gotoEnd );
  7160. }
  7161. if ( type == null ) {
  7162. for ( index in data ) {
  7163. if ( data[ index ] && data[ index ].stop && index.indexOf(".run") === index.length - 4 ) {
  7164. stopQueue( this, data, index );
  7165. }
  7166. }
  7167. } else if ( data[ index = type + ".run" ] && data[ index ].stop ){
  7168. stopQueue( this, data, index );
  7169. }
  7170. for ( index = timers.length; index--; ) {
  7171. if ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) {
  7172. if ( gotoEnd ) {
  7173. // force the next step to be the last
  7174. timers[ index ]( true );
  7175. } else {
  7176. timers[ index ].saveState();
  7177. }
  7178. hadTimers = true;
  7179. timers.splice( index, 1 );
  7180. }
  7181. }
  7182. // start the next in the queue if the last step wasn't forced
  7183. // timers currently will call their complete callbacks, which will dequeue
  7184. // but only if they were gotoEnd
  7185. if ( !( gotoEnd && hadTimers ) ) {
  7186. jQuery.dequeue( this, type );
  7187. }
  7188. });
  7189. }
  7190. });
  7191. // Animations created synchronously will run synchronously
  7192. function createFxNow() {
  7193. setTimeout( clearFxNow, 0 );
  7194. return ( fxNow = jQuery.now() );
  7195. }
  7196. function clearFxNow() {
  7197. fxNow = undefined;
  7198. }
  7199. // Generate parameters to create a standard animation
  7200. function genFx( type, num ) {
  7201. var obj = {};
  7202. jQuery.each( fxAttrs.concat.apply([], fxAttrs.slice( 0, num )), function() {
  7203. obj[ this ] = type;
  7204. });
  7205. return obj;
  7206. }
  7207. // Generate shortcuts for custom animations
  7208. jQuery.each({
  7209. slideDown: genFx( "show", 1 ),
  7210. slideUp: genFx( "hide", 1 ),
  7211. slideToggle: genFx( "toggle", 1 ),
  7212. fadeIn: { opacity: "show" },
  7213. fadeOut: { opacity: "hide" },
  7214. fadeToggle: { opacity: "toggle" }
  7215. }, function( name, props ) {
  7216. jQuery.fn[ name ] = function( speed, easing, callback ) {
  7217. return this.animate( props, speed, easing, callback );
  7218. };
  7219. });
  7220. jQuery.extend({
  7221. speed: function( speed, easing, fn ) {
  7222. var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
  7223. complete: fn || !fn && easing ||
  7224. jQuery.isFunction( speed ) && speed,
  7225. duration: speed,
  7226. easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing
  7227. };
  7228. opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
  7229. opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;
  7230. // normalize opt.queue - true/undefined/null -> "fx"
  7231. if ( opt.queue == null || opt.queue === true ) {
  7232. opt.queue = "fx";
  7233. }
  7234. // Queueing
  7235. opt.old = opt.complete;
  7236. opt.complete = function( noUnmark ) {
  7237. if ( jQuery.isFunction( opt.old ) ) {
  7238. opt.old.call( this );
  7239. }
  7240. if ( opt.queue ) {
  7241. jQuery.dequeue( this, opt.queue );
  7242. } else if ( noUnmark !== false ) {
  7243. jQuery._unmark( this );
  7244. }
  7245. };
  7246. return opt;
  7247. },
  7248. easing: {
  7249. linear: function( p ) {
  7250. return p;
  7251. },
  7252. swing: function( p ) {
  7253. return ( -Math.cos( p*Math.PI ) / 2 ) + 0.5;
  7254. }
  7255. },
  7256. timers: [],
  7257. fx: function( elem, options, prop ) {
  7258. this.options = options;
  7259. this.elem = elem;
  7260. this.prop = prop;
  7261. options.orig = options.orig || {};
  7262. }
  7263. });
  7264. jQuery.fx.prototype = {
  7265. // Simple function for setting a style value
  7266. update: function() {
  7267. if ( this.options.step ) {
  7268. this.options.step.call( this.elem, this.now, this );
  7269. }
  7270. ( jQuery.fx.step[ this.prop ] || jQuery.fx.step._default )( this );
  7271. },
  7272. // Get the current size
  7273. cur: function() {
  7274. if ( this.elem[ this.prop ] != null && (!this.elem.style || this.elem.style[ this.prop ] == null) ) {
  7275. return this.elem[ this.prop ];
  7276. }
  7277. var parsed,
  7278. r = jQuery.css( this.elem, this.prop );
  7279. // Empty strings, null, undefined and "auto" are converted to 0,
  7280. // complex values such as "rotate(1rad)" are returned as is,
  7281. // simple values such as "10px" are parsed to Float.
  7282. return isNaN( parsed = parseFloat( r ) ) ? !r || r === "auto" ? 0 : r : parsed;
  7283. },
  7284. // Start an animation from one number to another
  7285. custom: function( from, to, unit ) {
  7286. var self = this,
  7287. fx = jQuery.fx;
  7288. this.startTime = fxNow || createFxNow();
  7289. this.end = to;
  7290. this.now = this.start = from;
  7291. this.pos = this.state = 0;
  7292. this.unit = unit || this.unit || ( jQuery.cssNumber[ this.prop ] ? "" : "px" );
  7293. function t( gotoEnd ) {
  7294. return self.step( gotoEnd );
  7295. }
  7296. t.queue = this.options.queue;
  7297. t.elem = this.elem;
  7298. t.saveState = function() {
  7299. if ( jQuery._data( self.elem, "fxshow" + self.prop ) === undefined ) {
  7300. if ( self.options.hide ) {
  7301. jQuery._data( self.elem, "fxshow" + self.prop, self.start );
  7302. } else if ( self.options.show ) {
  7303. jQuery._data( self.elem, "fxshow" + self.prop, self.end );
  7304. }
  7305. }
  7306. };
  7307. if ( t() && jQuery.timers.push(t) && !timerId ) {
  7308. timerId = setInterval( fx.tick, fx.interval );
  7309. }
  7310. },
  7311. // Simple 'show' function
  7312. show: function() {
  7313. var dataShow = jQuery._data( this.elem, "fxshow" + this.prop );
  7314. // Remember where we started, so that we can go back to it later
  7315. this.options.orig[ this.prop ] = dataShow || jQuery.style( this.elem, this.prop );
  7316. this.options.show = true;
  7317. // Begin the animation
  7318. // Make sure that we start at a small width/height to avoid any flash of content
  7319. if ( dataShow !== undefined ) {
  7320. // This show is picking up where a previous hide or show left off
  7321. this.custom( this.cur(), dataShow );
  7322. } else {
  7323. this.custom( this.prop === "width" || this.prop === "height" ? 1 : 0, this.cur() );
  7324. }
  7325. // Start by showing the element
  7326. jQuery( this.elem ).show();
  7327. },
  7328. // Simple 'hide' function
  7329. hide: function() {
  7330. // Remember where we started, so that we can go back to it later
  7331. this.options.orig[ this.prop ] = jQuery._data( this.elem, "fxshow" + this.prop ) || jQuery.style( this.elem, this.prop );
  7332. this.options.hide = true;
  7333. // Begin the animation
  7334. this.custom( this.cur(), 0 );
  7335. },
  7336. // Each step of an animation
  7337. step: function( gotoEnd ) {
  7338. var p, n, complete,
  7339. t = fxNow || createFxNow(),
  7340. done = true,
  7341. elem = this.elem,
  7342. options = this.options;
  7343. if ( gotoEnd || t >= options.duration + this.startTime ) {
  7344. this.now = this.end;
  7345. this.pos = this.state = 1;
  7346. this.update();
  7347. options.animatedProperties[ this.prop ] = true;
  7348. for ( p in options.animatedProperties ) {
  7349. if ( options.animatedProperties[ p ] !== true ) {
  7350. done = false;
  7351. }
  7352. }
  7353. if ( done ) {
  7354. // Reset the overflow
  7355. if ( options.overflow != null && !jQuery.support.shrinkWrapBlocks ) {
  7356. jQuery.each( [ "", "X", "Y" ], function( index, value ) {
  7357. elem.style[ "overflow" + value ] = options.overflow[ index ];
  7358. });
  7359. }
  7360. // Hide the element if the "hide" operation was done
  7361. if ( options.hide ) {
  7362. jQuery( elem ).hide();
  7363. }
  7364. // Reset the properties, if the item has been hidden or shown
  7365. if ( options.hide || options.show ) {
  7366. for ( p in options.animatedProperties ) {
  7367. jQuery.style( elem, p, options.orig[ p ] );
  7368. jQuery.removeData( elem, "fxshow" + p, true );
  7369. // Toggle data is no longer needed
  7370. jQuery.removeData( elem, "toggle" + p, true );
  7371. }
  7372. }
  7373. // Execute the complete function
  7374. // in the event that the complete function throws an exception
  7375. // we must ensure it won't be called twice. #5684
  7376. complete = options.complete;
  7377. if ( complete ) {
  7378. options.complete = false;
  7379. complete.call( elem );
  7380. }
  7381. }
  7382. return false;
  7383. } else {
  7384. // classical easing cannot be used with an Infinity duration
  7385. if ( options.duration == Infinity ) {
  7386. this.now = t;
  7387. } else {
  7388. n = t - this.startTime;
  7389. this.state = n / options.duration;
  7390. // Perform the easing function, defaults to swing
  7391. this.pos = jQuery.easing[ options.animatedProperties[this.prop] ]( this.state, n, 0, 1, options.duration );
  7392. this.now = this.start + ( (this.end - this.start) * this.pos );
  7393. }
  7394. // Perform the next step of the animation
  7395. this.update();
  7396. }
  7397. return true;
  7398. }
  7399. };
  7400. jQuery.extend( jQuery.fx, {
  7401. tick: function() {
  7402. var timer,
  7403. timers = jQuery.timers,
  7404. i = 0;
  7405. for ( ; i < timers.length; i++ ) {
  7406. timer = timers[ i ];
  7407. // Checks the timer has not already been removed
  7408. if ( !timer() && timers[ i ] === timer ) {
  7409. timers.splice( i--, 1 );
  7410. }
  7411. }
  7412. if ( !timers.length ) {
  7413. jQuery.fx.stop();
  7414. }
  7415. },
  7416. interval: 13,
  7417. stop: function() {
  7418. clearInterval( timerId );
  7419. timerId = null;
  7420. },
  7421. speeds: {
  7422. slow: 600,
  7423. fast: 200,
  7424. // Default speed
  7425. _default: 400
  7426. },
  7427. step: {
  7428. opacity: function( fx ) {
  7429. jQuery.style( fx.elem, "opacity", fx.now );
  7430. },
  7431. _default: function( fx ) {
  7432. if ( fx.elem.style && fx.elem.style[ fx.prop ] != null ) {
  7433. fx.elem.style[ fx.prop ] = fx.now + fx.unit;
  7434. } else {
  7435. fx.elem[ fx.prop ] = fx.now;
  7436. }
  7437. }
  7438. }
  7439. });
  7440. // Ensure props that can't be negative don't go there on undershoot easing
  7441. jQuery.each( fxAttrs.concat.apply( [], fxAttrs ), function( i, prop ) {
  7442. // exclude marginTop, marginLeft, marginBottom and marginRight from this list
  7443. if ( prop.indexOf( "margin" ) ) {
  7444. jQuery.fx.step[ prop ] = function( fx ) {
  7445. jQuery.style( fx.elem, prop, Math.max(0, fx.now) + fx.unit );
  7446. };
  7447. }
  7448. });
  7449. if ( jQuery.expr && jQuery.expr.filters ) {
  7450. jQuery.expr.filters.animated = function( elem ) {
  7451. return jQuery.grep(jQuery.timers, function( fn ) {
  7452. return elem === fn.elem;
  7453. }).length;
  7454. };
  7455. }
  7456. // Try to restore the default display value of an element
  7457. function defaultDisplay( nodeName ) {
  7458. if ( !elemdisplay[ nodeName ] ) {
  7459. var body = document.body,
  7460. elem = jQuery( "<" + nodeName + ">" ).appendTo( body ),
  7461. display = elem.css( "display" );
  7462. elem.remove();
  7463. // If the simple way fails,
  7464. // get element's real default display by attaching it to a temp iframe
  7465. if ( display === "none" || display === "" ) {
  7466. // No iframe to use yet, so create it
  7467. if ( !iframe ) {
  7468. iframe = document.createElement( "iframe" );
  7469. iframe.frameBorder = iframe.width = iframe.height = 0;
  7470. }
  7471. body.appendChild( iframe );
  7472. // Create a cacheable copy of the iframe document on first call.
  7473. // IE and Opera will allow us to reuse the iframeDoc without re-writing the fake HTML
  7474. // document to it; WebKit & Firefox won't allow reusing the iframe document.
  7475. if ( !iframeDoc || !iframe.createElement ) {
  7476. iframeDoc = ( iframe.contentWindow || iframe.contentDocument ).document;
  7477. iframeDoc.write( ( jQuery.support.boxModel ? "<!doctype html>" : "" ) + "<html><body>" );
  7478. iframeDoc.close();
  7479. }
  7480. elem = iframeDoc.createElement( nodeName );
  7481. iframeDoc.body.appendChild( elem );
  7482. display = jQuery.css( elem, "display" );
  7483. body.removeChild( iframe );
  7484. }
  7485. // Store the correct default display
  7486. elemdisplay[ nodeName ] = display;
  7487. }
  7488. return elemdisplay[ nodeName ];
  7489. }
  7490. var getOffset,
  7491. rtable = /^t(?:able|d|h)$/i,
  7492. rroot = /^(?:body|html)$/i;
  7493. if ( "getBoundingClientRect" in document.documentElement ) {
  7494. getOffset = function( elem, doc, docElem, box ) {
  7495. try {
  7496. box = elem.getBoundingClientRect();
  7497. } catch(e) {}
  7498. // Make sure we're not dealing with a disconnected DOM node
  7499. if ( !box || !jQuery.contains( docElem, elem ) ) {
  7500. return box ? { top: box.top, left: box.left } : { top: 0, left: 0 };
  7501. }
  7502. var body = doc.body,
  7503. win = getWindow( doc ),
  7504. clientTop = docElem.clientTop || body.clientTop || 0,
  7505. clientLeft = docElem.clientLeft || body.clientLeft || 0,
  7506. scrollTop = win.pageYOffset || jQuery.support.boxModel && docElem.scrollTop || body.scrollTop,
  7507. scrollLeft = win.pageXOffset || jQuery.support.boxModel && docElem.scrollLeft || body.scrollLeft,
  7508. top = box.top + scrollTop - clientTop,
  7509. left = box.left + scrollLeft - clientLeft;
  7510. return { top: top, left: left };
  7511. };
  7512. } else {
  7513. getOffset = function( elem, doc, docElem ) {
  7514. var computedStyle,
  7515. offsetParent = elem.offsetParent,
  7516. prevOffsetParent = elem,
  7517. body = doc.body,
  7518. defaultView = doc.defaultView,
  7519. prevComputedStyle = defaultView ? defaultView.getComputedStyle( elem, null ) : elem.currentStyle,
  7520. top = elem.offsetTop,
  7521. left = elem.offsetLeft;
  7522. while ( (elem = elem.parentNode) && elem !== body && elem !== docElem ) {
  7523. if ( jQuery.support.fixedPosition && prevComputedStyle.position === "fixed" ) {
  7524. break;
  7525. }
  7526. computedStyle = defaultView ? defaultView.getComputedStyle(elem, null) : elem.currentStyle;
  7527. top -= elem.scrollTop;
  7528. left -= elem.scrollLeft;
  7529. if ( elem === offsetParent ) {
  7530. top += elem.offsetTop;
  7531. left += elem.offsetLeft;
  7532. if ( jQuery.support.doesNotAddBorder && !(jQuery.support.doesAddBorderForTableAndCells && rtable.test(elem.nodeName)) ) {
  7533. top += parseFloat( computedStyle.borderTopWidth ) || 0;
  7534. left += parseFloat( computedStyle.borderLeftWidth ) || 0;
  7535. }
  7536. prevOffsetParent = offsetParent;
  7537. offsetParent = elem.offsetParent;
  7538. }
  7539. if ( jQuery.support.subtractsBorderForOverflowNotVisible && computedStyle.overflow !== "visible" ) {
  7540. top += parseFloat( computedStyle.borderTopWidth ) || 0;
  7541. left += parseFloat( computedStyle.borderLeftWidth ) || 0;
  7542. }
  7543. prevComputedStyle = computedStyle;
  7544. }
  7545. if ( prevComputedStyle.position === "relative" || prevComputedStyle.position === "static" ) {
  7546. top += body.offsetTop;
  7547. left += body.offsetLeft;
  7548. }
  7549. if ( jQuery.support.fixedPosition && prevComputedStyle.position === "fixed" ) {
  7550. top += Math.max( docElem.scrollTop, body.scrollTop );
  7551. left += Math.max( docElem.scrollLeft, body.scrollLeft );
  7552. }
  7553. return { top: top, left: left };
  7554. };
  7555. }
  7556. jQuery.fn.offset = function( options ) {
  7557. if ( arguments.length ) {
  7558. return options === undefined ?
  7559. this :
  7560. this.each(function( i ) {
  7561. jQuery.offset.setOffset( this, options, i );
  7562. });
  7563. }
  7564. var elem = this[0],
  7565. doc = elem && elem.ownerDocument;
  7566. if ( !doc ) {
  7567. return null;
  7568. }
  7569. if ( elem === doc.body ) {
  7570. return jQuery.offset.bodyOffset( elem );
  7571. }
  7572. return getOffset( elem, doc, doc.documentElement );
  7573. };
  7574. jQuery.offset = {
  7575. bodyOffset: function( body ) {
  7576. var top = body.offsetTop,
  7577. left = body.offsetLeft;
  7578. if ( jQuery.support.doesNotIncludeMarginInBodyOffset ) {
  7579. top += parseFloat( jQuery.css(body, "marginTop") ) || 0;
  7580. left += parseFloat( jQuery.css(body, "marginLeft") ) || 0;
  7581. }
  7582. return { top: top, left: left };
  7583. },
  7584. setOffset: function( elem, options, i ) {
  7585. var position = jQuery.css( elem, "position" );
  7586. // set position first, in-case top/left are set even on static elem
  7587. if ( position === "static" ) {
  7588. elem.style.position = "relative";
  7589. }
  7590. var curElem = jQuery( elem ),
  7591. curOffset = curElem.offset(),
  7592. curCSSTop = jQuery.css( elem, "top" ),
  7593. curCSSLeft = jQuery.css( elem, "left" ),
  7594. calculatePosition = ( position === "absolute" || position === "fixed" ) && jQuery.inArray("auto", [curCSSTop, curCSSLeft]) > -1,
  7595. props = {}, curPosition = {}, curTop, curLeft;
  7596. // need to be able to calculate position if either top or left is auto and position is either absolute or fixed
  7597. if ( calculatePosition ) {
  7598. curPosition = curElem.position();
  7599. curTop = curPosition.top;
  7600. curLeft = curPosition.left;
  7601. } else {
  7602. curTop = parseFloat( curCSSTop ) || 0;
  7603. curLeft = parseFloat( curCSSLeft ) || 0;
  7604. }
  7605. if ( jQuery.isFunction( options ) ) {
  7606. options = options.call( elem, i, curOffset );
  7607. }
  7608. if ( options.top != null ) {
  7609. props.top = ( options.top - curOffset.top ) + curTop;
  7610. }
  7611. if ( options.left != null ) {
  7612. props.left = ( options.left - curOffset.left ) + curLeft;
  7613. }
  7614. if ( "using" in options ) {
  7615. options.using.call( elem, props );
  7616. } else {
  7617. curElem.css( props );
  7618. }
  7619. }
  7620. };
  7621. jQuery.fn.extend({
  7622. position: function() {
  7623. if ( !this[0] ) {
  7624. return null;
  7625. }
  7626. var elem = this[0],
  7627. // Get *real* offsetParent
  7628. offsetParent = this.offsetParent(),
  7629. // Get correct offsets
  7630. offset = this.offset(),
  7631. parentOffset = rroot.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset();
  7632. // Subtract element margins
  7633. // note: when an element has margin: auto the offsetLeft and marginLeft
  7634. // are the same in Safari causing offset.left to incorrectly be 0
  7635. offset.top -= parseFloat( jQuery.css(elem, "marginTop") ) || 0;
  7636. offset.left -= parseFloat( jQuery.css(elem, "marginLeft") ) || 0;
  7637. // Add offsetParent borders
  7638. parentOffset.top += parseFloat( jQuery.css(offsetParent[0], "borderTopWidth") ) || 0;
  7639. parentOffset.left += parseFloat( jQuery.css(offsetParent[0], "borderLeftWidth") ) || 0;
  7640. // Subtract the two offsets
  7641. return {
  7642. top: offset.top - parentOffset.top,
  7643. left: offset.left - parentOffset.left
  7644. };
  7645. },
  7646. offsetParent: function() {
  7647. return this.map(function() {
  7648. var offsetParent = this.offsetParent || document.body;
  7649. while ( offsetParent && (!rroot.test(offsetParent.nodeName) && jQuery.css(offsetParent, "position") === "static") ) {
  7650. offsetParent = offsetParent.offsetParent;
  7651. }
  7652. return offsetParent;
  7653. });
  7654. }
  7655. });
  7656. // Create scrollLeft and scrollTop methods
  7657. jQuery.each( {scrollLeft: "pageXOffset", scrollTop: "pageYOffset"}, function( method, prop ) {
  7658. var top = /Y/.test( prop );
  7659. jQuery.fn[ method ] = function( val ) {
  7660. return jQuery.access( this, function( elem, method, val ) {
  7661. var win = getWindow( elem );
  7662. if ( val === undefined ) {
  7663. return win ? (prop in win) ? win[ prop ] :
  7664. jQuery.support.boxModel && win.document.documentElement[ method ] ||
  7665. win.document.body[ method ] :
  7666. elem[ method ];
  7667. }
  7668. if ( win ) {
  7669. win.scrollTo(
  7670. !top ? val : jQuery( win ).scrollLeft(),
  7671. top ? val : jQuery( win ).scrollTop()
  7672. );
  7673. } else {
  7674. elem[ method ] = val;
  7675. }
  7676. }, method, val, arguments.length, null );
  7677. };
  7678. });
  7679. function getWindow( elem ) {
  7680. return jQuery.isWindow( elem ) ?
  7681. elem :
  7682. elem.nodeType === 9 ?
  7683. elem.defaultView || elem.parentWindow :
  7684. false;
  7685. }
  7686. // Create width, height, innerHeight, innerWidth, outerHeight and outerWidth methods
  7687. jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
  7688. var clientProp = "client" + name,
  7689. scrollProp = "scroll" + name,
  7690. offsetProp = "offset" + name;
  7691. // innerHeight and innerWidth
  7692. jQuery.fn[ "inner" + name ] = function() {
  7693. var elem = this[0];
  7694. return elem ?
  7695. elem.style ?
  7696. parseFloat( jQuery.css( elem, type, "padding" ) ) :
  7697. this[ type ]() :
  7698. null;
  7699. };
  7700. // outerHeight and outerWidth
  7701. jQuery.fn[ "outer" + name ] = function( margin ) {
  7702. var elem = this[0];
  7703. return elem ?
  7704. elem.style ?
  7705. parseFloat( jQuery.css( elem, type, margin ? "margin" : "border" ) ) :
  7706. this[ type ]() :
  7707. null;
  7708. };
  7709. jQuery.fn[ type ] = function( value ) {
  7710. return jQuery.access( this, function( elem, type, value ) {
  7711. var doc, docElemProp, orig, ret;
  7712. if ( jQuery.isWindow( elem ) ) {
  7713. // 3rd condition allows Nokia support, as it supports the docElem prop but not CSS1Compat
  7714. doc = elem.document;
  7715. docElemProp = doc.documentElement[ clientProp ];
  7716. return jQuery.support.boxModel && docElemProp ||
  7717. doc.body && doc.body[ clientProp ] || docElemProp;
  7718. }
  7719. // Get document width or height
  7720. if ( elem.nodeType === 9 ) {
  7721. // Either scroll[Width/Height] or offset[Width/Height], whichever is greater
  7722. doc = elem.documentElement;
  7723. // when a window > document, IE6 reports a offset[Width/Height] > client[Width/Height]
  7724. // so we can't use max, as it'll choose the incorrect offset[Width/Height]
  7725. // instead we use the correct client[Width/Height]
  7726. // support:IE6
  7727. if ( doc[ clientProp ] >= doc[ scrollProp ] ) {
  7728. return doc[ clientProp ];
  7729. }
  7730. return Math.max(
  7731. elem.body[ scrollProp ], doc[ scrollProp ],
  7732. elem.body[ offsetProp ], doc[ offsetProp ]
  7733. );
  7734. }
  7735. // Get width or height on the element
  7736. if ( value === undefined ) {
  7737. orig = jQuery.css( elem, type );
  7738. ret = parseFloat( orig );
  7739. return jQuery.isNumeric( ret ) ? ret : orig;
  7740. }
  7741. // Set the width or height on the element
  7742. jQuery( elem ).css( type, value );
  7743. }, type, value, arguments.length, null );
  7744. };
  7745. });
  7746. // Expose jQuery to the global object
  7747. window.jQuery = window.$ = jQuery;
  7748. // Expose jQuery as an AMD module, but only for AMD loaders that
  7749. // understand the issues with loading multiple versions of jQuery
  7750. // in a page that all might call define(). The loader will indicate
  7751. // they have special allowances for multiple jQuery versions by
  7752. // specifying define.amd.jQuery = true. Register as a named module,
  7753. // since jQuery can be concatenated with other files that may use define,
  7754. // but not use a proper concatenation script that understands anonymous
  7755. // AMD modules. A named AMD is safest and most robust way to register.
  7756. // Lowercase jquery is used because AMD module names are derived from
  7757. // file names, and jQuery is normally delivered in a lowercase file name.
  7758. // Do this after creating the global so that if an AMD module wants to call
  7759. // noConflict to hide this version of jQuery, it will work.
  7760. if ( typeof define === "function" && define.amd && define.amd.jQuery ) {
  7761. define( "jquery", [], function () { return jQuery; } );
  7762. }
  7763. })( window );
  7764. /*!
  7765. * jQuery UI @VERSION
  7766. *
  7767. * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
  7768. * Dual licensed under the MIT or GPL Version 2 licenses.
  7769. * http://jquery.org/license
  7770. *
  7771. * http://docs.jquery.com/UI
  7772. */
  7773. (function( $, undefined ) {
  7774. // prevent duplicate loading
  7775. // this is only a problem because we proxy existing functions
  7776. // and we don't want to double proxy them
  7777. $.ui = $.ui || {};
  7778. if ( $.ui.version ) {
  7779. return;
  7780. }
  7781. $.extend( $.ui, {
  7782. version: "@VERSION",
  7783. keyCode: {
  7784. ALT: 18,
  7785. BACKSPACE: 8,
  7786. CAPS_LOCK: 20,
  7787. COMMA: 188,
  7788. COMMAND: 91,
  7789. COMMAND_LEFT: 91, // COMMAND
  7790. COMMAND_RIGHT: 93,
  7791. CONTROL: 17,
  7792. DELETE: 46,
  7793. DOWN: 40,
  7794. END: 35,
  7795. ENTER: 13,
  7796. ESCAPE: 27,
  7797. HOME: 36,
  7798. INSERT: 45,
  7799. LEFT: 37,
  7800. MENU: 93, // COMMAND_RIGHT
  7801. NUMPAD_ADD: 107,
  7802. NUMPAD_DECIMAL: 110,
  7803. NUMPAD_DIVIDE: 111,
  7804. NUMPAD_ENTER: 108,
  7805. NUMPAD_MULTIPLY: 106,
  7806. NUMPAD_SUBTRACT: 109,
  7807. PAGE_DOWN: 34,
  7808. PAGE_UP: 33,
  7809. PERIOD: 190,
  7810. RIGHT: 39,
  7811. SHIFT: 16,
  7812. SPACE: 32,
  7813. TAB: 9,
  7814. UP: 38,
  7815. WINDOWS: 91 // COMMAND
  7816. }
  7817. });
  7818. // plugins
  7819. $.fn.extend({
  7820. propAttr: $.fn.prop || $.fn.attr,
  7821. _focus: $.fn.focus,
  7822. focus: function( delay, fn ) {
  7823. return typeof delay === "number" ?
  7824. this.each(function() {
  7825. var elem = this;
  7826. setTimeout(function() {
  7827. $( elem ).focus();
  7828. if ( fn ) {
  7829. fn.call( elem );
  7830. }
  7831. }, delay );
  7832. }) :
  7833. this._focus.apply( this, arguments );
  7834. },
  7835. scrollParent: function() {
  7836. var scrollParent;
  7837. if (($.browser.msie && (/(static|relative)/).test(this.css('position'))) || (/absolute/).test(this.css('position'))) {
  7838. scrollParent = this.parents().filter(function() {
  7839. return (/(relative|absolute|fixed)/).test($.curCSS(this,'position',1)) && (/(auto|scroll)/).test($.curCSS(this,'overflow',1)+$.curCSS(this,'overflow-y',1)+$.curCSS(this,'overflow-x',1));
  7840. }).eq(0);
  7841. } else {
  7842. scrollParent = this.parents().filter(function() {
  7843. return (/(auto|scroll)/).test($.curCSS(this,'overflow',1)+$.curCSS(this,'overflow-y',1)+$.curCSS(this,'overflow-x',1));
  7844. }).eq(0);
  7845. }
  7846. return (/fixed/).test(this.css('position')) || !scrollParent.length ? $(document) : scrollParent;
  7847. },
  7848. zIndex: function( zIndex ) {
  7849. if ( zIndex !== undefined ) {
  7850. return this.css( "zIndex", zIndex );
  7851. }
  7852. if ( this.length ) {
  7853. var elem = $( this[ 0 ] ), position, value;
  7854. while ( elem.length && elem[ 0 ] !== document ) {
  7855. // Ignore z-index if position is set to a value where z-index is ignored by the browser
  7856. // This makes behavior of this function consistent across browsers
  7857. // WebKit always returns auto if the element is positioned
  7858. position = elem.css( "position" );
  7859. if ( position === "absolute" || position === "relative" || position === "fixed" ) {
  7860. // IE returns 0 when zIndex is not specified
  7861. // other browsers return a string
  7862. // we ignore the case of nested elements with an explicit value of 0
  7863. // <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
  7864. value = parseInt( elem.css( "zIndex" ), 10 );
  7865. if ( !isNaN( value ) && value !== 0 ) {
  7866. return value;
  7867. }
  7868. }
  7869. elem = elem.parent();
  7870. }
  7871. }
  7872. return 0;
  7873. },
  7874. disableSelection: function() {
  7875. return this.bind( ( $.support.selectstart ? "selectstart" : "mousedown" ) +
  7876. ".ui-disableSelection", function( event ) {
  7877. event.preventDefault();
  7878. });
  7879. },
  7880. enableSelection: function() {
  7881. return this.unbind( ".ui-disableSelection" );
  7882. }
  7883. });
  7884. $.each( [ "Width", "Height" ], function( i, name ) {
  7885. var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ],
  7886. type = name.toLowerCase(),
  7887. orig = {
  7888. innerWidth: $.fn.innerWidth,
  7889. innerHeight: $.fn.innerHeight,
  7890. outerWidth: $.fn.outerWidth,
  7891. outerHeight: $.fn.outerHeight
  7892. };
  7893. function reduce( elem, size, border, margin ) {
  7894. $.each( side, function() {
  7895. size -= parseFloat( $.curCSS( elem, "padding" + this, true) ) || 0;
  7896. if ( border ) {
  7897. size -= parseFloat( $.curCSS( elem, "border" + this + "Width", true) ) || 0;
  7898. }
  7899. if ( margin ) {
  7900. size -= parseFloat( $.curCSS( elem, "margin" + this, true) ) || 0;
  7901. }
  7902. });
  7903. return size;
  7904. }
  7905. $.fn[ "inner" + name ] = function( size ) {
  7906. if ( size === undefined ) {
  7907. return orig[ "inner" + name ].call( this );
  7908. }
  7909. return this.each(function() {
  7910. $( this ).css( type, reduce( this, size ) + "px" );
  7911. });
  7912. };
  7913. $.fn[ "outer" + name] = function( size, margin ) {
  7914. if ( typeof size !== "number" ) {
  7915. return orig[ "outer" + name ].call( this, size );
  7916. }
  7917. return this.each(function() {
  7918. $( this).css( type, reduce( this, size, true, margin ) + "px" );
  7919. });
  7920. };
  7921. });
  7922. // selectors
  7923. function focusable( element, isTabIndexNotNaN ) {
  7924. var nodeName = element.nodeName.toLowerCase();
  7925. if ( "area" === nodeName ) {
  7926. var map = element.parentNode,
  7927. mapName = map.name,
  7928. img;
  7929. if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) {
  7930. return false;
  7931. }
  7932. img = $( "img[usemap=#" + mapName + "]" )[0];
  7933. return !!img && visible( img );
  7934. }
  7935. return ( /input|select|textarea|button|object/.test( nodeName )
  7936. ? !element.disabled
  7937. : "a" == nodeName
  7938. ? element.href || isTabIndexNotNaN
  7939. : isTabIndexNotNaN)
  7940. // the element and all of its ancestors must be visible
  7941. && visible( element );
  7942. }
  7943. function visible( element ) {
  7944. return !$( element ).parents().andSelf().filter(function() {
  7945. return $.curCSS( this, "visibility" ) === "hidden" ||
  7946. $.expr.filters.hidden( this );
  7947. }).length;
  7948. }
  7949. $.extend( $.expr[ ":" ], {
  7950. data: function( elem, i, match ) {
  7951. return !!$.data( elem, match[ 3 ] );
  7952. },
  7953. focusable: function( element ) {
  7954. return focusable( element, !isNaN( $.attr( element, "tabindex" ) ) );
  7955. },
  7956. tabbable: function( element ) {
  7957. var tabIndex = $.attr( element, "tabindex" ),
  7958. isTabIndexNaN = isNaN( tabIndex );
  7959. return ( isTabIndexNaN || tabIndex >= 0 ) && focusable( element, !isTabIndexNaN );
  7960. }
  7961. });
  7962. // support
  7963. $(function() {
  7964. var body = document.body,
  7965. div = body.appendChild( div = document.createElement( "div" ) );
  7966. // access offsetHeight before setting the style to prevent a layout bug
  7967. // in IE 9 which causes the elemnt to continue to take up space even
  7968. // after it is removed from the DOM (#8026)
  7969. div.offsetHeight;
  7970. $.extend( div.style, {
  7971. minHeight: "100px",
  7972. height: "auto",
  7973. padding: 0,
  7974. borderWidth: 0
  7975. });
  7976. $.support.minHeight = div.offsetHeight === 100;
  7977. $.support.selectstart = "onselectstart" in div;
  7978. // set display to none to avoid a layout bug in IE
  7979. // http://dev.jquery.com/ticket/4014
  7980. body.removeChild( div ).style.display = "none";
  7981. });
  7982. // deprecated
  7983. $.extend( $.ui, {
  7984. // $.ui.plugin is deprecated. Use the proxy pattern instead.
  7985. plugin: {
  7986. add: function( module, option, set ) {
  7987. var proto = $.ui[ module ].prototype;
  7988. for ( var i in set ) {
  7989. proto.plugins[ i ] = proto.plugins[ i ] || [];
  7990. proto.plugins[ i ].push( [ option, set[ i ] ] );
  7991. }
  7992. },
  7993. call: function( instance, name, args ) {
  7994. var set = instance.plugins[ name ];
  7995. if ( !set || !instance.element[ 0 ].parentNode ) {
  7996. return;
  7997. }
  7998. for ( var i = 0; i < set.length; i++ ) {
  7999. if ( instance.options[ set[ i ][ 0 ] ] ) {
  8000. set[ i ][ 1 ].apply( instance.element, args );
  8001. }
  8002. }
  8003. }
  8004. },
  8005. // will be deprecated when we switch to jQuery 1.4 - use jQuery.contains()
  8006. contains: function( a, b ) {
  8007. return document.compareDocumentPosition ?
  8008. a.compareDocumentPosition( b ) & 16 :
  8009. a !== b && a.contains( b );
  8010. },
  8011. // only used by resizable
  8012. hasScroll: function( el, a ) {
  8013. //If overflow is hidden, the element might have extra content, but the user wants to hide it
  8014. if ( $( el ).css( "overflow" ) === "hidden") {
  8015. return false;
  8016. }
  8017. var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop",
  8018. has = false;
  8019. if ( el[ scroll ] > 0 ) {
  8020. return true;
  8021. }
  8022. // TODO: determine which cases actually cause this to happen
  8023. // if the element doesn't have the scroll set, see if it's possible to
  8024. // set the scroll
  8025. el[ scroll ] = 1;
  8026. has = ( el[ scroll ] > 0 );
  8027. el[ scroll ] = 0;
  8028. return has;
  8029. },
  8030. // these are odd functions, fix the API or move into individual plugins
  8031. isOverAxis: function( x, reference, size ) {
  8032. //Determines when x coordinate is over "b" element axis
  8033. return ( x > reference ) && ( x < ( reference + size ) );
  8034. },
  8035. isOver: function( y, x, top, left, height, width ) {
  8036. //Determines when x, y coordinates is over "b" element
  8037. return $.ui.isOverAxis( y, top, height ) && $.ui.isOverAxis( x, left, width );
  8038. }
  8039. });
  8040. })( jQuery );
  8041. /*!
  8042. * jQuery UI Widget @VERSION
  8043. *
  8044. * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
  8045. * Dual licensed under the MIT or GPL Version 2 licenses.
  8046. * http://jquery.org/license
  8047. *
  8048. * http://docs.jquery.com/UI/Widget
  8049. */
  8050. (function( $, undefined ) {
  8051. // jQuery 1.4+
  8052. if ( $.cleanData ) {
  8053. var _cleanData = $.cleanData;
  8054. $.cleanData = function( elems ) {
  8055. for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
  8056. try {
  8057. $( elem ).triggerHandler( "remove" );
  8058. // http://bugs.jquery.com/ticket/8235
  8059. } catch( e ) {}
  8060. }
  8061. _cleanData( elems );
  8062. };
  8063. } else {
  8064. var _remove = $.fn.remove;
  8065. $.fn.remove = function( selector, keepData ) {
  8066. return this.each(function() {
  8067. if ( !keepData ) {
  8068. if ( !selector || $.filter( selector, [ this ] ).length ) {
  8069. $( "*", this ).add( [ this ] ).each(function() {
  8070. try {
  8071. $( this ).triggerHandler( "remove" );
  8072. // http://bugs.jquery.com/ticket/8235
  8073. } catch( e ) {}
  8074. });
  8075. }
  8076. }
  8077. return _remove.call( $(this), selector, keepData );
  8078. });
  8079. };
  8080. }
  8081. $.widget = function( name, base, prototype ) {
  8082. var namespace = name.split( "." )[ 0 ],
  8083. fullName;
  8084. name = name.split( "." )[ 1 ];
  8085. fullName = namespace + "-" + name;
  8086. if ( !prototype ) {
  8087. prototype = base;
  8088. base = $.Widget;
  8089. }
  8090. // create selector for plugin
  8091. $.expr[ ":" ][ fullName ] = function( elem ) {
  8092. return !!$.data( elem, name );
  8093. };
  8094. $[ namespace ] = $[ namespace ] || {};
  8095. $[ namespace ][ name ] = function( options, element ) {
  8096. // allow instantiation without initializing for simple inheritance
  8097. if ( arguments.length ) {
  8098. this._createWidget( options, element );
  8099. }
  8100. };
  8101. var basePrototype = new base();
  8102. // we need to make the options hash a property directly on the new instance
  8103. // otherwise we'll modify the options hash on the prototype that we're
  8104. // inheriting from
  8105. // $.each( basePrototype, function( key, val ) {
  8106. // if ( $.isPlainObject(val) ) {
  8107. // basePrototype[ key ] = $.extend( {}, val );
  8108. // }
  8109. // });
  8110. basePrototype.options = $.extend( true, {}, basePrototype.options );
  8111. $[ namespace ][ name ].prototype = $.extend( true, basePrototype, {
  8112. namespace: namespace,
  8113. widgetName: name,
  8114. widgetEventPrefix: $[ namespace ][ name ].prototype.widgetEventPrefix || name,
  8115. widgetBaseClass: fullName
  8116. }, prototype );
  8117. $.widget.bridge( name, $[ namespace ][ name ] );
  8118. };
  8119. $.widget.bridge = function( name, object ) {
  8120. $.fn[ name ] = function( options ) {
  8121. var isMethodCall = typeof options === "string",
  8122. args = Array.prototype.slice.call( arguments, 1 ),
  8123. returnValue = this;
  8124. // allow multiple hashes to be passed on init
  8125. options = !isMethodCall && args.length ?
  8126. $.extend.apply( null, [ true, options ].concat(args) ) :
  8127. options;
  8128. // prevent calls to internal methods
  8129. if ( isMethodCall && options.charAt( 0 ) === "_" ) {
  8130. return returnValue;
  8131. }
  8132. if ( isMethodCall ) {
  8133. this.each(function() {
  8134. var instance = $.data( this, name ),
  8135. methodValue = instance && $.isFunction( instance[options] ) ?
  8136. instance[ options ].apply( instance, args ) :
  8137. instance;
  8138. // TODO: add this back in 1.9 and use $.error() (see #5972)
  8139. // if ( !instance ) {
  8140. // throw "cannot call methods on " + name + " prior to initialization; " +
  8141. // "attempted to call method '" + options + "'";
  8142. // }
  8143. // if ( !$.isFunction( instance[options] ) ) {
  8144. // throw "no such method '" + options + "' for " + name + " widget instance";
  8145. // }
  8146. // var methodValue = instance[ options ].apply( instance, args );
  8147. if ( methodValue !== instance && methodValue !== undefined ) {
  8148. returnValue = methodValue;
  8149. return false;
  8150. }
  8151. });
  8152. } else {
  8153. this.each(function() {
  8154. var instance = $.data( this, name );
  8155. if ( instance ) {
  8156. instance.option( options || {} )._init();
  8157. } else {
  8158. $.data( this, name, new object( options, this ) );
  8159. }
  8160. });
  8161. }
  8162. return returnValue;
  8163. };
  8164. };
  8165. $.Widget = function( options, element ) {
  8166. // allow instantiation without initializing for simple inheritance
  8167. if ( arguments.length ) {
  8168. this._createWidget( options, element );
  8169. }
  8170. };
  8171. $.Widget.prototype = {
  8172. widgetName: "widget",
  8173. widgetEventPrefix: "",
  8174. options: {
  8175. disabled: false
  8176. },
  8177. _createWidget: function( options, element ) {
  8178. // $.widget.bridge stores the plugin instance, but we do it anyway
  8179. // so that it's stored even before the _create function runs
  8180. $.data( element, this.widgetName, this );
  8181. this.element = $( element );
  8182. this.options = $.extend( true, {},
  8183. this.options,
  8184. this._getCreateOptions(),
  8185. options );
  8186. var self = this;
  8187. this.element.bind( "remove." + this.widgetName, function() {
  8188. self.destroy();
  8189. });
  8190. this._create();
  8191. this._trigger( "create" );
  8192. this._init();
  8193. },
  8194. _getCreateOptions: function() {
  8195. return $.metadata && $.metadata.get( this.element[0] )[ this.widgetName ];
  8196. },
  8197. _create: function() {},
  8198. _init: function() {},
  8199. destroy: function() {
  8200. this.element
  8201. .unbind( "." + this.widgetName )
  8202. .removeData( this.widgetName );
  8203. this.widget()
  8204. .unbind( "." + this.widgetName )
  8205. .removeAttr( "aria-disabled" )
  8206. .removeClass(
  8207. this.widgetBaseClass + "-disabled " +
  8208. "ui-state-disabled" );
  8209. },
  8210. widget: function() {
  8211. return this.element;
  8212. },
  8213. option: function( key, value ) {
  8214. var options = key;
  8215. if ( arguments.length === 0 ) {
  8216. // don't return a reference to the internal hash
  8217. return $.extend( {}, this.options );
  8218. }
  8219. if (typeof key === "string" ) {
  8220. if ( value === undefined ) {
  8221. return this.options[ key ];
  8222. }
  8223. options = {};
  8224. options[ key ] = value;
  8225. }
  8226. this._setOptions( options );
  8227. return this;
  8228. },
  8229. _setOptions: function( options ) {
  8230. var self = this;
  8231. $.each( options, function( key, value ) {
  8232. self._setOption( key, value );
  8233. });
  8234. return this;
  8235. },
  8236. _setOption: function( key, value ) {
  8237. this.options[ key ] = value;
  8238. if ( key === "disabled" ) {
  8239. this.widget()
  8240. [ value ? "addClass" : "removeClass"](
  8241. this.widgetBaseClass + "-disabled" + " " +
  8242. "ui-state-disabled" )
  8243. .attr( "aria-disabled", value );
  8244. }
  8245. return this;
  8246. },
  8247. enable: function() {
  8248. return this._setOption( "disabled", false );
  8249. },
  8250. disable: function() {
  8251. return this._setOption( "disabled", true );
  8252. },
  8253. _trigger: function( type, event, data ) {
  8254. var prop, orig,
  8255. callback = this.options[ type ];
  8256. data = data || {};
  8257. event = $.Event( event );
  8258. event.type = ( type === this.widgetEventPrefix ?
  8259. type :
  8260. this.widgetEventPrefix + type ).toLowerCase();
  8261. // the original event may come from any element
  8262. // so we need to reset the target on the new event
  8263. event.target = this.element[ 0 ];
  8264. // copy original event properties over to the new event
  8265. orig = event.originalEvent;
  8266. if ( orig ) {
  8267. for ( prop in orig ) {
  8268. if ( !( prop in event ) ) {
  8269. event[ prop ] = orig[ prop ];
  8270. }
  8271. }
  8272. }
  8273. this.element.trigger( event, data );
  8274. return !( $.isFunction(callback) &&
  8275. callback.call( this.element[0], event, data ) === false ||
  8276. event.isDefaultPrevented() );
  8277. }
  8278. };
  8279. })( jQuery );
  8280. /*!
  8281. * jQuery UI Mouse @VERSION
  8282. *
  8283. * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
  8284. * Dual licensed under the MIT or GPL Version 2 licenses.
  8285. * http://jquery.org/license
  8286. *
  8287. * http://docs.jquery.com/UI/Mouse
  8288. *
  8289. * Depends:
  8290. * jquery.ui.widget.js
  8291. */
  8292. (function( $, undefined ) {
  8293. var mouseHandled = false;
  8294. $( document ).mouseup( function( e ) {
  8295. mouseHandled = false;
  8296. });
  8297. $.widget("ui.mouse", {
  8298. options: {
  8299. cancel: ':input,option',
  8300. distance: 1,
  8301. delay: 0
  8302. },
  8303. _mouseInit: function() {
  8304. var self = this;
  8305. this.element
  8306. .bind('mousedown.'+this.widgetName, function(event) {
  8307. return self._mouseDown(event);
  8308. })
  8309. .bind('click.'+this.widgetName, function(event) {
  8310. if (true === $.data(event.target, self.widgetName + '.preventClickEvent')) {
  8311. $.removeData(event.target, self.widgetName + '.preventClickEvent');
  8312. event.stopImmediatePropagation();
  8313. return false;
  8314. }
  8315. });
  8316. this.started = false;
  8317. },
  8318. // TODO: make sure destroying one instance of mouse doesn't mess with
  8319. // other instances of mouse
  8320. _mouseDestroy: function() {
  8321. this.element.unbind('.'+this.widgetName);
  8322. },
  8323. _mouseDown: function(event) {
  8324. // don't let more than one widget handle mouseStart
  8325. if( mouseHandled ) { return };
  8326. // we may have missed mouseup (out of window)
  8327. (this._mouseStarted && this._mouseUp(event));
  8328. this._mouseDownEvent = event;
  8329. var self = this,
  8330. btnIsLeft = (event.which == 1),
  8331. // event.target.nodeName works around a bug in IE 8 with
  8332. // disabled inputs (#7620)
  8333. elIsCancel = (typeof this.options.cancel == "string" && event.target.nodeName ? $(event.target).closest(this.options.cancel).length : false);
  8334. if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) {
  8335. return true;
  8336. }
  8337. this.mouseDelayMet = !this.options.delay;
  8338. if (!this.mouseDelayMet) {
  8339. this._mouseDelayTimer = setTimeout(function() {
  8340. self.mouseDelayMet = true;
  8341. }, this.options.delay);
  8342. }
  8343. if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
  8344. this._mouseStarted = (this._mouseStart(event) !== false);
  8345. if (!this._mouseStarted) {
  8346. event.preventDefault();
  8347. return true;
  8348. }
  8349. }
  8350. // Click event may never have fired (Gecko & Opera)
  8351. if (true === $.data(event.target, this.widgetName + '.preventClickEvent')) {
  8352. $.removeData(event.target, this.widgetName + '.preventClickEvent');
  8353. }
  8354. // these delegates are required to keep context
  8355. this._mouseMoveDelegate = function(event) {
  8356. return self._mouseMove(event);
  8357. };
  8358. this._mouseUpDelegate = function(event) {
  8359. return self._mouseUp(event);
  8360. };
  8361. $(document)
  8362. .bind('mousemove.'+this.widgetName, this._mouseMoveDelegate)
  8363. .bind('mouseup.'+this.widgetName, this._mouseUpDelegate);
  8364. event.preventDefault();
  8365. mouseHandled = true;
  8366. return true;
  8367. },
  8368. _mouseMove: function(event) {
  8369. // IE mouseup check - mouseup happened when mouse was out of window
  8370. if ($.browser.msie && !(document.documentMode >= 9) && !event.button) {
  8371. return this._mouseUp(event);
  8372. }
  8373. if (this._mouseStarted) {
  8374. this._mouseDrag(event);
  8375. return event.preventDefault();
  8376. }
  8377. if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
  8378. this._mouseStarted =
  8379. (this._mouseStart(this._mouseDownEvent, event) !== false);
  8380. (this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event));
  8381. }
  8382. return !this._mouseStarted;
  8383. },
  8384. _mouseUp: function(event) {
  8385. $(document)
  8386. .unbind('mousemove.'+this.widgetName, this._mouseMoveDelegate)
  8387. .unbind('mouseup.'+this.widgetName, this._mouseUpDelegate);
  8388. if (this._mouseStarted) {
  8389. this._mouseStarted = false;
  8390. if (event.target == this._mouseDownEvent.target) {
  8391. $.data(event.target, this.widgetName + '.preventClickEvent', true);
  8392. }
  8393. this._mouseStop(event);
  8394. }
  8395. return false;
  8396. },
  8397. _mouseDistanceMet: function(event) {
  8398. return (Math.max(
  8399. Math.abs(this._mouseDownEvent.pageX - event.pageX),
  8400. Math.abs(this._mouseDownEvent.pageY - event.pageY)
  8401. ) >= this.options.distance
  8402. );
  8403. },
  8404. _mouseDelayMet: function(event) {
  8405. return this.mouseDelayMet;
  8406. },
  8407. // These are placeholder methods, to be overriden by extending plugin
  8408. _mouseStart: function(event) {},
  8409. _mouseDrag: function(event) {},
  8410. _mouseStop: function(event) {},
  8411. _mouseCapture: function(event) { return true; }
  8412. });
  8413. })(jQuery);
  8414. /*
  8415. * jQuery UI Position @VERSION
  8416. *
  8417. * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
  8418. * Dual licensed under the MIT or GPL Version 2 licenses.
  8419. * http://jquery.org/license
  8420. *
  8421. * http://docs.jquery.com/UI/Position
  8422. */
  8423. (function( $, undefined ) {
  8424. $.ui = $.ui || {};
  8425. var horizontalPositions = /left|center|right/,
  8426. verticalPositions = /top|center|bottom/,
  8427. center = "center",
  8428. support = {},
  8429. _position = $.fn.position,
  8430. _offset = $.fn.offset;
  8431. $.fn.position = function( options ) {
  8432. if ( !options || !options.of ) {
  8433. return _position.apply( this, arguments );
  8434. }
  8435. // make a copy, we don't want to modify arguments
  8436. options = $.extend( {}, options );
  8437. var target = $( options.of ),
  8438. targetElem = target[0],
  8439. collision = ( options.collision || "flip" ).split( " " ),
  8440. offset = options.offset ? options.offset.split( " " ) : [ 0, 0 ],
  8441. targetWidth,
  8442. targetHeight,
  8443. basePosition;
  8444. if ( targetElem.nodeType === 9 ) {
  8445. targetWidth = target.width();
  8446. targetHeight = target.height();
  8447. basePosition = { top: 0, left: 0 };
  8448. // TODO: use $.isWindow() in 1.9
  8449. } else if ( targetElem.setTimeout ) {
  8450. targetWidth = target.width();
  8451. targetHeight = target.height();
  8452. basePosition = { top: target.scrollTop(), left: target.scrollLeft() };
  8453. } else if ( targetElem.preventDefault ) {
  8454. // force left top to allow flipping
  8455. options.at = "left top";
  8456. targetWidth = targetHeight = 0;
  8457. basePosition = { top: options.of.pageY, left: options.of.pageX };
  8458. } else {
  8459. targetWidth = target.outerWidth();
  8460. targetHeight = target.outerHeight();
  8461. basePosition = target.offset();
  8462. }
  8463. // force my and at to have valid horizontal and veritcal positions
  8464. // if a value is missing or invalid, it will be converted to center
  8465. $.each( [ "my", "at" ], function() {
  8466. var pos = ( options[this] || "" ).split( " " );
  8467. if ( pos.length === 1) {
  8468. pos = horizontalPositions.test( pos[0] ) ?
  8469. pos.concat( [center] ) :
  8470. verticalPositions.test( pos[0] ) ?
  8471. [ center ].concat( pos ) :
  8472. [ center, center ];
  8473. }
  8474. pos[ 0 ] = horizontalPositions.test( pos[0] ) ? pos[ 0 ] : center;
  8475. pos[ 1 ] = verticalPositions.test( pos[1] ) ? pos[ 1 ] : center;
  8476. options[ this ] = pos;
  8477. });
  8478. // normalize collision option
  8479. if ( collision.length === 1 ) {
  8480. collision[ 1 ] = collision[ 0 ];
  8481. }
  8482. // normalize offset option
  8483. offset[ 0 ] = parseInt( offset[0], 10 ) || 0;
  8484. if ( offset.length === 1 ) {
  8485. offset[ 1 ] = offset[ 0 ];
  8486. }
  8487. offset[ 1 ] = parseInt( offset[1], 10 ) || 0;
  8488. if ( options.at[0] === "right" ) {
  8489. basePosition.left += targetWidth;
  8490. } else if ( options.at[0] === center ) {
  8491. basePosition.left += targetWidth / 2;
  8492. }
  8493. if ( options.at[1] === "bottom" ) {
  8494. basePosition.top += targetHeight;
  8495. } else if ( options.at[1] === center ) {
  8496. basePosition.top += targetHeight / 2;
  8497. }
  8498. basePosition.left += offset[ 0 ];
  8499. basePosition.top += offset[ 1 ];
  8500. return this.each(function() {
  8501. var elem = $( this ),
  8502. elemWidth = elem.outerWidth(),
  8503. elemHeight = elem.outerHeight(),
  8504. marginLeft = parseInt( $.curCSS( this, "marginLeft", true ) ) || 0,
  8505. marginTop = parseInt( $.curCSS( this, "marginTop", true ) ) || 0,
  8506. collisionWidth = elemWidth + marginLeft +
  8507. ( parseInt( $.curCSS( this, "marginRight", true ) ) || 0 ),
  8508. collisionHeight = elemHeight + marginTop +
  8509. ( parseInt( $.curCSS( this, "marginBottom", true ) ) || 0 ),
  8510. position = $.extend( {}, basePosition ),
  8511. collisionPosition;
  8512. if ( options.my[0] === "right" ) {
  8513. position.left -= elemWidth;
  8514. } else if ( options.my[0] === center ) {
  8515. position.left -= elemWidth / 2;
  8516. }
  8517. if ( options.my[1] === "bottom" ) {
  8518. position.top -= elemHeight;
  8519. } else if ( options.my[1] === center ) {
  8520. position.top -= elemHeight / 2;
  8521. }
  8522. // prevent fractions if jQuery version doesn't support them (see #5280)
  8523. if ( !support.fractions ) {
  8524. position.left = Math.round( position.left );
  8525. position.top = Math.round( position.top );
  8526. }
  8527. collisionPosition = {
  8528. left: position.left - marginLeft,
  8529. top: position.top - marginTop
  8530. };
  8531. $.each( [ "left", "top" ], function( i, dir ) {
  8532. if ( $.ui.position[ collision[i] ] ) {
  8533. $.ui.position[ collision[i] ][ dir ]( position, {
  8534. targetWidth: targetWidth,
  8535. targetHeight: targetHeight,
  8536. elemWidth: elemWidth,
  8537. elemHeight: elemHeight,
  8538. collisionPosition: collisionPosition,
  8539. collisionWidth: collisionWidth,
  8540. collisionHeight: collisionHeight,
  8541. offset: offset,
  8542. my: options.my,
  8543. at: options.at
  8544. });
  8545. }
  8546. });
  8547. if ( $.fn.bgiframe ) {
  8548. elem.bgiframe();
  8549. }
  8550. elem.offset( $.extend( position, { using: options.using } ) );
  8551. });
  8552. };
  8553. $.ui.position = {
  8554. fit: {
  8555. left: function( position, data ) {
  8556. var win = $( window ),
  8557. over = data.collisionPosition.left + data.collisionWidth - win.width() - win.scrollLeft();
  8558. position.left = over > 0 ? position.left - over : Math.max( position.left - data.collisionPosition.left, position.left );
  8559. },
  8560. top: function( position, data ) {
  8561. var win = $( window ),
  8562. over = data.collisionPosition.top + data.collisionHeight - win.height() - win.scrollTop();
  8563. position.top = over > 0 ? position.top - over : Math.max( position.top - data.collisionPosition.top, position.top );
  8564. }
  8565. },
  8566. flip: {
  8567. left: function( position, data ) {
  8568. if ( data.at[0] === center ) {
  8569. return;
  8570. }
  8571. var win = $( window ),
  8572. over = data.collisionPosition.left + data.collisionWidth - win.width() - win.scrollLeft(),
  8573. myOffset = data.my[ 0 ] === "left" ?
  8574. -data.elemWidth :
  8575. data.my[ 0 ] === "right" ?
  8576. data.elemWidth :
  8577. 0,
  8578. atOffset = data.at[ 0 ] === "left" ?
  8579. data.targetWidth :
  8580. -data.targetWidth,
  8581. offset = -2 * data.offset[ 0 ];
  8582. position.left += data.collisionPosition.left < 0 ?
  8583. myOffset + atOffset + offset :
  8584. over > 0 ?
  8585. myOffset + atOffset + offset :
  8586. 0;
  8587. },
  8588. top: function( position, data ) {
  8589. if ( data.at[1] === center ) {
  8590. return;
  8591. }
  8592. var win = $( window ),
  8593. over = data.collisionPosition.top + data.collisionHeight - win.height() - win.scrollTop(),
  8594. myOffset = data.my[ 1 ] === "top" ?
  8595. -data.elemHeight :
  8596. data.my[ 1 ] === "bottom" ?
  8597. data.elemHeight :
  8598. 0,
  8599. atOffset = data.at[ 1 ] === "top" ?
  8600. data.targetHeight :
  8601. -data.targetHeight,
  8602. offset = -2 * data.offset[ 1 ];
  8603. position.top += data.collisionPosition.top < 0 ?
  8604. myOffset + atOffset + offset :
  8605. over > 0 ?
  8606. myOffset + atOffset + offset :
  8607. 0;
  8608. }
  8609. }
  8610. };
  8611. // offset setter from jQuery 1.4
  8612. if ( !$.offset.setOffset ) {
  8613. $.offset.setOffset = function( elem, options ) {
  8614. // set position first, in-case top/left are set even on static elem
  8615. if ( /static/.test( $.curCSS( elem, "position" ) ) ) {
  8616. elem.style.position = "relative";
  8617. }
  8618. var curElem = $( elem ),
  8619. curOffset = curElem.offset(),
  8620. curTop = parseInt( $.curCSS( elem, "top", true ), 10 ) || 0,
  8621. curLeft = parseInt( $.curCSS( elem, "left", true ), 10) || 0,
  8622. props = {
  8623. top: (options.top - curOffset.top) + curTop,
  8624. left: (options.left - curOffset.left) + curLeft
  8625. };
  8626. if ( 'using' in options ) {
  8627. options.using.call( elem, props );
  8628. } else {
  8629. curElem.css( props );
  8630. }
  8631. };
  8632. $.fn.offset = function( options ) {
  8633. var elem = this[ 0 ];
  8634. if ( !elem || !elem.ownerDocument ) { return null; }
  8635. if ( options ) {
  8636. return this.each(function() {
  8637. $.offset.setOffset( this, options );
  8638. });
  8639. }
  8640. return _offset.call( this );
  8641. };
  8642. }
  8643. // fraction support test (older versions of jQuery don't support fractions)
  8644. (function () {
  8645. var body = document.getElementsByTagName( "body" )[ 0 ],
  8646. div = document.createElement( "div" ),
  8647. testElement, testElementParent, testElementStyle, offset, offsetTotal;
  8648. //Create a "fake body" for testing based on method used in jQuery.support
  8649. testElement = document.createElement( body ? "div" : "body" );
  8650. testElementStyle = {
  8651. visibility: "hidden",
  8652. width: 0,
  8653. height: 0,
  8654. border: 0,
  8655. margin: 0,
  8656. background: "none"
  8657. };
  8658. if ( body ) {
  8659. $.extend( testElementStyle, {
  8660. position: "absolute",
  8661. left: "-1000px",
  8662. top: "-1000px"
  8663. });
  8664. }
  8665. for ( var i in testElementStyle ) {
  8666. testElement.style[ i ] = testElementStyle[ i ];
  8667. }
  8668. testElement.appendChild( div );
  8669. testElementParent = body || document.documentElement;
  8670. testElementParent.insertBefore( testElement, testElementParent.firstChild );
  8671. div.style.cssText = "position: absolute; left: 10.7432222px; top: 10.432325px; height: 30px; width: 201px;";
  8672. offset = $( div ).offset( function( _, offset ) {
  8673. return offset;
  8674. }).offset();
  8675. testElement.innerHTML = "";
  8676. testElementParent.removeChild( testElement );
  8677. offsetTotal = offset.top + offset.left + ( body ? 2000 : 0 );
  8678. support.fractions = offsetTotal > 21 && offsetTotal < 22;
  8679. })();
  8680. }( jQuery ));
  8681. /*!
  8682. * Fluid Infusion v1.5
  8683. *
  8684. * Infusion is distributed under the Educational Community License 2.0 and new BSD licenses:
  8685. * http://wiki.fluidproject.org/display/fluid/Fluid+Licensing
  8686. *
  8687. * For information on copyright, see the individual Infusion source code files:
  8688. * https://github.com/fluid-project/infusion/
  8689. */
  8690. /*
  8691. Copyright 2007-2010 University of Cambridge
  8692. Copyright 2007-2009 University of Toronto
  8693. Copyright 2007-2009 University of California, Berkeley
  8694. Copyright 2010-2011 Lucendo Development Ltd.
  8695. Copyright 2010 OCAD University
  8696. Copyright 2011 Charly Molter
  8697. Licensed under the Educational Community License (ECL), Version 2.0 or the New
  8698. BSD license. You may not use this file except in compliance with one these
  8699. Licenses.
  8700. You may obtain a copy of the ECL 2.0 License and BSD License at
  8701. https://github.com/fluid-project/infusion/raw/master/Infusion-LICENSE.txt
  8702. */
  8703. // Declare dependencies
  8704. /*global console, window, fluid:true, fluid_1_5:true, jQuery, opera, YAHOO*/
  8705. // JSLint options
  8706. /*jslint white: true, trailing: true, funcinvoke: true, continue: true, jslintok: true, undef: true, newcap: true, nomen: true, regexp: true, bitwise: true, browser: true, forin: true, maxerr: 100, indent: 4 */
  8707. var fluid_1_5 = fluid_1_5 || {};
  8708. var fluid = fluid || fluid_1_5;
  8709. (function ($, fluid) {
  8710. fluid.version = "Infusion 1.5";
  8711. // Export this for use in environments like node.js, where it is useful for
  8712. // configuring stack trace behaviour
  8713. fluid.Error = Error;
  8714. fluid.environment = {
  8715. fluid: fluid
  8716. };
  8717. var globalObject = window || {};
  8718. fluid.singleThreadLocal = function (initFunc) {
  8719. var value = initFunc();
  8720. return function () {
  8721. return value;
  8722. };
  8723. };
  8724. // Return to the old strategy of monkey-patching this, since this is a most frequently used function within IoC
  8725. fluid.threadLocal = fluid.singleThreadLocal;
  8726. var softFailure = [false];
  8727. // This function will be patched from FluidIoC.js in order to describe complex activities
  8728. fluid.describeActivity = function () {
  8729. return [];
  8730. };
  8731. /**
  8732. * Causes an error message to be logged to the console and a real runtime error to be thrown.
  8733. *
  8734. * @param {String|Error} message the error message to log
  8735. * @param ... Additional arguments
  8736. */
  8737. fluid.fail = function (message /*, ... */) { // jslint:ok - whitespace in arg list
  8738. fluid.setLogging(true);
  8739. fluid.log.apply(null, ["ASSERTION FAILED: "].concat(fluid.makeArray(arguments)).concat(fluid.describeActivity()));
  8740. if (softFailure[0]) {
  8741. throw new Error(message);
  8742. } else {
  8743. message.fail(); // Intentionally cause a browser error by invoking a nonexistent function.
  8744. }
  8745. };
  8746. fluid.pushSoftFailure = function (condition) {
  8747. if (typeof (condition) === "boolean") {
  8748. softFailure.unshift(condition);
  8749. } else if (condition === -1) {
  8750. softFailure.shift();
  8751. }
  8752. };
  8753. fluid.notrycatch = false;
  8754. // A wrapper for the try/catch/finally language feature, to aid debugging on environments
  8755. // such as IE, where any try will destroy stack information for errors
  8756. fluid.tryCatch = function (tryfun, catchfun, finallyfun) {
  8757. finallyfun = finallyfun || fluid.identity;
  8758. if (fluid.notrycatch) {
  8759. var togo = tryfun();
  8760. finallyfun();
  8761. return togo;
  8762. } else {
  8763. try {
  8764. return tryfun();
  8765. } catch (e) {
  8766. if (catchfun) {
  8767. catchfun(e);
  8768. } else {
  8769. throw (e);
  8770. }
  8771. } finally {
  8772. finallyfun();
  8773. }
  8774. }
  8775. };
  8776. // TODO: rescued from kettleCouchDB.js - clean up in time
  8777. fluid.expect = function (name, members, target) {
  8778. fluid.transform(fluid.makeArray(members), function (key) {
  8779. if (typeof target[key] === "undefined") {
  8780. fluid.fail(name + " missing required parameter " + key);
  8781. }
  8782. });
  8783. };
  8784. // Logging
  8785. var logging;
  8786. /** Returns whether logging is enabled **/
  8787. fluid.isLogging = function () {
  8788. return logging;
  8789. };
  8790. /** method to allow user to enable logging (off by default) */
  8791. fluid.setLogging = function (enabled) {
  8792. if (typeof enabled === "boolean") {
  8793. logging = enabled;
  8794. } else {
  8795. logging = false;
  8796. }
  8797. };
  8798. // On some dodgy environments (notably IE9 and recent alphas of Firebug 1.8),
  8799. // console.log/debug are incomplete function objects and need to be operated via
  8800. // this trick: http://stackoverflow.com/questions/5472938/does-ie9-support-console-log-and-is-it-a-real-function
  8801. fluid.applyHostFunction = function (obj, func, args) {
  8802. if (func.apply) {
  8803. func.apply(obj, args);
  8804. } else {
  8805. var applier = Function.prototype.bind.call(func, obj);
  8806. applier.apply(obj, args);
  8807. }
  8808. };
  8809. /** Log a message to a suitable environmental console. If the standard "console"
  8810. * stream is available, the message will be sent there - otherwise either the
  8811. * YAHOO logger or the Opera "postError" stream will be used. Logging must first
  8812. * be enabled with a call to the fluid.setLogging(true) function.
  8813. */
  8814. fluid.log = function (message /*, ... */) { // jslint:ok - whitespace in arg list
  8815. if (logging) {
  8816. var arg0 = fluid.renderTimestamp(new Date()) + ": ";
  8817. var args = [arg0].concat(fluid.makeArray(arguments));
  8818. var str = args.join("");
  8819. if (typeof (console) !== "undefined") {
  8820. if (console.debug) {
  8821. fluid.applyHostFunction(console, console.debug, args);
  8822. } else if (typeof (console.log) === "function") {
  8823. fluid.applyHostFunction(console, console.log, args);
  8824. } else {
  8825. console.log(str); // this branch executes on old IE, fully synthetic console.log
  8826. }
  8827. } else if (typeof (YAHOO) !== "undefined") {
  8828. YAHOO.log(str);
  8829. } else if (typeof (opera) !== "undefined") {
  8830. opera.postError(str);
  8831. }
  8832. }
  8833. };
  8834. // Functional programming utilities.
  8835. /** A basic utility that returns its argument unchanged */
  8836. fluid.identity = function (arg) {
  8837. return arg;
  8838. };
  8839. // Framework and instantiation functions.
  8840. /** Returns true if the argument is a value other than null or undefined **/
  8841. fluid.isValue = function (value) {
  8842. return value !== undefined && value !== null;
  8843. };
  8844. /** Returns true if the argument is a primitive type **/
  8845. fluid.isPrimitive = function (value) {
  8846. var valueType = typeof (value);
  8847. return !value || valueType === "string" || valueType === "boolean" || valueType === "number" || valueType === "function";
  8848. };
  8849. /** Determines whether the supplied object is an array. The strategy used is an optimised
  8850. * approach taken from an earlier version of jQuery - detecting whether the toString() version
  8851. * of the object agrees with the textual form [object Array], or else whether the object is a
  8852. * jQuery object (the most common source of "fake arrays").
  8853. */
  8854. fluid.isArrayable = function (totest) {
  8855. return totest && (totest.jquery || Object.prototype.toString.call(totest) === "[object Array]");
  8856. };
  8857. fluid.isDOMNode = function (obj) {
  8858. // This could be more sound, but messy:
  8859. // http://stackoverflow.com/questions/384286/javascript-isdom-how-do-you-check-if-a-javascript-object-is-a-dom-object
  8860. return obj && typeof (obj.nodeType) === "number";
  8861. };
  8862. /** Return an empty container as the same type as the argument (either an
  8863. * array or hash */
  8864. fluid.freshContainer = function (tocopy) {
  8865. return fluid.isArrayable(tocopy) ? [] : {};
  8866. };
  8867. /** Performs a deep copy (clone) of its argument **/
  8868. fluid.copy = function (tocopy) {
  8869. if (fluid.isPrimitive(tocopy)) {
  8870. return tocopy;
  8871. }
  8872. return $.extend(true, fluid.freshContainer(tocopy), tocopy);
  8873. };
  8874. /** Corrected version of jQuery makeArray that returns an empty array on undefined rather than crashing.
  8875. * We don't deal with as many pathological cases as jQuery **/
  8876. fluid.makeArray = function (arg) {
  8877. var togo = [];
  8878. if (arg !== null && arg !== undefined) {
  8879. if (fluid.isPrimitive(arg) || typeof(arg.length) !== "number") {
  8880. togo.push(arg);
  8881. }
  8882. else {
  8883. for (var i = 0; i < arg.length; ++ i) {
  8884. togo[i] = arg[i];
  8885. }
  8886. }
  8887. }
  8888. return togo;
  8889. };
  8890. function transformInternal(source, togo, key, args) {
  8891. var transit = source[key];
  8892. for (var j = 0; j < args.length - 1; ++j) {
  8893. transit = args[j + 1](transit, key);
  8894. }
  8895. togo[key] = transit;
  8896. }
  8897. /** Return a list or hash of objects, transformed by one or more functions. Similar to
  8898. * jQuery.map, only will accept an arbitrary list of transformation functions and also
  8899. * works on non-arrays.
  8900. * @param source {Array or Object} The initial container of objects to be transformed.
  8901. * @param fn1, fn2, etc. {Function} An arbitrary number of optional further arguments,
  8902. * all of type Function, accepting the signature (object, index), where object is the
  8903. * list member to be transformed, and index is its list index. Each function will be
  8904. * applied in turn to each list member, which will be replaced by the return value
  8905. * from the function.
  8906. * @return The finally transformed list, where each member has been replaced by the
  8907. * original member acted on by the function or functions.
  8908. */
  8909. fluid.transform = function (source) {
  8910. var togo = fluid.freshContainer(source);
  8911. if (fluid.isArrayable(source)) {
  8912. for (var i = 0; i < source.length; ++i) {
  8913. transformInternal(source, togo, i, arguments);
  8914. }
  8915. } else {
  8916. for (var key in source) {
  8917. transformInternal(source, togo, key, arguments);
  8918. }
  8919. }
  8920. return togo;
  8921. };
  8922. /** Better jQuery.each which works on hashes as well as having the arguments
  8923. * the right way round.
  8924. * @param source {Arrayable or Object} The container to be iterated over
  8925. * @param func {Function} A function accepting (value, key) for each iterated
  8926. * object. This function may return a value to terminate the iteration
  8927. */
  8928. fluid.each = function (source, func) {
  8929. if (fluid.isArrayable(source)) {
  8930. for (var i = 0; i < source.length; ++i) {
  8931. func(source[i], i);
  8932. }
  8933. } else {
  8934. for (var key in source) {
  8935. func(source[key], key);
  8936. }
  8937. }
  8938. };
  8939. /** Scan through a list or hash of objects, terminating on the first member which
  8940. * matches a predicate function.
  8941. * @param source {Arrayable or Object} The list or hash of objects to be searched.
  8942. * @param func {Function} A predicate function, acting on a member. A predicate which
  8943. * returns any value which is not <code>undefined</code> will terminate
  8944. * the search. The function accepts (object, index).
  8945. * @param deflt {Object} A value to be returned in the case no predicate function matches
  8946. * a list member. The default will be the natural value of <code>undefined</code>
  8947. * @return The first return value from the predicate function which is not <code>undefined</code>
  8948. */
  8949. fluid.find = function (source, func, deflt) {
  8950. var disp;
  8951. if (fluid.isArrayable(source)) {
  8952. for (var i = 0; i < source.length; ++i) {
  8953. disp = func(source[i], i);
  8954. if (disp !== undefined) {
  8955. return disp;
  8956. }
  8957. }
  8958. } else {
  8959. for (var key in source) {
  8960. disp = func(source[key], key);
  8961. if (disp !== undefined) {
  8962. return disp;
  8963. }
  8964. }
  8965. }
  8966. return deflt;
  8967. };
  8968. /** Scan through a list of objects, "accumulating" a value over them
  8969. * (may be a straightforward "sum" or some other chained computation).
  8970. * @param list {Array} The list of objects to be accumulated over.
  8971. * @param fn {Function} An "accumulation function" accepting the signature (object, total, index) where
  8972. * object is the list member, total is the "running total" object (which is the return value from the previous function),
  8973. * and index is the index number.
  8974. * @param arg {Object} The initial value for the "running total" object.
  8975. * @return {Object} the final running total object as returned from the final invocation of the function on the last list member.
  8976. */
  8977. fluid.accumulate = function (list, fn, arg) {
  8978. for (var i = 0; i < list.length; ++i) {
  8979. arg = fn(list[i], arg, i);
  8980. }
  8981. return arg;
  8982. };
  8983. /** Can through a list of objects, removing those which match a predicate. Similar to
  8984. * jQuery.grep, only acts on the list in-place by removal, rather than by creating
  8985. * a new list by inclusion.
  8986. * @param source {Array|Object} The list of objects to be scanned over.
  8987. * @param fn {Function} A predicate function determining whether an element should be
  8988. * removed. This accepts the standard signature (object, index) and returns a "truthy"
  8989. * result in order to determine that the supplied object should be removed from the list.
  8990. * @return The list, transformed by the operation of removing the matched elements. The
  8991. * supplied list is modified by this operation.
  8992. */
  8993. fluid.remove_if = function (source, fn) {
  8994. if (fluid.isArrayable(source)) {
  8995. for (var i = 0; i < source.length; ++i) {
  8996. if (fn(source[i], i)) {
  8997. source.splice(i, 1);
  8998. --i;
  8999. }
  9000. }
  9001. } else {
  9002. for (var key in source) {
  9003. if (fn(source[key], key)) {
  9004. delete source[key];
  9005. }
  9006. }
  9007. }
  9008. return source;
  9009. };
  9010. /** Accepts an object to be filtered, and a list of keys. Either all keys not present in
  9011. * the list are removed, or only keys present in the list are returned.
  9012. * @param toFilter {Array|Object} The object to be filtered - this will be modified by the operation
  9013. * @param keys {Array of String} The list of keys to operate with
  9014. * @param exclude {boolean} If <code>true</code>, the keys listed are removed rather than included
  9015. * @return the filtered object (the same object that was supplied as <code>toFilter</code>
  9016. */
  9017. fluid.filterKeys = function (toFilter, keys, exclude) {
  9018. return fluid.remove_if($.extend({}, toFilter), function (value, key) {
  9019. return exclude ^ ($.inArray(key, keys) === -1);
  9020. });
  9021. };
  9022. /** A convenience wrapper for <code>fluid.filterKeys</code> with the parameter <code>exclude</code> set to <code>true</code>
  9023. * Returns the supplied object with listed keys removed */
  9024. fluid.censorKeys = function (toCensor, keys) {
  9025. return fluid.filterKeys(toCensor, keys, true);
  9026. };
  9027. fluid.makeFlatten = function (index) {
  9028. return function (obj) {
  9029. var togo = [];
  9030. fluid.each(obj, function (value, key) {
  9031. togo.push(arguments[index]);
  9032. });
  9033. return togo;
  9034. };
  9035. };
  9036. /** Return the keys in the supplied object as an array **/
  9037. fluid.keys = fluid.makeFlatten(1);
  9038. /** Return the values in the supplied object as an array **/
  9039. fluid.values = fluid.makeFlatten(0);
  9040. /**
  9041. * Searches through the supplied object, and returns <code>true</code> if the supplied value
  9042. * can be found
  9043. */
  9044. fluid.contains = function (obj, value) {
  9045. return obj ? fluid.find(obj, function (thisValue, key) {
  9046. if (value === thisValue) {
  9047. return true;
  9048. }
  9049. }) : undefined;
  9050. };
  9051. /**
  9052. * Searches through the supplied object for the first value which matches the one supplied.
  9053. * @param obj {Object} the Object to be searched through
  9054. * @param value {Object} the value to be found. This will be compared against the object's
  9055. * member using === equality.
  9056. * @return {String} The first key whose value matches the one supplied, or <code>null</code> if no
  9057. * such key is found.
  9058. */
  9059. fluid.keyForValue = function (obj, value) {
  9060. return fluid.find(obj, function (thisValue, key) {
  9061. if (value === thisValue) {
  9062. return key;
  9063. }
  9064. });
  9065. };
  9066. /**
  9067. * This method is now deprecated and will be removed in a future release of Infusion.
  9068. * See fluid.keyForValue instead.
  9069. */
  9070. fluid.findKeyInObject = fluid.keyForValue;
  9071. /** Converts an array into an object whose keys are the elements of the array, each with the value "true"
  9072. */
  9073. fluid.arrayToHash = function (array) {
  9074. var togo = {};
  9075. fluid.each(array, function (el) {
  9076. togo[el] = true;
  9077. });
  9078. return togo;
  9079. };
  9080. /**
  9081. * Clears an object or array of its contents. For objects, each property is deleted.
  9082. *
  9083. * @param {Object|Array} target the target to be cleared
  9084. */
  9085. fluid.clear = function (target) {
  9086. if (fluid.isArrayable(target)) {
  9087. target.length = 0;
  9088. } else {
  9089. for (var i in target) {
  9090. delete target[i];
  9091. }
  9092. }
  9093. };
  9094. /**
  9095. * @param boolean ascending <code>true</code> if a comparator is to be returned which
  9096. * sorts strings in descending order of length
  9097. */
  9098. fluid.compareStringLength = function (ascending) {
  9099. return ascending ? function (a, b) {
  9100. return a.length - b.length;
  9101. } : function (a, b) {
  9102. return b.length - a.length;
  9103. };
  9104. };
  9105. // Model functions
  9106. fluid.model = {}; // cannot call registerNamespace yet since it depends on fluid.model
  9107. /** Another special "marker object" representing that a distinguished
  9108. * (probably context-dependent) value should be substituted.
  9109. */
  9110. fluid.VALUE = {type: "fluid.marker", value: "VALUE"};
  9111. /** Another special "marker object" representing that no value is present (where
  9112. * signalling using the value "undefined" is not possible) */
  9113. fluid.NO_VALUE = {type: "fluid.marker", value: "NO_VALUE"};
  9114. /** A marker indicating that a value requires to be expanded after component construction begins **/
  9115. fluid.EXPAND = {type: "fluid.marker", value: "EXPAND"};
  9116. /** A marker indicating that a value requires to be expanded immediately**/
  9117. fluid.EXPAND_NOW = {type: "fluid.marker", value: "EXPAND_NOW"};
  9118. /** Determine whether an object is any marker, or a particular marker - omit the
  9119. * 2nd argument to detect any marker
  9120. */
  9121. fluid.isMarker = function (totest, type) {
  9122. if (!totest || typeof (totest) !== 'object' || totest.type !== "fluid.marker") {
  9123. return false;
  9124. }
  9125. if (!type) {
  9126. return true;
  9127. }
  9128. return totest === type;
  9129. };
  9130. /** Copy a source "model" onto a target **/
  9131. fluid.model.copyModel = function (target, source) {
  9132. fluid.clear(target);
  9133. $.extend(true, target, source);
  9134. };
  9135. /** Parse an EL expression separated by periods (.) into its component segments.
  9136. * @param {String} EL The EL expression to be split
  9137. * @return {Array of String} the component path expressions.
  9138. * TODO: This needs to be upgraded to handle (the same) escaping rules (as RSF), so that
  9139. * path segments containing periods and backslashes etc. can be processed, and be harmonised
  9140. * with the more complex implementations in fluid.pathUtil(data binding).
  9141. */
  9142. fluid.model.parseEL = function (EL) {
  9143. return EL === "" ? [] : String(EL).split('.');
  9144. };
  9145. /** Compose an EL expression from two separate EL expressions. The returned
  9146. * expression will be the one that will navigate the first expression, and then
  9147. * the second, from the value reached by the first. Either prefix or suffix may be
  9148. * the empty string **/
  9149. fluid.model.composePath = function (prefix, suffix) {
  9150. return prefix === "" ? suffix : (suffix === "" ? prefix : prefix + "." + suffix);
  9151. };
  9152. /** Compose any number of path segments, none of which may be empty **/
  9153. fluid.model.composeSegments = function () {
  9154. return fluid.makeArray(arguments).join(".");
  9155. };
  9156. /** Helpful alias for old-style API **/
  9157. fluid.path = fluid.model.composeSegments;
  9158. fluid.composePath = fluid.model.composePath;
  9159. // unsupported, NON-API function
  9160. fluid.requireDataBinding = function () {
  9161. fluid.fail("Please include DataBinding.js in order to operate complex model accessor configuration");
  9162. };
  9163. fluid.model.trundle = fluid.model.getPenultimate = fluid.requireDataBinding;
  9164. // unsupported, NON-API function
  9165. fluid.model.resolvePathSegment = function (root, segment, create, origEnv) {
  9166. if (!origEnv && root.resolvePathSegment) {
  9167. return root.resolvePathSegment(segment);
  9168. }
  9169. if (create && root[segment] === undefined) {
  9170. // This optimisation in this heavily used function has a fair effect
  9171. return root[segment] = {};
  9172. }
  9173. return root[segment];
  9174. };
  9175. // unsupported, NON-API function
  9176. fluid.model.getPenultimateSimple = function (root, EL, environment, create) {
  9177. var origEnv = environment;
  9178. var segs = fluid.model.parseEL(EL);
  9179. for (var i = 0; i < segs.length - 1; ++i) {
  9180. if (!root) {
  9181. return {root: root };
  9182. }
  9183. var segment = segs[i];
  9184. if (environment && environment[segment]) {
  9185. root = environment[segment];
  9186. environment = null;
  9187. } else {
  9188. root = fluid.model.resolvePathSegment(root, segment, create, origEnv);
  9189. }
  9190. }
  9191. return {root: root, last: segs[segs.length - 1]};
  9192. };
  9193. fluid.model.setSimple = function (root, EL, newValue, environment) {
  9194. var pen = fluid.model.getPenultimateSimple(root, EL, environment, true);
  9195. pen.root[pen.last] = newValue;
  9196. };
  9197. /** Evaluates an EL expression by fetching a dot-separated list of members
  9198. * recursively from a provided root.
  9199. * @param root The root data structure in which the EL expression is to be evaluated
  9200. * @param {string} EL The EL expression to be evaluated
  9201. * @param environment An optional "environment" which, if it contains any members
  9202. * at top level, will take priority over the root data structure.
  9203. * @return The fetched data value.
  9204. */
  9205. fluid.model.getSimple = function (root, EL, environment) {
  9206. if (EL === "" || EL === null || EL === undefined) {
  9207. return root;
  9208. }
  9209. var pen = fluid.model.getPenultimateSimple(root, EL, environment);
  9210. return pen.root ? pen.root[pen.last] : pen.root;
  9211. };
  9212. // unsupported, NON-API function
  9213. // Returns undefined to signal complex configuration which needs to be farmed out to DataBinding.js
  9214. // any other return represents an environment value AND a simple configuration we can handle here
  9215. fluid.decodeAccessorArg = function (arg3) {
  9216. return (!arg3 || arg3 === fluid.model.defaultGetConfig || arg3 === fluid.model.defaultSetConfig) ?
  9217. null : (arg3.type === "environment" ? arg3.value : undefined);
  9218. };
  9219. fluid.set = function (root, EL, newValue, config) {
  9220. var env = fluid.decodeAccessorArg(config);
  9221. if (env === undefined) {
  9222. var trundler = fluid.model.getPenultimate(root, EL, config);
  9223. trundler.root[trundler.last] = newValue;
  9224. } else {
  9225. fluid.model.setSimple(root, EL, newValue, env);
  9226. }
  9227. };
  9228. /** Evaluates an EL expression by fetching a dot-separated list of members
  9229. * recursively from a provided root.
  9230. * @param root The root data structure in which the EL expression is to be evaluated
  9231. * @param {string} EL The EL expression to be evaluated
  9232. * @param environment An optional "environment" which, if it contains any members
  9233. * at top level, will take priority over the root data structure.
  9234. * @return The fetched data value.
  9235. */
  9236. fluid.get = function (root, EL, config) {
  9237. var env = fluid.decodeAccessorArg(config);
  9238. return env === undefined ?
  9239. fluid.model.trundle(root, EL, config).root
  9240. : fluid.model.getSimple(root, EL, env);
  9241. };
  9242. // This backward compatibility will be maintained for a number of releases, probably until Fluid 2.0
  9243. fluid.model.setBeanValue = fluid.set;
  9244. fluid.model.getBeanValue = fluid.get;
  9245. fluid.getGlobalValue = function (path, env) {
  9246. if (path) {
  9247. env = env || fluid.environment;
  9248. return fluid.get(globalObject, path, {type: "environment", value: env});
  9249. }
  9250. };
  9251. /**
  9252. * Allows for the calling of a function from an EL expression "functionPath", with the arguments "args", scoped to an framework version "environment".
  9253. * @param {Object} functionPath - An EL expression
  9254. * @param {Object} args - An array of arguments to be applied to the function, specified in functionPath
  9255. * @param {Object} environment - (optional) The object to scope the functionPath to (typically the framework root for version control)
  9256. */
  9257. fluid.invokeGlobalFunction = function (functionPath, args, environment) {
  9258. var func = fluid.getGlobalValue(functionPath, environment);
  9259. if (!func) {
  9260. fluid.fail("Error invoking global function: " + functionPath + " could not be located");
  9261. } else {
  9262. return func.apply(null, args);
  9263. }
  9264. };
  9265. /** Registers a new global function at a given path (currently assumes that
  9266. * it lies within the fluid namespace)
  9267. */
  9268. fluid.registerGlobalFunction = function (functionPath, func, env) {
  9269. env = env || fluid.environment;
  9270. fluid.set(globalObject, functionPath, func, {type: "environment", value: env});
  9271. };
  9272. fluid.setGlobalValue = fluid.registerGlobalFunction;
  9273. /** Ensures that an entry in the global namespace exists **/
  9274. fluid.registerNamespace = function (naimspace, env) {
  9275. env = env || fluid.environment;
  9276. var existing = fluid.getGlobalValue(naimspace, env);
  9277. if (!existing) {
  9278. existing = {};
  9279. fluid.setGlobalValue(naimspace, existing, env);
  9280. }
  9281. return existing;
  9282. };
  9283. // stubs for two functions in FluidDebugging.js
  9284. fluid.dumpEl = fluid.identity;
  9285. fluid.renderTimestamp = fluid.identity;
  9286. /*** The Model Events system. ***/
  9287. fluid.registerNamespace("fluid.event");
  9288. fluid.generateUniquePrefix = function () {
  9289. return (Math.floor(Math.random() * 1e12)).toString(36) + "-";
  9290. };
  9291. var fluid_prefix = fluid.generateUniquePrefix();
  9292. var fluid_guid = 1;
  9293. /** Allocate an string value that will be very likely unique within this Fluid scope (frame or process) **/
  9294. fluid.allocateGuid = function () {
  9295. return fluid_prefix + (fluid_guid++);
  9296. };
  9297. fluid.event.identifyListener = function (listener) {
  9298. if (!listener.$$fluid_guid) {
  9299. listener.$$fluid_guid = fluid.allocateGuid();
  9300. }
  9301. return listener.$$fluid_guid;
  9302. };
  9303. // unsupported, NON-API function
  9304. fluid.event.mapPriority = function (priority, count) {
  9305. return (priority === null || priority === undefined ? -count :
  9306. (priority === "last" ? -Number.MAX_VALUE :
  9307. (priority === "first" ? Number.MAX_VALUE : priority)));
  9308. };
  9309. // unsupported, NON-API function
  9310. fluid.event.listenerComparator = function (recA, recB) {
  9311. return recB.priority - recA.priority;
  9312. };
  9313. // unsupported, NON-API function
  9314. fluid.event.sortListeners = function (listeners) {
  9315. var togo = [];
  9316. fluid.each(listeners, function (listener) {
  9317. togo.push(listener);
  9318. });
  9319. return togo.sort(fluid.event.listenerComparator);
  9320. };
  9321. // unsupported, NON-API function
  9322. fluid.event.resolveListener = function (listener) {
  9323. if (typeof (listener) === "string") {
  9324. var listenerFunc = fluid.getGlobalValue(listener);
  9325. if (!listenerFunc) {
  9326. fluid.fail("Unable to look up name " + listener + " as a global function");
  9327. } else {
  9328. listener = listenerFunc;
  9329. }
  9330. }
  9331. return listener;
  9332. };
  9333. fluid.event.nameEvent = function (that, eventName) {
  9334. return eventName + " of " + fluid.nameComponent(that);
  9335. };
  9336. /** Construct an "event firer" object which can be used to register and deregister
  9337. * listeners, to which "events" can be fired. These events consist of an arbitrary
  9338. * function signature. General documentation on the Fluid events system is at
  9339. * http://wiki.fluidproject.org/display/fluid/The+Fluid+Event+System .
  9340. * @param {Boolean} unicast If <code>true</code>, this is a "unicast" event which may only accept
  9341. * a single listener.
  9342. * @param {Boolean} preventable If <code>true</code> the return value of each handler will
  9343. * be checked for <code>false</code> in which case further listeners will be shortcircuited, and this
  9344. * will be the return value of fire()
  9345. */
  9346. // This name will be deprecated in Fluid 2.0 for fluid.makeEventFirer (or fluid.eventFirer)
  9347. fluid.event.getEventFirer = function (unicast, preventable, name) {
  9348. var listeners; // = {}
  9349. var byId; // = {}
  9350. var sortedListeners; // = []
  9351. function fireToListeners(listeners, args, wrapper) {
  9352. if (!listeners) { return; }
  9353. fluid.log("Firing event " + name + " to list of " + listeners.length + " listeners");
  9354. for (var i = 0; i < listeners.length; ++i) {
  9355. var lisrec = listeners[i];
  9356. lisrec.listener = fluid.event.resolveListener(lisrec.listener);
  9357. var listener = lisrec.listener;
  9358. if (lisrec.predicate && !lisrec.predicate(listener, args)) {
  9359. continue;
  9360. }
  9361. var value = fluid.tryCatch(function () {
  9362. var ret = (wrapper ? wrapper(listener) : listener).apply(null, args);
  9363. if (preventable && ret === false) {
  9364. return false;
  9365. }
  9366. if (unicast) {
  9367. return ret;
  9368. }
  9369. }, function (e) { // jslint:ok - function within a loop, only invoked synchronously
  9370. fluid.log("FireEvent received exception " + e.message + " e " + e + " firing to listener " + i);
  9371. throw (e);
  9372. }); // jslint:ok - function within loop
  9373. if (value !== undefined) {
  9374. return value;
  9375. }
  9376. }
  9377. }
  9378. var that;
  9379. var lazyInit = function () { // Lazy init function to economise on object references
  9380. listeners = {};
  9381. byId = {};
  9382. sortedListeners = [];
  9383. that.addListener = function (listener, namespace, predicate, priority) {
  9384. if (!listener) {
  9385. return;
  9386. }
  9387. if (unicast) {
  9388. namespace = "unicast";
  9389. }
  9390. var id = identify(listener);
  9391. namespace = namespace || id;
  9392. var record = {listener: listener, predicate: predicate,
  9393. namespace: namespace,
  9394. priority: fluid.event.mapPriority(priority, sortedListeners.length)};
  9395. listeners[namespace] = byId[id] = record;
  9396. sortedListeners = fluid.event.sortListeners(listeners);
  9397. };
  9398. that.addListener.apply(null, arguments);
  9399. };
  9400. var identify = fluid.event.identifyListener;
  9401. that = {
  9402. name: name,
  9403. typeName: "fluid.event.firer",
  9404. addListener: function () {
  9405. lazyInit.apply(null, arguments);
  9406. },
  9407. removeListener: function (listener) {
  9408. if (!listeners) { return; }
  9409. var namespace;
  9410. if (typeof (listener) === "string") {
  9411. namespace = listener;
  9412. var record = listeners[listener];
  9413. listener = record.listener;
  9414. }
  9415. var id = identify(listener);
  9416. if (!id) {
  9417. fluid.fail("Cannot remove unregistered listener function ", listener, " from event " + that.name);
  9418. }
  9419. namespace = namespace || byId[id].namespace || id;
  9420. delete byId[id];
  9421. delete listeners[namespace];
  9422. sortedListeners = fluid.event.sortListeners(listeners);
  9423. },
  9424. // NB - this method exists currently solely for the convenience of the new,
  9425. // transactional changeApplier. As it exists it is hard to imagine the function
  9426. // being helpful to any other client. We need to get more experience on the kinds
  9427. // of listeners that are useful, and ultimately factor this method away.
  9428. fireToListeners: function (listeners, args, wrapper) {
  9429. return fireToListeners(listeners, args, wrapper);
  9430. },
  9431. fire: function () {
  9432. return fireToListeners(sortedListeners, arguments);
  9433. }
  9434. };
  9435. return that;
  9436. };
  9437. fluid.makeEventFirer = fluid.event.getEventFirer;
  9438. /** Fire the specified event with supplied arguments. This call is an optimisation utility
  9439. * which handles the case where the firer has not been instantiated (presumably as a result
  9440. * of having no listeners registered
  9441. */
  9442. fluid.fireEvent = function (component, path, args) {
  9443. var firer = fluid.get(component, path);
  9444. if (firer) {
  9445. firer.fire.apply(null, fluid.makeArray(args));
  9446. }
  9447. };
  9448. // unsupported, NON-API function
  9449. fluid.event.addListenerToFirer = function (firer, value, namespace, wrapper) {
  9450. wrapper = wrapper || fluid.identity;
  9451. if (fluid.isArrayable(value)) {
  9452. for (var i = 0; i < value.length; ++i) {
  9453. fluid.event.addListenerToFirer(firer, value[i], namespace, wrapper);
  9454. }
  9455. } else if (typeof (value) === "function" || typeof (value) === "string") {
  9456. wrapper(firer).addListener(value, namespace);
  9457. } else if (value && typeof (value) === "object") {
  9458. wrapper(firer).addListener(value.listener, namespace || value.namespace, value.predicate, value.priority);
  9459. }
  9460. };
  9461. // unsupported, NON-API function - non-IOC passthrough
  9462. fluid.event.resolveListenerRecord = function (records) {
  9463. return { records: records };
  9464. };
  9465. // unsupported, NON-API function
  9466. fluid.mergeListeners = function (that, events, listeners) {
  9467. fluid.each(listeners, function (value, key) {
  9468. var firer, namespace;
  9469. if (key.charAt(0) === "{") {
  9470. if (!fluid.expandOptions) {
  9471. fluid.fail("fluid.expandOptions could not be loaded - please include FluidIoC.js in order to operate IoC-driven event with descriptor " +
  9472. key);
  9473. }
  9474. firer = fluid.expandOptions(key, that);
  9475. } else {
  9476. var keydot = key.indexOf(".");
  9477. if (keydot !== -1) {
  9478. namespace = key.substring(keydot + 1);
  9479. key = key.substring(0, keydot);
  9480. }
  9481. if (!events[key]) {
  9482. fluid.fail("Listener registered for event " + key + " which is not defined for this component");
  9483. events[key] = fluid.makeEventFirer(null, null, fluid.event.nameEvent(that, key));
  9484. }
  9485. firer = events[key];
  9486. }
  9487. record = fluid.event.resolveListenerRecord(value, that, key);
  9488. fluid.event.addListenerToFirer(firer, record.records, namespace, record.adderWrapper);
  9489. });
  9490. };
  9491. function initEvents(that, events, pass) {
  9492. fluid.each(events, function (eventSpec, eventKey) {
  9493. var isIoCEvent = eventSpec && (typeof (eventSpec) !== "string" || eventSpec.charAt(0) === "{");
  9494. var event;
  9495. if (isIoCEvent && pass === "IoC") {
  9496. if (!fluid.event.resolveEvent) {
  9497. fluid.fail("fluid.event.resolveEvent could not be loaded - please include FluidIoC.js in order to operate IoC-driven event with descriptor ",
  9498. eventSpec);
  9499. } else {
  9500. event = fluid.event.resolveEvent(that, eventKey, eventSpec);
  9501. }
  9502. } else if (pass === "flat") {
  9503. event = fluid.makeEventFirer(eventSpec === "unicast", eventSpec === "preventable", fluid.event.nameEvent(that, eventKey));
  9504. }
  9505. if (event) {
  9506. that.events[eventKey] = event;
  9507. }
  9508. });
  9509. }
  9510. // unsupported, NON-API function
  9511. fluid.instantiateFirers = function (that, options) {
  9512. that.events = {};
  9513. // TODO: manual 2-phase instantiation since we have no GINGER WORLD
  9514. initEvents(that, options.events, "flat");
  9515. initEvents(that, options.events, "IoC");
  9516. // TODO: manually expand these late so that members attached to ourselves with preInitFunction can be detected
  9517. //var listeners = fluid.expandOptions ? fluid.expandOptions(options.listeners, that) : options.listeners;
  9518. fluid.mergeListeners(that, that.events, options.listeners);
  9519. };
  9520. fluid.mergeListenerPolicy = function (target, source, key) {
  9521. // cf. triage in mergeListeners
  9522. var hasNamespace = key.charAt(0) !== "{" && key.indexOf(".") !== -1;
  9523. return hasNamespace ? (source ? source : target)
  9524. : fluid.makeArray(target).concat(fluid.makeArray(source));
  9525. };
  9526. fluid.mergeListenersPolicy = function (target, source) {
  9527. target = target || {};
  9528. fluid.each(source, function (listeners, key) {
  9529. target[key] = fluid.mergeListenerPolicy(target[key], listeners, key);
  9530. });
  9531. return target;
  9532. };
  9533. /*** DEFAULTS AND OPTIONS MERGING SYSTEM ***/
  9534. var defaultsStore = {};
  9535. var resolveGradesImpl = function (gs, gradeNames) {
  9536. gradeNames = fluid.makeArray(gradeNames);
  9537. fluid.each(gradeNames, function (gradeName) {
  9538. var options = fluid.rawDefaults(gradeName) || {};
  9539. gs.gradeHash[gradeName] = true;
  9540. gs.gradeChain.push(gradeName);
  9541. gs.optionsChain.push(options);
  9542. var oGradeNames = fluid.makeArray(options.gradeNames);
  9543. fluid.each(oGradeNames, function (parent) {
  9544. if (!gs.gradeHash[parent]) {
  9545. resolveGradesImpl(gs, parent);
  9546. }
  9547. });
  9548. });
  9549. return gs;
  9550. };
  9551. // unsupported, NON-API function
  9552. fluid.resolveGradeStructure = function (gradeNames) {
  9553. var gradeStruct = {
  9554. gradeChain: [],
  9555. gradeHash: {},
  9556. optionsChain: []
  9557. };
  9558. return resolveGradesImpl(gradeStruct, gradeNames);
  9559. };
  9560. var mergedDefaultsCache = {};
  9561. fluid.gradeNamesToKey = function (gradeNames, defaultName) {
  9562. return defaultName + "|" + fluid.makeArray(gradeNames).sort().join("|");
  9563. };
  9564. // unsupported, NON-API function
  9565. fluid.resolveGrade = function (defaults, defaultName, gradeNames) {
  9566. var mergeArgs = [defaults];
  9567. if (gradeNames) {
  9568. var gradeStruct = fluid.resolveGradeStructure(gradeNames);
  9569. mergeArgs = gradeStruct.optionsChain.reverse().concat(mergeArgs).concat({gradeNames: gradeStruct.gradeChain});
  9570. }
  9571. var mergePolicy = {};
  9572. for (var i = 0; i < mergeArgs.length; ++ i) {
  9573. mergePolicy = $.extend(true, mergePolicy, mergeArgs[i].mergePolicy);
  9574. }
  9575. mergeArgs = [mergePolicy, {}].concat(mergeArgs);
  9576. var mergedDefaults = fluid.merge.apply(null, mergeArgs);
  9577. return mergedDefaults;
  9578. };
  9579. fluid.getGradedDefaults = function (defaults, defaultName, gradeNames) {
  9580. var key = fluid.gradeNamesToKey(gradeNames, defaultName);
  9581. var mergedDefaults = mergedDefaultsCache[key];
  9582. if (!mergedDefaults) {
  9583. mergedDefaults = mergedDefaultsCache[key] = fluid.resolveGrade(defaults, defaultName, gradeNames);
  9584. }
  9585. return mergedDefaults;
  9586. };
  9587. // unsupported, NON-API function
  9588. fluid.resolveGradedOptions = function (componentName) {
  9589. var defaults = fluid.rawDefaults(componentName);
  9590. if (!defaults) {
  9591. return defaults;
  9592. } else {
  9593. return fluid.getGradedDefaults(defaults, componentName, defaults.gradeNames);
  9594. }
  9595. };
  9596. // unsupported, NON-API function
  9597. fluid.rawDefaults = function (componentName, options) {
  9598. if (options === undefined) {
  9599. return defaultsStore[componentName];
  9600. } else {
  9601. defaultsStore[componentName] = options;
  9602. }
  9603. };
  9604. fluid.hasGrade = function (options, gradeName) {
  9605. return !options || !options.gradeNames ? false : fluid.contains(options.gradeNames, gradeName);
  9606. };
  9607. /**
  9608. * Retrieves and stores a component's default settings centrally.
  9609. * @param {boolean} (options) if true, manipulate a global option (for the head
  9610. * component) rather than instance options. NB - the use of "global options"
  9611. * is deprecated and will be removed from the framework in release 1.6
  9612. * @param {String} componentName the name of the component
  9613. * @param {Object} (optional) an container of key/value pairs to set
  9614. */
  9615. fluid.defaults = function () {
  9616. var offset = 0;
  9617. if (typeof arguments[0] === "boolean") {
  9618. offset = 1;
  9619. }
  9620. var componentName = (offset === 0 ? "" : "*.global-") + arguments[offset];
  9621. var options = arguments[offset + 1];
  9622. if (options === undefined) {
  9623. return fluid.resolveGradedOptions(componentName);
  9624. } else {
  9625. if (options && options.options) {
  9626. fluid.fail("Probable error in options structure for " + componentName +
  9627. " with option named \"options\" - perhaps you meant to write these options at top level in fluid.defaults? - ", options);
  9628. }
  9629. fluid.rawDefaults(componentName, options);
  9630. if (fluid.hasGrade(options, "autoInit")) {
  9631. fluid.makeComponent(componentName, fluid.resolveGradedOptions(componentName));
  9632. }
  9633. }
  9634. };
  9635. fluid.makeComponent = function (componentName, options) {
  9636. if (!options.initFunction || !options.gradeNames) {
  9637. fluid.fail("Cannot autoInit component " + componentName + " which does not have an initFunction and gradeName defined");
  9638. }
  9639. var creator = function () {
  9640. return fluid.initComponent(componentName, arguments);
  9641. };
  9642. var existing = fluid.getGlobalValue(componentName);
  9643. if (existing) {
  9644. $.extend(creator, existing);
  9645. }
  9646. fluid.setGlobalValue(componentName, creator);
  9647. };
  9648. fluid.makeComponents = function (components, env) {
  9649. fluid.each(components, function (value, key) {
  9650. var options = {
  9651. gradeNames: fluid.makeArray(value).concat(["autoInit"])
  9652. };
  9653. fluid.defaults(key, options);
  9654. });
  9655. };
  9656. // The base system grade definitions
  9657. fluid.defaults("fluid.function", {});
  9658. fluid.lifecycleFunctions = {
  9659. preInitFunction: true,
  9660. postInitFunction: true,
  9661. finalInitFunction: true
  9662. };
  9663. fluid.rootMergePolicy = fluid.transform(fluid.lifecycleFunctions, function () {
  9664. return fluid.mergeListenerPolicy;
  9665. });
  9666. fluid.defaults("fluid.littleComponent", {
  9667. initFunction: "fluid.initLittleComponent",
  9668. mergePolicy: fluid.rootMergePolicy,
  9669. argumentMap: {
  9670. options: 0
  9671. }
  9672. });
  9673. fluid.defaults("fluid.eventedComponent", {
  9674. gradeNames: ["fluid.littleComponent"],
  9675. events: { // Four standard lifecycle points common to all components
  9676. onCreate: null,
  9677. onAttach: null, // events other than onCreate are only fired for IoC-configured components
  9678. onClear: null,
  9679. onDestroy: null
  9680. },
  9681. mergePolicy: {
  9682. listeners: fluid.mergeListenersPolicy
  9683. }
  9684. });
  9685. fluid.preInitModelComponent = function (that) {
  9686. that.model = that.options.model || {};
  9687. that.applier = that.options.applier || (fluid.makeChangeApplier ? fluid.makeChangeApplier(that.model, that.options.changeApplierOptions) : null);
  9688. };
  9689. fluid.defaults("fluid.modelComponent", {
  9690. gradeNames: ["fluid.littleComponent"],
  9691. preInitFunction: {
  9692. namespace: "preInitModelComponent",
  9693. listener: "fluid.preInitModelComponent"
  9694. },
  9695. mergePolicy: {
  9696. model: "preserve",
  9697. applier: "nomerge"
  9698. }
  9699. });
  9700. /** Generate a name for a component for debugging purposes */
  9701. fluid.nameComponent = function (that) {
  9702. return that ? "component with typename " + that.typeName + " and id " + that.id : "[unknown component]";
  9703. };
  9704. // unsupported, NON-API function
  9705. fluid.guardCircularity = function (seenIds, source, message1, message2) {
  9706. if (source && source.id) {
  9707. if (!seenIds[source.id]) {
  9708. seenIds[source.id] = source;
  9709. } else if (seenIds[source.id] === source) {
  9710. fluid.fail("Circularity in options " + message1 + " - " + fluid.nameComponent(source)
  9711. + " has already been seen" + message2);
  9712. }
  9713. }
  9714. };
  9715. // TODO: so far, profiling does not suggest that this implementation is a performance risk, but we really should start
  9716. // "precompiling" these.
  9717. // unsupported, NON-API function
  9718. fluid.mergePolicyIs = function (policy, test) {
  9719. return typeof (policy) === "string" && $.inArray(test, policy.split(/\s*,\s*/)) !== -1;
  9720. };
  9721. // Cheapskate implementation which avoids dependency on DataBinding.js
  9722. fluid.model.mergeModel = function (target, source, applier) {
  9723. if (!fluid.isPrimitive(target)) {
  9724. var copySource = fluid.copy(source);
  9725. $.extend(true, source, target);
  9726. $.extend(true, source, copySource);
  9727. }
  9728. return source;
  9729. };
  9730. function mergeImpl(policy, basePath, target, source, thisPolicy, rec) {
  9731. if (fluid.isTracing) {
  9732. fluid.tracing.pathCount.push(basePath);
  9733. }
  9734. if (fluid.mergePolicyIs(thisPolicy, "replace")) {
  9735. fluid.clear(target);
  9736. }
  9737. fluid.guardCircularity(rec.seenIds, source, "merging", " when evaluating path " + basePath + " - please protect components from merging using the \"nomerge\" merge policy");
  9738. for (var name in source) {
  9739. var path = (basePath ? basePath + "." : "") + name;
  9740. var newPolicy = policy && typeof (policy) !== "string" ? policy[path] : policy;
  9741. var funcPolicy = typeof (newPolicy) === "function";
  9742. var thisTarget = target[name];
  9743. var thisSource = source[name];
  9744. var primitiveTarget = fluid.isPrimitive(thisTarget);
  9745. if (thisSource !== undefined) {
  9746. if (!funcPolicy && thisSource !== null && typeof (thisSource) === "object" &&
  9747. !fluid.isDOMNode(thisSource) && !thisSource.jquery && thisSource !== fluid.VALUE &&
  9748. !fluid.mergePolicyIs(newPolicy, "preserve") && !fluid.mergePolicyIs(newPolicy, "nomerge")) {
  9749. if (primitiveTarget) {
  9750. target[name] = thisTarget = fluid.freshContainer(thisSource);
  9751. }
  9752. mergeImpl(policy, path, thisTarget, thisSource, newPolicy, rec);
  9753. } else {
  9754. if (funcPolicy) {
  9755. target[name] = newPolicy.call(null, thisTarget, thisSource, name);
  9756. } else if (!fluid.isValue(thisTarget) || !fluid.mergePolicyIs(newPolicy, "reverse")) {
  9757. // TODO: When "grades" are implemented, grandfather in any paired applier to perform these operations
  9758. // NB: mergePolicy of "preserve" now creates dependency on DataBinding.js
  9759. target[name] = fluid.isValue(thisTarget) && fluid.mergePolicyIs(newPolicy, "preserve") ? fluid.model.mergeModel(thisTarget, thisSource) : thisSource;
  9760. }
  9761. }
  9762. }
  9763. }
  9764. return target;
  9765. }
  9766. // TODO: deprecate this method of detecting default value merge policies before 1.6 in favour of
  9767. // explicit typed records a la ModelTransformations
  9768. // unsupported, NON-API function
  9769. fluid.isDefaultValueMergePolicy = function (policy) {
  9770. return typeof(policy) === "string"
  9771. && (policy.indexOf(",") === -1 && !/replace|preserve|nomerge|noexpand|reverse/.test(policy));
  9772. };
  9773. // unsupported, NON-API function
  9774. fluid.applyDefaultValueMergePolicy = function (defaults, merged) {
  9775. var policy = merged.mergePolicy;
  9776. if (policy && typeof (policy) !== "string") {
  9777. for (var key in policy) {
  9778. var elrh = policy[key];
  9779. if (fluid.isDefaultValueMergePolicy(elrh)) {
  9780. var defaultTarget = fluid.get(defaults, key);
  9781. var mergedTarget = fluid.get(merged, key);
  9782. // TODO: this implementation is faulty since it will trigger if a user modifies a source value to its default value
  9783. // - and also will still copy over a target if user modifies it to its default value
  9784. // probably needs FLUID-4392 for a proper fix since the algorithm will need a fundamental change to progress from
  9785. // R2L rather than L2R (is that even possible!)
  9786. if (defaultTarget === mergedTarget) {
  9787. var defaultSource = fluid.get(defaults, elrh);
  9788. var mergedSource = fluid.get(merged, elrh);
  9789. // NB: This line represents a change in policy - will not apply default value policy to defaults themselves
  9790. if (defaultSource !== mergedSource) {
  9791. fluid.set(merged, key, mergedSource);
  9792. }
  9793. }
  9794. }
  9795. }
  9796. }
  9797. return merged;
  9798. };
  9799. /** Merge a collection of options structures onto a target, following an optional policy.
  9800. * This function is typically called automatically, as a result of an invocation of
  9801. * <code>fluid.initLittleComponent</code>. The behaviour of this function is explained more fully on
  9802. * the page http://wiki.fluidproject.org/display/fluid/Options+Merging+for+Fluid+Components .
  9803. * @param policy {Object/String} A "policy object" specifiying the type of merge to be performed.
  9804. * If policy is of type {String} it should take on the value "reverse" or "replace" representing
  9805. * a static policy. If it is an
  9806. * Object, it should contain a mapping of EL paths onto these String values, representing a
  9807. * fine-grained policy. If it is an Object, the values may also themselves be EL paths
  9808. * representing that a default value is to be taken from that path.
  9809. * @param target {Object} The options structure which is to be modified by receiving the merge results.
  9810. * @param options1, options2, .... {Object} an arbitrary list of options structure which are to
  9811. * be merged "on top of" the <code>target</code>. These will not be modified.
  9812. */
  9813. fluid.merge = function (policy, target) {
  9814. var path = "";
  9815. for (var i = 2; i < arguments.length; ++i) {
  9816. var source = arguments[i];
  9817. if (source !== null && source !== undefined) {
  9818. mergeImpl(policy, path, target, source, policy ? policy[""] : null, {seenIds: {}});
  9819. }
  9820. }
  9821. return target;
  9822. };
  9823. // unsupported, NON-API function
  9824. fluid.transformOptions = function (mergeArgs, transRec) {
  9825. fluid.expect("Options transformation record", ["transformer", "config"], transRec);
  9826. var transFunc = fluid.getGlobalValue(transRec.transformer);
  9827. var togo = fluid.transform(mergeArgs, function (value, key) {
  9828. return key === 0 ? value : transFunc.call(null, value, transRec.config);
  9829. });
  9830. return togo;
  9831. };
  9832. // unsupporter, NON-API function
  9833. fluid.lastTransformationRecord = function (extraArgs) {
  9834. for (var i = extraArgs.length - 1; i >= 0; --i) {
  9835. if (extraArgs[i] && extraArgs[i].transformOptions) {
  9836. return extraArgs[i].transformOptions;
  9837. }
  9838. }
  9839. };
  9840. /**
  9841. * Merges the component's declared defaults, as obtained from fluid.defaults(),
  9842. * with the user's specified overrides.
  9843. *
  9844. * @param {Object} that the instance to attach the options to
  9845. * @param {String} componentName the unique "name" of the component, which will be used
  9846. * to fetch the default options from store. By recommendation, this should be the global
  9847. * name of the component's creator function.
  9848. * @param {Object} userOptions the user-specified configuration options for this component
  9849. */
  9850. // unsupported, NON-API function
  9851. fluid.mergeComponentOptions = function (that, componentName, userOptions, localOptions) {
  9852. var defaults = fluid.defaults(componentName) || {};
  9853. var mergePolicy = $.extend({}, fluid.rootMergePolicy, defaults.mergePolicy);
  9854. var defaultGrades = defaults.gradeNames;
  9855. localOptions = defaultGrades ? {} : fluid.copy(fluid.getGradedDefaults({}, "", localOptions.gradeNames));
  9856. var mergeArgs = [mergePolicy, localOptions];
  9857. var extraArgs;
  9858. if (fluid.expandComponentOptions) {
  9859. extraArgs = fluid.expandComponentOptions(defaults, userOptions, that);
  9860. } else {
  9861. extraArgs = [defaults, userOptions];
  9862. }
  9863. var transRec = fluid.lastTransformationRecord(extraArgs);
  9864. if (transRec) {
  9865. extraArgs = fluid.transformOptions(extraArgs, transRec);
  9866. }
  9867. mergeArgs = mergeArgs.concat(extraArgs);
  9868. var merged = fluid.merge.apply(null, mergeArgs);
  9869. merged = fluid.applyDefaultValueMergePolicy(defaults, merged);
  9870. that.options = merged;
  9871. };
  9872. // The Fluid Component System proper
  9873. /** A special "marker object" which is recognised as one of the arguments to
  9874. * fluid.initSubcomponents. This object is recognised by reference equality -
  9875. * where it is found, it is replaced in the actual argument position supplied
  9876. * to the specific subcomponent instance, with the particular options block
  9877. * for that instance attached to the overall "that" object.
  9878. * NOTE: The use of this marker has been deprecated as of the Fluid 1.4 release in
  9879. * favour of the contextual EL path "{options}" - it will be removed in a future
  9880. * release of the framework.
  9881. */
  9882. fluid.COMPONENT_OPTIONS = {type: "fluid.marker", value: "COMPONENT_OPTIONS"};
  9883. /** Construct a dummy or "placeholder" subcomponent, that optionally provides empty
  9884. * implementations for a set of methods.
  9885. */
  9886. fluid.emptySubcomponent = function (options) {
  9887. var that = {};
  9888. options = $.makeArray(options);
  9889. for (var i = 0; i < options.length; ++i) {
  9890. that[options[i]] = fluid.identity;
  9891. }
  9892. return that;
  9893. };
  9894. /** Compute a "nickname" given a fully qualified typename, by returning the last path
  9895. * segment.
  9896. */
  9897. fluid.computeNickName = function (typeName) {
  9898. var segs = fluid.model.parseEL(typeName);
  9899. return segs[segs.length - 1];
  9900. };
  9901. /** Create a "type tag" component with no state but simply a type name and id. The most
  9902. * minimal form of Fluid component */
  9903. fluid.typeTag = function (name) {
  9904. return name ? {
  9905. typeName: name,
  9906. id: fluid.allocateGuid()
  9907. } : null;
  9908. };
  9909. /** A combined "component and grade name" which allows type tags to be declaratively constructed
  9910. * from options material */
  9911. fluid.typeFount = function (options) {
  9912. var that = fluid.initLittleComponent("fluid.typeFount", options);
  9913. return fluid.typeTag(that.options.targetTypeName);
  9914. };
  9915. /**
  9916. * Creates a new "little component": a that-ist object with options merged into it by the framework.
  9917. * This method is a convenience for creating small objects that have options but don't require full
  9918. * View-like features such as the DOM Binder or events
  9919. *
  9920. * @param {Object} name the name of the little component to create
  9921. * @param {Object} options user-supplied options to merge with the defaults
  9922. */
  9923. // NOTE: the 3rd argument localOptions is NOT to be advertised as part of the stable API, it is present
  9924. // just to allow backward compatibility whilst grade specifications are not mandatory
  9925. fluid.initLittleComponent = function (name, options, localOptions) {
  9926. var that = fluid.typeTag(name);
  9927. // TODO: nickName must be available earlier than other merged options so that component may resolve to itself
  9928. that.nickName = options && options.nickName ? options.nickName : fluid.computeNickName(that.typeName);
  9929. localOptions = localOptions || {gradeNames: "fluid.littleComponent"};
  9930. fluid.mergeComponentOptions(that, name, options, localOptions);
  9931. fluid.initLifecycleFunctions(that);
  9932. fluid.fireEvent(that.options, "preInitFunction", that);
  9933. if (fluid.hasGrade(that.options, "fluid.eventedComponent")) {
  9934. fluid.instantiateFirers(that, that.options);
  9935. }
  9936. if (!fluid.hasGrade(that.options, "autoInit")) {
  9937. fluid.clearLifecycleFunctions(that.options);
  9938. }
  9939. return that;
  9940. };
  9941. // unsupported, NON-API function
  9942. fluid.initLifecycleFunctions = function (that) {
  9943. fluid.each(fluid.lifecycleFunctions, function (func, key) {
  9944. var value = that.options[key];
  9945. if (value) {
  9946. that.options[key] = fluid.makeEventFirer(null, null, key);
  9947. fluid.event.addListenerToFirer(that.options[key], value);
  9948. }
  9949. });
  9950. };
  9951. // unsupported, NON-API function
  9952. fluid.clearLifecycleFunctions = function (options) {
  9953. fluid.each(fluid.lifecycleFunctions, function (value, key) {
  9954. delete options[key];
  9955. });
  9956. delete options.initFunction;
  9957. };
  9958. fluid.diagnoseFailedView = fluid.identity;
  9959. fluid.makeRootDestroy = function (that) {
  9960. return function () {
  9961. fluid.fireEvent(that, "events.onClear", [that, "", null]);
  9962. fluid.fireEvent(that, "events.onDestroy", [that, "", null]);
  9963. };
  9964. };
  9965. fluid.initComponent = function (componentName, initArgs) {
  9966. var options = fluid.defaults(componentName);
  9967. if (!options.gradeNames) {
  9968. fluid.fail("Cannot initialise component " + componentName + " which has no gradeName registered");
  9969. }
  9970. var args = [componentName].concat(fluid.makeArray(initArgs)); // TODO: support different initFunction variants
  9971. var that = fluid.invokeGlobalFunction(options.initFunction, args);
  9972. fluid.diagnoseFailedView(componentName, that, options, args);
  9973. fluid.fireEvent(that.options, "postInitFunction", that);
  9974. if (fluid.initDependents) {
  9975. fluid.initDependents(that);
  9976. }
  9977. fluid.fireEvent(that.options, "finalInitFunction", that);
  9978. fluid.clearLifecycleFunctions(that.options);
  9979. that.destroy = fluid.makeRootDestroy(that); // overwritten by FluidIoC for constructed subcomponents
  9980. fluid.fireEvent(that, "events.onCreate", that);
  9981. return that.options.returnedPath ? fluid.get(that, that.options.returnedPath) : that;
  9982. };
  9983. // unsupported, NON-API function
  9984. fluid.initSubcomponentImpl = function (that, entry, args) {
  9985. var togo;
  9986. if (typeof (entry) !== "function") {
  9987. var entryType = typeof (entry) === "string" ? entry : entry.type;
  9988. var globDef = fluid.defaults(true, entryType);
  9989. fluid.merge("reverse", that.options, globDef);
  9990. togo = entryType === "fluid.emptySubcomponent" ?
  9991. fluid.emptySubcomponent(entry.options) :
  9992. fluid.invokeGlobalFunction(entryType, args);
  9993. } else {
  9994. togo = entry.apply(null, args);
  9995. }
  9996. // TODO: deprecate "returnedOptions" and incorporate into regular ginger world system
  9997. var returnedOptions = togo ? togo.returnedOptions : null;
  9998. if (returnedOptions) {
  9999. fluid.merge(that.options.mergePolicy, that.options, returnedOptions);
  10000. if (returnedOptions.listeners) {
  10001. fluid.mergeListeners(that, that.events, returnedOptions.listeners);
  10002. }
  10003. }
  10004. return togo;
  10005. };
  10006. /** Initialise all the "subcomponents" which are configured to be attached to
  10007. * the supplied top-level component, which share a particular "class name".
  10008. * @param {Component} that The top-level component for which sub-components are
  10009. * to be instantiated. It contains specifications for these subcomponents in its
  10010. * <code>options</code> structure.
  10011. * @param {String} className The "class name" or "category" for the subcomponents to
  10012. * be instantiated. A class name specifies an overall "function" for a class of
  10013. * subcomponents and represents a category which accept the same signature of
  10014. * instantiation arguments.
  10015. * @param {Array of Object} args The instantiation arguments to be passed to each
  10016. * constructed subcomponent. These will typically be members derived from the
  10017. * top-level <code>that</code> or perhaps globally discovered from elsewhere. One
  10018. * of these arguments may be <code>fluid.COMPONENT_OPTIONS</code> in which case this
  10019. * placeholder argument will be replaced by instance-specific options configured
  10020. * into the member of the top-level <code>options</code> structure named for the
  10021. * <code>className</code>
  10022. * @return {Array of Object} The instantiated subcomponents, one for each member
  10023. * of <code>that.options[className]</code>.
  10024. */
  10025. fluid.initSubcomponents = function (that, className, args) {
  10026. var entry = that.options[className];
  10027. if (!entry) {
  10028. return;
  10029. }
  10030. var entries = $.makeArray(entry);
  10031. var optindex = -1;
  10032. var togo = [];
  10033. args = $.makeArray(args);
  10034. for (var i = 0; i < args.length; ++i) {
  10035. if (args[i] === fluid.COMPONENT_OPTIONS) {
  10036. optindex = i;
  10037. }
  10038. }
  10039. for (i = 0; i < entries.length; ++i) {
  10040. entry = entries[i];
  10041. if (optindex !== -1) {
  10042. args[optindex] = entry.options;
  10043. }
  10044. togo[i] = fluid.initSubcomponentImpl(that, entry, args);
  10045. }
  10046. return togo;
  10047. };
  10048. fluid.initSubcomponent = function (that, className, args) {
  10049. return fluid.initSubcomponents(that, className, args)[0];
  10050. };
  10051. // Message resolution and templating
  10052. /**
  10053. * Converts a string to a regexp with the specified flags given in parameters
  10054. * @param {String} a string that has to be turned into a regular expression
  10055. * @param {String} the flags to provide to the reg exp
  10056. */
  10057. fluid.stringToRegExp = function (str, flags) {
  10058. return new RegExp(str.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&"), flags);
  10059. };
  10060. /**
  10061. * Simple string template system.
  10062. * Takes a template string containing tokens in the form of "%value".
  10063. * Returns a new string with the tokens replaced by the specified values.
  10064. * Keys and values can be of any data type that can be coerced into a string. Arrays will work here as well.
  10065. *
  10066. * @param {String} template a string (can be HTML) that contains tokens embedded into it
  10067. * @param {object} values a collection of token keys and values
  10068. */
  10069. fluid.stringTemplate = function (template, values) {
  10070. var keys = fluid.keys(values);
  10071. keys = keys.sort(fluid.compareStringLength());
  10072. for (var i = 0; i < keys.length; ++i) {
  10073. var key = keys[i];
  10074. var re = fluid.stringToRegExp("%" + key, "g");
  10075. template = template.replace(re, values[key]);
  10076. }
  10077. return template;
  10078. };
  10079. fluid.messageResolver = function (options) {
  10080. var that = fluid.initLittleComponent("fluid.messageResolver", options);
  10081. that.messageBase = that.options.parseFunc(that.options.messageBase);
  10082. that.lookup = function (messagecodes) {
  10083. var resolved = fluid.messageResolver.resolveOne(that.messageBase, messagecodes);
  10084. if (resolved === undefined) {
  10085. return fluid.find(that.options.parents, function (parent) {
  10086. return parent.lookup(messagecodes);
  10087. });
  10088. } else {
  10089. return {template: resolved, resolveFunc: that.options.resolveFunc};
  10090. }
  10091. };
  10092. that.resolve = function (messagecodes, args) {
  10093. if (!messagecodes) {
  10094. return "[No messagecodes provided]";
  10095. }
  10096. messagecodes = fluid.makeArray(messagecodes);
  10097. var looked = that.lookup(messagecodes);
  10098. return looked ? looked.resolveFunc(looked.template, args) :
  10099. "[Message string for key " + messagecodes[0] + " not found]";
  10100. };
  10101. return that;
  10102. };
  10103. fluid.defaults("fluid.messageResolver", {
  10104. mergePolicy: {
  10105. messageBase: "preserve",
  10106. parents: "nomerge"
  10107. },
  10108. resolveFunc: fluid.stringTemplate,
  10109. parseFunc: fluid.identity,
  10110. messageBase: {},
  10111. parents: []
  10112. });
  10113. fluid.messageResolver.resolveOne = function (messageBase, messagecodes) {
  10114. for (var i = 0; i < messagecodes.length; ++i) {
  10115. var code = messagecodes[i];
  10116. var message = messageBase[code];
  10117. if (message !== undefined) {
  10118. return message;
  10119. }
  10120. }
  10121. };
  10122. /** Converts a data structure consisting of a mapping of keys to message strings,
  10123. * into a "messageLocator" function which maps an array of message codes, to be
  10124. * tried in sequence until a key is found, and an array of substitution arguments,
  10125. * into a substituted message string.
  10126. */
  10127. fluid.messageLocator = function (messageBase, resolveFunc) {
  10128. var resolver = fluid.messageResolver({messageBase: messageBase, resolveFunc: resolveFunc});
  10129. return function (messagecodes, args) {
  10130. return resolver.resolve(messagecodes, args);
  10131. };
  10132. };
  10133. })(jQuery, fluid_1_5);
  10134. /*
  10135. Copyright 2007-2010 University of Cambridge
  10136. Copyright 2007-2009 University of Toronto
  10137. Copyright 2010-2011 Lucendo Development Ltd.
  10138. Copyright 2010 OCAD University
  10139. Licensed under the Educational Community License (ECL), Version 2.0 or the New
  10140. BSD license. You may not use this file except in compliance with one these
  10141. Licenses.
  10142. You may obtain a copy of the ECL 2.0 License and BSD License at
  10143. https://github.com/fluid-project/infusion/raw/master/Infusion-LICENSE.txt
  10144. */
  10145. /** This file contains functions which depend on the presence of a DOM document
  10146. * but which do not depend on the contents of Fluid.js **/
  10147. // Declare dependencies
  10148. /*global fluid_1_5:true, jQuery*/
  10149. // JSLint options
  10150. /*jslint white: true, funcinvoke: true, undef: true, newcap: true, nomen: true, regexp: true, bitwise: true, browser: true, forin: true, maxerr: 100, indent: 4 */
  10151. var fluid_1_5 = fluid_1_5 || {};
  10152. (function ($, fluid) {
  10153. // Private constants.
  10154. var NAMESPACE_KEY = "fluid-scoped-data";
  10155. /**
  10156. * Gets stored state from the jQuery instance's data map.
  10157. * This function is unsupported: It is not really intended for use by implementors.
  10158. */
  10159. fluid.getScopedData = function(target, key) {
  10160. var data = $(target).data(NAMESPACE_KEY);
  10161. return data ? data[key] : undefined;
  10162. };
  10163. /**
  10164. * Stores state in the jQuery instance's data map. Unlike jQuery's version,
  10165. * accepts multiple-element jQueries.
  10166. * This function is unsupported: It is not really intended for use by implementors.
  10167. */
  10168. fluid.setScopedData = function(target, key, value) {
  10169. $(target).each(function() {
  10170. var data = $.data(this, NAMESPACE_KEY) || {};
  10171. data[key] = value;
  10172. $.data(this, NAMESPACE_KEY, data);
  10173. });
  10174. };
  10175. /** Global focus manager - makes use of "focusin" event supported in jquery 1.4.2 or later.
  10176. */
  10177. var lastFocusedElement = null;
  10178. $(document).bind("focusin", function(event){
  10179. lastFocusedElement = event.target;
  10180. });
  10181. fluid.getLastFocusedElement = function() {
  10182. return lastFocusedElement;
  10183. }
  10184. var ENABLEMENT_KEY = "enablement";
  10185. /** Queries or sets the enabled status of a control. An activatable node
  10186. * may be "disabled" in which case its keyboard bindings will be inoperable
  10187. * (but still stored) until it is reenabled again.
  10188. * This function is unsupported: It is not really intended for use by implementors.
  10189. */
  10190. fluid.enabled = function(target, state) {
  10191. target = $(target);
  10192. if (state === undefined) {
  10193. return fluid.getScopedData(target, ENABLEMENT_KEY) !== false;
  10194. }
  10195. else {
  10196. $("*", target).add(target).each(function() {
  10197. if (fluid.getScopedData(this, ENABLEMENT_KEY) !== undefined) {
  10198. fluid.setScopedData(this, ENABLEMENT_KEY, state);
  10199. }
  10200. else if (/select|textarea|input/i.test(this.nodeName)) {
  10201. $(this).prop("disabled", !state);
  10202. }
  10203. });
  10204. fluid.setScopedData(target, ENABLEMENT_KEY, state);
  10205. }
  10206. };
  10207. fluid.initEnablement = function(target) {
  10208. fluid.setScopedData(target, ENABLEMENT_KEY, true);
  10209. };
  10210. // This function is necessary since simulation of focus events by jQuery under IE
  10211. // is not sufficiently good to intercept the "focusin" binding. Any code which triggers
  10212. // focus or blur synthetically throughout the framework and client code must use this function,
  10213. // especially if correct cross-platform interaction is required with the "deadMansBlur" function.
  10214. function applyOp(node, func) {
  10215. node = $(node);
  10216. node.trigger("fluid-"+func);
  10217. node[func]();
  10218. }
  10219. $.each(["focus", "blur"], function(i, name) {
  10220. fluid[name] = function(elem) {
  10221. applyOp(elem, name);
  10222. }
  10223. });
  10224. })(jQuery, fluid_1_5);
  10225. /*
  10226. Copyright 2008-2010 University of Cambridge
  10227. Copyright 2008-2009 University of Toronto
  10228. Licensed under the Educational Community License (ECL), Version 2.0 or the New
  10229. BSD license. You may not use this file except in compliance with one these
  10230. Licenses.
  10231. You may obtain a copy of the ECL 2.0 License and BSD License at
  10232. https://github.com/fluid-project/infusion/raw/master/Infusion-LICENSE.txt
  10233. */
  10234. // Declare dependencies
  10235. /*global fluid_1_5:true, jQuery */
  10236. // JSLint options
  10237. /*jslint white: true, funcinvoke: true, undef: true, newcap: true, nomen: true, regexp: true, bitwise: true, browser: true, forin: true, maxerr: 100, indent: 4 */
  10238. var fluid_1_5 = fluid_1_5 || {};
  10239. (function ($, fluid) {
  10240. fluid.dom = fluid.dom || {};
  10241. // Node walker function for iterateDom.
  10242. var getNextNode = function (iterator) {
  10243. if (iterator.node.firstChild) {
  10244. iterator.node = iterator.node.firstChild;
  10245. iterator.depth += 1;
  10246. return iterator;
  10247. }
  10248. while (iterator.node) {
  10249. if (iterator.node.nextSibling) {
  10250. iterator.node = iterator.node.nextSibling;
  10251. return iterator;
  10252. }
  10253. iterator.node = iterator.node.parentNode;
  10254. iterator.depth -= 1;
  10255. }
  10256. return iterator;
  10257. };
  10258. /**
  10259. * Walks the DOM, applying the specified acceptor function to each element.
  10260. * There is a special case for the acceptor, allowing for quick deletion of elements and their children.
  10261. * Return "delete" from your acceptor function if you want to delete the element in question.
  10262. * Return "stop" to terminate iteration.
  10263. * Implementation note - this utility exists mainly for performance reasons. It was last tested
  10264. * carefully some time ago (around jQuery 1.2) but at that time was around 3-4x faster at raw DOM
  10265. * filtration tasks than the jQuery equivalents, which was an important source of performance loss in the
  10266. * Reorderer component. General clients of the framework should use this method with caution if at all, and
  10267. * the performance issues should be reassessed when we have time.
  10268. *
  10269. * @param {Element} node the node to start walking from
  10270. * @param {Function} acceptor the function to invoke with each DOM element
  10271. * @param {Boolean} allnodes Use <code>true</code> to call acceptor on all nodes,
  10272. * rather than just element nodes (type 1)
  10273. */
  10274. fluid.dom.iterateDom = function (node, acceptor, allNodes) {
  10275. var currentNode = {node: node, depth: 0};
  10276. var prevNode = node;
  10277. var condition;
  10278. while (currentNode.node !== null && currentNode.depth >= 0 && currentNode.depth < fluid.dom.iterateDom.DOM_BAIL_DEPTH) {
  10279. condition = null;
  10280. if (currentNode.node.nodeType === 1 || allNodes) {
  10281. condition = acceptor(currentNode.node, currentNode.depth);
  10282. }
  10283. if (condition) {
  10284. if (condition === "delete") {
  10285. currentNode.node.parentNode.removeChild(currentNode.node);
  10286. currentNode.node = prevNode;
  10287. }
  10288. else if (condition === "stop") {
  10289. return currentNode.node;
  10290. }
  10291. }
  10292. prevNode = currentNode.node;
  10293. currentNode = getNextNode(currentNode);
  10294. }
  10295. };
  10296. // Work around IE circular DOM issue. This is the default max DOM depth on IE.
  10297. // http://msdn2.microsoft.com/en-us/library/ms761392(VS.85).aspx
  10298. fluid.dom.iterateDom.DOM_BAIL_DEPTH = 256;
  10299. /**
  10300. * Checks if the specified container is actually the parent of containee.
  10301. *
  10302. * @param {Element} container the potential parent
  10303. * @param {Element} containee the child in question
  10304. */
  10305. fluid.dom.isContainer = function (container, containee) {
  10306. for (; containee; containee = containee.parentNode) {
  10307. if (container === containee) {
  10308. return true;
  10309. }
  10310. }
  10311. return false;
  10312. };
  10313. /** Return the element text from the supplied DOM node as a single String.
  10314. * Implementation note - this is a special-purpose utility used in the framework in just one
  10315. * position in the Reorderer. It only performs a "shallow" traversal of the text and was intended
  10316. * as a quick and dirty means of extracting element labels where the user had not explicitly provided one.
  10317. * It should not be used by general users of the framework and its presence here needs to be
  10318. * reassessed.
  10319. */
  10320. fluid.dom.getElementText = function (element) {
  10321. var nodes = element.childNodes;
  10322. var text = "";
  10323. for (var i = 0; i < nodes.length; ++i) {
  10324. var child = nodes[i];
  10325. if (child.nodeType === 3) {
  10326. text = text + child.nodeValue;
  10327. }
  10328. }
  10329. return text;
  10330. };
  10331. })(jQuery, fluid_1_5);
  10332. /*
  10333. Copyright 2008-2010 University of Cambridge
  10334. Copyright 2008-2009 University of Toronto
  10335. Copyright 2010 Lucendo Development Ltd.
  10336. Licensed under the Educational Community License (ECL), Version 2.0 or the New
  10337. BSD license. You may not use this file except in compliance with one these
  10338. Licenses.
  10339. You may obtain a copy of the ECL 2.0 License and BSD License at
  10340. https://github.com/fluid-project/infusion/raw/master/Infusion-LICENSE.txt
  10341. */
  10342. // Declare dependencies
  10343. /*global fluid_1_5:true, jQuery*/
  10344. // JSLint options
  10345. /*jslint white: true, funcinvoke: true, undef: true, newcap: true, nomen: true, regexp: true, bitwise: true, browser: true, forin: true, maxerr: 100, indent: 4 */
  10346. fluid_1_5 = fluid_1_5 || {};
  10347. (function ($, fluid) {
  10348. var unUnicode = /(\\u[\dabcdef]{4}|\\x[\dabcdef]{2})/g;
  10349. fluid.unescapeProperties = function (string) {
  10350. string = string.replace(unUnicode, function(match) {
  10351. var code = match.substring(2);
  10352. var parsed = parseInt(code, 16);
  10353. return String.fromCharCode(parsed);
  10354. }
  10355. );
  10356. var pos = 0;
  10357. while (true) {
  10358. var backpos = string.indexOf("\\", pos);
  10359. if (backpos === -1) {
  10360. break;
  10361. }
  10362. if (backpos === string.length - 1) {
  10363. return [string.substring(0, string.length - 1), true];
  10364. }
  10365. var replace = string.charAt(backpos + 1);
  10366. if (replace === "n") replace = "\n";
  10367. if (replace === "r") replace = "\r";
  10368. if (replace === "t") replace = "\t";
  10369. string = string.substring(0, backpos) + replace + string.substring(backpos + 2);
  10370. pos = backpos + 1;
  10371. }
  10372. return [string, false];
  10373. };
  10374. var breakPos = /[^\\][\s:=]/;
  10375. fluid.parseJavaProperties = function(text) {
  10376. // File format described at http://java.sun.com/javase/6/docs/api/java/util/Properties.html#load(java.io.Reader)
  10377. var togo = {};
  10378. text = text.replace(/\r\n/g, "\n");
  10379. text = text.replace(/\r/g, "\n");
  10380. lines = text.split("\n");
  10381. var contin, key, valueComp, valueRaw, valueEsc;
  10382. for (var i = 0; i < lines.length; ++ i) {
  10383. var line = $.trim(lines[i]);
  10384. if (!line || line.charAt(0) === "#" || line.charAt(0) === '!') {
  10385. continue;
  10386. }
  10387. if (!contin) {
  10388. valueComp = "";
  10389. var breakpos = line.search(breakPos);
  10390. if (breakpos === -1) {
  10391. key = line;
  10392. valueRaw = "";
  10393. }
  10394. else {
  10395. key = $.trim(line.substring(0, breakpos + 1)); // +1 since first char is escape exclusion
  10396. valueRaw = $.trim(line.substring(breakpos + 2));
  10397. if (valueRaw.charAt(0) === ":" || valueRaw.charAt(0) === "=") {
  10398. valueRaw = $.trim(valueRaw.substring(1));
  10399. }
  10400. }
  10401. key = fluid.unescapeProperties(key)[0];
  10402. valueEsc = fluid.unescapeProperties(valueRaw);
  10403. }
  10404. else {
  10405. valueEsc = fluid.unescapeProperties(line);
  10406. }
  10407. contin = valueEsc[1];
  10408. if (!valueEsc[1]) { // this line was not a continuation line - store the value
  10409. togo[key] = valueComp + valueEsc[0];
  10410. }
  10411. else {
  10412. valueComp += valueEsc[0];
  10413. }
  10414. }
  10415. return togo;
  10416. };
  10417. /**
  10418. * Expand a message string with respect to a set of arguments, following a basic
  10419. * subset of the Java MessageFormat rules.
  10420. * http://java.sun.com/j2se/1.4.2/docs/api/java/text/MessageFormat.html
  10421. *
  10422. * The message string is expected to contain replacement specifications such
  10423. * as {0}, {1}, {2}, etc.
  10424. * @param messageString {String} The message key to be expanded
  10425. * @param args {String/Array of String} An array of arguments to be substituted into the message.
  10426. * @return The expanded message string.
  10427. */
  10428. fluid.formatMessage = function (messageString, args) {
  10429. if (!args) {
  10430. return messageString;
  10431. }
  10432. if (typeof(args) === "string") {
  10433. args = [args];
  10434. }
  10435. for (var i = 0; i < args.length; ++ i) {
  10436. messageString = messageString.replace("{" + i + "}", args[i]);
  10437. }
  10438. return messageString;
  10439. };
  10440. })(jQuery, fluid_1_5);
  10441. /*
  10442. Copyright 2007-2010 University of Cambridge
  10443. Copyright 2007-2009 University of Toronto
  10444. Copyright 2007-2009 University of California, Berkeley
  10445. Copyright 2010 OCAD University
  10446. Copyright 2010-2011 Lucendo Development Ltd.
  10447. Licensed under the Educational Community License (ECL), Version 2.0 or the New
  10448. BSD license. You may not use this file except in compliance with one these
  10449. Licenses.
  10450. You may obtain a copy of the ECL 2.0 License and BSD License at
  10451. https://github.com/fluid-project/infusion/raw/master/Infusion-LICENSE.txt
  10452. */
  10453. // Declare dependencies
  10454. /*global fluid:true, fluid_1_5:true, jQuery*/
  10455. // JSLint options
  10456. /*jslint white: true, funcinvoke: true, undef: true, newcap: true, nomen: true, regexp: true, bitwise: true, browser: true, forin: true, maxerr: 100, indent: 4 */
  10457. var fluid_1_5 = fluid_1_5 || {};
  10458. var fluid = fluid || fluid_1_5;
  10459. (function ($, fluid) {
  10460. fluid.renderTimestamp = function (date) {
  10461. var zeropad = function (num, width) {
  10462. if (!width) width = 2;
  10463. var numstr = (num == undefined? "" : num.toString());
  10464. return "00000".substring(5 - width + numstr.length) + numstr;
  10465. }
  10466. return zeropad(date.getHours()) + ":" + zeropad(date.getMinutes()) + ":" + zeropad(date.getSeconds()) + "." + zeropad(date.getMilliseconds(), 3);
  10467. };
  10468. fluid.isTracing = true;
  10469. fluid.registerNamespace("fluid.tracing");
  10470. fluid.tracing.pathCount = [];
  10471. fluid.tracing.summarisePathCount = function (pathCount) {
  10472. pathCount = pathCount || fluid.tracing.pathCount;
  10473. var togo = {};
  10474. for (var i = 0; i < pathCount.length; ++ i) {
  10475. var path = pathCount[i];
  10476. if (!togo[path]) {
  10477. togo[path] = 1;
  10478. }
  10479. else {
  10480. ++togo[path];
  10481. }
  10482. }
  10483. var toReallyGo = [];
  10484. fluid.each(togo, function(el, path) {
  10485. toReallyGo.push({path: path, count: el});
  10486. });
  10487. toReallyGo.sort(function(a, b) {return b.count - a.count});
  10488. return toReallyGo;
  10489. };
  10490. fluid.tracing.condensePathCount = function (prefixes, pathCount) {
  10491. prefixes = fluid.makeArray(prefixes);
  10492. var prefixCount = {};
  10493. fluid.each(prefixes, function(prefix) {
  10494. prefixCount[prefix] = 0;
  10495. });
  10496. var togo = [];
  10497. fluid.each(pathCount, function(el) {
  10498. var path = el.path;
  10499. if (!fluid.find(prefixes, function(prefix) {
  10500. if (path.indexOf(prefix) === 0) {
  10501. prefixCount[prefix] += el.count;
  10502. return true;
  10503. }
  10504. })) {
  10505. togo.push(el);
  10506. }
  10507. });
  10508. fluid.each(prefixCount, function(count, path) {
  10509. togo.unshift({path: path, count: count});
  10510. });
  10511. return togo;
  10512. };
  10513. // Exception stripping code taken from https://github.com/emwendelin/javascript-stacktrace/blob/master/stacktrace.js
  10514. // BSD licence, see header
  10515. fluid.detectStackStyle = function (e) {
  10516. var style = "other";
  10517. var stackStyle = {
  10518. offset: 0
  10519. };
  10520. if (e["arguments"]) {
  10521. style = "chrome";
  10522. } else if (typeof window !== "undefined" && window.opera && e.stacktrace) {
  10523. style = "opera10";
  10524. } else if (e.stack) {
  10525. style = "firefox";
  10526. // Detect FireFox 4-style stacks which are 1 level less deep
  10527. stackStyle.offset = e.stack.indexOf("Trace exception") === -1? 1 : 0;
  10528. } else if (typeof window !== 'undefined' && window.opera && !('stacktrace' in e)) { //Opera 9-
  10529. style = "opera";
  10530. }
  10531. stackStyle.style = style;
  10532. return stackStyle;
  10533. };
  10534. fluid.obtainException = function() {
  10535. try {
  10536. throw new Error("Trace exception");
  10537. }
  10538. catch (e) {
  10539. return e;
  10540. }
  10541. };
  10542. var stackStyle = fluid.detectStackStyle(fluid.obtainException());
  10543. fluid.registerNamespace("fluid.exceptionDecoders");
  10544. fluid.decodeStack = function() {
  10545. if (stackStyle.style !== "firefox") {
  10546. return null;
  10547. }
  10548. var e = fluid.obtainException();
  10549. return fluid.exceptionDecoders[stackStyle.style](e);
  10550. };
  10551. fluid.exceptionDecoders.firefox = function(e) {
  10552. var lines = e.stack.replace(/(?:\n@:0)?\s+$/m, '').replace(/^\(/gm, '{anonymous}(').split('\n');
  10553. return fluid.transform(lines, function(line) {
  10554. var atind = line.indexOf("@");
  10555. return atind === -1? [line] : [line.substring(atind + 1), line.substring(0, atind)];
  10556. });
  10557. };
  10558. fluid.getCallerInfo = function(atDepth) {
  10559. atDepth = (atDepth || 3) - stackStyle.offset;
  10560. var stack = fluid.decodeStack();
  10561. return stack? stack[atDepth][0] : null;
  10562. };
  10563. function generate(c, count) {
  10564. var togo = "";
  10565. for (var i = 0; i < count; ++ i) {
  10566. togo += c;
  10567. }
  10568. return togo;
  10569. }
  10570. function printImpl(obj, small, options) {
  10571. var big = small + options.indentChars;
  10572. if (obj === null) {
  10573. return "null";
  10574. }
  10575. else if (fluid.isPrimitive(obj)) {
  10576. return JSON.stringify(obj);
  10577. }
  10578. else {
  10579. var j = [];
  10580. if (fluid.isArrayable(obj)) {
  10581. if (obj.length === 0) {
  10582. return "[]";
  10583. }
  10584. for (var i = 0; i < obj.length; ++ i) {
  10585. j[i] = printImpl(obj[i], big, options);
  10586. }
  10587. return "[\n" + big + j.join(",\n" + big) + "\n" + small + "]";
  10588. }
  10589. else {
  10590. var i = 0;
  10591. fluid.each(obj, function(value, key) {
  10592. j[i++] = JSON.stringify(key) + ": " + printImpl(value, big, options);
  10593. });
  10594. return "{\n" + big + j.join(",\n" + big) + "\n" + small + "}";
  10595. }
  10596. }
  10597. }
  10598. fluid.prettyPrintJSON = function(obj, options) {
  10599. options = $.extend({indent: 4}, options);
  10600. options.indentChars = generate(" ", options.indent);
  10601. return printImpl(obj, "", options);
  10602. }
  10603. /**
  10604. * Dumps a DOM element into a readily recognisable form for debugging - produces a
  10605. * "semi-selector" summarising its tag name, class and id, whichever are set.
  10606. *
  10607. * @param {jQueryable} element The element to be dumped
  10608. * @return A string representing the element.
  10609. */
  10610. fluid.dumpEl = function (element) {
  10611. var togo;
  10612. if (!element) {
  10613. return "null";
  10614. }
  10615. if (element.nodeType === 3 || element.nodeType === 8) {
  10616. return "[data: " + element.data + "]";
  10617. }
  10618. if (element.nodeType === 9) {
  10619. return "[document: location " + element.location + "]";
  10620. }
  10621. if (!element.nodeType && fluid.isArrayable(element)) {
  10622. togo = "[";
  10623. for (var i = 0; i < element.length; ++ i) {
  10624. togo += fluid.dumpEl(element[i]);
  10625. if (i < element.length - 1) {
  10626. togo += ", ";
  10627. }
  10628. }
  10629. return togo + "]";
  10630. }
  10631. element = $(element);
  10632. togo = element.get(0).tagName;
  10633. if (element.id) {
  10634. togo += "#" + element.id;
  10635. }
  10636. if (element.attr("class")) {
  10637. togo += "." + element.attr("class");
  10638. }
  10639. return togo;
  10640. };
  10641. })(jQuery, fluid_1_5);
  10642. /*
  10643. Copyright 2008-2010 University of Cambridge
  10644. Copyright 2008-2009 University of Toronto
  10645. Copyright 2010-2011 Lucendo Development Ltd.
  10646. Copyright 2010 OCAD University
  10647. Licensed under the Educational Community License (ECL), Version 2.0 or the New
  10648. BSD license. You may not use this file except in compliance with one these
  10649. Licenses.
  10650. You may obtain a copy of the ECL 2.0 License and BSD License at
  10651. https://github.com/fluid-project/infusion/raw/master/Infusion-LICENSE.txt
  10652. */
  10653. // Declare dependencies
  10654. /*global fluid_1_5:true, jQuery*/
  10655. // JSLint options
  10656. /*jslint white: true, funcinvoke: true, continue: true, elsecatch: true, operator: true, jslintok:true, undef: true, newcap: true, regexp: true, bitwise: true, browser: true, forin: true, maxerr: 100, indent: 4 */
  10657. var fluid_1_5 = fluid_1_5 || {};
  10658. (function ($, fluid) {
  10659. fluid.BINDING_ROOT_KEY = "fluid-binding-root";
  10660. /** Recursively find any data stored under a given name from a node upwards
  10661. * in its DOM hierarchy **/
  10662. fluid.findData = function (elem, name) {
  10663. while (elem) {
  10664. var data = $.data(elem, name);
  10665. if (data) {
  10666. return data;
  10667. }
  10668. elem = elem.parentNode;
  10669. }
  10670. };
  10671. fluid.bindFossils = function (node, data, fossils) {
  10672. $.data(node, fluid.BINDING_ROOT_KEY, {data: data, fossils: fossils});
  10673. };
  10674. fluid.boundPathForNode = function (node, fossils) {
  10675. node = fluid.unwrap(node);
  10676. var key = node.name || node.id;
  10677. var record = fossils[key];
  10678. return record ? record.EL : null;
  10679. };
  10680. /** "Automatically" apply to whatever part of the data model is
  10681. * relevant, the changed value received at the given DOM node*/
  10682. fluid.applyBoundChange = function (node, newValue, applier) {
  10683. node = fluid.unwrap(node);
  10684. if (newValue === undefined) {
  10685. newValue = fluid.value(node);
  10686. }
  10687. if (node.nodeType === undefined && node.length > 0) {
  10688. node = node[0];
  10689. } // assume here that they share name and parent
  10690. var root = fluid.findData(node, fluid.BINDING_ROOT_KEY);
  10691. if (!root) {
  10692. fluid.fail("Bound data could not be discovered in any node above " + fluid.dumpEl(node));
  10693. }
  10694. var name = node.name;
  10695. var fossil = root.fossils[name];
  10696. if (!fossil) {
  10697. fluid.fail("No fossil discovered for name " + name + " in fossil record above " + fluid.dumpEl(node));
  10698. }
  10699. if (typeof(fossil.oldvalue) === "boolean") { // deal with the case of an "isolated checkbox"
  10700. newValue = newValue[0] ? true : false;
  10701. }
  10702. var EL = root.fossils[name].EL;
  10703. if (applier) {
  10704. applier.fireChangeRequest({path: EL, value: newValue, source: node.id});
  10705. } else {
  10706. fluid.set(root.data, EL, newValue);
  10707. }
  10708. };
  10709. /** MODEL ACCESSOR ENGINE (trundler) **/
  10710. /** Standard strategies for resolving path segments **/
  10711. fluid.model.environmentStrategy = function (initEnvironment) {
  10712. return {
  10713. init: function () {
  10714. var environment = initEnvironment;
  10715. return function (root, segment, index) {
  10716. var togo;
  10717. if (environment && environment[segment]) {
  10718. togo = environment[segment];
  10719. }
  10720. environment = null;
  10721. return togo;
  10722. };
  10723. }
  10724. };
  10725. };
  10726. fluid.model.defaultCreatorStrategy = function (root, segment) {
  10727. if (root[segment] === undefined) {
  10728. root[segment] = {};
  10729. return root[segment];
  10730. }
  10731. };
  10732. fluid.model.defaultFetchStrategy = function (root, segment) {
  10733. return segment === "" ? root : root[segment];
  10734. };
  10735. fluid.model.funcResolverStrategy = function (root, segment) {
  10736. if (root.resolvePathSegment) {
  10737. return root.resolvePathSegment(segment);
  10738. }
  10739. };
  10740. fluid.model.defaultGetConfig = {
  10741. strategies: [fluid.model.funcResolverStrategy, fluid.model.defaultFetchStrategy]
  10742. };
  10743. fluid.model.defaultSetConfig = {
  10744. strategies: [fluid.model.funcResolverStrategy, fluid.model.defaultFetchStrategy, fluid.model.defaultCreatorStrategy]
  10745. };
  10746. // unsupported, NON-API function
  10747. fluid.model.applyStrategy = function (strategy, root, segment, path) {
  10748. if (typeof (strategy) === "function") {
  10749. return strategy(root, segment, path);
  10750. } else if (strategy && strategy.next) {
  10751. return strategy.next(root, segment, path);
  10752. }
  10753. };
  10754. // unsupported, NON-API function
  10755. fluid.model.initStrategy = function (baseStrategy, index, oldStrategies) {
  10756. return baseStrategy.init ? baseStrategy.init(oldStrategies ? oldStrategies[index] : undefined) : baseStrategy;
  10757. };
  10758. // unsupported, NON-API function
  10759. fluid.model.makeTrundler = function (root, config, oldStrategies) {
  10760. var that = {
  10761. root: root,
  10762. strategies: fluid.isArrayable(config) ? config :
  10763. fluid.transform(config.strategies, function (strategy, index) {
  10764. return fluid.model.initStrategy(strategy, index, oldStrategies);
  10765. })
  10766. };
  10767. that.trundle = function (EL, uncess) {
  10768. uncess = uncess || 0;
  10769. var newThat = fluid.model.makeTrundler(that.root, config, that.strategies);
  10770. newThat.segs = config.parser? config.parser.parse(EL) : fluid.model.parseEL(EL);
  10771. newThat.index = 0;
  10772. newThat.path = "";
  10773. newThat.step(newThat.segs.length - uncess);
  10774. return newThat;
  10775. };
  10776. that.next = function () {
  10777. if (!that.root) {
  10778. return;
  10779. }
  10780. var accepted;
  10781. // TODO: Temporary adjustment before trundlers are destroyed by FLUID-4705
  10782. // In the final system "new strategies" should be able to declare whether any of them
  10783. // require this path computed or not
  10784. that.path = (config.parser? config.parser.compose : fluid.model.composePath)(that.path, that.segs[that.index]);
  10785. for (var i = 0; i < that.strategies.length; ++i) {
  10786. var value = fluid.model.applyStrategy(that.strategies[i], that.root, that.segs[that.index], that.path);
  10787. if (accepted === undefined) {
  10788. accepted = value;
  10789. }
  10790. }
  10791. if (accepted === fluid.NO_VALUE) {
  10792. accepted = undefined;
  10793. }
  10794. that.root = accepted;
  10795. ++that.index;
  10796. };
  10797. that.step = function (limit) {
  10798. for (var i = 0; i < limit; ++i) {
  10799. that.next();
  10800. }
  10801. that.last = that.segs[that.index];
  10802. };
  10803. return that;
  10804. };
  10805. // unsupported, NON-API function
  10806. // core trundling recursion point
  10807. fluid.model.trundleImpl = function (trundler, EL, config, uncess) {
  10808. if (typeof (EL) === "string") {
  10809. trundler = trundler.trundle(EL, uncess);
  10810. } else {
  10811. var key = EL.type || "default";
  10812. var resolver = config.resolvers[key];
  10813. if (!resolver) {
  10814. fluid.fail("Unable to find resolver of type " + key);
  10815. }
  10816. trundler = resolver(EL, trundler) || {};
  10817. if (EL.path && trundler.trundle && trundler.root !== undefined) {
  10818. trundler = fluid.model.trundleImpl(trundler, EL.path, config, uncess);
  10819. }
  10820. }
  10821. return trundler;
  10822. };
  10823. // unsupported, NON-API function
  10824. // entry point for initially unbased trundling
  10825. fluid.model.trundle = function (root, EL, config, uncess) {
  10826. EL = EL || "";
  10827. config = config || fluid.model.defaultGetConfig;
  10828. var trundler = fluid.model.makeTrundler(root, config);
  10829. return fluid.model.trundleImpl(trundler, EL, config, uncess);
  10830. };
  10831. fluid.model.getPenultimate = function (root, EL, config) {
  10832. return fluid.model.trundle(root, EL, config, 1);
  10833. };
  10834. // Implementation notes: The EL path manipulation utilities here are somewhat more thorough
  10835. // and expensive versions of those provided in Fluid.js - there is some duplication of
  10836. // functionality. This is a tradeoff between stability and performance - the versions in
  10837. // Fluid.js are the most frequently used and do not implement escaping of characters .
  10838. // as \. and \ as \\ as the versions here. The implementations here are not
  10839. // performant and are left here partially as an implementation note. Problems will
  10840. // arise if clients manipulate JSON structures containing "." characters in keys as if they
  10841. // are models. The basic utilities fluid.path(), fluid.parseEL and fluid.composePath are
  10842. // the ones recommended for general users and the following implementations will
  10843. // be upgraded to use regexes in future to make them better alternatives
  10844. fluid.pathUtil = {};
  10845. var getPathSegmentImpl = function (accept, path, i) {
  10846. var segment = null; // TODO: rewrite this with regexes and replaces
  10847. if (accept) {
  10848. segment = "";
  10849. }
  10850. var escaped = false;
  10851. var limit = path.length;
  10852. for (; i < limit; ++i) {
  10853. var c = path.charAt(i);
  10854. if (!escaped) {
  10855. if (c === '.') {
  10856. break;
  10857. }
  10858. else if (c === '\\') {
  10859. escaped = true;
  10860. }
  10861. else if (segment !== null) {
  10862. segment += c;
  10863. }
  10864. }
  10865. else {
  10866. escaped = false;
  10867. if (segment !== null) {
  10868. segment += c;
  10869. }
  10870. }
  10871. }
  10872. if (segment !== null) {
  10873. accept[0] = segment;
  10874. }
  10875. return i;
  10876. };
  10877. var globalAccept = []; // TODO: serious reentrancy risk here, why is this impl like this?
  10878. /** Parses a path segment, following escaping rules, starting from character index i in the supplied path */
  10879. fluid.pathUtil.getPathSegment = function (path, i) {
  10880. getPathSegmentImpl(globalAccept, path, i);
  10881. return globalAccept[0];
  10882. };
  10883. /** Returns just the head segment of an EL path */
  10884. fluid.pathUtil.getHeadPath = function (path) {
  10885. return fluid.pathUtil.getPathSegment(path, 0);
  10886. };
  10887. /** Returns all of an EL path minus its first segment - if the path consists of just one segment, returns "" */
  10888. fluid.pathUtil.getFromHeadPath = function (path) {
  10889. var firstdot = getPathSegmentImpl(null, path, 0);
  10890. return firstdot === path.length ? "" : path.substring(firstdot + 1);
  10891. };
  10892. function lastDotIndex(path) {
  10893. // TODO: proper escaping rules
  10894. return path.lastIndexOf(".");
  10895. }
  10896. /** Returns all of an EL path minus its final segment - if the path consists of just one segment, returns "" -
  10897. * WARNING - this method does not follow escaping rules */
  10898. fluid.pathUtil.getToTailPath = function (path) {
  10899. var lastdot = lastDotIndex(path);
  10900. return lastdot === -1 ? "" : path.substring(0, lastdot);
  10901. };
  10902. /** Returns the very last path component of an EL path
  10903. * WARNING - this method does not follow escaping rules */
  10904. fluid.pathUtil.getTailPath = function (path) {
  10905. var lastdot = lastDotIndex(path);
  10906. return fluid.pathUtil.getPathSegment(path, lastdot + 1);
  10907. };
  10908. /** A version of fluid.model.parseEL that apples escaping rules - this allows path segments
  10909. * to contain period characters . - characters "\" and "}" will also be escaped. WARNING -
  10910. * this current implementation is EXTREMELY slow compared to fluid.model.parseEL and should
  10911. * not be used in performance-sensitive applications */
  10912. fluid.pathUtil.parseEL = function (path) {
  10913. var togo = [];
  10914. var index = 0;
  10915. var limit = path.length;
  10916. while (index < limit) {
  10917. var firstdot = getPathSegmentImpl(globalAccept, path, index);
  10918. togo.push(globalAccept[0]);
  10919. index = firstdot + 1;
  10920. }
  10921. return togo;
  10922. };
  10923. var composeSegment = function (prefix, toappend) {
  10924. for (var i = 0; i < toappend.length; ++i) {
  10925. var c = toappend.charAt(i);
  10926. if (c === '.' || c === '\\' || c === '}') {
  10927. prefix += '\\';
  10928. }
  10929. prefix += c;
  10930. }
  10931. return prefix;
  10932. };
  10933. /** Escapes a single path segment by replacing any character ".", "\" or "}" with
  10934. * itself prepended by \
  10935. */
  10936. fluid.pathUtil.escapeSegment = function (segment) {
  10937. return composeSegment("", segment);
  10938. };
  10939. /**
  10940. * Compose a prefix and suffix EL path, where the prefix is already escaped.
  10941. * Prefix may be empty, but not null. The suffix will become escaped.
  10942. */
  10943. fluid.pathUtil.composePath = function (prefix, suffix) {
  10944. if (prefix.length !== 0) {
  10945. prefix += '.';
  10946. }
  10947. return composeSegment(prefix, suffix);
  10948. };
  10949. /** Determine the path by which a given path is nested within another **/
  10950. fluid.pathUtil.getExcessPath = function (base, longer) {
  10951. var index = longer.indexOf(base);
  10952. if (index !== 0) {
  10953. fluid.fail("Path " + base + " is not a prefix of path " + longer);
  10954. }
  10955. if (base.length === longer.length) {
  10956. return "";
  10957. }
  10958. if (longer[base.length] !== ".") {
  10959. fluid.fail("Path " + base + " is not properly nested in path " + longer);
  10960. }
  10961. return longer.substring(base.length + 1);
  10962. };
  10963. /** Determines whether a particular EL path matches a given path specification.
  10964. * The specification consists of a path with optional wildcard segments represented by "*".
  10965. * @param spec (string) The specification to be matched
  10966. * @param path (string) The path to be tested
  10967. * @param exact (boolean) Whether the path must exactly match the length of the specification in
  10968. * terms of path segments in order to count as match. If exact is falsy, short specifications will
  10969. * match all longer paths as if they were padded out with "*" segments
  10970. * @return (string) The path which matched the specification, or <code>null</code> if there was no match
  10971. */
  10972. fluid.pathUtil.matchPath = function (spec, path, exact) {
  10973. var togo = "";
  10974. while (true) {
  10975. if (((path === "") ^ (spec === "")) && exact) {
  10976. return null;
  10977. }
  10978. // FLUID-4625 - symmetry on spec and path is actually undesirable, but this
  10979. // quickly avoids at least missed notifications - improved (but slower)
  10980. // implementation should explode composite changes
  10981. if (!spec || !path) {
  10982. break;
  10983. }
  10984. var spechead = fluid.pathUtil.getHeadPath(spec);
  10985. var pathhead = fluid.pathUtil.getHeadPath(path);
  10986. // if we fail to match on a specific component, fail.
  10987. if (spechead !== "*" && spechead !== pathhead) {
  10988. return null;
  10989. }
  10990. togo = fluid.pathUtil.composePath(togo, pathhead);
  10991. spec = fluid.pathUtil.getFromHeadPath(spec);
  10992. path = fluid.pathUtil.getFromHeadPath(path);
  10993. }
  10994. return togo;
  10995. };
  10996. /** CHANGE APPLIER **/
  10997. fluid.model.isNullChange = function (model, request, resolverGetConfig) {
  10998. if (request.type === "ADD") {
  10999. var existing = fluid.get(model, request.path, resolverGetConfig);
  11000. if (existing === request.value) {
  11001. return true;
  11002. }
  11003. }
  11004. };
  11005. /** Applies the supplied ChangeRequest object directly to the supplied model.
  11006. */
  11007. fluid.model.applyChangeRequest = function (model, request, resolverSetConfig) {
  11008. var pen = fluid.model.getPenultimate(model, request.path, resolverSetConfig || fluid.model.defaultSetConfig);
  11009. if (request.type === "ADD" || request.type === "MERGE") {
  11010. if (request.path === "" || request.type === "MERGE") {
  11011. if (request.type === "ADD") {
  11012. fluid.clear(pen.root);
  11013. }
  11014. $.extend(true, request.path === "" ? pen.root : pen.root[pen.last], request.value);
  11015. }
  11016. else {
  11017. pen.root[pen.last] = request.value;
  11018. }
  11019. }
  11020. else if (request.type === "DELETE") {
  11021. if (request.path === "") {
  11022. fluid.clear(pen.root);
  11023. }
  11024. else {
  11025. delete pen.root[pen.last];
  11026. }
  11027. }
  11028. };
  11029. /** Add a listener to a ChangeApplier event that only acts in the case the event
  11030. * has not come from the specified source (typically ourself)
  11031. * @param modelEvent An model event held by a changeApplier (typically applier.modelChanged)
  11032. * @param path The path specification to listen to
  11033. * @param source The source value to exclude (direct equality used)
  11034. * @param func The listener to be notified of a change
  11035. * @param [eventName] - optional - the event name to be listened to - defaults to "modelChanged"
  11036. */
  11037. fluid.addSourceGuardedListener = function(applier, path, source, func, eventName) {
  11038. eventName = eventName || "modelChanged";
  11039. applier[eventName].addListener(path,
  11040. function() {
  11041. if (!applier.hasChangeSource(source)) {
  11042. func.apply(null, arguments);
  11043. }
  11044. });
  11045. };
  11046. /** Convenience method to fire a change event to a specified applier, including
  11047. * a supplied "source" identified (perhaps for use with addSourceGuardedListener)
  11048. */
  11049. fluid.fireSourcedChange = function (applier, path, value, source) {
  11050. applier.fireChangeRequest({
  11051. path: path,
  11052. value: value,
  11053. source: source
  11054. });
  11055. };
  11056. /** Dispatches a list of changes to the supplied applier */
  11057. fluid.requestChanges = function (applier, changes) {
  11058. for (var i = 0; i < changes.length; ++i) {
  11059. applier.fireChangeRequest(changes[i]);
  11060. }
  11061. };
  11062. // Utility shared between changeApplier and superApplier
  11063. function bindRequestChange(that) {
  11064. that.requestChange = function (path, value, type) {
  11065. var changeRequest = {
  11066. path: path,
  11067. value: value,
  11068. type: type
  11069. };
  11070. that.fireChangeRequest(changeRequest);
  11071. };
  11072. }
  11073. // Utility used for source tracking in changeApplier
  11074. function sourceWrapModelChanged(modelChanged, threadLocal) {
  11075. return function(changeRequest) {
  11076. var sources = threadLocal().sources;
  11077. var args = arguments;
  11078. var source = changeRequest.source || "";
  11079. fluid.tryCatch(function() {
  11080. if (sources[source] === undefined) {
  11081. sources[source] = 0;
  11082. }
  11083. ++sources[source];
  11084. modelChanged.apply(null, args);
  11085. }, null, function() {
  11086. --sources[source];
  11087. });
  11088. };
  11089. }
  11090. /** The core creator function constructing ChangeAppliers. See API documentation
  11091. * at http://wiki.fluidproject.org/display/fluid/ChangeApplier+API for the various
  11092. * options supported in the options structure */
  11093. fluid.makeChangeApplier = function (model, options) {
  11094. options = options || {};
  11095. var baseEvents = {
  11096. guards: fluid.event.getEventFirer(false, true, "guard event"),
  11097. postGuards: fluid.event.getEventFirer(false, true, "postGuard event"),
  11098. modelChanged: fluid.event.getEventFirer(false, false, "modelChanged event")
  11099. };
  11100. var threadLocal = fluid.threadLocal(function() { return {sources: {}};});
  11101. var that = {
  11102. // For now, we don't use "id" to avoid confusing component detection which uses
  11103. // a simple algorithm looking for that field
  11104. changeid: fluid.allocateGuid(),
  11105. model: model
  11106. };
  11107. function makeGuardWrapper(cullUnchanged) {
  11108. if (!cullUnchanged) {
  11109. return null;
  11110. }
  11111. var togo = function (guard) {
  11112. return function (model, changeRequest, internalApplier) {
  11113. var oldRet = guard(model, changeRequest, internalApplier);
  11114. if (oldRet === false) {
  11115. return false;
  11116. }
  11117. else {
  11118. if (fluid.model.isNullChange(model, changeRequest)) {
  11119. togo.culled = true;
  11120. return false;
  11121. }
  11122. }
  11123. };
  11124. };
  11125. return togo;
  11126. }
  11127. function wrapListener(listener, spec) {
  11128. var pathSpec = spec;
  11129. var transactional = false;
  11130. var priority = Number.MAX_VALUE;
  11131. if (typeof (spec) !== "string") {
  11132. pathSpec = spec.path;
  11133. transactional = spec.transactional;
  11134. if (spec.priority !== undefined) {
  11135. priority = spec.priority;
  11136. }
  11137. }
  11138. else {
  11139. if (pathSpec.charAt(0) === "!") {
  11140. transactional = true;
  11141. pathSpec = pathSpec.substring(1);
  11142. }
  11143. }
  11144. return function (changePath, fireSpec, accum) {
  11145. var guid = fluid.event.identifyListener(listener);
  11146. var exist = fireSpec.guids[guid];
  11147. if (!exist) {
  11148. var match = fluid.pathUtil.matchPath(pathSpec, changePath);
  11149. if (match !== null) {
  11150. var record = {
  11151. changePath: changePath,
  11152. pathSpec: pathSpec,
  11153. listener: listener,
  11154. priority: priority,
  11155. transactional: transactional
  11156. };
  11157. if (accum) {
  11158. record.accumulate = [accum];
  11159. }
  11160. fireSpec.guids[guid] = record;
  11161. var collection = transactional ? "transListeners" : "listeners";
  11162. fireSpec[collection].push(record);
  11163. fireSpec.all.push(record);
  11164. }
  11165. }
  11166. else if (accum) {
  11167. if (!exist.accumulate) {
  11168. exist.accumulate = [];
  11169. }
  11170. exist.accumulate.push(accum);
  11171. }
  11172. };
  11173. }
  11174. function fireFromSpec(name, fireSpec, args, category, wrapper) {
  11175. return baseEvents[name].fireToListeners(fireSpec[category], args, wrapper);
  11176. }
  11177. function fireComparator(recA, recB) {
  11178. return recA.priority - recB.priority;
  11179. }
  11180. function prepareFireEvent(name, changePath, fireSpec, accum) {
  11181. baseEvents[name].fire(changePath, fireSpec, accum);
  11182. fireSpec.all.sort(fireComparator);
  11183. fireSpec.listeners.sort(fireComparator);
  11184. fireSpec.transListeners.sort(fireComparator);
  11185. }
  11186. function makeFireSpec() {
  11187. return {guids: {}, all: [], listeners: [], transListeners: []};
  11188. }
  11189. function getFireSpec(name, changePath) {
  11190. var fireSpec = makeFireSpec();
  11191. prepareFireEvent(name, changePath, fireSpec);
  11192. return fireSpec;
  11193. }
  11194. function fireEvent(name, changePath, args, wrapper) {
  11195. var fireSpec = getFireSpec(name, changePath);
  11196. return fireFromSpec(name, fireSpec, args, "all", wrapper);
  11197. }
  11198. function adaptListener(that, name) {
  11199. that[name] = {
  11200. addListener: function (spec, listener, namespace) {
  11201. baseEvents[name].addListener(wrapListener(listener, spec), namespace);
  11202. },
  11203. removeListener: function (listener) {
  11204. baseEvents[name].removeListener(listener);
  11205. }
  11206. };
  11207. }
  11208. adaptListener(that, "guards");
  11209. adaptListener(that, "postGuards");
  11210. adaptListener(that, "modelChanged");
  11211. function preFireChangeRequest(changeRequest) {
  11212. if (!changeRequest.type) {
  11213. changeRequest.type = "ADD";
  11214. }
  11215. }
  11216. var bareApplier = {
  11217. fireChangeRequest: function (changeRequest) {
  11218. that.fireChangeRequest(changeRequest, true);
  11219. }
  11220. };
  11221. bindRequestChange(bareApplier);
  11222. that.fireChangeRequest = function (changeRequest, defeatGuards) {
  11223. preFireChangeRequest(changeRequest);
  11224. var guardFireSpec = defeatGuards ? null : getFireSpec("guards", changeRequest.path);
  11225. if (guardFireSpec && guardFireSpec.transListeners.length > 0) {
  11226. var ation = that.initiate();
  11227. ation.fireChangeRequest(changeRequest, guardFireSpec);
  11228. ation.commit();
  11229. }
  11230. else {
  11231. if (!defeatGuards) {
  11232. // TODO: this use of "listeners" seems pointless since we have just verified that there are no transactional listeners
  11233. var prevent = fireFromSpec("guards", guardFireSpec, [model, changeRequest, bareApplier], "listeners");
  11234. if (prevent === false) {
  11235. return false;
  11236. }
  11237. }
  11238. var oldModel = model;
  11239. if (!options.thin) {
  11240. oldModel = {};
  11241. fluid.model.copyModel(oldModel, model);
  11242. }
  11243. fluid.model.applyChangeRequest(model, changeRequest, options.resolverSetConfig);
  11244. fireEvent("modelChanged", changeRequest.path, [model, oldModel, [changeRequest]]);
  11245. }
  11246. };
  11247. that.fireChangeRequest = sourceWrapModelChanged(that.fireChangeRequest, threadLocal);
  11248. bindRequestChange(that);
  11249. function fireAgglomerated(eventName, formName, changes, args, accpos) {
  11250. var fireSpec = makeFireSpec();
  11251. for (var i = 0; i < changes.length; ++i) {
  11252. prepareFireEvent(eventName, changes[i].path, fireSpec, changes[i]);
  11253. }
  11254. for (var j = 0; j < fireSpec[formName].length; ++j) {
  11255. var spec = fireSpec[formName][j];
  11256. if (accpos) {
  11257. args[accpos] = spec.accumulate;
  11258. }
  11259. var ret = spec.listener.apply(null, args);
  11260. if (ret === false) {
  11261. return false;
  11262. }
  11263. }
  11264. }
  11265. that.initiate = function (newModel) {
  11266. var cancelled = false;
  11267. var changes = [];
  11268. if (options.thin) {
  11269. newModel = model;
  11270. }
  11271. else {
  11272. newModel = newModel || {};
  11273. fluid.model.copyModel(newModel, model);
  11274. }
  11275. // the guard in the inner world is given a private applier to "fast track"
  11276. // and glob collateral changes it requires
  11277. var internalApplier = {
  11278. fireChangeRequest: function (changeRequest) {
  11279. preFireChangeRequest(changeRequest);
  11280. fluid.model.applyChangeRequest(newModel, changeRequest, options.resolverSetConfig);
  11281. changes.push(changeRequest);
  11282. }
  11283. };
  11284. bindRequestChange(internalApplier);
  11285. var ation = {
  11286. commit: function () {
  11287. var oldModel;
  11288. if (cancelled) {
  11289. return false;
  11290. }
  11291. var ret = fireAgglomerated("postGuards", "transListeners", changes, [newModel, null, internalApplier], 1);
  11292. if (ret === false) {
  11293. return false;
  11294. }
  11295. if (options.thin) {
  11296. oldModel = model;
  11297. }
  11298. else {
  11299. oldModel = {};
  11300. fluid.model.copyModel(oldModel, model);
  11301. fluid.clear(model);
  11302. fluid.model.copyModel(model, newModel);
  11303. }
  11304. fireAgglomerated("modelChanged", "all", changes, [model, oldModel, null], 2);
  11305. },
  11306. fireChangeRequest: function (changeRequest) {
  11307. preFireChangeRequest(changeRequest);
  11308. if (options.cullUnchanged && fluid.model.isNullChange(model, changeRequest, options.resolverGetConfig)) {
  11309. return;
  11310. }
  11311. var wrapper = makeGuardWrapper(options.cullUnchanged);
  11312. var prevent = fireEvent("guards", changeRequest.path, [newModel, changeRequest, internalApplier], wrapper);
  11313. if (prevent === false && !(wrapper && wrapper.culled)) {
  11314. cancelled = true;
  11315. }
  11316. if (!cancelled) {
  11317. if (!(wrapper && wrapper.culled)) {
  11318. fluid.model.applyChangeRequest(newModel, changeRequest, options.resolverSetConfig);
  11319. changes.push(changeRequest);
  11320. }
  11321. }
  11322. }
  11323. };
  11324. ation.fireChangeRequest = sourceWrapModelChanged(ation.fireChangeRequest, threadLocal);
  11325. bindRequestChange(ation);
  11326. return ation;
  11327. };
  11328. that.hasChangeSource = function (source) {
  11329. return threadLocal().sources[source] > 0;
  11330. };
  11331. return that;
  11332. };
  11333. fluid.makeSuperApplier = function () {
  11334. var subAppliers = [];
  11335. var that = {};
  11336. that.addSubApplier = function (path, subApplier) {
  11337. subAppliers.push({path: path, subApplier: subApplier});
  11338. };
  11339. that.fireChangeRequest = function (request) {
  11340. for (var i = 0; i < subAppliers.length; ++i) {
  11341. var path = subAppliers[i].path;
  11342. if (request.path.indexOf(path) === 0) {
  11343. var subpath = request.path.substring(path.length + 1);
  11344. var subRequest = fluid.copy(request);
  11345. subRequest.path = subpath;
  11346. // TODO: Deal with the as yet unsupported case of an EL rvalue DAR
  11347. subAppliers[i].subApplier.fireChangeRequest(subRequest);
  11348. }
  11349. }
  11350. };
  11351. bindRequestChange(that);
  11352. return that;
  11353. };
  11354. fluid.attachModel = function (baseModel, path, model) {
  11355. var segs = fluid.model.parseEL(path);
  11356. for (var i = 0; i < segs.length - 1; ++i) {
  11357. var seg = segs[i];
  11358. var subModel = baseModel[seg];
  11359. if (!subModel) {
  11360. baseModel[seg] = subModel = {};
  11361. }
  11362. baseModel = subModel;
  11363. }
  11364. baseModel[segs[segs.length - 1]] = model;
  11365. };
  11366. fluid.assembleModel = function (modelSpec) {
  11367. var model = {};
  11368. var superApplier = fluid.makeSuperApplier();
  11369. var togo = {model: model, applier: superApplier};
  11370. for (var path in modelSpec) {
  11371. var rec = modelSpec[path];
  11372. fluid.attachModel(model, path, rec.model);
  11373. if (rec.applier) {
  11374. superApplier.addSubApplier(path, rec.applier);
  11375. }
  11376. }
  11377. return togo;
  11378. };
  11379. })(jQuery, fluid_1_5);
  11380. /*
  11381. Copyright 2010 University of Toronto
  11382. Copyright 2010-2011 OCAD University
  11383. Licensed under the Educational Community License (ECL), Version 2.0 or the New
  11384. BSD license. You may not use this file except in compliance with one these
  11385. Licenses.
  11386. You may obtain a copy of the ECL 2.0 License and BSD License at
  11387. https://github.com/fluid-project/infusion/raw/master/Infusion-LICENSE.txt
  11388. */
  11389. // Declare dependencies
  11390. /*global fluid:true, fluid_1_5:true, jQuery*/
  11391. // JSLint options
  11392. /*jslint white: true, elsecatch: true, jslintok: true, funcinvoke: true, undef: true, newcap: true, nomen: true, regexp: true, bitwise: true, browser: true, forin: true, maxerr: 100, indent: 4 */
  11393. var fluid_1_5 = fluid_1_5 || {};
  11394. var fluid = fluid || fluid_1_5;
  11395. (function ($) {
  11396. fluid.registerNamespace("fluid.model.transform");
  11397. /** Grade definitions for standard transformation function hierarchy **/
  11398. fluid.defaults("fluid.transformFunction", {
  11399. gradeNames: "fluid.function"
  11400. });
  11401. // uses standard layout and workflow involving inputPath
  11402. fluid.defaults("fluid.standardInputTransformFunction", {
  11403. gradeNames: "fluid.transformFunction"
  11404. });
  11405. fluid.defaults("fluid.standardOutputTransformFunction", {
  11406. gradeNames: "fluid.transformFunction"
  11407. });
  11408. // uses the standard layout and workflow involving inputPath and outputPath
  11409. fluid.defaults("fluid.standardTransformFunction", {
  11410. gradeNames: ["fluid.standardInputTransformFunction", "fluid.standardOutputTransformFunction"]
  11411. });
  11412. fluid.defaults("fluid.lens", {
  11413. gradeNames: "fluid.transformFunction",
  11414. invertConfiguration: null
  11415. // this function method returns "inverted configuration" rather than actually performing inversion
  11416. // TODO: harmonise with strategy used in VideoPlayer_framework.js
  11417. });
  11418. /***********************************
  11419. * Base utilities for transformers *
  11420. ***********************************/
  11421. // unsupported, NON-API function
  11422. fluid.model.transform.pathToRule = function (inputPath) {
  11423. return {
  11424. expander: {
  11425. type: "fluid.model.transform.value",
  11426. inputPath: inputPath
  11427. }
  11428. };
  11429. };
  11430. // unsupported, NON-API function
  11431. fluid.model.transform.valueToRule = function (value) {
  11432. return {
  11433. expander: {
  11434. type: "fluid.model.transform.literalValue",
  11435. value: value
  11436. }
  11437. };
  11438. };
  11439. /** Accepts two fully escaped paths, either of which may be empty or null **/
  11440. fluid.model.composePaths = function (prefix, suffix) {
  11441. prefix = prefix || "";
  11442. suffix = suffix || "";
  11443. return !prefix ? suffix : (!suffix ? prefix : prefix + "." + suffix);
  11444. };
  11445. fluid.model.transform.accumulateInputPath = function (inputPath, expander, paths) {
  11446. if (inputPath !== undefined) {
  11447. paths.push(fluid.model.composePaths(expander.inputPrefix, inputPath));
  11448. }
  11449. };
  11450. fluid.model.transform.getValue = function (inputPath, value, expander) {
  11451. var togo;
  11452. if (inputPath !== undefined) { // NB: We may one day want to reverse the crazy jQuery-like convention that "no path means root path"
  11453. togo = fluid.get(expander.source, fluid.model.composePaths(expander.inputPrefix, inputPath), expander.resolverGetConfig);
  11454. }
  11455. if (togo === undefined) {
  11456. togo = fluid.isPrimitive(value) ? value : expander.expand(value);
  11457. }
  11458. return togo;
  11459. };
  11460. // distinguished value which indicates that a transformation rule supplied a
  11461. // non-default output path, and so the user should be prevented from making use of it
  11462. // in a compound expander definition
  11463. fluid.model.transform.NONDEFAULT_OUTPUT_PATH_RETURN = {};
  11464. fluid.model.transform.setValue = function (userOutputPath, value, expander) {
  11465. // avoid crosslinking to input object - this might be controlled by a "nocopy" option in future
  11466. var toset = fluid.copy(value);
  11467. var outputPath = fluid.model.composePaths(expander.outputPrefix, userOutputPath);
  11468. // TODO: custom resolver config here to create non-hash output model structure
  11469. if (toset !== undefined) {
  11470. expander.applier.requestChange(outputPath, toset);
  11471. }
  11472. return userOutputPath ? fluid.model.transform.NONDEFAULT_OUTPUT_PATH_RETURN : toset;
  11473. };
  11474. /**********************************
  11475. * Standard transformer functions *
  11476. **********************************/
  11477. fluid.model.transform.value = fluid.identity;
  11478. fluid.defaults("fluid.model.transform.value", {
  11479. gradeNames: "fluid.standardTransformFunction",
  11480. invertConfiguration: "fluid.model.transform.invertValue"
  11481. });
  11482. fluid.model.transform.invertValue = function (expandSpec, expander) {
  11483. var togo = fluid.copy(expandSpec);
  11484. // TODO: this will not behave correctly in the face of compound "value" which contains
  11485. // further expanders
  11486. togo.inputPath = fluid.model.composePaths(expander.outputPrefix, expandSpec.outputPath);
  11487. togo.outputPath = fluid.model.composePaths(expander.inputPrefix, expandSpec.inputPath);
  11488. return togo;
  11489. };
  11490. fluid.model.transform.literalValue = function (expanderSpec) {
  11491. return expanderSpec.value;
  11492. };
  11493. fluid.defaults("fluid.model.transform.literalValue", {
  11494. gradeNames: "fluid.standardOutputTransformFunction"
  11495. });
  11496. fluid.model.transform.arrayValue = fluid.makeArray;
  11497. fluid.defaults("fluid.model.transform.arrayValue", {
  11498. gradeNames: "fluid.standardTransformFunction"
  11499. });
  11500. fluid.model.transform.count = function (value) {
  11501. return fluid.makeArray(value).length;
  11502. };
  11503. fluid.defaults("fluid.model.transform.count", {
  11504. gradeNames: "fluid.standardTransformFunction"
  11505. });
  11506. fluid.model.transform.firstValue = function (expandSpec, expander) {
  11507. if (!expandSpec.values || !expandSpec.values.length) {
  11508. fluid.fail("firstValue transformer requires an array of values at path named \"values\", supplied", expandSpec);
  11509. }
  11510. for (var i = 0; i < expandSpec.values.length; i++) {
  11511. var value = expandSpec.values[i];
  11512. var expanded = expander.expand(value);
  11513. if (expanded !== undefined) {
  11514. return expanded;
  11515. }
  11516. }
  11517. };
  11518. fluid.defaults("fluid.model.transform.firstValue", {
  11519. gradeNames: "fluid.transformFunction"
  11520. });
  11521. // TODO: Incomplete implementation which only checks expected paths
  11522. fluid.deepEquals = function (expected, actual, stats) {
  11523. if (fluid.isPrimitive(expected)) {
  11524. if (expected === actual) {
  11525. ++stats.matchCount;
  11526. } else {
  11527. ++stats.mismatchCount;
  11528. stats.messages.push("Value mismatch at path " + stats.path + ": expected " + expected + " actual " + actual);
  11529. }
  11530. }
  11531. else {
  11532. if (typeof(expected) !== typeof(actual)) {
  11533. ++stats.mismatchCount;
  11534. stats.messages.push("Type mismatch at path " + stats.path + ": expected " + typeof(expected) + " actual " + typeof(actual));
  11535. } else {
  11536. fluid.each(expected, function (value, key) {
  11537. stats.pathOps.push(key);
  11538. fluid.deepEquals(expected[key], actual[key], stats);
  11539. stats.pathOps.pop(key);
  11540. });
  11541. }
  11542. }
  11543. };
  11544. fluid.model.transform.matchValue = function (expected, actual) {
  11545. if (fluid.isPrimitive(expected)) {
  11546. return expected === actual ? 1 : 0;
  11547. } else {
  11548. var stats = {
  11549. matchCount: 0,
  11550. mismatchCount: 0,
  11551. messages: []
  11552. };
  11553. fluid.model.makePathStack(stats, "path");
  11554. fluid.deepEquals(expected, actual, stats);
  11555. return stats.matchCount;
  11556. }
  11557. };
  11558. // unsupported, NON-API function
  11559. fluid.model.transform.compareMatches = function (speca, specb) {
  11560. return specb.matchCount - speca.matchCount;
  11561. };
  11562. fluid.firstDefined = function (a, b) {
  11563. return a === undefined ? b : a;
  11564. };
  11565. // unsupported, NON-API function
  11566. fluid.model.transform.matchValueMapperFull = function (outerValue, expander, expandSpec) {
  11567. var o = expandSpec.options;
  11568. if (o.length === 0) {
  11569. fluid.fail("valueMapper supplied empty list of options: ", expandSpec);
  11570. }
  11571. if (o.length === 1) {
  11572. return 0;
  11573. }
  11574. var matchPower = [];
  11575. for (var i = 0; i < o.length; ++i) {
  11576. var option = o[i];
  11577. var value = fluid.firstDefined(fluid.model.transform.getValue(option.inputPath, undefined, expander),
  11578. outerValue);
  11579. var matchCount = fluid.model.transform.matchValue(option.undefinedInputValue ? undefined : option.inputValue, value);
  11580. matchPower[i] = {index: i, matchCount: matchCount};
  11581. }
  11582. matchPower.sort(fluid.model.transform.compareMatches);
  11583. return matchPower[0].matchCount === matchPower[1].matchCount ? -1 : matchPower[0].index;
  11584. };
  11585. fluid.model.transform.valueMapper = function (expandSpec, expander) {
  11586. if (!expandSpec.options) {
  11587. fluid.fail("demultiplexValue requires a list or hash of options at path named \"options\", supplied ", expandSpec);
  11588. }
  11589. var value = fluid.model.transform.getValue(expandSpec.inputPath, undefined, expander);
  11590. var deref = fluid.isArrayable(expandSpec.options) ? // long form with list of records
  11591. function (testVal) {
  11592. var index = fluid.model.transform.matchValueMapperFull(testVal, expander, expandSpec);
  11593. return index === -1 ? null : expandSpec.options[index];
  11594. } :
  11595. function (testVal) {
  11596. return expandSpec.options[testVal];
  11597. };
  11598. var indexed = deref(value);
  11599. if (!indexed) {
  11600. // if no branch matches, try again using this value - WARNING, this seriously
  11601. // threatens invertibility
  11602. indexed = deref(expandSpec.defaultInputValue);
  11603. }
  11604. if (!indexed) {
  11605. return;
  11606. }
  11607. var outputValue = fluid.isPrimitive(indexed) ? indexed :
  11608. (indexed.undefinedOutputValue ? undefined :
  11609. (indexed.outputValue === undefined ? expandSpec.defaultOutputValue : indexed.outputValue));
  11610. var outputPath = indexed.outputPath === undefined ? expandSpec.outputPath : indexed.outputPath;
  11611. return fluid.model.transform.setValue(outputPath, outputValue, expander);
  11612. };
  11613. fluid.model.transform.valueMapper.invert = function (expandSpec, expander) {
  11614. var options = [];
  11615. var togo = {
  11616. type: "fluid.model.transform.valueMapper",
  11617. options: options
  11618. };
  11619. var isArray = fluid.isArrayable(expandSpec.options);
  11620. var findCustom = function (name) {
  11621. return fluid.find(expandSpec.options, function (option) {
  11622. if (option[name]) {
  11623. return true;
  11624. }
  11625. });
  11626. };
  11627. var anyCustomOutput = findCustom("outputPath");
  11628. var anyCustomInput = findCustom("inputPath");
  11629. if (!anyCustomOutput) {
  11630. togo.inputPath = fluid.model.composePaths(expander.outputPrefix, expandSpec.outputPath);
  11631. }
  11632. if (!anyCustomInput) {
  11633. togo.outputPath = fluid.model.composePaths(expander.inputPrefix, expandSpec.inputPath);
  11634. }
  11635. var def = fluid.firstDefined;
  11636. fluid.each(expandSpec.options, function (option, key) {
  11637. var outOption = {};
  11638. var origInputValue = def(isArray ? option.inputValue : key, expandSpec.defaultInputValue);
  11639. if (origInputValue === undefined) {
  11640. fluid.fail("Failure inverting configuration for valueMapper - inputValue could not be resolved for record " + key + ": ", expandSpec);
  11641. }
  11642. outOption.outputValue = origInputValue;
  11643. var origOutputValue = def(option.outputValue, expandSpec.defaultOutputValue);
  11644. outOption.inputValue = origOutputValue;
  11645. if (anyCustomOutput) {
  11646. outOption.inputPath = fluid.model.composePaths(expander.outputPrefix, def(option.outputPath, expandSpec.outputPath));
  11647. }
  11648. if (anyCustomInput) {
  11649. outOption.outputPath = fluid.model.composePaths(expander.inputPrefix, def(option.inputPath, expandSpec.inputPath));
  11650. }
  11651. options.push(outOption);
  11652. });
  11653. return togo;
  11654. };
  11655. fluid.model.transform.valueMapper.collect = function (expandSpec, expander) {
  11656. var togo = [];
  11657. fluid.model.transform.accumulateInputPath(expandSpec.inputPath, expander, togo);
  11658. fluid.each(expandSpec.options, function (option) {
  11659. fluid.model.transform.accumulateInputPath(option.inputPath, expander, togo);
  11660. });
  11661. return togo;
  11662. };
  11663. fluid.defaults("fluid.model.transform.valueMapper", {
  11664. gradeNames: ["fluid.transformFunction", "fluid.lens"],
  11665. invertConfiguration: "fluid.model.transform.valueMapper.invert",
  11666. collectInputPaths: "fluid.model.transform.valueMapper.collect"
  11667. });
  11668. // TODO: prefixApplier is an expander which is currently unused and untested
  11669. fluid.model.transform.prefixApplier = function (expandSpec, expander) {
  11670. if (expandSpec.inputPrefix) {
  11671. expander.inputPrefixOp.push(expandSpec.inputPrefix);
  11672. }
  11673. if (expandSpec.outputPrefix) {
  11674. expander.outputPrefixOp.push(expandSpec.outputPrefix);
  11675. }
  11676. expander.expand(expandSpec.value);
  11677. if (expandSpec.inputPrefix) {
  11678. expander.inputPrefixOp.pop();
  11679. }
  11680. if (expandSpec.outputPrefix) {
  11681. expander.outputPrefixOp.pop();
  11682. }
  11683. };
  11684. fluid.defaults("fluid.model.transform.prefixApplier", {
  11685. gradeNames: ["fluid.transformFunction"]
  11686. });
  11687. // unsupported, NON-API function
  11688. fluid.model.makePathStack = function (expander, prefixName) {
  11689. var stack = expander[prefixName + "Stack"] = [];
  11690. expander[prefixName] = "";
  11691. return {
  11692. push: function (prefix) {
  11693. var newPath = fluid.model.composePaths(expander[prefixName], prefix);
  11694. stack.push(expander[prefixName]);
  11695. expander[prefixName] = newPath;
  11696. },
  11697. pop: function () {
  11698. expander[prefixName] = stack.pop();
  11699. }
  11700. };
  11701. };
  11702. // unsupported, NON-API function
  11703. fluid.model.transform.expandExpander = function (expandSpec, expander) {
  11704. var typeName = expandSpec.type;
  11705. if (!typeName) {
  11706. fluid.fail("Transformation record is missing a type name: ", expandSpec);
  11707. }
  11708. if (typeName.indexOf(".") === -1) {
  11709. typeName = "fluid.model.transform." + typeName;
  11710. }
  11711. var expanderFn = fluid.getGlobalValue(typeName);
  11712. var expdef = fluid.defaults(typeName);
  11713. if (typeof(expanderFn) !== "function") {
  11714. fluid.fail("Transformation record specifies transformation function with name " +
  11715. expandSpec.type + " which is not a function - ", expanderFn);
  11716. }
  11717. if (!fluid.hasGrade(expdef, "fluid.transformFunction")) {
  11718. // If no suitable grade is set up, assume that it is intended to be used as a standardTransformFunction
  11719. expdef = fluid.defaults("fluid.standardTransformFunction");
  11720. }
  11721. var expanderArgs = [expandSpec, expander];
  11722. if (fluid.hasGrade(expdef, "fluid.standardInputTransformFunction")) {
  11723. var expanded = fluid.model.transform.getValue(expandSpec.inputPath, expandSpec.value, expander);
  11724. expanderArgs[0] = expanded;
  11725. expanderArgs[2] = expandSpec;
  11726. }
  11727. var transformed = expanderFn.apply(null, expanderArgs);
  11728. if (fluid.hasGrade(expdef, "fluid.standardOutputTransformFunction")) {
  11729. transformed = fluid.model.transform.setValue(expandSpec.outputPath, transformed, expander);
  11730. }
  11731. return transformed;
  11732. };
  11733. // unsupported, NON-API function
  11734. fluid.model.transform.expandWildcards = function (expander, source) {
  11735. fluid.each(source, function (value, key) {
  11736. var q = expander.queued;
  11737. expander.pathOp.push(fluid.pathUtil.escapeSegment(key.toString()));
  11738. for (var i = 0; i < q.length; ++i) {
  11739. if (fluid.pathUtil.matchPath(q[i].matchPath, expander.path, true)) {
  11740. var esCopy = fluid.copy(q[i].expandSpec);
  11741. if (esCopy.inputPath === undefined || fluid.model.transform.hasWildcard(esCopy.inputPath)) {
  11742. esCopy.inputPath = "";
  11743. }
  11744. // TODO: allow some kind of interpolation for output path
  11745. expander.inputPrefixOp.push(expander.path);
  11746. expander.outputPrefixOp.push(expander.path);
  11747. fluid.model.transform.expandExpander(esCopy, expander);
  11748. expander.outputPrefixOp.pop();
  11749. expander.inputPrefixOp.pop();
  11750. }
  11751. }
  11752. if (!fluid.isPrimitive(value)) {
  11753. fluid.model.transform.expandWildcards(expander, value);
  11754. }
  11755. expander.pathOp.pop();
  11756. });
  11757. };
  11758. // unsupported, NON-API function
  11759. fluid.model.transform.hasWildcard = function (path) {
  11760. return typeof(path) === "string" && path.indexOf("*") !== -1;
  11761. };
  11762. // unsupported, NON-API function
  11763. fluid.model.transform.maybePushWildcard = function (expander, expandSpec) {
  11764. var hw = fluid.model.transform.hasWildcard;
  11765. var matchPath;
  11766. if (hw(expandSpec.inputPath)) {
  11767. matchPath = fluid.model.composePaths(expander.inputPrefix, expandSpec.inputPath);
  11768. }
  11769. else if (hw(expander.outputPrefix) || hw(expandSpec.outputPath)) {
  11770. matchPath = fluid.model.composePaths(expander.outputPrefix, expandSpec.outputPath);
  11771. }
  11772. if (matchPath) {
  11773. expander.queued.push({expandSpec: expandSpec, outputPrefix: expander.outputPrefix, inputPrefix: expander.inputPrefix, matchPath: matchPath});
  11774. return true;
  11775. }
  11776. return false;
  11777. };
  11778. // From UIOptions utility fluid.uiOptions.sortByKeyLength!
  11779. fluid.model.sortByKeyLength = function (inObject) {
  11780. var keys = fluid.keys(inObject);
  11781. return keys.sort(fluid.compareStringLength(true));
  11782. };
  11783. // Three handler functions operating the (currently) three different processing modes
  11784. // unsupported, NON-API function
  11785. fluid.model.transform.handleExpandExpander = function (expander, expandSpec) {
  11786. if (fluid.model.transform.maybePushWildcard(expander, expandSpec)) {
  11787. return;
  11788. }
  11789. else {
  11790. return fluid.model.transform.expandExpander(expandSpec, expander);
  11791. }
  11792. };
  11793. // unsupported, NON-API function
  11794. fluid.model.transform.handleInvertExpander = function (expander, expandSpec, expdef) {
  11795. var invertor = expdef.invertConfiguration;
  11796. if (invertor) {
  11797. var inverted = fluid.invokeGlobalFunction(invertor, [expandSpec, expander]);
  11798. expander.inverted.push(inverted);
  11799. }
  11800. };
  11801. // unsupported, NON-API function
  11802. fluid.model.transform.handlerCollectExpander = function (expander, expandSpec, expdef) {
  11803. var standardInput = fluid.hasGrade(expdef, "fluid.standardInputTransformFunction");
  11804. if (standardInput) {
  11805. fluid.model.transform.accumulateInputPath(expandSpec.inputPath, expander, expander.inputPaths);
  11806. }
  11807. else {
  11808. var collector = expdef.collectInputPaths;
  11809. if (collector) {
  11810. var collected = fluid.makeArray(fluid.invokeGlobalFunction(collector, [expandSpec, expander]));
  11811. expander.inputPaths = expander.inputPaths.concat(collected);
  11812. }
  11813. }
  11814. };
  11815. // unsupported, NON-API function
  11816. fluid.model.transform.expandValue = function (rule, expander) {
  11817. if (typeof(rule) === "string") {
  11818. rule = fluid.model.transform.pathToRule(rule);
  11819. }
  11820. // special dispensation to allow "value" at top level
  11821. // TODO: Proper escaping rules
  11822. else if (rule.value && expander.outputPrefix !== "") {
  11823. rule = fluid.model.transform.valueToRule(rule.value);
  11824. }
  11825. var togo;
  11826. if (rule.expander) {
  11827. var expanders = fluid.makeArray(rule.expander);
  11828. for (var i = 0; i < expanders.length; ++i) {
  11829. var expandSpec = expanders[i];
  11830. var expdef = fluid.defaults(expandSpec.type);
  11831. var returned = expander.expanderHandler(expander, expandSpec, expdef);
  11832. if (returned !== undefined) {
  11833. togo = returned;
  11834. }
  11835. }
  11836. }
  11837. // always apply rules with shortest keys first
  11838. var keys = fluid.model.sortByKeyLength(rule);
  11839. for (var i = 0; i < keys.length; ++i) { // jslint:ok - already defined
  11840. var key = keys[i];
  11841. if (key !== "expander") {
  11842. var value = rule[key];
  11843. expander.outputPrefixOp.push(key);
  11844. expander.expand(value, expander);
  11845. expander.outputPrefixOp.pop();
  11846. }
  11847. }
  11848. togo = fluid.get(expander.target, expander.outputPrefix);
  11849. return togo;
  11850. };
  11851. // unsupported, NON-API function
  11852. fluid.model.transform.makeExpander = function (expander, handleFn, expandFn) {
  11853. expandFn = expandFn || fluid.model.transform.expandValue;
  11854. expander.expand = function (rules) {
  11855. return expandFn(rules, expander);
  11856. };
  11857. expander.outputPrefixOp = fluid.model.makePathStack(expander, "outputPrefix");
  11858. expander.inputPrefixOp = fluid.model.makePathStack(expander, "inputPrefix");
  11859. expander.expanderHandler = handleFn;
  11860. };
  11861. fluid.model.transform.invertConfiguration = function (rules) {
  11862. var expander = {
  11863. inverted: []
  11864. };
  11865. fluid.model.transform.makeExpander(expander, fluid.model.transform.handleInvertExpander);
  11866. expander.expand(rules);
  11867. return {
  11868. expander: expander.inverted
  11869. };
  11870. };
  11871. fluid.model.transform.collectInputPaths = function (rules) {
  11872. var expander = {
  11873. inputPaths: []
  11874. };
  11875. fluid.model.transform.makeExpander(expander, fluid.model.transform.handlerCollectExpander);
  11876. expander.expand(rules);
  11877. return expander.inputPaths;
  11878. };
  11879. // unsupported, NON-API function
  11880. fluid.model.transform.flatSchemaStrategy = function (flatSchema) {
  11881. var keys = fluid.model.sortByKeyLength(flatSchema);
  11882. return function (root, segment, path) {
  11883. // TODO: clearly this implementation could be much more efficient
  11884. for (var i = 0; i < keys.length; ++i) {
  11885. var key = keys[i];
  11886. if (fluid.pathUtil.matchPath(key, path, true) !== null) {
  11887. return flatSchema[key];
  11888. }
  11889. }
  11890. };
  11891. };
  11892. // unsupported, NON-API function
  11893. fluid.model.transform.defaultSchemaValue = function (schemaValue) {
  11894. var type = fluid.isPrimitive(schemaValue) ? schemaValue : schemaValue.type;
  11895. return type === "array" ? [] : {};
  11896. };
  11897. // unsupported, NON-API function
  11898. fluid.model.transform.isomorphicSchemaStrategy = function (source, getConfig) {
  11899. return function (root, segment, path) {
  11900. var existing = fluid.get(source, path, getConfig);
  11901. return fluid.isArrayable(existing) ? "array" : "object";
  11902. };
  11903. };
  11904. // unsupported, NON-API function
  11905. fluid.model.transform.decodeStrategy = function (source, options, getConfig) {
  11906. if (options.isomorphic) {
  11907. return fluid.model.transform.isomorphicSchemaStrategy(source, getConfig);
  11908. }
  11909. else if (options.flatSchema) {
  11910. return fluid.model.transform.flatSchemaStrategy(options.flatSchema, getConfig);
  11911. }
  11912. };
  11913. // unsupported, NON-API function
  11914. fluid.model.transform.schemaToCreatorStrategy = function (strategy) {
  11915. return function (root, segment, path) {
  11916. if (root[segment] === undefined) {
  11917. var schemaValue = strategy(root, segment, path);
  11918. return root[segment] = fluid.model.transform.defaultSchemaValue(schemaValue);
  11919. }
  11920. };
  11921. };
  11922. /** Transforms a model by a sequence of rules. Parameters as for fluid.model.transform,
  11923. * only with an array accepted for "rules"
  11924. */
  11925. fluid.model.transform.sequence = function (source, rules, options) {
  11926. for (var i = 0; i < rules.length; ++i) {
  11927. source = fluid.model.transform(source, rules[i], options);
  11928. }
  11929. return source;
  11930. };
  11931. /**
  11932. * Transforms a model based on a specified expansion rules objects.
  11933. * Rules objects take the form of:
  11934. * {
  11935. * "target.path": "value.el.path" || {
  11936. * expander: {
  11937. * type: "expander.function.path",
  11938. * ...
  11939. * }
  11940. * }
  11941. * }
  11942. *
  11943. * @param {Object} source the model to transform
  11944. * @param {Object} rules a rules object containing instructions on how to transform the model
  11945. * @param {Object} options a set of rules governing the transformations. At present this may contain
  11946. * the values <code>isomorphic: true</code> indicating that the output model is to be governed by the
  11947. * same schema found in the input model, or <code>flatSchema</code> holding a flat schema object which
  11948. * consists of a hash of EL path specifications with wildcards, to the values "array"/"object" defining
  11949. * the schema to be used to construct missing trunk values.
  11950. */
  11951. fluid.model.transformWithRules = function (source, rules, options) {
  11952. options = options || {};
  11953. var parser = {
  11954. parse: fluid.pathUtil.parseEL,
  11955. compose: fluid.pathUtil.composePath
  11956. };
  11957. var getConfig = {
  11958. parser: parser,
  11959. strategies: [fluid.model.defaultFetchStrategy]
  11960. };
  11961. var schemaStrategy = fluid.model.transform.decodeStrategy(source, options, getConfig);
  11962. var setConfig = {
  11963. parser: parser,
  11964. strategies: [fluid.model.defaultFetchStrategy, schemaStrategy ? fluid.model.transform.schemaToCreatorStrategy(schemaStrategy)
  11965. : fluid.model.defaultCreatorStrategy]
  11966. };
  11967. var expander = {
  11968. source: source,
  11969. target: schemaStrategy ? fluid.model.transform.defaultSchemaValue(schemaStrategy(null, "", "")) : {},
  11970. resolverGetConfig: getConfig,
  11971. queued: []
  11972. };
  11973. fluid.model.transform.makeExpander(expander, fluid.model.transform.handleExpandExpander);
  11974. expander.applier = fluid.makeChangeApplier(expander.target, {resolverSetConfig: setConfig});
  11975. expander.expand(rules);
  11976. if (expander.queued.length > 0) {
  11977. expander.typeStack = [];
  11978. expander.pathOp = fluid.model.makePathStack(expander, "path");
  11979. fluid.model.transform.expandWildcards(expander, source);
  11980. }
  11981. return expander.target;
  11982. };
  11983. $.extend(fluid.model.transformWithRules, fluid.model.transform);
  11984. fluid.model.transform = fluid.model.transformWithRules;
  11985. })(jQuery, fluid_1_5);
  11986. /*
  11987. Copyright 2008-2010 University of Cambridge
  11988. Copyright 2008-2010 University of Toronto
  11989. Copyright 2010-2011 Lucendo Development Ltd.
  11990. Copyright 2010-2011 OCAD University
  11991. Licensed under the Educational Community License (ECL), Version 2.0 or the New
  11992. BSD license. You may not use this file except in compliance with one these
  11993. Licenses.
  11994. You may obtain a copy of the ECL 2.0 License and BSD License at
  11995. https://github.com/fluid-project/infusion/raw/master/Infusion-LICENSE.txt
  11996. */
  11997. // Declare dependencies
  11998. /*global fluid:true, fluid_1_5:true, jQuery*/
  11999. // JSLint options
  12000. /*jslint white: true, funcinvoke: true, elsecatch: true, operator: true, undef: true, newcap: true, nomen: true, regexp: true, bitwise: true, browser: true, forin: true, maxerr: 100, indent: 4 */
  12001. var fluid_1_5 = fluid_1_5 || {};
  12002. var fluid = fluid || fluid_1_5;
  12003. (function ($, fluid) {
  12004. // $().fluid("selectable", args)
  12005. // $().fluid("selectable".that()
  12006. // $().fluid("pager.pagerBar", args)
  12007. // $().fluid("reorderer", options)
  12008. /** Create a "bridge" from code written in the Fluid standard "that-ist" style,
  12009. * to the standard JQuery UI plugin architecture specified at http://docs.jquery.com/UI/Guidelines .
  12010. * Every Fluid component corresponding to the top-level standard signature (JQueryable, options)
  12011. * will automatically convert idiomatically to the JQuery UI standard via this adapter.
  12012. * Any return value which is a primitive or array type will become the return value
  12013. * of the "bridged" function - however, where this function returns a general hash
  12014. * (object) this is interpreted as forming part of the Fluid "return that" pattern,
  12015. * and the function will instead be bridged to "return this" as per JQuery standard,
  12016. * permitting chaining to occur. However, as a courtesy, the particular "this" returned
  12017. * will be augmented with a function that() which will allow the original return
  12018. * value to be retrieved if desired.
  12019. * @param {String} name The name under which the "plugin space" is to be injected into
  12020. * JQuery
  12021. * @param {Object} peer The root of the namespace corresponding to the peer object.
  12022. */
  12023. fluid.thatistBridge = function (name, peer) {
  12024. var togo = function (funcname) {
  12025. var segs = funcname.split(".");
  12026. var move = peer;
  12027. for (var i = 0; i < segs.length; ++i) {
  12028. move = move[segs[i]];
  12029. }
  12030. var args = [this];
  12031. if (arguments.length === 2) {
  12032. args = args.concat($.makeArray(arguments[1]));
  12033. }
  12034. var ret = move.apply(null, args);
  12035. this.that = function () {
  12036. return ret;
  12037. };
  12038. var type = typeof(ret);
  12039. return !ret || type === "string" || type === "number" || type === "boolean"
  12040. || (ret && ret.length !== undefined) ? ret : this;
  12041. };
  12042. $.fn[name] = togo;
  12043. return togo;
  12044. };
  12045. fluid.thatistBridge("fluid", fluid);
  12046. fluid.thatistBridge("fluid_1_5", fluid_1_5);
  12047. /*************************************************************************
  12048. * Tabindex normalization - compensate for browser differences in naming
  12049. * and function of "tabindex" attribute and tabbing order.
  12050. */
  12051. // -- Private functions --
  12052. var normalizeTabindexName = function () {
  12053. return $.browser.msie ? "tabIndex" : "tabindex";
  12054. };
  12055. var canHaveDefaultTabindex = function (elements) {
  12056. if (elements.length <= 0) {
  12057. return false;
  12058. }
  12059. return $(elements[0]).is("a, input, button, select, area, textarea, object");
  12060. };
  12061. var getValue = function (elements) {
  12062. if (elements.length <= 0) {
  12063. return undefined;
  12064. }
  12065. if (!fluid.tabindex.hasAttr(elements)) {
  12066. return canHaveDefaultTabindex(elements) ? Number(0) : undefined;
  12067. }
  12068. // Get the attribute and return it as a number value.
  12069. var value = elements.attr(normalizeTabindexName());
  12070. return Number(value);
  12071. };
  12072. var setValue = function (elements, toIndex) {
  12073. return elements.each(function (i, item) {
  12074. $(item).attr(normalizeTabindexName(), toIndex);
  12075. });
  12076. };
  12077. // -- Public API --
  12078. /**
  12079. * Gets the value of the tabindex attribute for the first item, or sets the tabindex value of all elements
  12080. * if toIndex is specified.
  12081. *
  12082. * @param {String|Number} toIndex
  12083. */
  12084. fluid.tabindex = function (target, toIndex) {
  12085. target = $(target);
  12086. if (toIndex !== null && toIndex !== undefined) {
  12087. return setValue(target, toIndex);
  12088. } else {
  12089. return getValue(target);
  12090. }
  12091. };
  12092. /**
  12093. * Removes the tabindex attribute altogether from each element.
  12094. */
  12095. fluid.tabindex.remove = function (target) {
  12096. target = $(target);
  12097. return target.each(function (i, item) {
  12098. $(item).removeAttr(normalizeTabindexName());
  12099. });
  12100. };
  12101. /**
  12102. * Determines if an element actually has a tabindex attribute present.
  12103. */
  12104. fluid.tabindex.hasAttr = function (target) {
  12105. target = $(target);
  12106. if (target.length <= 0) {
  12107. return false;
  12108. }
  12109. var togo = target.map(
  12110. function () {
  12111. var attributeNode = this.getAttributeNode(normalizeTabindexName());
  12112. return attributeNode ? attributeNode.specified : false;
  12113. }
  12114. );
  12115. return togo.length === 1 ? togo[0] : togo;
  12116. };
  12117. /**
  12118. * Determines if an element either has a tabindex attribute or is naturally tab-focussable.
  12119. */
  12120. fluid.tabindex.has = function (target) {
  12121. target = $(target);
  12122. return fluid.tabindex.hasAttr(target) || canHaveDefaultTabindex(target);
  12123. };
  12124. // Keyboard navigation
  12125. // Public, static constants needed by the rest of the library.
  12126. fluid.a11y = $.a11y || {};
  12127. fluid.a11y.orientation = {
  12128. HORIZONTAL: 0,
  12129. VERTICAL: 1,
  12130. BOTH: 2
  12131. };
  12132. var UP_DOWN_KEYMAP = {
  12133. next: $.ui.keyCode.DOWN,
  12134. previous: $.ui.keyCode.UP
  12135. };
  12136. var LEFT_RIGHT_KEYMAP = {
  12137. next: $.ui.keyCode.RIGHT,
  12138. previous: $.ui.keyCode.LEFT
  12139. };
  12140. // Private functions.
  12141. var unwrap = function (element) {
  12142. return element.jquery ? element[0] : element; // Unwrap the element if it's a jQuery.
  12143. };
  12144. var makeElementsTabFocussable = function (elements) {
  12145. // If each element doesn't have a tabindex, or has one set to a negative value, set it to 0.
  12146. elements.each(function (idx, item) {
  12147. item = $(item);
  12148. if (!item.fluid("tabindex.has") || item.fluid("tabindex") < 0) {
  12149. item.fluid("tabindex", 0);
  12150. }
  12151. });
  12152. };
  12153. // Public API.
  12154. /**
  12155. * Makes all matched elements available in the tab order by setting their tabindices to "0".
  12156. */
  12157. fluid.tabbable = function (target) {
  12158. target = $(target);
  12159. makeElementsTabFocussable(target);
  12160. };
  12161. /***********************************************************************
  12162. * Selectable functionality - geometrising a set of nodes such that they
  12163. * can be navigated (by setting focus) using a set of directional keys
  12164. */
  12165. var CONTEXT_KEY = "selectionContext";
  12166. var NO_SELECTION = -32768;
  12167. var cleanUpWhenLeavingContainer = function (selectionContext) {
  12168. if (selectionContext.activeItemIndex !== NO_SELECTION) {
  12169. if (selectionContext.options.onLeaveContainer) {
  12170. selectionContext.options.onLeaveContainer(
  12171. selectionContext.selectables[selectionContext.activeItemIndex]
  12172. );
  12173. } else if (selectionContext.options.onUnselect) {
  12174. selectionContext.options.onUnselect(
  12175. selectionContext.selectables[selectionContext.activeItemIndex]
  12176. );
  12177. }
  12178. }
  12179. if (!selectionContext.options.rememberSelectionState) {
  12180. selectionContext.activeItemIndex = NO_SELECTION;
  12181. }
  12182. };
  12183. /**
  12184. * Does the work of selecting an element and delegating to the client handler.
  12185. */
  12186. var drawSelection = function (elementToSelect, handler) {
  12187. if (handler) {
  12188. handler(elementToSelect);
  12189. }
  12190. };
  12191. /**
  12192. * Does does the work of unselecting an element and delegating to the client handler.
  12193. */
  12194. var eraseSelection = function (selectedElement, handler) {
  12195. if (handler && selectedElement) {
  12196. handler(selectedElement);
  12197. }
  12198. };
  12199. var unselectElement = function (selectedElement, selectionContext) {
  12200. eraseSelection(selectedElement, selectionContext.options.onUnselect);
  12201. };
  12202. var selectElement = function (elementToSelect, selectionContext) {
  12203. // It's possible that we're being called programmatically, in which case we should clear any previous selection.
  12204. unselectElement(selectionContext.selectedElement(), selectionContext);
  12205. elementToSelect = unwrap(elementToSelect);
  12206. var newIndex = selectionContext.selectables.index(elementToSelect);
  12207. // Next check if the element is a known selectable. If not, do nothing.
  12208. if (newIndex === -1) {
  12209. return;
  12210. }
  12211. // Select the new element.
  12212. selectionContext.activeItemIndex = newIndex;
  12213. drawSelection(elementToSelect, selectionContext.options.onSelect);
  12214. };
  12215. var selectableFocusHandler = function (selectionContext) {
  12216. return function (evt) {
  12217. // FLUID-3590: newer browsers (FF 3.6, Webkit 4) have a form of "bug" in that they will go bananas
  12218. // on attempting to move focus off an element which has tabindex dynamically set to -1.
  12219. $(evt.target).fluid("tabindex", 0);
  12220. selectElement(evt.target, selectionContext);
  12221. // Force focus not to bubble on some browsers.
  12222. return evt.stopPropagation();
  12223. };
  12224. };
  12225. var selectableBlurHandler = function (selectionContext) {
  12226. return function (evt) {
  12227. $(evt.target).fluid("tabindex", selectionContext.options.selectablesTabindex);
  12228. unselectElement(evt.target, selectionContext);
  12229. // Force blur not to bubble on some browsers.
  12230. return evt.stopPropagation();
  12231. };
  12232. };
  12233. var reifyIndex = function (sc_that) {
  12234. var elements = sc_that.selectables;
  12235. if (sc_that.activeItemIndex >= elements.length) {
  12236. sc_that.activeItemIndex = (sc_that.options.noWrap ? elements.length - 1 : 0);
  12237. }
  12238. if (sc_that.activeItemIndex < 0 && sc_that.activeItemIndex !== NO_SELECTION) {
  12239. sc_that.activeItemIndex = (sc_that.options.noWrap ? 0 : elements.length - 1);
  12240. }
  12241. if (sc_that.activeItemIndex >= 0) {
  12242. fluid.focus(elements[sc_that.activeItemIndex]);
  12243. }
  12244. };
  12245. var prepareShift = function (selectionContext) {
  12246. // FLUID-3590: FF 3.6 and Safari 4.x won't fire blur() when programmatically moving focus.
  12247. var selElm = selectionContext.selectedElement();
  12248. if (selElm) {
  12249. fluid.blur(selElm);
  12250. }
  12251. unselectElement(selectionContext.selectedElement(), selectionContext);
  12252. if (selectionContext.activeItemIndex === NO_SELECTION) {
  12253. selectionContext.activeItemIndex = -1;
  12254. }
  12255. };
  12256. var focusNextElement = function (selectionContext) {
  12257. prepareShift(selectionContext);
  12258. ++selectionContext.activeItemIndex;
  12259. reifyIndex(selectionContext);
  12260. };
  12261. var focusPreviousElement = function (selectionContext) {
  12262. prepareShift(selectionContext);
  12263. --selectionContext.activeItemIndex;
  12264. reifyIndex(selectionContext);
  12265. };
  12266. var arrowKeyHandler = function (selectionContext, keyMap, userHandlers) {
  12267. return function (evt) {
  12268. if (evt.which === keyMap.next) {
  12269. focusNextElement(selectionContext);
  12270. evt.preventDefault();
  12271. } else if (evt.which === keyMap.previous) {
  12272. focusPreviousElement(selectionContext);
  12273. evt.preventDefault();
  12274. }
  12275. };
  12276. };
  12277. var getKeyMapForDirection = function (direction) {
  12278. // Determine the appropriate mapping for next and previous based on the specified direction.
  12279. var keyMap;
  12280. if (direction === fluid.a11y.orientation.HORIZONTAL) {
  12281. keyMap = LEFT_RIGHT_KEYMAP;
  12282. }
  12283. else if (direction === fluid.a11y.orientation.VERTICAL) {
  12284. // Assume vertical in any other case.
  12285. keyMap = UP_DOWN_KEYMAP;
  12286. }
  12287. return keyMap;
  12288. };
  12289. var tabKeyHandler = function (selectionContext) {
  12290. return function (evt) {
  12291. if (evt.which !== $.ui.keyCode.TAB) {
  12292. return;
  12293. }
  12294. cleanUpWhenLeavingContainer(selectionContext);
  12295. // Catch Shift-Tab and note that focus is on its way out of the container.
  12296. if (evt.shiftKey) {
  12297. selectionContext.focusIsLeavingContainer = true;
  12298. }
  12299. };
  12300. };
  12301. var containerFocusHandler = function (selectionContext) {
  12302. return function (evt) {
  12303. var shouldOrig = selectionContext.options.autoSelectFirstItem;
  12304. var shouldSelect = typeof(shouldOrig) === "function" ? shouldOrig() : shouldOrig;
  12305. // Override the autoselection if we're on the way out of the container.
  12306. if (selectionContext.focusIsLeavingContainer) {
  12307. shouldSelect = false;
  12308. }
  12309. // This target check works around the fact that sometimes focus bubbles, even though it shouldn't.
  12310. if (shouldSelect && evt.target === selectionContext.container.get(0)) {
  12311. if (selectionContext.activeItemIndex === NO_SELECTION) {
  12312. selectionContext.activeItemIndex = 0;
  12313. }
  12314. fluid.focus(selectionContext.selectables[selectionContext.activeItemIndex]);
  12315. }
  12316. // Force focus not to bubble on some browsers.
  12317. return evt.stopPropagation();
  12318. };
  12319. };
  12320. var containerBlurHandler = function (selectionContext) {
  12321. return function (evt) {
  12322. selectionContext.focusIsLeavingContainer = false;
  12323. // Force blur not to bubble on some browsers.
  12324. return evt.stopPropagation();
  12325. };
  12326. };
  12327. var makeElementsSelectable = function (container, defaults, userOptions) {
  12328. var options = $.extend(true, {}, defaults, userOptions);
  12329. var keyMap = getKeyMapForDirection(options.direction);
  12330. var selectableElements = options.selectableElements ? options.selectableElements :
  12331. container.find(options.selectableSelector);
  12332. // Context stores the currently active item(undefined to start) and list of selectables.
  12333. var that = {
  12334. container: container,
  12335. activeItemIndex: NO_SELECTION,
  12336. selectables: selectableElements,
  12337. focusIsLeavingContainer: false,
  12338. options: options
  12339. };
  12340. that.selectablesUpdated = function (focusedItem) {
  12341. // Remove selectables from the tab order and add focus/blur handlers
  12342. if (typeof(that.options.selectablesTabindex) === "number") {
  12343. that.selectables.fluid("tabindex", that.options.selectablesTabindex);
  12344. }
  12345. that.selectables.unbind("focus." + CONTEXT_KEY);
  12346. that.selectables.unbind("blur." + CONTEXT_KEY);
  12347. that.selectables.bind("focus." + CONTEXT_KEY, selectableFocusHandler(that));
  12348. that.selectables.bind("blur." + CONTEXT_KEY, selectableBlurHandler(that));
  12349. if (keyMap && that.options.noBubbleListeners) {
  12350. that.selectables.unbind("keydown." + CONTEXT_KEY);
  12351. that.selectables.bind("keydown." + CONTEXT_KEY, arrowKeyHandler(that, keyMap));
  12352. }
  12353. if (focusedItem) {
  12354. selectElement(focusedItem, that);
  12355. }
  12356. else {
  12357. reifyIndex(that);
  12358. }
  12359. };
  12360. that.refresh = function () {
  12361. if (!that.options.selectableSelector) {
  12362. fluid.fail("Cannot refresh selectable context which was not initialised by a selector");
  12363. }
  12364. that.selectables = container.find(options.selectableSelector);
  12365. that.selectablesUpdated();
  12366. };
  12367. that.selectedElement = function () {
  12368. return that.activeItemIndex < 0 ? null : that.selectables[that.activeItemIndex];
  12369. };
  12370. // Add various handlers to the container.
  12371. if (keyMap && !that.options.noBubbleListeners) {
  12372. container.keydown(arrowKeyHandler(that, keyMap));
  12373. }
  12374. container.keydown(tabKeyHandler(that));
  12375. container.focus(containerFocusHandler(that));
  12376. container.blur(containerBlurHandler(that));
  12377. that.selectablesUpdated();
  12378. return that;
  12379. };
  12380. /**
  12381. * Makes all matched elements selectable with the arrow keys.
  12382. * Supply your own handlers object with onSelect: and onUnselect: properties for custom behaviour.
  12383. * Options provide configurability, including direction: and autoSelectFirstItem:
  12384. * Currently supported directions are jQuery.a11y.directions.HORIZONTAL and VERTICAL.
  12385. */
  12386. fluid.selectable = function (target, options) {
  12387. target = $(target);
  12388. var that = makeElementsSelectable(target, fluid.selectable.defaults, options);
  12389. fluid.setScopedData(target, CONTEXT_KEY, that);
  12390. return that;
  12391. };
  12392. /**
  12393. * Selects the specified element.
  12394. */
  12395. fluid.selectable.select = function (target, toSelect) {
  12396. fluid.focus(toSelect);
  12397. };
  12398. /**
  12399. * Selects the next matched element.
  12400. */
  12401. fluid.selectable.selectNext = function (target) {
  12402. target = $(target);
  12403. focusNextElement(fluid.getScopedData(target, CONTEXT_KEY));
  12404. };
  12405. /**
  12406. * Selects the previous matched element.
  12407. */
  12408. fluid.selectable.selectPrevious = function (target) {
  12409. target = $(target);
  12410. focusPreviousElement(fluid.getScopedData(target, CONTEXT_KEY));
  12411. };
  12412. /**
  12413. * Returns the currently selected item wrapped as a jQuery object.
  12414. */
  12415. fluid.selectable.currentSelection = function (target) {
  12416. target = $(target);
  12417. var that = fluid.getScopedData(target, CONTEXT_KEY);
  12418. return $(that.selectedElement());
  12419. };
  12420. fluid.selectable.defaults = {
  12421. direction: fluid.a11y.orientation.VERTICAL,
  12422. selectablesTabindex: -1,
  12423. autoSelectFirstItem: true,
  12424. rememberSelectionState: true,
  12425. selectableSelector: ".selectable",
  12426. selectableElements: null,
  12427. onSelect: null,
  12428. onUnselect: null,
  12429. onLeaveContainer: null,
  12430. noWrap: false
  12431. };
  12432. /********************************************************************
  12433. * Activation functionality - declaratively associating actions with
  12434. * a set of keyboard bindings.
  12435. */
  12436. var checkForModifier = function (binding, evt) {
  12437. // If no modifier was specified, just return true.
  12438. if (!binding.modifier) {
  12439. return true;
  12440. }
  12441. var modifierKey = binding.modifier;
  12442. var isCtrlKeyPresent = modifierKey && evt.ctrlKey;
  12443. var isAltKeyPresent = modifierKey && evt.altKey;
  12444. var isShiftKeyPresent = modifierKey && evt.shiftKey;
  12445. return isCtrlKeyPresent || isAltKeyPresent || isShiftKeyPresent;
  12446. };
  12447. /** Constructs a raw "keydown"-facing handler, given a binding entry. This
  12448. * checks whether the key event genuinely triggers the event and forwards it
  12449. * to any "activateHandler" registered in the binding.
  12450. */
  12451. var makeActivationHandler = function (binding) {
  12452. return function (evt) {
  12453. var target = evt.target;
  12454. if (!fluid.enabled(target)) {
  12455. return;
  12456. }
  12457. // The following 'if' clause works in the real world, but there's a bug in the jQuery simulation
  12458. // that causes keyboard simulation to fail in Safari, causing our tests to fail:
  12459. // http://ui.jquery.com/bugs/ticket/3229
  12460. // The replacement 'if' clause works around this bug.
  12461. // When this issue is resolved, we should revert to the original clause.
  12462. // if (evt.which === binding.key && binding.activateHandler && checkForModifier(binding, evt)) {
  12463. var code = evt.which ? evt.which : evt.keyCode;
  12464. if (code === binding.key && binding.activateHandler && checkForModifier(binding, evt)) {
  12465. var event = $.Event("fluid-activate");
  12466. $(target).trigger(event, [binding.activateHandler]);
  12467. if (event.isDefaultPrevented()) {
  12468. evt.preventDefault();
  12469. }
  12470. }
  12471. };
  12472. };
  12473. var makeElementsActivatable = function (elements, onActivateHandler, defaultKeys, options) {
  12474. // Create bindings for each default key.
  12475. var bindings = [];
  12476. $(defaultKeys).each(function (index, key) {
  12477. bindings.push({
  12478. modifier: null,
  12479. key: key,
  12480. activateHandler: onActivateHandler
  12481. });
  12482. });
  12483. // Merge with any additional key bindings.
  12484. if (options && options.additionalBindings) {
  12485. bindings = bindings.concat(options.additionalBindings);
  12486. }
  12487. fluid.initEnablement(elements);
  12488. // Add listeners for each key binding.
  12489. for (var i = 0; i < bindings.length; ++i) {
  12490. var binding = bindings[i];
  12491. elements.keydown(makeActivationHandler(binding));
  12492. }
  12493. elements.bind("fluid-activate", function (evt, handler) {
  12494. handler = handler || onActivateHandler;
  12495. return handler ? handler(evt) : null;
  12496. });
  12497. };
  12498. /**
  12499. * Makes all matched elements activatable with the Space and Enter keys.
  12500. * Provide your own handler function for custom behaviour.
  12501. * Options allow you to provide a list of additionalActivationKeys.
  12502. */
  12503. fluid.activatable = function (target, fn, options) {
  12504. target = $(target);
  12505. makeElementsActivatable(target, fn, fluid.activatable.defaults.keys, options);
  12506. };
  12507. /**
  12508. * Activates the specified element.
  12509. */
  12510. fluid.activate = function (target) {
  12511. $(target).trigger("fluid-activate");
  12512. };
  12513. // Public Defaults.
  12514. fluid.activatable.defaults = {
  12515. keys: [$.ui.keyCode.ENTER, $.ui.keyCode.SPACE]
  12516. };
  12517. })(jQuery, fluid_1_5);
  12518. /*
  12519. Copyright 2010-2011 Lucendo Development Ltd.
  12520. Copyright 2010-2011 OCAD University
  12521. Licensed under the Educational Community License (ECL), Version 2.0 or the New
  12522. BSD license. You may not use this file except in compliance with one these
  12523. Licenses.
  12524. You may obtain a copy of the ECL 2.0 License and BSD License at
  12525. https://github.com/fluid-project/infusion/raw/master/Infusion-LICENSE.txt
  12526. */
  12527. /** This file contains functions which depend on the presence of a DOM document
  12528. * and which depend on the contents of Fluid.js **/
  12529. // Declare dependencies
  12530. /*global fluid_1_5:true, jQuery*/
  12531. // JSLint options
  12532. /*jslint white: true, funcinvoke: true, undef: true, newcap: true, nomen: true, regexp: true, bitwise: true, browser: true, forin: true, maxerr: 100, indent: 4 */
  12533. var fluid_1_5 = fluid_1_5 || {};
  12534. (function ($, fluid) {
  12535. fluid.defaults("fluid.viewComponent", {
  12536. gradeNames: ["fluid.littleComponent", "fluid.modelComponent", "fluid.eventedComponent"],
  12537. initFunction: "fluid.initView",
  12538. argumentMap: {
  12539. container: 0,
  12540. options: 1
  12541. }
  12542. });
  12543. // unsupported, NON-API function
  12544. // NOTE: this function represents a temporary strategy until we have more integrated IoC debugging.
  12545. // It preserves the current framework behaviour for the 1.4 release, but provides a more informative
  12546. // diagnostic - in fact, it is perfectly acceptable for a component's creator to return no value and
  12547. // the failure is really in assumptions in fluid.initComponent. Revisit this issue for 1.5
  12548. fluid.diagnoseFailedView = function (componentName, that, options, args) {
  12549. if (!that && fluid.hasGrade(options, "fluid.viewComponent")) {
  12550. var container = fluid.wrap(args[1]);
  12551. var message1 = "Instantiation of autoInit component with type " + componentName + " failed, since ";
  12552. if (container.length === 0) {
  12553. fluid.fail(message1 + "selector \"", args[1], "\" did not match any markup in the document");
  12554. } else {
  12555. fluid.fail(message1 + " component creator function did not return a value");
  12556. }
  12557. }
  12558. };
  12559. fluid.checkTryCatchParameter = function () {
  12560. var location = window.location || { search: "", protocol: "file:" };
  12561. var GETParams = location.search.slice(1).split('&');
  12562. return fluid.contains(GETParams, "notrycatch");
  12563. };
  12564. fluid.notrycatch = fluid.checkTryCatchParameter();
  12565. /**
  12566. * Wraps an object in a jQuery if it isn't already one. This function is useful since
  12567. * it ensures to wrap a null or otherwise falsy argument to itself, rather than the
  12568. * often unhelpful jQuery default of returning the overall document node.
  12569. *
  12570. * @param {Object} obj the object to wrap in a jQuery
  12571. * @param {jQuery} userJQuery the jQuery object to use for the wrapping, optional - use the current jQuery if absent
  12572. */
  12573. fluid.wrap = function (obj, userJQuery) {
  12574. userJQuery = userJQuery || $;
  12575. return ((!obj || obj.jquery) ? obj : userJQuery(obj));
  12576. };
  12577. /**
  12578. * If obj is a jQuery, this function will return the first DOM element within it.
  12579. *
  12580. * @param {jQuery} obj the jQuery instance to unwrap into a pure DOM element
  12581. */
  12582. fluid.unwrap = function (obj) {
  12583. return obj && obj.jquery && obj.length === 1 ? obj[0] : obj; // Unwrap the element if it's a jQuery.
  12584. };
  12585. /**
  12586. * Fetches a single container element and returns it as a jQuery.
  12587. *
  12588. * @param {String||jQuery||element} containerSpec an id string, a single-element jQuery, or a DOM element specifying a unique container
  12589. * @param {Boolean} fallible <code>true</code> if an empty container is to be reported as a valid condition
  12590. * @return a single-element jQuery of container
  12591. */
  12592. fluid.container = function (containerSpec, fallible, userJQuery) {
  12593. if (userJQuery) {
  12594. containerSpec = fluid.unwrap(containerSpec);
  12595. }
  12596. var container = fluid.wrap(containerSpec, userJQuery);
  12597. if (fallible && (!container || container.length === 0)) {
  12598. return null;
  12599. }
  12600. // Throw an exception if we've got more or less than one element.
  12601. if (!container || !container.jquery || container.length !== 1) {
  12602. if (typeof (containerSpec) !== "string") {
  12603. containerSpec = container.selector;
  12604. }
  12605. var count = container.length !== undefined ? container.length : 0;
  12606. fluid.fail((count > 1 ? "More than one (" + count + ") container elements were"
  12607. : "No container element was") + " found for selector " + containerSpec);
  12608. }
  12609. if (!fluid.isDOMNode(container[0])) {
  12610. fluid.fail("fluid.container was supplied a non-jQueryable element");
  12611. }
  12612. return container;
  12613. };
  12614. /**
  12615. * Creates a new DOM Binder instance, used to locate elements in the DOM by name.
  12616. *
  12617. * @param {Object} container the root element in which to locate named elements
  12618. * @param {Object} selectors a collection of named jQuery selectors
  12619. */
  12620. fluid.createDomBinder = function (container, selectors) {
  12621. var cache = {}, that = {};
  12622. var userJQuery = container.constructor;
  12623. function cacheKey(name, thisContainer) {
  12624. return fluid.allocateSimpleId(thisContainer) + "-" + name;
  12625. }
  12626. function record(name, thisContainer, result) {
  12627. cache[cacheKey(name, thisContainer)] = result;
  12628. }
  12629. that.locate = function (name, localContainer) {
  12630. var selector, thisContainer, togo;
  12631. selector = selectors[name];
  12632. thisContainer = localContainer ? localContainer : container;
  12633. if (!thisContainer) {
  12634. fluid.fail("DOM binder invoked for selector " + name + " without container");
  12635. }
  12636. if (!selector) {
  12637. return thisContainer;
  12638. }
  12639. if (typeof (selector) === "function") {
  12640. togo = userJQuery(selector.call(null, fluid.unwrap(thisContainer)));
  12641. } else {
  12642. togo = userJQuery(selector, thisContainer);
  12643. }
  12644. if (togo.get(0) === document) {
  12645. togo = [];
  12646. }
  12647. if (!togo.selector) {
  12648. togo.selector = selector;
  12649. togo.context = thisContainer;
  12650. }
  12651. togo.selectorName = name;
  12652. record(name, thisContainer, togo);
  12653. return togo;
  12654. };
  12655. that.fastLocate = function (name, localContainer) {
  12656. var thisContainer = localContainer ? localContainer : container;
  12657. var key = cacheKey(name, thisContainer);
  12658. var togo = cache[key];
  12659. return togo ? togo : that.locate(name, localContainer);
  12660. };
  12661. that.clear = function () {
  12662. cache = {};
  12663. };
  12664. that.refresh = function (names, localContainer) {
  12665. var thisContainer = localContainer ? localContainer : container;
  12666. if (typeof names === "string") {
  12667. names = [names];
  12668. }
  12669. if (thisContainer.length === undefined) {
  12670. thisContainer = [thisContainer];
  12671. }
  12672. for (var i = 0; i < names.length; ++i) {
  12673. for (var j = 0; j < thisContainer.length; ++j) {
  12674. that.locate(names[i], thisContainer[j]);
  12675. }
  12676. }
  12677. };
  12678. that.resolvePathSegment = that.locate;
  12679. return that;
  12680. };
  12681. /** Expect that jQuery selector query has resulted in a non-empty set of
  12682. * results. If none are found, this function will fail with a diagnostic message,
  12683. * with the supplied message prepended.
  12684. */
  12685. fluid.expectFilledSelector = function (result, message) {
  12686. if (result && result.length === 0 && result.jquery) {
  12687. fluid.fail(message + ": selector \"" + result.selector + "\" with name " + result.selectorName +
  12688. " returned no results in context " + fluid.dumpEl(result.context));
  12689. }
  12690. };
  12691. /**
  12692. * The central initialiation method called as the first act of every Fluid
  12693. * component. This function automatically merges user options with defaults,
  12694. * attaches a DOM Binder to the instance, and configures events.
  12695. *
  12696. * @param {String} componentName The unique "name" of the component, which will be used
  12697. * to fetch the default options from store. By recommendation, this should be the global
  12698. * name of the component's creator function.
  12699. * @param {jQueryable} container A specifier for the single root "container node" in the
  12700. * DOM which will house all the markup for this component.
  12701. * @param {Object} userOptions The configuration options for this component.
  12702. */
  12703. // 4th argument is NOT SUPPORTED, see comments for initLittleComponent
  12704. fluid.initView = function (componentName, containerSpec, userOptions, localOptions) {
  12705. var container = fluid.container(containerSpec, true);
  12706. fluid.expectFilledSelector(container, "Error instantiating component with name \"" + componentName);
  12707. if (!container) {
  12708. return null;
  12709. }
  12710. var that = fluid.initLittleComponent(componentName, userOptions, localOptions || {gradeNames: ["fluid.viewComponent"]});
  12711. var userJQuery = that.options.jQuery; // Do it a second time to correct for jQuery injection
  12712. if (userJQuery) {
  12713. container = fluid.container(containerSpec, true, userJQuery);
  12714. }
  12715. fluid.log("Constructing view component " + componentName + " with container " + container.constructor.expando +
  12716. (userJQuery ? " user jQuery " + userJQuery.expando : "") + " env: " + $.expando);
  12717. that.container = container;
  12718. fluid.initDomBinder(that);
  12719. return that;
  12720. };
  12721. /**
  12722. * Creates a new DOM Binder instance for the specified component and mixes it in.
  12723. *
  12724. * @param {Object} that the component instance to attach the new DOM Binder to
  12725. */
  12726. fluid.initDomBinder = function (that) {
  12727. that.dom = fluid.createDomBinder(that.container, that.options.selectors);
  12728. that.locate = that.dom.locate;
  12729. };
  12730. // DOM Utilities.
  12731. /**
  12732. * Finds the nearest ancestor of the element that passes the test
  12733. * @param {Element} element DOM element
  12734. * @param {Function} test A function which takes an element as a parameter and return true or false for some test
  12735. */
  12736. fluid.findAncestor = function (element, test) {
  12737. element = fluid.unwrap(element);
  12738. while (element) {
  12739. if (test(element)) {
  12740. return element;
  12741. }
  12742. element = element.parentNode;
  12743. }
  12744. };
  12745. fluid.findForm = function (node) {
  12746. return fluid.findAncestor(node, function (element) {
  12747. return element.nodeName.toLowerCase() === "form";
  12748. });
  12749. };
  12750. /** A utility with the same signature as jQuery.text and jQuery.html, but without the API irregularity
  12751. * that treats a single argument of undefined as different to no arguments */
  12752. // in jQuery 1.7.1, jQuery pulled the same dumb trick with $.text() that they did with $.val() previously,
  12753. // see comment in fluid.value below
  12754. fluid.each(["text", "html"], function (method) {
  12755. fluid[method] = function (node, newValue) {
  12756. node = $(node);
  12757. return newValue === undefined ? node[method]() : node[method](newValue);
  12758. };
  12759. });
  12760. /** A generalisation of jQuery.val to correctly handle the case of acquiring and
  12761. * setting the value of clustered radio button/checkbox sets, potentially, given
  12762. * a node corresponding to just one element.
  12763. */
  12764. fluid.value = function (nodeIn, newValue) {
  12765. var node = fluid.unwrap(nodeIn);
  12766. var multiple = false;
  12767. if (node.nodeType === undefined && node.length > 1) {
  12768. node = node[0];
  12769. multiple = true;
  12770. }
  12771. if ("input" !== node.nodeName.toLowerCase() || !/radio|checkbox/.test(node.type)) {
  12772. // resist changes to contract of jQuery.val() in jQuery 1.5.1 (see FLUID-4113)
  12773. return newValue === undefined ? $(node).val() : $(node).val(newValue);
  12774. }
  12775. var name = node.name;
  12776. if (name === undefined) {
  12777. fluid.fail("Cannot acquire value from node " + fluid.dumpEl(node) + " which does not have name attribute set");
  12778. }
  12779. var elements;
  12780. if (multiple) {
  12781. elements = nodeIn;
  12782. } else {
  12783. elements = node.ownerDocument.getElementsByName(name);
  12784. var scope = fluid.findForm(node);
  12785. elements = $.grep(elements, function (element) {
  12786. if (element.name !== name) {
  12787. return false;
  12788. }
  12789. return !scope || fluid.dom.isContainer(scope, element);
  12790. });
  12791. }
  12792. if (newValue !== undefined) {
  12793. if (typeof(newValue) === "boolean") {
  12794. newValue = (newValue ? "true" : "false");
  12795. }
  12796. // jQuery gets this partially right, but when dealing with radio button array will
  12797. // set all of their values to "newValue" rather than setting the checked property
  12798. // of the corresponding control.
  12799. $.each(elements, function () {
  12800. this.checked = (newValue instanceof Array ?
  12801. $.inArray(this.value, newValue) !== -1 : newValue === this.value);
  12802. });
  12803. } else { // this part jQuery will not do - extracting value from <input> array
  12804. var checked = $.map(elements, function (element) {
  12805. return element.checked ? element.value : null;
  12806. });
  12807. return node.type === "radio" ? checked[0] : checked;
  12808. }
  12809. };
  12810. /**
  12811. * Returns a jQuery object given the id of a DOM node. In the case the element
  12812. * is not found, will return an empty list.
  12813. */
  12814. fluid.jById = function (id, dokkument) {
  12815. dokkument = dokkument && dokkument.nodeType === 9 ? dokkument : document;
  12816. var element = fluid.byId(id, dokkument);
  12817. var togo = element ? $(element) : [];
  12818. togo.selector = "#" + id;
  12819. togo.context = dokkument;
  12820. return togo;
  12821. };
  12822. /**
  12823. * Returns an DOM element quickly, given an id
  12824. *
  12825. * @param {Object} id the id of the DOM node to find
  12826. * @param {Document} dokkument the document in which it is to be found (if left empty, use the current document)
  12827. * @return The DOM element with this id, or null, if none exists in the document.
  12828. */
  12829. fluid.byId = function (id, dokkument) {
  12830. dokkument = dokkument && dokkument.nodeType === 9 ? dokkument : document;
  12831. var el = dokkument.getElementById(id);
  12832. if (el) {
  12833. // Use element id property here rather than attribute, to work around FLUID-3953
  12834. if (el.id !== id) {
  12835. fluid.fail("Problem in document structure - picked up element " +
  12836. fluid.dumpEl(el) + " for id " + id +
  12837. " without this id - most likely the element has a name which conflicts with this id");
  12838. }
  12839. return el;
  12840. } else {
  12841. return null;
  12842. }
  12843. };
  12844. /**
  12845. * Returns the id attribute from a jQuery or pure DOM element.
  12846. *
  12847. * @param {jQuery||Element} element the element to return the id attribute for
  12848. */
  12849. fluid.getId = function (element) {
  12850. return fluid.unwrap(element).id;
  12851. };
  12852. /**
  12853. * Allocate an id to the supplied element if it has none already, by a simple
  12854. * scheme resulting in ids "fluid-id-nnnn" where nnnn is an increasing integer.
  12855. */
  12856. fluid.allocateSimpleId = function (element) {
  12857. var simpleId = "fluid-id-" + fluid.allocateGuid();
  12858. if (!element) {
  12859. return simpleId;
  12860. }
  12861. element = fluid.unwrap(element);
  12862. if (!element.id) {
  12863. element.id = simpleId;
  12864. }
  12865. return element.id;
  12866. };
  12867. fluid.defaults("fluid.ariaLabeller", {
  12868. labelAttribute: "aria-label",
  12869. liveRegionMarkup: "<div class=\"liveRegion fl-offScreen-hidden\" aria-live=\"polite\"></div>",
  12870. liveRegionId: "fluid-ariaLabeller-liveRegion",
  12871. events: {
  12872. generateLiveElement: "unicast"
  12873. },
  12874. listeners: {
  12875. generateLiveElement: "fluid.ariaLabeller.generateLiveElement"
  12876. }
  12877. });
  12878. fluid.ariaLabeller = function (element, options) {
  12879. var that = fluid.initView("fluid.ariaLabeller", element, options);
  12880. that.update = function (newOptions) {
  12881. newOptions = newOptions || that.options;
  12882. that.container.attr(that.options.labelAttribute, newOptions.text);
  12883. if (newOptions.dynamicLabel) {
  12884. var live = fluid.jById(that.options.liveRegionId);
  12885. if (live.length === 0) {
  12886. live = that.events.generateLiveElement.fire(that);
  12887. }
  12888. live.text(newOptions.text);
  12889. }
  12890. };
  12891. that.update();
  12892. return that;
  12893. };
  12894. fluid.ariaLabeller.generateLiveElement = function (that) {
  12895. var liveEl = $(that.options.liveRegionMarkup);
  12896. liveEl.prop("id", that.options.liveRegionId);
  12897. $("body").append(liveEl);
  12898. return liveEl;
  12899. };
  12900. var LABEL_KEY = "aria-labelling";
  12901. fluid.getAriaLabeller = function (element) {
  12902. element = $(element);
  12903. var that = fluid.getScopedData(element, LABEL_KEY);
  12904. return that;
  12905. };
  12906. /** Manages an ARIA-mediated label attached to a given DOM element. An
  12907. * aria-labelledby attribute and target node is fabricated in the document
  12908. * if they do not exist already, and a "little component" is returned exposing a method
  12909. * "update" that allows the text to be updated. */
  12910. fluid.updateAriaLabel = function (element, text, options) {
  12911. options = $.extend({}, options || {}, {text: text});
  12912. var that = fluid.getAriaLabeller(element);
  12913. if (!that) {
  12914. that = fluid.ariaLabeller(element, options);
  12915. fluid.setScopedData(element, LABEL_KEY, that);
  12916. } else {
  12917. that.update(options);
  12918. }
  12919. return that;
  12920. };
  12921. /** "Global Dismissal Handler" for the entire page. Attaches a click handler to the
  12922. * document root that will cause dismissal of any elements (typically dialogs) which
  12923. * have registered themselves. Dismissal through this route will automatically clean up
  12924. * the record - however, the dismisser themselves must take care to deregister in the case
  12925. * dismissal is triggered through the dialog interface itself. This component can also be
  12926. * automatically configured by fluid.deadMansBlur by means of the "cancelByDefault" option */
  12927. var dismissList = {};
  12928. $(document).click(function (event) {
  12929. var target = event.target;
  12930. while (target) {
  12931. if (dismissList[target.id]) {
  12932. return;
  12933. }
  12934. target = target.parentNode;
  12935. }
  12936. fluid.each(dismissList, function (dismissFunc, key) {
  12937. dismissFunc(event);
  12938. delete dismissList[key];
  12939. });
  12940. });
  12941. // TODO: extend a configurable equivalent of the above dealing with "focusin" events
  12942. /** Accepts a free hash of nodes and an optional "dismissal function".
  12943. * If dismissFunc is set, this "arms" the dismissal system, such that when a click
  12944. * is received OUTSIDE any of the hierarchy covered by "nodes", the dismissal function
  12945. * will be executed.
  12946. */
  12947. fluid.globalDismissal = function (nodes, dismissFunc) {
  12948. fluid.each(nodes, function (node) {
  12949. // Don't bother to use the real id if it is from a foreign document - we will never receive events
  12950. // from it directly in any case - and foreign documents may be under the control of malign fiends
  12951. // such as tinyMCE who allocate the same id to everything
  12952. var id = fluid.unwrap(node).ownerDocument === document? fluid.allocateSimpleId(node) : fluid.allocateGuid();
  12953. if (dismissFunc) {
  12954. dismissList[id] = dismissFunc;
  12955. }
  12956. else {
  12957. delete dismissList[id];
  12958. }
  12959. });
  12960. };
  12961. /** Sets an interation on a target control, which morally manages a "blur" for
  12962. * a possibly composite region.
  12963. * A timed blur listener is set on the control, which waits for a short period of
  12964. * time (options.delay, defaults to 150ms) to discover whether the reason for the
  12965. * blur interaction is that either a focus or click is being serviced on a nominated
  12966. * set of "exclusions" (options.exclusions, a free hash of elements or jQueries).
  12967. * If no such event is received within the window, options.handler will be called
  12968. * with the argument "control", to service whatever interaction is required of the
  12969. * blur.
  12970. */
  12971. fluid.deadMansBlur = function (control, options) {
  12972. var that = fluid.initLittleComponent("fluid.deadMansBlur", options);
  12973. that.blurPending = false;
  12974. that.lastCancel = 0;
  12975. that.canceller = function (event) {
  12976. fluid.log("Cancellation through " + event.type + " on " + fluid.dumpEl(event.target));
  12977. that.lastCancel = Date.now();
  12978. that.blurPending = false;
  12979. };
  12980. that.noteProceeded = function () {
  12981. fluid.globalDismissal(that.options.exclusions);
  12982. };
  12983. that.reArm = function () {
  12984. fluid.globalDismissal(that.options.exclusions, that.proceed);
  12985. };
  12986. that.addExclusion = function (exclusions) {
  12987. fluid.globalDismissal(exclusions, that.proceed);
  12988. };
  12989. that.proceed = function (event) {
  12990. fluid.log("Direct proceed through " + event.type + " on " + fluid.dumpEl(event.target));
  12991. that.blurPending = false;
  12992. that.options.handler(control);
  12993. };
  12994. fluid.each(that.options.exclusions, function (exclusion) {
  12995. exclusion = $(exclusion);
  12996. fluid.each(exclusion, function (excludeEl) {
  12997. $(excludeEl).bind("focusin", that.canceller).
  12998. bind("fluid-focus", that.canceller).
  12999. click(that.canceller).mousedown(that.canceller);
  13000. // Mousedown is added for FLUID-4212, as a result of Chrome bug 6759, 14204
  13001. });
  13002. });
  13003. if (!that.options.cancelByDefault) {
  13004. $(control).bind("focusout", function (event) {
  13005. fluid.log("Starting blur timer for element " + fluid.dumpEl(event.target));
  13006. var now = Date.now();
  13007. fluid.log("back delay: " + (now - that.lastCancel));
  13008. if (now - that.lastCancel > that.options.backDelay) {
  13009. that.blurPending = true;
  13010. }
  13011. setTimeout(function () {
  13012. if (that.blurPending) {
  13013. that.options.handler(control);
  13014. }
  13015. }, that.options.delay);
  13016. });
  13017. }
  13018. else {
  13019. that.reArm();
  13020. }
  13021. return that;
  13022. };
  13023. fluid.defaults("fluid.deadMansBlur", {
  13024. delay: 150,
  13025. backDelay: 100
  13026. });
  13027. })(jQuery, fluid_1_5);
  13028. /*
  13029. Copyright 2011 OCAD University
  13030. Copyright 2010-2011 Lucendo Development Ltd.
  13031. Licensed under the Educational Community License (ECL), Version 2.0 or the New
  13032. BSD license. You may not use this file except in compliance with one these
  13033. Licenses.
  13034. You may obtain a copy of the ECL 2.0 License and BSD License at
  13035. https://github.com/fluid-project/infusion/raw/master/Infusion-LICENSE.txt
  13036. */
  13037. // Declare dependencies
  13038. /*global fluid_1_5:true, jQuery*/
  13039. // JSLint options
  13040. /*jslint white: true, funcinvoke: true, continue: true, elsecatch: true, operator: true, jslintok:true, undef: true, newcap: true, regexp: true, bitwise: true, browser: true, forin: true, maxerr: 100, indent: 4 */
  13041. var fluid_1_5 = fluid_1_5 || {};
  13042. (function ($, fluid) {
  13043. /** The Fluid "IoC System proper" - resolution of references and
  13044. * completely automated instantiation of declaratively defined
  13045. * component trees */
  13046. var inCreationMarker = "__CURRENTLY_IN_CREATION__";
  13047. // unsupported, non-API function
  13048. fluid.isFireBreak = function(component) {
  13049. return component.options && component.options["fluid.visitComponents.fireBreak"];
  13050. };
  13051. // unsupported, non-API function
  13052. // Currently still uses manual traversal - once we ban manually instantiated components,
  13053. // it will use the instantiator's records instead. In that day, "fireBreak" will bite the dust too
  13054. fluid.visitComponentChildren = function(that, visitor, options, path) {
  13055. for (var name in that) {
  13056. var newPath = options.instantiator.composePath(path, name);
  13057. var component = that[name];
  13058. //Every component *should* have an id, but some clients may not yet be compliant
  13059. //if (component && component.typeName && !component.id) {
  13060. // fluid.fail("No id");
  13061. //}
  13062. if (!component || !component.typeName || (component.id && options.visited && options.visited[component.id])) {continue; }
  13063. if (options.visited) {
  13064. options.visited[component.id] = true;
  13065. }
  13066. if (visitor(component, name, newPath, path)) {
  13067. return true;
  13068. }
  13069. if (!fluid.isFireBreak(component) && !options.flat) {
  13070. fluid.visitComponentChildren(component, visitor, options, newPath);
  13071. }
  13072. }
  13073. };
  13074. // thatStack contains an increasing list of MORE SPECIFIC thats.
  13075. // this visits all components starting from the current location (end of stack)
  13076. // in visibility order up the tree.
  13077. var visitComponents = function(instantiator, thatStack, visitor, options) {
  13078. options = options || {
  13079. visited: {},
  13080. flat: true,
  13081. instantiator: instantiator
  13082. };
  13083. for (var i = thatStack.length - 1; i >= 0; --i) {
  13084. var that = thatStack[i];
  13085. if (fluid.isFireBreak(that)) {
  13086. return;
  13087. }
  13088. var path = instantiator.idToPath[that.id] || ""; // This resolves FLUID-4338
  13089. if (that.typeName) {
  13090. options.visited[that.id] = true;
  13091. var memberName = fluid.pathUtil.getTailPath(path);
  13092. if (visitor(that, memberName, path)) {
  13093. return;
  13094. }
  13095. }
  13096. if (fluid.visitComponentChildren(that, visitor, options, path)) {
  13097. return;
  13098. }
  13099. }
  13100. };
  13101. // An EL segment resolver strategy that will attempt to trigger creation of
  13102. // components that it discovers along the EL path, if they have been defined but not yet
  13103. // constructed. Spring, eat your heart out! Wot no SPR-2048?
  13104. function makeGingerStrategy(instantiator, that, thatStack) {
  13105. return function(component, thisSeg) {
  13106. var atval = component[thisSeg];
  13107. if (atval === undefined) {
  13108. var parentPath = instantiator.idToPath[component.id];
  13109. var childPath = fluid.composePath(parentPath, thisSeg);
  13110. atval = instantiator.pathToComponent[childPath];
  13111. // if it was not attached to the component, but it is in the instantiator, it MUST be in creation - prepare to fail
  13112. if (atval) {
  13113. atval[inCreationMarker] = true;
  13114. }
  13115. }
  13116. if (atval !== undefined) {
  13117. if (atval[inCreationMarker]) {
  13118. fluid.fail("Component " + fluid.dumpThat(atval) + " at path \"" + thisSeg
  13119. + "\" of parent " + fluid.dumpThat(component) + " cannot be used for lookup"
  13120. + " since it is still in creation. Please reorganise your dependencies so that they no longer contain circular references");
  13121. }
  13122. }
  13123. else {
  13124. if (fluid.get(component, fluid.path("options", "components", thisSeg, "type"))) {
  13125. fluid.initDependent(component, thisSeg);
  13126. atval = component[thisSeg];
  13127. }
  13128. }
  13129. return atval;
  13130. };
  13131. }
  13132. // unsupported, non-API function
  13133. fluid.dumpThat = function(that) {
  13134. return "{ typeName: \"" + that.typeName + "\" id: " + that.id + "}";
  13135. };
  13136. // unsupported, non-API function
  13137. fluid.dumpThatStack = function(thatStack, instantiator) {
  13138. var togo = fluid.transform(thatStack, function(that) {
  13139. var path = instantiator.idToPath[that.id];
  13140. return fluid.dumpThat(that) + (path? (" - path: " + path) : "");
  13141. });
  13142. return togo.join("\n");
  13143. };
  13144. // Return an array of objects describing the current activity
  13145. // unsupported, non-API function
  13146. fluid.describeActivity = function() {
  13147. return fluid.globalThreadLocal().activityStack || [];
  13148. };
  13149. // Execute the supplied function with the specified activity description pushed onto the stack
  13150. // unsupported, non-API function
  13151. fluid.pushActivity = function(func, message) {
  13152. if (!message || fluid.notrycatch) {
  13153. return func();
  13154. }
  13155. var root = fluid.globalThreadLocal();
  13156. if (!root.activityStack) {
  13157. root.activityStack = [];
  13158. }
  13159. var frames = fluid.makeArray(message);
  13160. frames.push("\n");
  13161. frames.unshift("\n");
  13162. root.activityStack = frames.concat(root.activityStack);
  13163. return fluid.tryCatch(func, null, function() {
  13164. root.activityStack = root.activityStack.slice(frames.length);
  13165. });
  13166. };
  13167. // Return a function wrapped by the activity of describing its activity
  13168. // unsupported, non-API function
  13169. fluid.wrapActivity = fluid.notrycatch? fluid.identity : function(func, messageSpec) {
  13170. return function() {
  13171. var args = fluid.makeArray(arguments);
  13172. var message = fluid.transform(fluid.makeArray(messageSpec), function(specEl) {
  13173. if (typeof(specEl) === "string" && specEl.indexOf("arguments.") === 0) {
  13174. var el = specEl.substring("arguments.".length);
  13175. return fluid.get(args, el);
  13176. }
  13177. else {
  13178. return specEl;
  13179. }
  13180. });
  13181. return fluid.pushActivity(function() {
  13182. return func.apply(null, args);
  13183. }, message);
  13184. };
  13185. };
  13186. var localRecordExpected = /arguments|options|container/;
  13187. function makeStackFetcher(instantiator, parentThat, localRecord, expandOptions) {
  13188. expandOptions = expandOptions || {};
  13189. var thatStack = instantiator.getFullStack(parentThat);
  13190. var fetchStrategies = [fluid.model.funcResolverStrategy, makeGingerStrategy(instantiator, parentThat, thatStack)];
  13191. var fetcher = function(parsed) {
  13192. var context = parsed.context;
  13193. var foundComponent;
  13194. if (context === "instantiator") {
  13195. // special treatment for the current instantiator which used to be discovered as unique in threadLocal
  13196. return instantiator;
  13197. }
  13198. else if (context === "that") {
  13199. foundComponent = parentThat;
  13200. }
  13201. else if (localRecord && localRecordExpected.test(context)) {
  13202. var fetched = fluid.get(localRecord[context], parsed.path);
  13203. return (context === "arguments" || expandOptions.direct)? fetched : {
  13204. marker: context === "options"? fluid.EXPAND : fluid.EXPAND_NOW,
  13205. value: fetched
  13206. };
  13207. }
  13208. if (!foundComponent) {
  13209. visitComponents(instantiator, thatStack, function(component, name) {
  13210. if (context === name || context === component.typeName || context === component.nickName) {
  13211. foundComponent = component;
  13212. return true; // YOUR VISIT IS AT AN END!!
  13213. }
  13214. if (fluid.get(component, fluid.path("options", "components", context, "type")) && !component[context]) {
  13215. foundComponent = fluid.get(component, context, {strategies: fetchStrategies});
  13216. return true;
  13217. }
  13218. });
  13219. }
  13220. if (!foundComponent && parsed.path !== "") {
  13221. var ref = fluid.renderContextReference(parsed);
  13222. fluid.log("Failed to resolve reference " + ref + ": thatStack contains\n" + fluid.dumpThatStack(thatStack, instantiator));
  13223. fluid.fail("Failed to resolve reference " + ref + " - could not match context with name "
  13224. + context + " from component leaf of type " + parentThat.typeName, "\ninstantiator contents: ", instantiator);
  13225. }
  13226. return fluid.get(foundComponent, parsed.path, fetchStrategies);
  13227. };
  13228. return fetcher;
  13229. }
  13230. function makeStackResolverOptions(instantiator, parentThat, localRecord, expandOptions) {
  13231. return $.extend(true, {}, fluid.defaults("fluid.resolveEnvironment"), {
  13232. fetcher: makeStackFetcher(instantiator, parentThat, localRecord, expandOptions)
  13233. });
  13234. }
  13235. // unsupported, non-API function
  13236. fluid.clearListeners = function (idToListeners, key) {
  13237. fluid.each(idToListeners[key], function (rec) {
  13238. rec.event.removeListener(rec.listener);
  13239. });
  13240. delete idToListeners[key];
  13241. }
  13242. // unsupported, non-API function - however, this structure is of considerable interest to those debugging
  13243. // into IoC issues. The structures idToPath and pathToComponent contain a complete map of the component tree
  13244. // forming the surrounding scope
  13245. fluid.instantiator = function(freeInstantiator) {
  13246. // NB: We may not use the options merging framework itself here, since "withInstantiator" below
  13247. // will blow up, as it tries to resolve the instantiator which we are instantiating *NOW*
  13248. var preThat = {
  13249. options: {
  13250. "fluid.visitComponents.fireBreak": true
  13251. },
  13252. idToPath: {},
  13253. pathToComponent: {},
  13254. idToListeners: {},
  13255. nickName: "instantiator",
  13256. composePath: fluid.composePath // For speed, we declare that no component's name may contain a period
  13257. };
  13258. var that = fluid.typeTag("fluid.instantiator");
  13259. that = $.extend(that, preThat);
  13260. that.recordListener = function (event, listener, source) {
  13261. var listeners = that.idToListeners[source.id];
  13262. if (!listeners) {
  13263. listeners = that.idToListeners[source.id] = [];
  13264. }
  13265. listeners.push({event: event, listener: listener});
  13266. };
  13267. that.getThatStack = function(component) {
  13268. var path = that.idToPath[component.id] || "";
  13269. var parsed = fluid.model.parseEL(path);
  13270. var togo = fluid.transform(parsed, function(value, i) {
  13271. var parentPath = fluid.model.composeSegments.apply(null, parsed.slice(0, i + 1));
  13272. return that.pathToComponent[parentPath];
  13273. });
  13274. var root = that.pathToComponent[""];
  13275. if (root) {
  13276. togo.unshift(root);
  13277. }
  13278. return togo;
  13279. };
  13280. that.getEnvironmentalStack = function() {
  13281. var togo = [fluid.staticEnvironment];
  13282. if (!freeInstantiator) {
  13283. togo.push(fluid.globalThreadLocal());
  13284. }
  13285. return togo;
  13286. };
  13287. that.getFullStack = function(component) {
  13288. var thatStack = component? that.getThatStack(component) : [];
  13289. return that.getEnvironmentalStack().concat(thatStack);
  13290. };
  13291. function recordComponent(component, path, created) {
  13292. if (created) {
  13293. that.idToPath[component.id] = path;
  13294. }
  13295. if (that.pathToComponent[path]) {
  13296. fluid.fail("Error during instantiation - path " + path + " which has just created component " + fluid.dumpThat(component)
  13297. + " has already been used for component " + fluid.dumpThat(that.pathToComponent[path]) + " - this is a circular instantiation or other oversight."
  13298. + " Please clear the component using instantiator.clearComponent() before reusing the path.");
  13299. }
  13300. that.pathToComponent[path] = component;
  13301. }
  13302. that.recordRoot = function(component) {
  13303. if (component && component.id && !that.pathToComponent[""]) {
  13304. recordComponent(component, "", true);
  13305. }
  13306. };
  13307. that.pushUpcomingInstantiation = function(parent, name) {
  13308. that.expectedParent = parent;
  13309. that.expectedName = name;
  13310. };
  13311. that.recordComponent = function(component) {
  13312. if (that.expectedName) {
  13313. that.recordKnownComponent(that.expectedParent, component, that.expectedName, true);
  13314. delete that.expectedName;
  13315. delete that.expectedParent;
  13316. }
  13317. else {
  13318. that.recordRoot(component);
  13319. }
  13320. };
  13321. that.clearComponent = function(component, name, child, options, noModTree, path) {
  13322. var record = that.idToPath[component.id];
  13323. // use flat recursion since we want to use our own recursion rather than rely on "visited" records
  13324. options = options || {flat: true, instantiator: that};
  13325. child = child || component[name];
  13326. path = path || record;
  13327. if (path === undefined) {
  13328. fluid.fail("Cannot clear component " + name + " from component ", component,
  13329. " which was not created by this instantiator");
  13330. }
  13331. fluid.fireEvent(child, "events.onClear", [child, name, component]);
  13332. var childPath = that.composePath(path, name);
  13333. var childRecord = that.idToPath[child.id];
  13334. // only recurse on components which were created in place - if the id record disagrees with the
  13335. // recurse path, it must have been injected
  13336. if (childRecord === childPath) {
  13337. fluid.fireEvent(child, "events.onDestroy", [child, name, component]);
  13338. fluid.clearListeners(that.idToListeners, child.id);
  13339. fluid.visitComponentChildren(child, function(gchild, gchildname, newPath, parentPath) {
  13340. that.clearComponent(child, gchildname, null, options, true, parentPath);
  13341. }, options, childPath);
  13342. }
  13343. delete that.idToPath[child.id]; // there may be no entry - if injected
  13344. delete that.pathToComponent[childPath]; // there may be no entry - if created informally
  13345. if (!noModTree) {
  13346. delete component[name]; // there may be no entry - if creation is not concluded
  13347. }
  13348. };
  13349. that.recordKnownComponent = function(parent, component, name, created) {
  13350. var parentPath = that.idToPath[parent.id] || "";
  13351. var path = that.composePath(parentPath, name);
  13352. recordComponent(component, path, created);
  13353. };
  13354. return that;
  13355. };
  13356. fluid.freeInstantiator = fluid.instantiator(true);
  13357. // unsupported, non-API function
  13358. fluid.argMapToDemands = function(argMap) {
  13359. var togo = [];
  13360. fluid.each(argMap, function(value, key) {
  13361. togo[value] = "{" + key + "}";
  13362. });
  13363. return togo;
  13364. };
  13365. // unsupported, non-API function
  13366. fluid.makePassArgsSpec = function(initArgs) {
  13367. return fluid.transform(initArgs, function(arg, index) {
  13368. return "{arguments}." + index;
  13369. });
  13370. };
  13371. function mergeToMergeAll(options) {
  13372. if (options && options.mergeOptions) {
  13373. options.mergeAllOptions = ["{options}"].concat(fluid.makeArray(options.mergeOptions));
  13374. }
  13375. }
  13376. function upgradeMergeOptions(demandspec) {
  13377. mergeToMergeAll(demandspec);
  13378. if (demandspec.mergeAllOptions) {
  13379. if (demandspec.options) {
  13380. fluid.fail("demandspec ", demandspec,
  13381. " is invalid - cannot specify literal options together with mergeOptions or mergeAllOptions");
  13382. }
  13383. demandspec.options = {
  13384. mergeAllOptions: demandspec.mergeAllOptions
  13385. };
  13386. }
  13387. if (demandspec.options) {
  13388. delete demandspec.options.mergeOptions;
  13389. }
  13390. }
  13391. /** Given a concrete argument list and/or options, determine the final concrete
  13392. * "invocation specification" which is coded by the supplied demandspec in the
  13393. * environment "thatStack" - the return is a package of concrete global function name
  13394. * and argument list which is suitable to be executed directly by fluid.invokeGlobalFunction.
  13395. */
  13396. // unsupported, non-API function
  13397. fluid.embodyDemands = function(instantiator, parentThat, demandspec, initArgs, options) {
  13398. options = options || {};
  13399. upgradeMergeOptions(demandspec);
  13400. var oldOptions = fluid.get(options, "componentRecord.options");
  13401. options.componentRecord = $.extend(true, {}, options.componentRecord,
  13402. fluid.censorKeys(demandspec, ["args", "funcName", "registeredFrom"]));
  13403. var mergeAllZero = fluid.get(options, "componentRecord.options.mergeAllOptions.0");
  13404. if (mergeAllZero === "{options}") {
  13405. fluid.set(options, "componentRecord.options.mergeAllOptions.0", oldOptions);
  13406. }
  13407. var demands = fluid.makeArray(demandspec.args);
  13408. var upDefaults = fluid.defaults(demandspec.funcName); // I can SEE into TIME!!
  13409. var argMap = upDefaults? upDefaults.argumentMap : null;
  13410. var inferMap = false;
  13411. if (!argMap && (upDefaults || (options && options.componentRecord)) && !options.passArgs) {
  13412. inferMap = true;
  13413. // infer that it must be a little component if we have any reason to believe it is a component
  13414. if (demands.length < 2) {
  13415. argMap = fluid.rawDefaults("fluid.littleComponent").argumentMap;
  13416. }
  13417. else {
  13418. argMap = {options: demands.length - 1}; // wild guess in the old style
  13419. }
  13420. }
  13421. options = options || {};
  13422. if (demands.length === 0) {
  13423. if (options.componentRecord && argMap) {
  13424. demands = fluid.argMapToDemands(argMap);
  13425. }
  13426. else if (options.passArgs) {
  13427. demands = fluid.makePassArgsSpec(initArgs);
  13428. }
  13429. }
  13430. var localRecord = $.extend({"arguments": initArgs}, fluid.censorKeys(options.componentRecord, ["type"]));
  13431. fluid.each(argMap, function(index, name) {
  13432. if (initArgs.length > 0) {
  13433. localRecord[name] = localRecord["arguments"][index];
  13434. }
  13435. if (demandspec[name] !== undefined && localRecord[name] === undefined) {
  13436. localRecord[name] = demandspec[name];
  13437. }
  13438. });
  13439. mergeToMergeAll(localRecord.options);
  13440. mergeToMergeAll(argMap && demands[argMap.options]);
  13441. var upstreamLocalRecord = $.extend({}, localRecord);
  13442. if (options.componentRecord.options !== undefined) {
  13443. upstreamLocalRecord.options = options.componentRecord.options;
  13444. }
  13445. var expandOptions = makeStackResolverOptions(instantiator, parentThat, localRecord);
  13446. var args = [];
  13447. if (demands) {
  13448. for (var i = 0; i < demands.length; ++i) {
  13449. var arg = demands[i];
  13450. // Weak detection since we cannot guarantee this material has not been copied
  13451. if (fluid.isMarker(arg) && arg.value === fluid.COMPONENT_OPTIONS.value) {
  13452. arg = "{options}";
  13453. // Backwards compatibility for non-users of GRADES - last-ditch chance to correct the inference
  13454. if (inferMap) {
  13455. argMap = {options: i};
  13456. }
  13457. }
  13458. if (typeof(arg) === "string") {
  13459. if (arg.charAt(0) === "@") {
  13460. var argpos = arg.substring(1);
  13461. arg = "{arguments}." + argpos;
  13462. }
  13463. }
  13464. if (!argMap || argMap.options !== i) {
  13465. // defer expansion required if it is non-pseudoarguments demands and this argument *is* the options
  13466. args[i] = fluid.expander.expandLight(arg, expandOptions);
  13467. }
  13468. else { // It is the component options
  13469. if (arg && typeof(arg) === "object" && !arg.targetTypeName) {
  13470. arg.targetTypeName = demandspec.funcName;
  13471. }
  13472. // ensure to copy the arg since it is an alias of the demand block material (FLUID-4223)
  13473. // and will be destructively expanded
  13474. args[i] = {marker: fluid.EXPAND, value: fluid.copy(arg), localRecord: upstreamLocalRecord};
  13475. }
  13476. if (args[i] && fluid.isMarker(args[i].marker, fluid.EXPAND_NOW)) {
  13477. args[i] = fluid.expander.expandLight(args[i].value, expandOptions);
  13478. }
  13479. }
  13480. }
  13481. else {
  13482. args = initArgs? initArgs : [];
  13483. }
  13484. var togo = {
  13485. args: args,
  13486. funcName: demandspec.funcName
  13487. };
  13488. return togo;
  13489. };
  13490. var aliasTable = {};
  13491. fluid.alias = function(demandingName, aliasName) {
  13492. if (aliasName) {
  13493. aliasTable[demandingName] = aliasName;
  13494. }
  13495. else {
  13496. return aliasTable[demandingName];
  13497. }
  13498. };
  13499. var dependentStore = {};
  13500. function searchDemands(demandingName, contextNames) {
  13501. var exist = dependentStore[demandingName] || [];
  13502. outer: for (var i = 0