├── GPL-LICENSE.txt ├── MIT-LICENSE.txt ├── external ├── jquery-1.0.1.js ├── jquery-1.0.2.js ├── jquery-1.0.3.js ├── jquery-1.0.4.js ├── jquery-1.0.js ├── jquery-1.1.1.js ├── jquery-1.1.2.js ├── jquery-1.1.3.js ├── jquery-1.1.4.js ├── jquery-1.1.js ├── jquery-1.2.1.js ├── jquery-1.2.2.js ├── jquery-1.2.3.js ├── jquery-1.2.4.js ├── jquery-1.2.5.js ├── jquery-1.2.6.js ├── jquery-1.2.js ├── jquery-1.3.1.js ├── jquery-1.3.2.js ├── jquery-1.3.js ├── jquery-1.4.1.js ├── jquery-1.4.2.js ├── jquery-1.4.3.js ├── jquery-1.4.4.js ├── jquery-1.4.js ├── jquery-1.5.1.js ├── jquery-1.5.2.js ├── jquery-1.5.js ├── jquery-1.6.1.js ├── jquery-1.6.js ├── json2.js ├── qunit.css └── qunit.js ├── jquery.jsoncookie.js ├── readme.md └── test ├── jquery.js ├── test.html └── unit.js /GPL-LICENSE.txt: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | -------------------------------------------------------------------------------- /MIT-LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright 2011 appendTo LLC. (http://appendto.com/team) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /external/jquery-1.0.1.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery - New Wave Javascript 3 | * 4 | * Copyright (c) 2006 John Resig (jquery.com) 5 | * Dual licensed under the MIT (MIT-LICENSE.txt) 6 | * and GPL (GPL-LICENSE.txt) licenses. 7 | * 8 | * $Date: 2006-10-27 23:14:48 -0400 (Fri, 27 Oct 2006) $ 9 | * $Rev: 509 $ 10 | */ 11 | 12 | // Global undefined variable 13 | window.undefined = window.undefined; 14 | function jQuery(a,c) { 15 | 16 | // Shortcut for document ready (because $(document).each() is silly) 17 | if ( a && a.constructor == Function && jQuery.fn.ready ) 18 | return jQuery(document).ready(a); 19 | 20 | // Make sure that a selection was provided 21 | a = a || jQuery.context || document; 22 | 23 | // Watch for when a jQuery object is passed as the selector 24 | if ( a.jquery ) 25 | return $( jQuery.merge( a, [] ) ); 26 | 27 | // Watch for when a jQuery object is passed at the context 28 | if ( c && c.jquery ) 29 | return $( c ).find(a); 30 | 31 | // If the context is global, return a new object 32 | if ( window == this ) 33 | return new jQuery(a,c); 34 | 35 | // Handle HTML strings 36 | var m = /^[^<]*(<.+>)[^>]*$/.exec(a); 37 | if ( m ) a = jQuery.clean( [ m[1] ] ); 38 | 39 | // Watch for when an array is passed in 40 | this.get( a.constructor == Array || a.length && !a.nodeType && a[0] != undefined && a[0].nodeType ? 41 | // Assume that it is an array of DOM Elements 42 | jQuery.merge( a, [] ) : 43 | 44 | // Find the matching elements and save them for later 45 | jQuery.find( a, c ) ); 46 | 47 | // See if an extra function was provided 48 | var fn = arguments[ arguments.length - 1 ]; 49 | 50 | // If so, execute it in context 51 | if ( fn && fn.constructor == Function ) 52 | this.each(fn); 53 | } 54 | 55 | // Map over the $ in case of overwrite 56 | if ( typeof $ != "undefined" ) 57 | jQuery._$ = $; 58 | 59 | // Map the jQuery namespace to the '$' one 60 | var $ = jQuery; 61 | 62 | jQuery.fn = jQuery.prototype = { 63 | jquery: "$Rev: 509 $", 64 | 65 | size: function() { 66 | return this.length; 67 | }, 68 | 69 | get: function( num ) { 70 | // Watch for when an array (of elements) is passed in 71 | if ( num && num.constructor == Array ) { 72 | 73 | // Use a tricky hack to make the jQuery object 74 | // look and feel like an array 75 | this.length = 0; 76 | [].push.apply( this, num ); 77 | 78 | return this; 79 | } else 80 | return num == undefined ? 81 | 82 | // Return a 'clean' array 83 | jQuery.map( this, function(a){ return a } ) : 84 | 85 | // Return just the object 86 | this[num]; 87 | }, 88 | each: function( fn, args ) { 89 | return jQuery.each( this, fn, args ); 90 | }, 91 | 92 | index: function( obj ) { 93 | var pos = -1; 94 | this.each(function(i){ 95 | if ( this == obj ) pos = i; 96 | }); 97 | return pos; 98 | }, 99 | 100 | attr: function( key, value, type ) { 101 | // Check to see if we're setting style values 102 | return key.constructor != String || value != undefined ? 103 | this.each(function(){ 104 | // See if we're setting a hash of styles 105 | if ( value == undefined ) 106 | // Set all the styles 107 | for ( var prop in key ) 108 | jQuery.attr( 109 | type ? this.style : this, 110 | prop, key[prop] 111 | ); 112 | 113 | // See if we're setting a single key/value style 114 | else 115 | jQuery.attr( 116 | type ? this.style : this, 117 | key, value 118 | ); 119 | }) : 120 | 121 | // Look for the case where we're accessing a style value 122 | jQuery[ type || "attr" ]( this[0], key ); 123 | }, 124 | 125 | css: function( key, value ) { 126 | return this.attr( key, value, "curCSS" ); 127 | }, 128 | text: function(e) { 129 | e = e || this; 130 | var t = ""; 131 | for ( var j = 0; j < e.length; j++ ) { 132 | var r = e[j].childNodes; 133 | for ( var i = 0; i < r.length; i++ ) 134 | if ( r[i].nodeType != 8 ) 135 | t += r[i].nodeType != 1 ? 136 | r[i].nodeValue : jQuery.fn.text([ r[i] ]); 137 | } 138 | return t; 139 | }, 140 | wrap: function() { 141 | // The elements to wrap the target around 142 | var a = jQuery.clean(arguments); 143 | 144 | // Wrap each of the matched elements individually 145 | return this.each(function(){ 146 | // Clone the structure that we're using to wrap 147 | var b = a[0].cloneNode(true); 148 | 149 | // Insert it before the element to be wrapped 150 | this.parentNode.insertBefore( b, this ); 151 | 152 | // Find he deepest point in the wrap structure 153 | while ( b.firstChild ) 154 | b = b.firstChild; 155 | 156 | // Move the matched element to within the wrap structure 157 | b.appendChild( this ); 158 | }); 159 | }, 160 | append: function() { 161 | return this.domManip(arguments, true, 1, function(a){ 162 | this.appendChild( a ); 163 | }); 164 | }, 165 | prepend: function() { 166 | return this.domManip(arguments, true, -1, function(a){ 167 | this.insertBefore( a, this.firstChild ); 168 | }); 169 | }, 170 | before: function() { 171 | return this.domManip(arguments, false, 1, function(a){ 172 | this.parentNode.insertBefore( a, this ); 173 | }); 174 | }, 175 | after: function() { 176 | return this.domManip(arguments, false, -1, function(a){ 177 | this.parentNode.insertBefore( a, this.nextSibling ); 178 | }); 179 | }, 180 | end: function() { 181 | return this.get( this.stack.pop() ); 182 | }, 183 | find: function(t) { 184 | return this.pushStack( jQuery.map( this, function(a){ 185 | return jQuery.find(t,a); 186 | }), arguments ); 187 | }, 188 | 189 | clone: function(deep) { 190 | return this.pushStack( jQuery.map( this, function(a){ 191 | return a.cloneNode( deep != undefined ? deep : true ); 192 | }), arguments ); 193 | }, 194 | 195 | filter: function(t) { 196 | return this.pushStack( 197 | t.constructor == Array && 198 | jQuery.map(this,function(a){ 199 | for ( var i = 0; i < t.length; i++ ) 200 | if ( jQuery.filter(t[i],[a]).r.length ) 201 | return a; 202 | }) || 203 | 204 | t.constructor == Boolean && 205 | ( t ? this.get() : [] ) || 206 | 207 | t.constructor == Function && 208 | jQuery.grep( this, t ) || 209 | 210 | jQuery.filter(t,this).r, arguments ); 211 | }, 212 | 213 | not: function(t) { 214 | return this.pushStack( t.constructor == String ? 215 | jQuery.filter(t,this,false).r : 216 | jQuery.grep(this,function(a){ return a != t; }), arguments ); 217 | }, 218 | 219 | add: function(t) { 220 | return this.pushStack( jQuery.merge( this, t.constructor == String ? 221 | jQuery.find(t) : t.constructor == Array ? t : [t] ), arguments ); 222 | }, 223 | is: function(expr) { 224 | return expr ? jQuery.filter(expr,this).r.length > 0 : this.length > 0; 225 | }, 226 | domManip: function(args, table, dir, fn){ 227 | var clone = this.size() > 1; 228 | var a = jQuery.clean(args); 229 | 230 | return this.each(function(){ 231 | var obj = this; 232 | 233 | if ( table && this.nodeName == "TABLE" && a[0].nodeName != "THEAD" ) { 234 | var tbody = this.getElementsByTagName("tbody"); 235 | 236 | if ( !tbody.length ) { 237 | obj = document.createElement("tbody"); 238 | this.appendChild( obj ); 239 | } else 240 | obj = tbody[0]; 241 | } 242 | 243 | for ( var i = ( dir < 0 ? a.length - 1 : 0 ); 244 | i != ( dir < 0 ? dir : a.length ); i += dir ) { 245 | fn.apply( obj, [ clone ? a[i].cloneNode(true) : a[i] ] ); 246 | } 247 | }); 248 | }, 249 | pushStack: function(a,args) { 250 | var fn = args && args[args.length-1]; 251 | 252 | if ( !fn || fn.constructor != Function ) { 253 | if ( !this.stack ) this.stack = []; 254 | this.stack.push( this.get() ); 255 | this.get( a ); 256 | } else { 257 | var old = this.get(); 258 | this.get( a ); 259 | if ( fn.constructor == Function ) 260 | return this.each( fn ); 261 | this.get( old ); 262 | } 263 | 264 | return this; 265 | } 266 | }; 267 | 268 | jQuery.extend = jQuery.fn.extend = function(obj,prop) { 269 | if ( !prop ) { prop = obj; obj = this; } 270 | for ( var i in prop ) obj[i] = prop[i]; 271 | return obj; 272 | }; 273 | 274 | jQuery.extend({ 275 | init: function(){ 276 | jQuery.initDone = true; 277 | 278 | jQuery.each( jQuery.macros.axis, function(i,n){ 279 | jQuery.fn[ i ] = function(a) { 280 | var ret = jQuery.map(this,n); 281 | if ( a && a.constructor == String ) 282 | ret = jQuery.filter(a,ret).r; 283 | return this.pushStack( ret, arguments ); 284 | }; 285 | }); 286 | 287 | jQuery.each( jQuery.macros.to, function(i,n){ 288 | jQuery.fn[ i ] = function(){ 289 | var a = arguments; 290 | return this.each(function(){ 291 | for ( var j = 0; j < a.length; j++ ) 292 | $(a[j])[n]( this ); 293 | }); 294 | }; 295 | }); 296 | 297 | jQuery.each( jQuery.macros.each, function(i,n){ 298 | jQuery.fn[ i ] = function() { 299 | return this.each( n, arguments ); 300 | }; 301 | }); 302 | 303 | jQuery.each( jQuery.macros.filter, function(i,n){ 304 | jQuery.fn[ n ] = function(num,fn) { 305 | return this.filter( ":" + n + "(" + num + ")", fn ); 306 | }; 307 | }); 308 | 309 | jQuery.each( jQuery.macros.attr, function(i,n){ 310 | n = n || i; 311 | jQuery.fn[ i ] = function(h) { 312 | return h == undefined ? 313 | this.length ? this[0][n] : null : 314 | this.attr( n, h ); 315 | }; 316 | }); 317 | 318 | jQuery.each( jQuery.macros.css, function(i,n){ 319 | jQuery.fn[ n ] = function(h) { 320 | return h == undefined ? 321 | ( this.length ? jQuery.css( this[0], n ) : null ) : 322 | this.css( n, h ); 323 | }; 324 | }); 325 | 326 | }, 327 | each: function( obj, fn, args ) { 328 | if ( obj.length == undefined ) 329 | for ( var i in obj ) 330 | fn.apply( obj[i], args || [i, obj[i]] ); 331 | else 332 | for ( var i = 0; i < obj.length; i++ ) 333 | fn.apply( obj[i], args || [i, obj[i]] ); 334 | return obj; 335 | }, 336 | 337 | className: { 338 | add: function(o,c){ 339 | if (jQuery.className.has(o,c)) return; 340 | o.className += ( o.className ? " " : "" ) + c; 341 | }, 342 | remove: function(o,c){ 343 | o.className = !c ? "" : 344 | o.className.replace( 345 | new RegExp("(^|\\s*\\b[^-])"+c+"($|\\b(?=[^-]))", "g"), ""); 346 | }, 347 | has: function(e,a) { 348 | if ( e.className != undefined ) 349 | e = e.className; 350 | return new RegExp("(^|\\s)" + a + "(\\s|$)").test(e); 351 | } 352 | }, 353 | swap: function(e,o,f) { 354 | for ( var i in o ) { 355 | e.style["old"+i] = e.style[i]; 356 | e.style[i] = o[i]; 357 | } 358 | f.apply( e, [] ); 359 | for ( var i in o ) 360 | e.style[i] = e.style["old"+i]; 361 | }, 362 | 363 | css: function(e,p) { 364 | if ( p == "height" || p == "width" ) { 365 | var old = {}, oHeight, oWidth, d = ["Top","Bottom","Right","Left"]; 366 | 367 | for ( var i in d ) { 368 | old["padding" + d[i]] = 0; 369 | old["border" + d[i] + "Width"] = 0; 370 | } 371 | 372 | jQuery.swap( e, old, function() { 373 | if (jQuery.css(e,"display") != "none") { 374 | oHeight = e.offsetHeight; 375 | oWidth = e.offsetWidth; 376 | } else { 377 | e = $(e.cloneNode(true)).css({ 378 | visibility: "hidden", position: "absolute", display: "block" 379 | }).prependTo("body")[0]; 380 | 381 | oHeight = e.clientHeight; 382 | oWidth = e.clientWidth; 383 | 384 | e.parentNode.removeChild(e); 385 | } 386 | }); 387 | 388 | return p == "height" ? oHeight : oWidth; 389 | } else if ( p == "opacity" && jQuery.browser.msie ) 390 | return parseFloat( jQuery.curCSS(e,"filter").replace(/[^0-9.]/,"") ) || 1; 391 | 392 | return jQuery.curCSS( e, p ); 393 | }, 394 | 395 | curCSS: function(elem, prop, force) { 396 | var ret; 397 | 398 | if (!force && elem.style[prop]) { 399 | 400 | ret = elem.style[prop]; 401 | 402 | } else if (elem.currentStyle) { 403 | 404 | var newProp = prop.replace(/\-(\w)/g,function(m,c){return c.toUpperCase()}); 405 | ret = elem.currentStyle[prop] || elem.currentStyle[newProp]; 406 | 407 | } else if (document.defaultView && document.defaultView.getComputedStyle) { 408 | 409 | prop = prop.replace(/([A-Z])/g,"-$1").toLowerCase(); 410 | var cur = document.defaultView.getComputedStyle(elem, null); 411 | 412 | if ( cur ) 413 | ret = cur.getPropertyValue(prop); 414 | else if ( prop == 'display' ) 415 | ret = 'none'; 416 | else 417 | jQuery.swap(elem, { display: 'block' }, function() { 418 | ret = document.defaultView.getComputedStyle(this,null).getPropertyValue(prop); 419 | }); 420 | 421 | } 422 | 423 | return ret; 424 | }, 425 | 426 | clean: function(a) { 427 | var r = []; 428 | for ( var i = 0; i < a.length; i++ ) { 429 | if ( a[i].constructor == String ) { 430 | 431 | var table = ""; 432 | 433 | if ( !a[i].indexOf(""; 436 | } else if ( !a[i].indexOf(""; 439 | } else if ( !a[i].indexOf(""; 442 | } 443 | 444 | var div = document.createElement("div"); 445 | div.innerHTML = a[i]; 446 | 447 | if ( table ) { 448 | div = div.firstChild; 449 | if ( table != "thead" ) div = div.firstChild; 450 | if ( table == "td" ) div = div.firstChild; 451 | } 452 | 453 | for ( var j = 0; j < div.childNodes.length; j++ ) 454 | r.push( div.childNodes[j] ); 455 | } else if ( a[i].jquery || a[i].length && !a[i].nodeType ) 456 | for ( var k = 0; k < a[i].length; k++ ) 457 | r.push( a[i][k] ); 458 | else if ( a[i] !== null ) 459 | r.push( a[i].nodeType ? a[i] : document.createTextNode(a[i].toString()) ); 460 | } 461 | return r; 462 | }, 463 | 464 | expr: { 465 | "": "m[2]== '*'||a.nodeName.toUpperCase()==m[2].toUpperCase()", 466 | "#": "a.getAttribute('id')&&a.getAttribute('id')==m[2]", 467 | ":": { 468 | // Position Checks 469 | lt: "im[3]-0", 471 | nth: "m[3]-0==i", 472 | eq: "m[3]-0==i", 473 | first: "i==0", 474 | last: "i==r.length-1", 475 | even: "i%2==0", 476 | odd: "i%2", 477 | 478 | // Child Checks 479 | "nth-child": "jQuery.sibling(a,m[3]).cur", 480 | "first-child": "jQuery.sibling(a,0).cur", 481 | "last-child": "jQuery.sibling(a,0).last", 482 | "only-child": "jQuery.sibling(a).length==1", 483 | 484 | // Parent Checks 485 | parent: "a.childNodes.length", 486 | empty: "!a.childNodes.length", 487 | 488 | // Text Check 489 | contains: "(a.innerText||a.innerHTML).indexOf(m[3])>=0", 490 | 491 | // Visibility 492 | visible: "a.type!='hidden'&&jQuery.css(a,'display')!='none'&&jQuery.css(a,'visibility')!='hidden'", 493 | hidden: "a.type=='hidden'||jQuery.css(a,'display')=='none'||jQuery.css(a,'visibility')=='hidden'", 494 | 495 | // Form elements 496 | enabled: "!a.disabled", 497 | disabled: "a.disabled", 498 | checked: "a.checked", 499 | selected: "a.selected" 500 | }, 501 | ".": "jQuery.className.has(a,m[2])", 502 | "@": { 503 | "=": "z==m[4]", 504 | "!=": "z!=m[4]", 505 | "^=": "!z.indexOf(m[4])", 506 | "$=": "z.substr(z.length - m[4].length,m[4].length)==m[4]", 507 | "*=": "z.indexOf(m[4])>=0", 508 | "": "z" 509 | }, 510 | "[": "jQuery.find(m[2],a).length" 511 | }, 512 | 513 | token: [ 514 | "\\.\\.|/\\.\\.", "a.parentNode", 515 | ">|/", "jQuery.sibling(a.firstChild)", 516 | "\\+", "jQuery.sibling(a).next", 517 | "~", function(a){ 518 | var r = []; 519 | var s = jQuery.sibling(a); 520 | if ( s.n > 0 ) 521 | for ( var i = s.n; i < s.length; i++ ) 522 | r.push( s[i] ); 523 | return r; 524 | } 525 | ], 526 | find: function( t, context ) { 527 | // Make sure that the context is a DOM Element 528 | if ( context && context.nodeType == undefined ) 529 | context = null; 530 | 531 | // Set the correct context (if none is provided) 532 | context = context || jQuery.context || document; 533 | 534 | if ( t.constructor != String ) return [t]; 535 | 536 | if ( !t.indexOf("//") ) { 537 | context = context.documentElement; 538 | t = t.substr(2,t.length); 539 | } else if ( !t.indexOf("/") ) { 540 | context = context.documentElement; 541 | t = t.substr(1,t.length); 542 | // FIX Assume the root element is right :( 543 | if ( t.indexOf("/") >= 1 ) 544 | t = t.substr(t.indexOf("/"),t.length); 545 | } 546 | 547 | var ret = [context]; 548 | var done = []; 549 | var last = null; 550 | 551 | while ( t.length > 0 && last != t ) { 552 | var r = []; 553 | last = t; 554 | 555 | t = jQuery.trim(t).replace( /^\/\//i, "" ); 556 | 557 | var foundToken = false; 558 | 559 | for ( var i = 0; i < jQuery.token.length; i += 2 ) { 560 | if ( foundToken ) continue; 561 | 562 | var re = new RegExp("^(" + jQuery.token[i] + ")"); 563 | var m = re.exec(t); 564 | 565 | if ( m ) { 566 | r = ret = jQuery.map( ret, jQuery.token[i+1] ); 567 | t = jQuery.trim( t.replace( re, "" ) ); 568 | foundToken = true; 569 | } 570 | } 571 | 572 | if ( !foundToken ) { 573 | if ( !t.indexOf(",") || !t.indexOf("|") ) { 574 | if ( ret[0] == context ) ret.shift(); 575 | done = jQuery.merge( done, ret ); 576 | r = ret = [context]; 577 | t = " " + t.substr(1,t.length); 578 | } else { 579 | var re2 = /^([#.]?)([a-z0-9\\*_-]*)/i; 580 | var m = re2.exec(t); 581 | 582 | if ( m[1] == "#" ) { 583 | // Ummm, should make this work in all XML docs 584 | var oid = document.getElementById(m[2]); 585 | r = ret = oid ? [oid] : []; 586 | t = t.replace( re2, "" ); 587 | } else { 588 | if ( !m[2] || m[1] == "." ) m[2] = "*"; 589 | 590 | for ( var i = 0; i < ret.length; i++ ) 591 | r = jQuery.merge( r, 592 | m[2] == "*" ? 593 | jQuery.getAll(ret[i]) : 594 | ret[i].getElementsByTagName(m[2]) 595 | ); 596 | } 597 | } 598 | 599 | } 600 | 601 | if ( t ) { 602 | var val = jQuery.filter(t,r); 603 | ret = r = val.r; 604 | t = jQuery.trim(val.t); 605 | } 606 | } 607 | 608 | if ( ret && ret[0] == context ) ret.shift(); 609 | done = jQuery.merge( done, ret ); 610 | 611 | return done; 612 | }, 613 | 614 | getAll: function(o,r) { 615 | r = r || []; 616 | var s = o.childNodes; 617 | for ( var i = 0; i < s.length; i++ ) 618 | if ( s[i].nodeType == 1 ) { 619 | r.push( s[i] ); 620 | jQuery.getAll( s[i], r ); 621 | } 622 | return r; 623 | }, 624 | 625 | attr: function(elem, name, value){ 626 | var fix = { 627 | "for": "htmlFor", 628 | "class": "className", 629 | "float": "cssFloat", 630 | innerHTML: "innerHTML", 631 | className: "className", 632 | value: "value", 633 | disabled: "disabled" 634 | }; 635 | 636 | if ( fix[name] ) { 637 | if ( value != undefined ) elem[fix[name]] = value; 638 | return elem[fix[name]]; 639 | } else if ( elem.getAttribute ) { 640 | if ( value != undefined ) elem.setAttribute( name, value ); 641 | return elem.getAttribute( name, 2 ); 642 | } else { 643 | name = name.replace(/-([a-z])/ig,function(z,b){return b.toUpperCase();}); 644 | if ( value != undefined ) elem[name] = value; 645 | return elem[name]; 646 | } 647 | }, 648 | 649 | // The regular expressions that power the parsing engine 650 | parse: [ 651 | // Match: [@value='test'], [@foo] 652 | [ "\\[ *(@)S *([!*$^=]*) *Q\\]", 1 ], 653 | 654 | // Match: [div], [div p] 655 | [ "(\\[)Q\\]", 0 ], 656 | 657 | // Match: :contains('foo') 658 | [ "(:)S\\(Q\\)", 0 ], 659 | 660 | // Match: :even, :last-chlid 661 | [ "([:.#]*)S", 0 ] 662 | ], 663 | 664 | filter: function(t,r,not) { 665 | // Figure out if we're doing regular, or inverse, filtering 666 | var g = not !== false ? jQuery.grep : 667 | function(a,f) {return jQuery.grep(a,f,true);}; 668 | 669 | while ( t && /^[a-z[({<*:.#]/i.test(t) ) { 670 | 671 | var p = jQuery.parse; 672 | 673 | for ( var i = 0; i < p.length; i++ ) { 674 | var re = new RegExp( "^" + p[i][0] 675 | 676 | // Look for a string-like sequence 677 | .replace( 'S', "([a-z*_-][a-z0-9_-]*)" ) 678 | 679 | // Look for something (optionally) enclosed with quotes 680 | .replace( 'Q', " *'?\"?([^'\"]*?)'?\"? *" ), "i" ); 681 | 682 | var m = re.exec( t ); 683 | 684 | if ( m ) { 685 | // Re-organize the match 686 | if ( p[i][1] ) 687 | m = ["", m[1], m[3], m[2], m[4]]; 688 | 689 | // Remove what we just matched 690 | t = t.replace( re, "" ); 691 | 692 | break; 693 | } 694 | } 695 | 696 | // :not() is a special case that can be optomized by 697 | // keeping it out of the expression list 698 | if ( m[1] == ":" && m[2] == "not" ) 699 | r = jQuery.filter(m[3],r,false).r; 700 | 701 | // Otherwise, find the expression to execute 702 | else { 703 | var f = jQuery.expr[m[1]]; 704 | if ( f.constructor != String ) 705 | f = jQuery.expr[m[1]][m[2]]; 706 | 707 | // Build a custom macro to enclose it 708 | eval("f = function(a,i){" + 709 | ( m[1] == "@" ? "z=jQuery.attr(a,m[3]);" : "" ) + 710 | "return " + f + "}"); 711 | 712 | // Execute it against the current filter 713 | r = g( r, f ); 714 | } 715 | } 716 | 717 | // Return an array of filtered elements (r) 718 | // and the modified expression string (t) 719 | return { r: r, t: t }; 720 | }, 721 | trim: function(t){ 722 | return t.replace(/^\s+|\s+$/g, ""); 723 | }, 724 | parents: function( elem ){ 725 | var matched = []; 726 | var cur = elem.parentNode; 727 | while ( cur && cur != document ) { 728 | matched.push( cur ); 729 | cur = cur.parentNode; 730 | } 731 | return matched; 732 | }, 733 | sibling: function(elem, pos, not) { 734 | var elems = []; 735 | 736 | var siblings = elem.parentNode.childNodes; 737 | for ( var i = 0; i < siblings.length; i++ ) { 738 | if ( not === true && siblings[i] == elem ) continue; 739 | 740 | if ( siblings[i].nodeType == 1 ) 741 | elems.push( siblings[i] ); 742 | if ( siblings[i] == elem ) 743 | elems.n = elems.length - 1; 744 | } 745 | 746 | return jQuery.extend( elems, { 747 | last: elems.n == elems.length - 1, 748 | cur: pos == "even" && elems.n % 2 == 0 || pos == "odd" && elems.n % 2 || elems[pos] == elem, 749 | prev: elems[elems.n - 1], 750 | next: elems[elems.n + 1] 751 | }); 752 | }, 753 | merge: function(first, second) { 754 | var result = []; 755 | 756 | // Move b over to the new array (this helps to avoid 757 | // StaticNodeList instances) 758 | for ( var k = 0; k < first.length; k++ ) 759 | result[k] = first[k]; 760 | 761 | // Now check for duplicates between a and b and only 762 | // add the unique items 763 | for ( var i = 0; i < second.length; i++ ) { 764 | var noCollision = true; 765 | 766 | // The collision-checking process 767 | for ( var j = 0; j < first.length; j++ ) 768 | if ( second[i] == first[j] ) 769 | noCollision = false; 770 | 771 | // If the item is unique, add it 772 | if ( noCollision ) 773 | result.push( second[i] ); 774 | } 775 | 776 | return result; 777 | }, 778 | grep: function(elems, fn, inv) { 779 | // If a string is passed in for the function, make a function 780 | // for it (a handy shortcut) 781 | if ( fn.constructor == String ) 782 | fn = new Function("a","i","return " + fn); 783 | 784 | var result = []; 785 | 786 | // Go through the array, only saving the items 787 | // that pass the validator function 788 | for ( var i = 0; i < elems.length; i++ ) 789 | if ( !inv && fn(elems[i],i) || inv && !fn(elems[i],i) ) 790 | result.push( elems[i] ); 791 | 792 | return result; 793 | }, 794 | map: function(elems, fn) { 795 | // If a string is passed in for the function, make a function 796 | // for it (a handy shortcut) 797 | if ( fn.constructor == String ) 798 | fn = new Function("a","return " + fn); 799 | 800 | var result = []; 801 | 802 | // Go through the array, translating each of the items to their 803 | // new value (or values). 804 | for ( var i = 0; i < elems.length; i++ ) { 805 | var val = fn(elems[i],i); 806 | 807 | if ( val !== null && val != undefined ) { 808 | if ( val.constructor != Array ) val = [val]; 809 | result = jQuery.merge( result, val ); 810 | } 811 | } 812 | 813 | return result; 814 | }, 815 | 816 | /* 817 | * A number of helper functions used for managing events. 818 | * Many of the ideas behind this code orignated from Dean Edwards' addEvent library. 819 | */ 820 | event: { 821 | 822 | // Bind an event to an element 823 | // Original by Dean Edwards 824 | add: function(element, type, handler) { 825 | // For whatever reason, IE has trouble passing the window object 826 | // around, causing it to be cloned in the process 827 | if ( jQuery.browser.msie && element.setInterval != undefined ) 828 | element = window; 829 | 830 | // Make sure that the function being executed has a unique ID 831 | if ( !handler.guid ) 832 | handler.guid = this.guid++; 833 | 834 | // Init the element's event structure 835 | if (!element.events) 836 | element.events = {}; 837 | 838 | // Get the current list of functions bound to this event 839 | var handlers = element.events[type]; 840 | 841 | // If it hasn't been initialized yet 842 | if (!handlers) { 843 | // Init the event handler queue 844 | handlers = element.events[type] = {}; 845 | 846 | // Remember an existing handler, if it's already there 847 | if (element["on" + type]) 848 | handlers[0] = element["on" + type]; 849 | } 850 | 851 | // Add the function to the element's handler list 852 | handlers[handler.guid] = handler; 853 | 854 | // And bind the global event handler to the element 855 | element["on" + type] = this.handle; 856 | 857 | // Remember the function in a global list (for triggering) 858 | if (!this.global[type]) 859 | this.global[type] = []; 860 | this.global[type].push( element ); 861 | }, 862 | 863 | guid: 1, 864 | global: {}, 865 | 866 | // Detach an event or set of events from an element 867 | remove: function(element, type, handler) { 868 | if (element.events) 869 | if (type && element.events[type]) 870 | if ( handler ) 871 | delete element.events[type][handler.guid]; 872 | else 873 | for ( var i in element.events[type] ) 874 | delete element.events[type][i]; 875 | else 876 | for ( var j in element.events ) 877 | this.remove( element, j ); 878 | }, 879 | 880 | trigger: function(type,data,element) { 881 | // Touch up the incoming data 882 | data = data || []; 883 | 884 | // Handle a global trigger 885 | if ( !element ) { 886 | var g = this.global[type]; 887 | if ( g ) 888 | for ( var i = 0; i < g.length; i++ ) 889 | this.trigger( type, data, g[i] ); 890 | 891 | // Handle triggering a single element 892 | } else if ( element["on" + type] ) { 893 | // Pass along a fake event 894 | data.unshift( this.fix({ type: type, target: element }) ); 895 | 896 | // Trigger the event 897 | element["on" + type].apply( element, data ); 898 | } 899 | }, 900 | 901 | handle: function(event) { 902 | if ( typeof jQuery == "undefined" ) return; 903 | 904 | event = event || jQuery.event.fix( window.event ); 905 | 906 | // If no correct event was found, fail 907 | if ( !event ) return; 908 | 909 | var returnValue = true; 910 | 911 | var c = this.events[event.type]; 912 | 913 | for ( var j in c ) { 914 | if ( c[j].apply( this, [event] ) === false ) { 915 | event.preventDefault(); 916 | event.stopPropagation(); 917 | returnValue = false; 918 | } 919 | } 920 | 921 | return returnValue; 922 | }, 923 | 924 | fix: function(event) { 925 | if ( event ) { 926 | event.preventDefault = function() { 927 | this.returnValue = false; 928 | }; 929 | 930 | event.stopPropagation = function() { 931 | this.cancelBubble = true; 932 | }; 933 | } 934 | 935 | return event; 936 | } 937 | 938 | } 939 | }); 940 | 941 | new function() { 942 | var b = navigator.userAgent.toLowerCase(); 943 | 944 | // Figure out what browser is being used 945 | jQuery.browser = { 946 | safari: /webkit/.test(b), 947 | opera: /opera/.test(b), 948 | msie: /msie/.test(b) && !/opera/.test(b), 949 | mozilla: /mozilla/.test(b) && !/compatible/.test(b) 950 | }; 951 | 952 | // Check to see if the W3C box model is being used 953 | jQuery.boxModel = !jQuery.browser.msie || document.compatMode == "CSS1Compat"; 954 | }; 955 | 956 | jQuery.macros = { 957 | to: { 958 | appendTo: "append", 959 | prependTo: "prepend", 960 | insertBefore: "before", 961 | insertAfter: "after" 962 | }, 963 | 964 | 965 | css: "width,height,top,left,position,float,overflow,color,background".split(","), 966 | 967 | filter: [ "eq", "lt", "gt", "contains" ], 968 | 969 | attr: { 970 | 971 | val: "value", 972 | 973 | html: "innerHTML", 974 | 975 | id: null, 976 | 977 | title: null, 978 | 979 | name: null, 980 | 981 | href: null, 982 | 983 | src: null, 984 | 985 | rel: null 986 | }, 987 | 988 | axis: { 989 | 990 | parent: "a.parentNode", 991 | 992 | ancestors: jQuery.parents, 993 | 994 | parents: jQuery.parents, 995 | 996 | next: "jQuery.sibling(a).next", 997 | 998 | prev: "jQuery.sibling(a).prev", 999 | 1000 | siblings: jQuery.sibling, 1001 | 1002 | children: "jQuery.sibling(a.firstChild)" 1003 | }, 1004 | 1005 | each: { 1006 | 1007 | removeAttr: function( key ) { 1008 | this.removeAttribute( key ); 1009 | }, 1010 | show: function(){ 1011 | this.style.display = this.oldblock ? this.oldblock : ""; 1012 | if ( jQuery.css(this,"display") == "none" ) 1013 | this.style.display = "block"; 1014 | }, 1015 | hide: function(){ 1016 | this.oldblock = this.oldblock || jQuery.css(this,"display"); 1017 | if ( this.oldblock == "none" ) 1018 | this.oldblock = "block"; 1019 | this.style.display = "none"; 1020 | }, 1021 | toggle: function(){ 1022 | $(this)[ $(this).is(":hidden") ? "show" : "hide" ].apply( $(this), arguments ); 1023 | }, 1024 | addClass: function(c){ 1025 | jQuery.className.add(this,c); 1026 | }, 1027 | removeClass: function(c){ 1028 | jQuery.className.remove(this,c); 1029 | }, 1030 | toggleClass: function( c ){ 1031 | jQuery.className[ jQuery.className.has(this,c) ? "remove" : "add" ](this,c); 1032 | }, 1033 | 1034 | remove: function(a){ 1035 | if ( !a || jQuery.filter( a, [this] ).r ) 1036 | this.parentNode.removeChild( this ); 1037 | }, 1038 | empty: function(){ 1039 | while ( this.firstChild ) 1040 | this.removeChild( this.firstChild ); 1041 | }, 1042 | bind: function( type, fn ) { 1043 | if ( fn.constructor == String ) 1044 | fn = new Function("e", ( !fn.indexOf(".") ? "$(this)" : "return " ) + fn); 1045 | jQuery.event.add( this, type, fn ); 1046 | }, 1047 | 1048 | unbind: function( type, fn ) { 1049 | jQuery.event.remove( this, type, fn ); 1050 | }, 1051 | trigger: function( type, data ) { 1052 | jQuery.event.trigger( type, data, this ); 1053 | } 1054 | } 1055 | }; 1056 | 1057 | jQuery.init(); 1058 | jQuery.fn.extend({ 1059 | 1060 | // We're overriding the old toggle function, so 1061 | // remember it for later 1062 | _toggle: jQuery.fn.toggle, 1063 | toggle: function(a,b) { 1064 | // If two functions are passed in, we're 1065 | // toggling on a click 1066 | return a && b && a.constructor == Function && b.constructor == Function ? this.click(function(e){ 1067 | // Figure out which function to execute 1068 | this.last = this.last == a ? b : a; 1069 | 1070 | // Make sure that clicks stop 1071 | e.preventDefault(); 1072 | 1073 | // and execute the function 1074 | return this.last.apply( this, [e] ) || false; 1075 | }) : 1076 | 1077 | // Otherwise, execute the old toggle function 1078 | this._toggle.apply( this, arguments ); 1079 | }, 1080 | 1081 | hover: function(f,g) { 1082 | 1083 | // A private function for haandling mouse 'hovering' 1084 | function handleHover(e) { 1085 | // Check if mouse(over|out) are still within the same parent element 1086 | var p = (e.type == "mouseover" ? e.fromElement : e.toElement) || e.relatedTarget; 1087 | 1088 | // Traverse up the tree 1089 | while ( p && p != this ) p = p.parentNode; 1090 | 1091 | // If we actually just moused on to a sub-element, ignore it 1092 | if ( p == this ) return false; 1093 | 1094 | // Execute the right function 1095 | return (e.type == "mouseover" ? f : g).apply(this, [e]); 1096 | } 1097 | 1098 | // Bind the function to the two event listeners 1099 | return this.mouseover(handleHover).mouseout(handleHover); 1100 | }, 1101 | ready: function(f) { 1102 | // If the DOM is already ready 1103 | if ( jQuery.isReady ) 1104 | // Execute the function immediately 1105 | f.apply( document ); 1106 | 1107 | // Otherwise, remember the function for later 1108 | else { 1109 | // Add the function to the wait list 1110 | jQuery.readyList.push( f ); 1111 | } 1112 | 1113 | return this; 1114 | } 1115 | }); 1116 | 1117 | jQuery.extend({ 1118 | /* 1119 | * All the code that makes DOM Ready work nicely. 1120 | */ 1121 | isReady: false, 1122 | readyList: [], 1123 | 1124 | // Handle when the DOM is ready 1125 | ready: function() { 1126 | // Make sure that the DOM is not already loaded 1127 | if ( !jQuery.isReady ) { 1128 | // Remember that the DOM is ready 1129 | jQuery.isReady = true; 1130 | 1131 | // If there are functions bound, to execute 1132 | if ( jQuery.readyList ) { 1133 | // Execute all of them 1134 | for ( var i = 0; i < jQuery.readyList.length; i++ ) 1135 | jQuery.readyList[i].apply( document ); 1136 | 1137 | // Reset the list of functions 1138 | jQuery.readyList = null; 1139 | } 1140 | } 1141 | } 1142 | }); 1143 | 1144 | new function(){ 1145 | 1146 | var e = ("blur,focus,load,resize,scroll,unload,click,dblclick," + 1147 | "mousedown,mouseup,mousemove,mouseover,mouseout,change,reset,select," + 1148 | "submit,keydown,keypress,keyup,error").split(","); 1149 | 1150 | // Go through all the event names, but make sure that 1151 | // it is enclosed properly 1152 | for ( var i = 0; i < e.length; i++ ) new function(){ 1153 | 1154 | var o = e[i]; 1155 | 1156 | // Handle event binding 1157 | jQuery.fn[o] = function(f){ 1158 | return f ? this.bind(o, f) : this.trigger(o); 1159 | }; 1160 | 1161 | // Handle event unbinding 1162 | jQuery.fn["un"+o] = function(f){ return this.unbind(o, f); }; 1163 | 1164 | // Finally, handle events that only fire once 1165 | jQuery.fn["one"+o] = function(f){ 1166 | // Attach the event listener 1167 | return this.each(function(){ 1168 | 1169 | var count = 0; 1170 | 1171 | // Add the event 1172 | jQuery.event.add( this, o, function(e){ 1173 | // If this function has already been executed, stop 1174 | if ( count++ ) return; 1175 | 1176 | // And execute the bound function 1177 | return f.apply(this, [e]); 1178 | }); 1179 | }); 1180 | }; 1181 | 1182 | }; 1183 | 1184 | // If Mozilla is used 1185 | if ( jQuery.browser.mozilla || jQuery.browser.opera ) { 1186 | // Use the handy event callback 1187 | document.addEventListener( "DOMContentLoaded", jQuery.ready, false ); 1188 | 1189 | // If IE is used, use the excellent hack by Matthias Miller 1190 | // http://www.outofhanwell.com/blog/index.php?title=the_window_onload_problem_revisited 1191 | } else if ( jQuery.browser.msie ) { 1192 | 1193 | // Only works if you document.write() it 1194 | document.write("<\/script>"); 1196 | 1197 | // Use the defer script hack 1198 | var script = document.getElementById("__ie_init"); 1199 | script.onreadystatechange = function() { 1200 | if ( this.readyState != "complete" ) return; 1201 | this.parentNode.removeChild( this ); 1202 | jQuery.ready(); 1203 | }; 1204 | 1205 | // Clear from memory 1206 | script = null; 1207 | 1208 | // If Safari is used 1209 | } else if ( jQuery.browser.safari ) { 1210 | // Continually check to see if the document.readyState is valid 1211 | jQuery.safariTimer = setInterval(function(){ 1212 | // loaded and complete are both valid states 1213 | if ( document.readyState == "loaded" || 1214 | document.readyState == "complete" ) { 1215 | 1216 | // If either one are found, remove the timer 1217 | clearInterval( jQuery.safariTimer ); 1218 | jQuery.safariTimer = null; 1219 | 1220 | // and execute any waiting functions 1221 | jQuery.ready(); 1222 | } 1223 | }, 10); 1224 | } 1225 | 1226 | // A fallback to window.onload, that will always work 1227 | jQuery.event.add( window, "load", jQuery.ready ); 1228 | 1229 | }; 1230 | jQuery.fn.extend({ 1231 | 1232 | // overwrite the old show method 1233 | _show: jQuery.fn.show, 1234 | 1235 | show: function(speed,callback){ 1236 | return speed ? this.animate({ 1237 | height: "show", width: "show", opacity: "show" 1238 | }, speed, callback) : this._show(); 1239 | }, 1240 | 1241 | // Overwrite the old hide method 1242 | _hide: jQuery.fn.hide, 1243 | 1244 | hide: function(speed,callback){ 1245 | return speed ? this.animate({ 1246 | height: "hide", width: "hide", opacity: "hide" 1247 | }, speed, callback) : this._hide(); 1248 | }, 1249 | 1250 | slideDown: function(speed,callback){ 1251 | return this.animate({height: "show"}, speed, callback); 1252 | }, 1253 | 1254 | slideUp: function(speed,callback){ 1255 | return this.animate({height: "hide"}, speed, callback); 1256 | }, 1257 | 1258 | slideToggle: function(speed,callback){ 1259 | return this.each(function(){ 1260 | var state = $(this).is(":hidden") ? "show" : "hide"; 1261 | $(this).animate({height: state}, speed, callback); 1262 | }); 1263 | }, 1264 | 1265 | fadeIn: function(speed,callback){ 1266 | return this.animate({opacity: "show"}, speed, callback); 1267 | }, 1268 | 1269 | fadeOut: function(speed,callback){ 1270 | return this.animate({opacity: "hide"}, speed, callback); 1271 | }, 1272 | 1273 | fadeTo: function(speed,to,callback){ 1274 | return this.animate({opacity: to}, speed, callback); 1275 | }, 1276 | animate: function(prop,speed,callback) { 1277 | return this.queue(function(){ 1278 | 1279 | this.curAnim = prop; 1280 | 1281 | for ( var p in prop ) { 1282 | var e = new jQuery.fx( this, jQuery.speed(speed,callback), p ); 1283 | if ( prop[p].constructor == Number ) 1284 | e.custom( e.cur(), prop[p] ); 1285 | else 1286 | e[ prop[p] ]( prop ); 1287 | } 1288 | 1289 | }); 1290 | }, 1291 | queue: function(type,fn){ 1292 | if ( !fn ) { 1293 | fn = type; 1294 | type = "fx"; 1295 | } 1296 | 1297 | return this.each(function(){ 1298 | if ( !this.queue ) 1299 | this.queue = {}; 1300 | 1301 | if ( !this.queue[type] ) 1302 | this.queue[type] = []; 1303 | 1304 | this.queue[type].push( fn ); 1305 | 1306 | if ( this.queue[type].length == 1 ) 1307 | fn.apply(this); 1308 | }); 1309 | } 1310 | 1311 | }); 1312 | 1313 | jQuery.extend({ 1314 | 1315 | setAuto: function(e,p) { 1316 | if ( e.notAuto ) return; 1317 | 1318 | if ( p == "height" && e.scrollHeight != parseInt(jQuery.curCSS(e,p)) ) return; 1319 | if ( p == "width" && e.scrollWidth != parseInt(jQuery.curCSS(e,p)) ) return; 1320 | 1321 | // Remember the original height 1322 | var a = e.style[p]; 1323 | 1324 | // Figure out the size of the height right now 1325 | var o = jQuery.curCSS(e,p,1); 1326 | 1327 | if ( p == "height" && e.scrollHeight != o || 1328 | p == "width" && e.scrollWidth != o ) return; 1329 | 1330 | // Set the height to auto 1331 | e.style[p] = e.currentStyle ? "" : "auto"; 1332 | 1333 | // See what the size of "auto" is 1334 | var n = jQuery.curCSS(e,p,1); 1335 | 1336 | // Revert back to the original size 1337 | if ( o != n && n != "auto" ) { 1338 | e.style[p] = a; 1339 | e.notAuto = true; 1340 | } 1341 | }, 1342 | 1343 | speed: function(s,o) { 1344 | o = o || {}; 1345 | 1346 | if ( o.constructor == Function ) 1347 | o = { complete: o }; 1348 | 1349 | var ss = { slow: 600, fast: 200 }; 1350 | o.duration = (s && s.constructor == Number ? s : ss[s]) || 400; 1351 | 1352 | // Queueing 1353 | o.oldComplete = o.complete; 1354 | o.complete = function(){ 1355 | jQuery.dequeue(this, "fx"); 1356 | if ( o.oldComplete && o.oldComplete.constructor == Function ) 1357 | o.oldComplete.apply( this ); 1358 | }; 1359 | 1360 | return o; 1361 | }, 1362 | 1363 | queue: {}, 1364 | 1365 | dequeue: function(elem,type){ 1366 | type = type || "fx"; 1367 | 1368 | if ( elem.queue && elem.queue[type] ) { 1369 | // Remove self 1370 | elem.queue[type].shift(); 1371 | 1372 | // Get next function 1373 | var f = elem.queue[type][0]; 1374 | 1375 | if ( f ) f.apply( elem ); 1376 | } 1377 | }, 1378 | 1379 | /* 1380 | * I originally wrote fx() as a clone of moo.fx and in the process 1381 | * of making it small in size the code became illegible to sane 1382 | * people. You've been warned. 1383 | */ 1384 | 1385 | fx: function( elem, options, prop ){ 1386 | 1387 | var z = this; 1388 | 1389 | // The users options 1390 | z.o = { 1391 | duration: options.duration || 400, 1392 | complete: options.complete, 1393 | step: options.step 1394 | }; 1395 | 1396 | // The element 1397 | z.el = elem; 1398 | 1399 | // The styles 1400 | var y = z.el.style; 1401 | 1402 | // Simple function for setting a style value 1403 | z.a = function(){ 1404 | if ( options.step ) 1405 | options.step.apply( elem, [ z.now ] ); 1406 | 1407 | if ( prop == "opacity" ) { 1408 | if (jQuery.browser.mozilla && z.now == 1) z.now = 0.9999; 1409 | if (window.ActiveXObject) 1410 | y.filter = "alpha(opacity=" + z.now*100 + ")"; 1411 | else 1412 | y.opacity = z.now; 1413 | 1414 | // My hate for IE will never die 1415 | } else if ( parseInt(z.now) ) 1416 | y[prop] = parseInt(z.now) + "px"; 1417 | 1418 | y.display = "block"; 1419 | }; 1420 | 1421 | // Figure out the maximum number to run to 1422 | z.max = function(){ 1423 | return parseFloat( jQuery.css(z.el,prop) ); 1424 | }; 1425 | 1426 | // Get the current size 1427 | z.cur = function(){ 1428 | var r = parseFloat( jQuery.curCSS(z.el, prop) ); 1429 | return r && r > -10000 ? r : z.max(); 1430 | }; 1431 | 1432 | // Start an animation from one number to another 1433 | z.custom = function(from,to){ 1434 | z.startTime = (new Date()).getTime(); 1435 | z.now = from; 1436 | z.a(); 1437 | 1438 | z.timer = setInterval(function(){ 1439 | z.step(from, to); 1440 | }, 13); 1441 | }; 1442 | 1443 | // Simple 'show' function 1444 | z.show = function( p ){ 1445 | if ( !z.el.orig ) z.el.orig = {}; 1446 | 1447 | // Remember where we started, so that we can go back to it later 1448 | z.el.orig[prop] = this.cur(); 1449 | 1450 | z.custom( 0, z.el.orig[prop] ); 1451 | 1452 | // Stupid IE, look what you made me do 1453 | if ( prop != "opacity" ) 1454 | y[prop] = "1px"; 1455 | }; 1456 | 1457 | // Simple 'hide' function 1458 | z.hide = function(){ 1459 | if ( !z.el.orig ) z.el.orig = {}; 1460 | 1461 | // Remember where we started, so that we can go back to it later 1462 | z.el.orig[prop] = this.cur(); 1463 | 1464 | z.o.hide = true; 1465 | 1466 | // Begin the animation 1467 | z.custom(z.el.orig[prop], 0); 1468 | }; 1469 | 1470 | // IE has trouble with opacity if it does not have layout 1471 | if ( jQuery.browser.msie && !z.el.currentStyle.hasLayout ) 1472 | y.zoom = "1"; 1473 | 1474 | // Remember the overflow of the element 1475 | if ( !z.el.oldOverlay ) 1476 | z.el.oldOverflow = jQuery.css( z.el, "overflow" ); 1477 | 1478 | // Make sure that nothing sneaks out 1479 | y.overflow = "hidden"; 1480 | 1481 | // Each step of an animation 1482 | z.step = function(firstNum, lastNum){ 1483 | var t = (new Date()).getTime(); 1484 | 1485 | if (t > z.o.duration + z.startTime) { 1486 | // Stop the timer 1487 | clearInterval(z.timer); 1488 | z.timer = null; 1489 | 1490 | z.now = lastNum; 1491 | z.a(); 1492 | 1493 | z.el.curAnim[ prop ] = true; 1494 | 1495 | var done = true; 1496 | for ( var i in z.el.curAnim ) 1497 | if ( z.el.curAnim[i] !== true ) 1498 | done = false; 1499 | 1500 | if ( done ) { 1501 | // Reset the overflow 1502 | y.overflow = z.el.oldOverflow; 1503 | 1504 | // Hide the element if the "hide" operation was done 1505 | if ( z.o.hide ) 1506 | y.display = 'none'; 1507 | 1508 | // Reset the property, if the item has been hidden 1509 | if ( z.o.hide ) { 1510 | for ( var p in z.el.curAnim ) { 1511 | y[ p ] = z.el.orig[p] + ( p == "opacity" ? "" : "px" ); 1512 | 1513 | // set its height and/or width to auto 1514 | if ( p == 'height' || p == 'width' ) 1515 | jQuery.setAuto( z.el, p ); 1516 | } 1517 | } 1518 | } 1519 | 1520 | // If a callback was provided, execute it 1521 | if( done && z.o.complete && z.o.complete.constructor == Function ) 1522 | // Execute the complete function 1523 | z.o.complete.apply( z.el ); 1524 | } else { 1525 | // Figure out where in the animation we are and set the number 1526 | var p = (t - this.startTime) / z.o.duration; 1527 | z.now = ((-Math.cos(p*Math.PI)/2) + 0.5) * (lastNum-firstNum) + firstNum; 1528 | 1529 | // Perform the next step of the animation 1530 | z.a(); 1531 | } 1532 | }; 1533 | 1534 | } 1535 | 1536 | }); 1537 | // AJAX Plugin 1538 | // Docs Here: 1539 | // http://jquery.com/docs/ajax/ 1540 | jQuery.fn.loadIfModified = function( url, params, callback ) { 1541 | this.load( url, params, callback, 1 ); 1542 | }; 1543 | 1544 | jQuery.fn.load = function( url, params, callback, ifModified ) { 1545 | if ( url.constructor == Function ) 1546 | return this.bind("load", url); 1547 | 1548 | callback = callback || function(){}; 1549 | 1550 | // Default to a GET request 1551 | var type = "GET"; 1552 | 1553 | // If the second parameter was provided 1554 | if ( params ) { 1555 | // If it's a function 1556 | if ( params.constructor == Function ) { 1557 | // We assume that it's the callback 1558 | callback = params; 1559 | params = null; 1560 | 1561 | // Otherwise, build a param string 1562 | } else { 1563 | params = jQuery.param( params ); 1564 | type = "POST"; 1565 | } 1566 | } 1567 | 1568 | var self = this; 1569 | 1570 | // Request the remote document 1571 | jQuery.ajax( type, url, params,function(res, status){ 1572 | 1573 | if ( status == "success" || !ifModified && status == "notmodified" ) { 1574 | // Inject the HTML into all the matched elements 1575 | self.html(res.responseText).each( callback, [res.responseText, status] ); 1576 | 1577 | // Execute all the scripts inside of the newly-injected HTML 1578 | $("script", self).each(function(){ 1579 | if ( this.src ) 1580 | $.getScript( this.src ); 1581 | else 1582 | eval.call( window, this.text || this.textContent || this.innerHTML || "" ); 1583 | }); 1584 | } else 1585 | callback.apply( self, [res.responseText, status] ); 1586 | 1587 | }, ifModified); 1588 | 1589 | return this; 1590 | }; 1591 | 1592 | // If IE is used, create a wrapper for the XMLHttpRequest object 1593 | if ( jQuery.browser.msie && typeof XMLHttpRequest == "undefined" ) 1594 | XMLHttpRequest = function(){ 1595 | return new ActiveXObject( 1596 | navigator.userAgent.indexOf("MSIE 5") >= 0 ? 1597 | "Microsoft.XMLHTTP" : "Msxml2.XMLHTTP" 1598 | ); 1599 | }; 1600 | 1601 | // Attach a bunch of functions for handling common AJAX events 1602 | new function(){ 1603 | var e = "ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess".split(','); 1604 | 1605 | for ( var i = 0; i < e.length; i++ ) new function(){ 1606 | var o = e[i]; 1607 | jQuery.fn[o] = function(f){ 1608 | return this.bind(o, f); 1609 | }; 1610 | }; 1611 | }; 1612 | 1613 | jQuery.extend({ 1614 | get: function( url, data, callback, type, ifModified ) { 1615 | if ( data.constructor == Function ) { 1616 | type = callback; 1617 | callback = data; 1618 | data = null; 1619 | } 1620 | 1621 | if ( data ) url += "?" + jQuery.param(data); 1622 | 1623 | // Build and start the HTTP Request 1624 | jQuery.ajax( "GET", url, null, function(r, status) { 1625 | if ( callback ) callback( jQuery.httpData(r,type), status ); 1626 | }, ifModified); 1627 | }, 1628 | 1629 | getIfModified: function( url, data, callback, type ) { 1630 | jQuery.get(url, data, callback, type, 1); 1631 | }, 1632 | 1633 | getScript: function( url, data, callback ) { 1634 | jQuery.get(url, data, callback, "script"); 1635 | }, 1636 | post: function( url, data, callback, type ) { 1637 | // Build and start the HTTP Request 1638 | jQuery.ajax( "POST", url, jQuery.param(data), function(r, status) { 1639 | if ( callback ) callback( jQuery.httpData(r,type), status ); 1640 | }); 1641 | }, 1642 | 1643 | // timeout (ms) 1644 | timeout: 0, 1645 | 1646 | ajaxTimeout: function(timeout) { 1647 | jQuery.timeout = timeout; 1648 | }, 1649 | 1650 | // Last-Modified header cache for next request 1651 | lastModified: {}, 1652 | ajax: function( type, url, data, ret, ifModified ) { 1653 | // If only a single argument was passed in, 1654 | // assume that it is a object of key/value pairs 1655 | if ( !url ) { 1656 | ret = type.complete; 1657 | var success = type.success; 1658 | var error = type.error; 1659 | data = type.data; 1660 | url = type.url; 1661 | type = type.type; 1662 | } 1663 | 1664 | // Watch for a new set of requests 1665 | if ( ! jQuery.active++ ) 1666 | jQuery.event.trigger( "ajaxStart" ); 1667 | 1668 | var requestDone = false; 1669 | 1670 | // Create the request object 1671 | var xml = new XMLHttpRequest(); 1672 | 1673 | // Open the socket 1674 | xml.open(type || "GET", url, true); 1675 | 1676 | // Set the correct header, if data is being sent 1677 | if ( data ) 1678 | xml.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); 1679 | 1680 | // Set the If-Modified-Since header, if ifModified mode. 1681 | if ( ifModified ) 1682 | xml.setRequestHeader("If-Modified-Since", 1683 | jQuery.lastModified[url] || "Thu, 01 Jan 1970 00:00:00 GMT" ); 1684 | 1685 | // Set header so calling script knows that it's an XMLHttpRequest 1686 | xml.setRequestHeader("X-Requested-With", "XMLHttpRequest"); 1687 | 1688 | // Make sure the browser sends the right content length 1689 | if ( xml.overrideMimeType ) 1690 | xml.setRequestHeader("Connection", "close"); 1691 | 1692 | // Wait for a response to come back 1693 | var onreadystatechange = function(istimeout){ 1694 | // The transfer is complete and the data is available, or the request timed out 1695 | if ( xml && (xml.readyState == 4 || istimeout == "timeout") ) { 1696 | requestDone = true; 1697 | 1698 | var status = jQuery.httpSuccess( xml ) && istimeout != "timeout" ? 1699 | ifModified && jQuery.httpNotModified( xml, url ) ? "notmodified" : "success" : "error"; 1700 | 1701 | // Make sure that the request was successful or notmodified 1702 | if ( status != "error" ) { 1703 | // Cache Last-Modified header, if ifModified mode. 1704 | var modRes = xml.getResponseHeader("Last-Modified"); 1705 | if ( ifModified && modRes ) jQuery.lastModified[url] = modRes; 1706 | 1707 | // If a local callback was specified, fire it 1708 | if ( success ) success( xml, status ); 1709 | 1710 | // Fire the global callback 1711 | jQuery.event.trigger( "ajaxSuccess" ); 1712 | 1713 | // Otherwise, the request was not successful 1714 | } else { 1715 | // If a local callback was specified, fire it 1716 | if ( error ) error( xml, status ); 1717 | 1718 | // Fire the global callback 1719 | jQuery.event.trigger( "ajaxError" ); 1720 | } 1721 | 1722 | // The request was completed 1723 | jQuery.event.trigger( "ajaxComplete" ); 1724 | 1725 | // Handle the global AJAX counter 1726 | if ( ! --jQuery.active ) 1727 | jQuery.event.trigger( "ajaxStop" ); 1728 | 1729 | // Process result 1730 | if ( ret ) ret(xml, status); 1731 | 1732 | // Stop memory leaks 1733 | xml.onreadystatechange = function(){}; 1734 | xml = null; 1735 | 1736 | } 1737 | }; 1738 | xml.onreadystatechange = onreadystatechange; 1739 | 1740 | // Timeout checker 1741 | if(jQuery.timeout > 0) 1742 | setTimeout(function(){ 1743 | // Check to see if the request is still happening 1744 | if (xml) { 1745 | // Cancel the request 1746 | xml.abort(); 1747 | 1748 | if ( !requestDone ) onreadystatechange( "timeout" ); 1749 | 1750 | // Clear from memory 1751 | xml = null; 1752 | } 1753 | }, jQuery.timeout); 1754 | 1755 | // Send the data 1756 | xml.send(data); 1757 | }, 1758 | 1759 | // Counter for holding the number of active queries 1760 | active: 0, 1761 | 1762 | // Determines if an XMLHttpRequest was successful or not 1763 | httpSuccess: function(r) { 1764 | try { 1765 | return !r.status && location.protocol == "file:" || 1766 | ( r.status >= 200 && r.status < 300 ) || r.status == 304 || 1767 | jQuery.browser.safari && r.status == undefined; 1768 | } catch(e){} 1769 | 1770 | return false; 1771 | }, 1772 | 1773 | // Determines if an XMLHttpRequest returns NotModified 1774 | httpNotModified: function(xml, url) { 1775 | try { 1776 | var xmlRes = xml.getResponseHeader("Last-Modified"); 1777 | 1778 | // Firefox always returns 200. check Last-Modified date 1779 | return xml.status == 304 || xmlRes == jQuery.lastModified[url] || 1780 | jQuery.browser.safari && xml.status == undefined; 1781 | } catch(e){} 1782 | 1783 | return false; 1784 | }, 1785 | 1786 | // Get the data out of an XMLHttpRequest. 1787 | // Return parsed XML if content-type header is "xml" and type is "xml" or omitted, 1788 | // otherwise return plain text. 1789 | httpData: function(r,type) { 1790 | var ct = r.getResponseHeader("content-type"); 1791 | var data = !type && ct && ct.indexOf("xml") >= 0; 1792 | data = type == "xml" || data ? r.responseXML : r.responseText; 1793 | 1794 | // If the type is "script", eval it 1795 | if ( type == "script" ) eval.call( window, data ); 1796 | 1797 | // Get the JavaScript object, if JSON is used. 1798 | if ( type == "json" ) eval( "data = " + data ); 1799 | 1800 | return data; 1801 | }, 1802 | 1803 | // Serialize an array of form elements or a set of 1804 | // key/values into a query string 1805 | param: function(a) { 1806 | var s = []; 1807 | 1808 | // If an array was passed in, assume that it is an array 1809 | // of form elements 1810 | if ( a.constructor == Array ) { 1811 | // Serialize the form elements 1812 | for ( var i = 0; i < a.length; i++ ) 1813 | s.push( a[i].name + "=" + encodeURIComponent( a[i].value ) ); 1814 | 1815 | // Otherwise, assume that it's an object of key/value pairs 1816 | } else { 1817 | // Serialize the key/values 1818 | for ( var j in a ) 1819 | s.push( j + "=" + encodeURIComponent( a[j] ) ); 1820 | } 1821 | 1822 | // Return the resulting serialization 1823 | return s.join("&"); 1824 | } 1825 | 1826 | }); 1827 | -------------------------------------------------------------------------------- /external/jquery-1.0.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery - New Wave Javascript 3 | * 4 | * Copyright (c) 2006 John Resig (jquery.com) 5 | * Dual licensed under the MIT (MIT-LICENSE.txt) 6 | * and GPL (GPL-LICENSE.txt) licenses. 7 | * 8 | * $Date: 2006-10-27 23:14:48 -0400 (Fri, 27 Oct 2006) $ 9 | * $Rev: 509 $ 10 | */ 11 | 12 | // Global undefined variable 13 | window.undefined = window.undefined; 14 | function jQuery(a,c) { 15 | 16 | // Shortcut for document ready (because $(document).each() is silly) 17 | if ( a && a.constructor == Function && jQuery.fn.ready ) 18 | return jQuery(document).ready(a); 19 | 20 | // Make sure that a selection was provided 21 | a = a || jQuery.context || document; 22 | 23 | // Watch for when a jQuery object is passed as the selector 24 | if ( a.jquery ) 25 | return $( jQuery.merge( a, [] ) ); 26 | 27 | // Watch for when a jQuery object is passed at the context 28 | if ( c && c.jquery ) 29 | return $( c ).find(a); 30 | 31 | // If the context is global, return a new object 32 | if ( window == this ) 33 | return new jQuery(a,c); 34 | 35 | // Handle HTML strings 36 | var m = /^[^<]*(<.+>)[^>]*$/.exec(a); 37 | if ( m ) a = jQuery.clean( [ m[1] ] ); 38 | 39 | // Watch for when an array is passed in 40 | this.get( a.constructor == Array || a.length && !a.nodeType && a[0] != undefined && a[0].nodeType ? 41 | // Assume that it is an array of DOM Elements 42 | jQuery.merge( a, [] ) : 43 | 44 | // Find the matching elements and save them for later 45 | jQuery.find( a, c ) ); 46 | 47 | // See if an extra function was provided 48 | var fn = arguments[ arguments.length - 1 ]; 49 | 50 | // If so, execute it in context 51 | if ( fn && fn.constructor == Function ) 52 | this.each(fn); 53 | } 54 | 55 | // Map over the $ in case of overwrite 56 | if ( $ ) 57 | jQuery._$ = $; 58 | 59 | // Map the jQuery namespace to the '$' one 60 | var $ = jQuery; 61 | 62 | jQuery.fn = jQuery.prototype = { 63 | jquery: "$Rev: 509 $", 64 | 65 | size: function() { 66 | return this.length; 67 | }, 68 | 69 | get: function( num ) { 70 | // Watch for when an array (of elements) is passed in 71 | if ( num && num.constructor == Array ) { 72 | 73 | // Use a tricky hack to make the jQuery object 74 | // look and feel like an array 75 | this.length = 0; 76 | [].push.apply( this, num ); 77 | 78 | return this; 79 | } else 80 | return num == undefined ? 81 | 82 | // Return a 'clean' array 83 | jQuery.map( this, function(a){ return a } ) : 84 | 85 | // Return just the object 86 | this[num]; 87 | }, 88 | each: function( fn, args ) { 89 | return jQuery.each( this, fn, args ); 90 | }, 91 | 92 | index: function( obj ) { 93 | var pos = -1; 94 | this.each(function(i){ 95 | if ( this == obj ) pos = i; 96 | }); 97 | return pos; 98 | }, 99 | 100 | attr: function( key, value, type ) { 101 | // Check to see if we're setting style values 102 | return key.constructor != String || value != undefined ? 103 | this.each(function(){ 104 | // See if we're setting a hash of styles 105 | if ( value == undefined ) 106 | // Set all the styles 107 | for ( var prop in key ) 108 | jQuery.attr( 109 | type ? this.style : this, 110 | prop, key[prop] 111 | ); 112 | 113 | // See if we're setting a single key/value style 114 | else 115 | jQuery.attr( 116 | type ? this.style : this, 117 | key, value 118 | ); 119 | }) : 120 | 121 | // Look for the case where we're accessing a style value 122 | jQuery[ type || "attr" ]( this[0], key ); 123 | }, 124 | 125 | css: function( key, value ) { 126 | return this.attr( key, value, "curCSS" ); 127 | }, 128 | text: function(e) { 129 | e = e || this; 130 | var t = ""; 131 | for ( var j = 0; j < e.length; j++ ) { 132 | var r = e[j].childNodes; 133 | for ( var i = 0; i < r.length; i++ ) 134 | t += r[i].nodeType != 1 ? 135 | r[i].nodeValue : jQuery.fn.text([ r[i] ]); 136 | } 137 | return t; 138 | }, 139 | wrap: function() { 140 | // The elements to wrap the target around 141 | var a = jQuery.clean(arguments); 142 | 143 | // Wrap each of the matched elements individually 144 | return this.each(function(){ 145 | // Clone the structure that we're using to wrap 146 | var b = a[0].cloneNode(true); 147 | 148 | // Insert it before the element to be wrapped 149 | this.parentNode.insertBefore( b, this ); 150 | 151 | // Find he deepest point in the wrap structure 152 | while ( b.firstChild ) 153 | b = b.firstChild; 154 | 155 | // Move the matched element to within the wrap structure 156 | b.appendChild( this ); 157 | }); 158 | }, 159 | append: function() { 160 | return this.domManip(arguments, true, 1, function(a){ 161 | this.appendChild( a ); 162 | }); 163 | }, 164 | prepend: function() { 165 | return this.domManip(arguments, true, -1, function(a){ 166 | this.insertBefore( a, this.firstChild ); 167 | }); 168 | }, 169 | before: function() { 170 | return this.domManip(arguments, false, 1, function(a){ 171 | this.parentNode.insertBefore( a, this ); 172 | }); 173 | }, 174 | after: function() { 175 | return this.domManip(arguments, false, -1, function(a){ 176 | this.parentNode.insertBefore( a, this.nextSibling ); 177 | }); 178 | }, 179 | end: function() { 180 | return this.get( this.stack.pop() ); 181 | }, 182 | find: function(t) { 183 | return this.pushStack( jQuery.map( this, function(a){ 184 | return jQuery.find(t,a); 185 | }), arguments ); 186 | }, 187 | 188 | clone: function(deep) { 189 | return this.pushStack( jQuery.map( this, function(a){ 190 | return a.cloneNode( deep != undefined ? deep : true ); 191 | }), arguments ); 192 | }, 193 | 194 | filter: function(t) { 195 | return this.pushStack( 196 | t.constructor == Array && 197 | jQuery.map(this,function(a){ 198 | for ( var i = 0; i < t.length; i++ ) 199 | if ( jQuery.filter(t[i],[a]).r.length ) 200 | return a; 201 | }) || 202 | 203 | t.constructor == Boolean && 204 | ( t ? this.get() : [] ) || 205 | 206 | t.constructor == Function && 207 | jQuery.grep( this, t ) || 208 | 209 | jQuery.filter(t,this).r, arguments ); 210 | }, 211 | 212 | not: function(t) { 213 | return this.pushStack( t.constructor == String ? 214 | jQuery.filter(t,this,false).r : 215 | jQuery.grep(this,function(a){ return a != t; }), arguments ); 216 | }, 217 | 218 | add: function(t) { 219 | return this.pushStack( jQuery.merge( this, t.constructor == String ? 220 | jQuery.find(t) : t.constructor == Array ? t : [t] ), arguments ); 221 | }, 222 | is: function(expr) { 223 | return expr ? jQuery.filter(expr,this).r.length > 0 : this.length > 0; 224 | }, 225 | domManip: function(args, table, dir, fn){ 226 | var clone = this.size() > 1; 227 | var a = jQuery.clean(args); 228 | 229 | return this.each(function(){ 230 | var obj = this; 231 | 232 | if ( table && this.nodeName == "TABLE" && a[0].nodeName != "THEAD" ) { 233 | var tbody = this.getElementsByTagName("tbody"); 234 | 235 | if ( !tbody.length ) { 236 | obj = document.createElement("tbody"); 237 | this.appendChild( obj ); 238 | } else 239 | obj = tbody[0]; 240 | } 241 | 242 | for ( var i = ( dir < 0 ? a.length - 1 : 0 ); 243 | i != ( dir < 0 ? dir : a.length ); i += dir ) { 244 | fn.apply( obj, [ clone ? a[i].cloneNode(true) : a[i] ] ); 245 | } 246 | }); 247 | }, 248 | pushStack: function(a,args) { 249 | var fn = args && args[args.length-1]; 250 | 251 | if ( !fn || fn.constructor != Function ) { 252 | if ( !this.stack ) this.stack = []; 253 | this.stack.push( this.get() ); 254 | this.get( a ); 255 | } else { 256 | var old = this.get(); 257 | this.get( a ); 258 | if ( fn.constructor == Function ) 259 | return this.each( fn ); 260 | this.get( old ); 261 | } 262 | 263 | return this; 264 | } 265 | }; 266 | 267 | jQuery.extend = jQuery.fn.extend = function(obj,prop) { 268 | if ( !prop ) { prop = obj; obj = this; } 269 | for ( var i in prop ) obj[i] = prop[i]; 270 | return obj; 271 | }; 272 | 273 | jQuery.extend({ 274 | init: function(){ 275 | jQuery.initDone = true; 276 | 277 | jQuery.each( jQuery.macros.axis, function(i,n){ 278 | jQuery.fn[ i ] = function(a) { 279 | var ret = jQuery.map(this,n); 280 | if ( a && a.constructor == String ) 281 | ret = jQuery.filter(a,ret).r; 282 | return this.pushStack( ret, arguments ); 283 | }; 284 | }); 285 | 286 | jQuery.each( jQuery.macros.to, function(i,n){ 287 | jQuery.fn[ i ] = function(){ 288 | var a = arguments; 289 | return this.each(function(){ 290 | for ( var j = 0; j < a.length; j++ ) 291 | $(a[j])[n]( this ); 292 | }); 293 | }; 294 | }); 295 | 296 | jQuery.each( jQuery.macros.each, function(i,n){ 297 | jQuery.fn[ i ] = function() { 298 | return this.each( n, arguments ); 299 | }; 300 | }); 301 | 302 | jQuery.each( jQuery.macros.filter, function(i,n){ 303 | jQuery.fn[ n ] = function(num,fn) { 304 | return this.filter( ":" + n + "(" + num + ")", fn ); 305 | }; 306 | }); 307 | 308 | jQuery.each( jQuery.macros.attr, function(i,n){ 309 | n = n || i; 310 | jQuery.fn[ i ] = function(h) { 311 | return h == undefined ? 312 | this.length ? this[0][n] : null : 313 | this.attr( n, h ); 314 | }; 315 | }); 316 | 317 | jQuery.each( jQuery.macros.css, function(i,n){ 318 | jQuery.fn[ n ] = function(h) { 319 | return h == undefined ? 320 | ( this.length ? jQuery.css( this[0], n ) : null ) : 321 | this.css( n, h ); 322 | }; 323 | }); 324 | 325 | }, 326 | each: function( obj, fn, args ) { 327 | if ( obj.length == undefined ) 328 | for ( var i in obj ) 329 | fn.apply( obj[i], args || [i, obj[i]] ); 330 | else 331 | for ( var i = 0; i < obj.length; i++ ) 332 | fn.apply( obj[i], args || [i, obj[i]] ); 333 | return obj; 334 | }, 335 | 336 | className: { 337 | add: function(o,c){ 338 | if (jQuery.className.has(o,c)) return; 339 | o.className += ( o.className ? " " : "" ) + c; 340 | }, 341 | remove: function(o,c){ 342 | o.className = !c ? "" : 343 | o.className.replace( 344 | new RegExp("(^|\\s*\\b[^-])"+c+"($|\\b(?=[^-]))", "g"), ""); 345 | }, 346 | has: function(e,a) { 347 | if ( e.className != undefined ) 348 | e = e.className; 349 | return new RegExp("(^|\\s)" + a + "(\\s|$)").test(e); 350 | } 351 | }, 352 | swap: function(e,o,f) { 353 | for ( var i in o ) { 354 | e.style["old"+i] = e.style[i]; 355 | e.style[i] = o[i]; 356 | } 357 | f.apply( e, [] ); 358 | for ( var i in o ) 359 | e.style[i] = e.style["old"+i]; 360 | }, 361 | 362 | css: function(e,p) { 363 | if ( p == "height" || p == "width" ) { 364 | var old = {}, oHeight, oWidth, d = ["Top","Bottom","Right","Left"]; 365 | 366 | for ( var i in d ) { 367 | old["padding" + d[i]] = 0; 368 | old["border" + d[i] + "Width"] = 0; 369 | } 370 | 371 | jQuery.swap( e, old, function() { 372 | if (jQuery.css(e,"display") != "none") { 373 | oHeight = e.offsetHeight; 374 | oWidth = e.offsetWidth; 375 | } else { 376 | e = $(e.cloneNode(true)).css({ 377 | visibility: "hidden", position: "absolute", display: "block" 378 | }).prependTo("body")[0]; 379 | 380 | oHeight = e.clientHeight; 381 | oWidth = e.clientWidth; 382 | 383 | e.parentNode.removeChild(e); 384 | } 385 | }); 386 | 387 | return p == "height" ? oHeight : oWidth; 388 | } else if ( p == "opacity" && jQuery.browser.msie ) 389 | return parseFloat( jQuery.curCSS(e,"filter").replace(/[^0-9.]/,"") ) || 1; 390 | 391 | return jQuery.curCSS( e, p ); 392 | }, 393 | 394 | curCSS: function(elem, prop, force) { 395 | var ret; 396 | 397 | if (!force && elem.style[prop]) { 398 | 399 | ret = elem.style[prop]; 400 | 401 | } else if (elem.currentStyle) { 402 | 403 | var newProp = prop.replace(/\-(\w)/g,function(m,c){return c.toUpperCase()}); 404 | ret = elem.currentStyle[prop] || elem.currentStyle[newProp]; 405 | 406 | } else if (document.defaultView && document.defaultView.getComputedStyle) { 407 | 408 | prop = prop.replace(/([A-Z])/g,"-$1").toLowerCase(); 409 | var cur = document.defaultView.getComputedStyle(elem, null); 410 | 411 | if ( cur ) 412 | ret = cur.getPropertyValue(prop); 413 | else if ( prop == 'display' ) 414 | ret = 'none'; 415 | else 416 | jQuery.swap(elem, { display: 'block' }, function() { 417 | ret = document.defaultView.getComputedStyle(this,null).getPropertyValue(prop); 418 | }); 419 | 420 | } 421 | 422 | return ret; 423 | }, 424 | 425 | clean: function(a) { 426 | var r = []; 427 | for ( var i = 0; i < a.length; i++ ) { 428 | if ( a[i].constructor == String ) { 429 | 430 | var table = ""; 431 | 432 | if ( !a[i].indexOf(""; 435 | } else if ( !a[i].indexOf(""; 438 | } else if ( !a[i].indexOf(""; 441 | } 442 | 443 | var div = document.createElement("div"); 444 | div.innerHTML = a[i]; 445 | 446 | if ( table ) { 447 | div = div.firstChild; 448 | if ( table != "thead" ) div = div.firstChild; 449 | if ( table == "td" ) div = div.firstChild; 450 | } 451 | 452 | for ( var j = 0; j < div.childNodes.length; j++ ) 453 | r.push( div.childNodes[j] ); 454 | } else if ( a[i].jquery || a[i].length && !a[i].nodeType ) 455 | for ( var k = 0; k < a[i].length; k++ ) 456 | r.push( a[i][k] ); 457 | else if ( a[i] !== null ) 458 | r.push( a[i].nodeType ? a[i] : document.createTextNode(a[i].toString()) ); 459 | } 460 | return r; 461 | }, 462 | 463 | expr: { 464 | "": "m[2]== '*'||a.nodeName.toUpperCase()==m[2].toUpperCase()", 465 | "#": "a.getAttribute('id')&&a.getAttribute('id')==m[2]", 466 | ":": { 467 | // Position Checks 468 | lt: "im[3]-0", 470 | nth: "m[3]-0==i", 471 | eq: "m[3]-0==i", 472 | first: "i==0", 473 | last: "i==r.length-1", 474 | even: "i%2==0", 475 | odd: "i%2", 476 | 477 | // Child Checks 478 | "first-child": "jQuery.sibling(a,0).cur", 479 | "last-child": "jQuery.sibling(a,0).last", 480 | "only-child": "jQuery.sibling(a).length==1", 481 | 482 | // Parent Checks 483 | parent: "a.childNodes.length", 484 | empty: "!a.childNodes.length", 485 | 486 | // Text Check 487 | contains: "(a.innerText||a.innerHTML).indexOf(m[3])>=0", 488 | 489 | // Visibility 490 | visible: "a.type!='hidden'&&jQuery.css(a,'display')!='none'&&jQuery.css(a,'visibility')!='hidden'", 491 | hidden: "a.type=='hidden'||jQuery.css(a,'display')=='none'||jQuery.css(a,'visibility')=='hidden'", 492 | 493 | // Form elements 494 | enabled: "!a.disabled", 495 | disabled: "a.disabled", 496 | checked: "a.checked", 497 | selected: "a.selected" 498 | }, 499 | ".": "jQuery.className.has(a,m[2])", 500 | "@": { 501 | "=": "z==m[4]", 502 | "!=": "z!=m[4]", 503 | "^=": "!z.indexOf(m[4])", 504 | "$=": "z.substr(z.length - m[4].length,m[4].length)==m[4]", 505 | "*=": "z.indexOf(m[4])>=0", 506 | "": "z" 507 | }, 508 | "[": "jQuery.find(m[2],a).length" 509 | }, 510 | 511 | token: [ 512 | "\\.\\.|/\\.\\.", "a.parentNode", 513 | ">|/", "jQuery.sibling(a.firstChild)", 514 | "\\+", "jQuery.sibling(a).next", 515 | "~", function(a){ 516 | var r = []; 517 | var s = jQuery.sibling(a); 518 | if ( s.n > 0 ) 519 | for ( var i = s.n; i < s.length; i++ ) 520 | r.push( s[i] ); 521 | return r; 522 | } 523 | ], 524 | find: function( t, context ) { 525 | // Make sure that the context is a DOM Element 526 | if ( context && context.nodeType == undefined ) 527 | context = null; 528 | 529 | // Set the correct context (if none is provided) 530 | context = context || jQuery.context || document; 531 | 532 | if ( t.constructor != String ) return [t]; 533 | 534 | if ( !t.indexOf("//") ) { 535 | context = context.documentElement; 536 | t = t.substr(2,t.length); 537 | } else if ( !t.indexOf("/") ) { 538 | context = context.documentElement; 539 | t = t.substr(1,t.length); 540 | // FIX Assume the root element is right :( 541 | if ( t.indexOf("/") >= 1 ) 542 | t = t.substr(t.indexOf("/"),t.length); 543 | } 544 | 545 | var ret = [context]; 546 | var done = []; 547 | var last = null; 548 | 549 | while ( t.length > 0 && last != t ) { 550 | var r = []; 551 | last = t; 552 | 553 | t = jQuery.trim(t).replace( /^\/\//i, "" ); 554 | 555 | var foundToken = false; 556 | 557 | for ( var i = 0; i < jQuery.token.length; i += 2 ) { 558 | var re = new RegExp("^(" + jQuery.token[i] + ")"); 559 | var m = re.exec(t); 560 | 561 | if ( m ) { 562 | r = ret = jQuery.map( ret, jQuery.token[i+1] ); 563 | t = jQuery.trim( t.replace( re, "" ) ); 564 | foundToken = true; 565 | } 566 | } 567 | 568 | if ( !foundToken ) { 569 | if ( !t.indexOf(",") || !t.indexOf("|") ) { 570 | if ( ret[0] == context ) ret.shift(); 571 | done = jQuery.merge( done, ret ); 572 | r = ret = [context]; 573 | t = " " + t.substr(1,t.length); 574 | } else { 575 | var re2 = /^([#.]?)([a-z0-9\\*_-]*)/i; 576 | var m = re2.exec(t); 577 | 578 | if ( m[1] == "#" ) { 579 | // Ummm, should make this work in all XML docs 580 | var oid = document.getElementById(m[2]); 581 | r = ret = oid ? [oid] : []; 582 | t = t.replace( re2, "" ); 583 | } else { 584 | if ( !m[2] || m[1] == "." ) m[2] = "*"; 585 | 586 | for ( var i = 0; i < ret.length; i++ ) 587 | r = jQuery.merge( r, 588 | m[2] == "*" ? 589 | jQuery.getAll(ret[i]) : 590 | ret[i].getElementsByTagName(m[2]) 591 | ); 592 | } 593 | } 594 | } 595 | 596 | if ( t ) { 597 | var val = jQuery.filter(t,r); 598 | ret = r = val.r; 599 | t = jQuery.trim(val.t); 600 | } 601 | } 602 | 603 | if ( ret && ret[0] == context ) ret.shift(); 604 | done = jQuery.merge( done, ret ); 605 | 606 | return done; 607 | }, 608 | 609 | getAll: function(o,r) { 610 | r = r || []; 611 | var s = o.childNodes; 612 | for ( var i = 0; i < s.length; i++ ) 613 | if ( s[i].nodeType == 1 ) { 614 | r.push( s[i] ); 615 | jQuery.getAll( s[i], r ); 616 | } 617 | return r; 618 | }, 619 | 620 | attr: function(elem, name, value){ 621 | var fix = { 622 | "for": "htmlFor", 623 | "class": "className", 624 | "float": "cssFloat", 625 | innerHTML: "innerHTML", 626 | className: "className" 627 | }; 628 | 629 | if ( fix[name] ) { 630 | if ( value != undefined ) elem[fix[name]] = value; 631 | return elem[fix[name]]; 632 | } else if ( elem.getAttribute ) { 633 | if ( value != undefined ) elem.setAttribute( name, value ); 634 | return elem.getAttribute( name, 2 ); 635 | } else { 636 | name = name.replace(/-([a-z])/ig,function(z,b){return b.toUpperCase();}); 637 | if ( value != undefined ) elem[name] = value; 638 | return elem[name]; 639 | } 640 | }, 641 | 642 | // The regular expressions that power the parsing engine 643 | parse: [ 644 | // Match: [@value='test'], [@foo] 645 | [ "\\[ *(@)S *([!*$^=]*) *Q\\]", 1 ], 646 | 647 | // Match: [div], [div p] 648 | [ "(\\[)Q\\]", 0 ], 649 | 650 | // Match: :contains('foo') 651 | [ "(:)S\\(Q\\)", 0 ], 652 | 653 | // Match: :even, :last-chlid 654 | [ "([:.#]*)S", 0 ] 655 | ], 656 | 657 | filter: function(t,r,not) { 658 | // Figure out if we're doing regular, or inverse, filtering 659 | var g = not !== false ? jQuery.grep : 660 | function(a,f) {return jQuery.grep(a,f,true);}; 661 | 662 | while ( t && /^[a-z[({<*:.#]/i.test(t) ) { 663 | 664 | var p = jQuery.parse; 665 | 666 | for ( var i = 0; i < p.length; i++ ) { 667 | var re = new RegExp( "^" + p[i][0] 668 | 669 | // Look for a string-like sequence 670 | .replace( 'S', "([a-z*_-][a-z0-9_-]*)" ) 671 | 672 | // Look for something (optionally) enclosed with quotes 673 | .replace( 'Q', " *'?\"?([^'\"]*?)'?\"? *" ), "i" ); 674 | 675 | var m = re.exec( t ); 676 | 677 | if ( m ) { 678 | // Re-organize the match 679 | if ( p[i][1] ) 680 | m = ["", m[1], m[3], m[2], m[4]]; 681 | 682 | // Remove what we just matched 683 | t = t.replace( re, "" ); 684 | 685 | break; 686 | } 687 | } 688 | 689 | // :not() is a special case that can be optomized by 690 | // keeping it out of the expression list 691 | if ( m[1] == ":" && m[2] == "not" ) 692 | r = jQuery.filter(m[3],r,false).r; 693 | 694 | // Otherwise, find the expression to execute 695 | else { 696 | var f = jQuery.expr[m[1]]; 697 | if ( f.constructor != String ) 698 | f = jQuery.expr[m[1]][m[2]]; 699 | 700 | // Build a custom macro to enclose it 701 | eval("f = function(a,i){" + 702 | ( m[1] == "@" ? "z=jQuery.attr(a,m[3]);" : "" ) + 703 | "return " + f + "}"); 704 | 705 | // Execute it against the current filter 706 | r = g( r, f ); 707 | } 708 | } 709 | 710 | // Return an array of filtered elements (r) 711 | // and the modified expression string (t) 712 | return { r: r, t: t }; 713 | }, 714 | trim: function(t){ 715 | return t.replace(/^\s+|\s+$/g, ""); 716 | }, 717 | parents: function( elem ){ 718 | var matched = []; 719 | var cur = elem.parentNode; 720 | while ( cur && cur != document ) { 721 | matched.push( cur ); 722 | cur = cur.parentNode; 723 | } 724 | return matched; 725 | }, 726 | sibling: function(elem, pos, not) { 727 | var elems = []; 728 | 729 | var siblings = elem.parentNode.childNodes; 730 | for ( var i = 0; i < siblings.length; i++ ) { 731 | if ( not === true && siblings[i] == elem ) continue; 732 | 733 | if ( siblings[i].nodeType == 1 ) 734 | elems.push( siblings[i] ); 735 | if ( siblings[i] == elem ) 736 | elems.n = elems.length - 1; 737 | } 738 | 739 | return jQuery.extend( elems, { 740 | last: elems.n == elems.length - 1, 741 | cur: pos == "even" && elems.n % 2 == 0 || pos == "odd" && elems.n % 2 || elems[pos] == elem, 742 | prev: elems[elems.n - 1], 743 | next: elems[elems.n + 1] 744 | }); 745 | }, 746 | merge: function(first, second) { 747 | var result = []; 748 | 749 | // Move b over to the new array (this helps to avoid 750 | // StaticNodeList instances) 751 | for ( var k = 0; k < first.length; k++ ) 752 | result[k] = first[k]; 753 | 754 | // Now check for duplicates between a and b and only 755 | // add the unique items 756 | for ( var i = 0; i < second.length; i++ ) { 757 | var noCollision = true; 758 | 759 | // The collision-checking process 760 | for ( var j = 0; j < first.length; j++ ) 761 | if ( second[i] == first[j] ) 762 | noCollision = false; 763 | 764 | // If the item is unique, add it 765 | if ( noCollision ) 766 | result.push( second[i] ); 767 | } 768 | 769 | return result; 770 | }, 771 | grep: function(elems, fn, inv) { 772 | // If a string is passed in for the function, make a function 773 | // for it (a handy shortcut) 774 | if ( fn.constructor == String ) 775 | fn = new Function("a","i","return " + fn); 776 | 777 | var result = []; 778 | 779 | // Go through the array, only saving the items 780 | // that pass the validator function 781 | for ( var i = 0; i < elems.length; i++ ) 782 | if ( !inv && fn(elems[i],i) || inv && !fn(elems[i],i) ) 783 | result.push( elems[i] ); 784 | 785 | return result; 786 | }, 787 | map: function(elems, fn) { 788 | // If a string is passed in for the function, make a function 789 | // for it (a handy shortcut) 790 | if ( fn.constructor == String ) 791 | fn = new Function("a","return " + fn); 792 | 793 | var result = []; 794 | 795 | // Go through the array, translating each of the items to their 796 | // new value (or values). 797 | for ( var i = 0; i < elems.length; i++ ) { 798 | var val = fn(elems[i],i); 799 | 800 | if ( val !== null && val != undefined ) { 801 | if ( val.constructor != Array ) val = [val]; 802 | result = jQuery.merge( result, val ); 803 | } 804 | } 805 | 806 | return result; 807 | }, 808 | 809 | /* 810 | * A number of helper functions used for managing events. 811 | * Many of the ideas behind this code orignated from Dean Edwards' addEvent library. 812 | */ 813 | event: { 814 | 815 | // Bind an event to an element 816 | // Original by Dean Edwards 817 | add: function(element, type, handler) { 818 | // For whatever reason, IE has trouble passing the window object 819 | // around, causing it to be cloned in the process 820 | if ( jQuery.browser.msie && element.setInterval != undefined ) 821 | element = window; 822 | 823 | // Make sure that the function being executed has a unique ID 824 | if ( !handler.guid ) 825 | handler.guid = this.guid++; 826 | 827 | // Init the element's event structure 828 | if (!element.events) 829 | element.events = {}; 830 | 831 | // Get the current list of functions bound to this event 832 | var handlers = element.events[type]; 833 | 834 | // If it hasn't been initialized yet 835 | if (!handlers) { 836 | // Init the event handler queue 837 | handlers = element.events[type] = {}; 838 | 839 | // Remember an existing handler, if it's already there 840 | if (element["on" + type]) 841 | handlers[0] = element["on" + type]; 842 | } 843 | 844 | // Add the function to the element's handler list 845 | handlers[handler.guid] = handler; 846 | 847 | // And bind the global event handler to the element 848 | element["on" + type] = this.handle; 849 | 850 | // Remember the function in a global list (for triggering) 851 | if (!this.global[type]) 852 | this.global[type] = []; 853 | this.global[type].push( element ); 854 | }, 855 | 856 | guid: 1, 857 | global: {}, 858 | 859 | // Detach an event or set of events from an element 860 | remove: function(element, type, handler) { 861 | if (element.events) 862 | if (type && element.events[type]) 863 | if ( handler ) 864 | delete element.events[type][handler.guid]; 865 | else 866 | for ( var i in element.events[type] ) 867 | delete element.events[type][i]; 868 | else 869 | for ( var j in element.events ) 870 | this.remove( element, j ); 871 | }, 872 | 873 | trigger: function(type,data,element) { 874 | // Touch up the incoming data 875 | data = data || []; 876 | 877 | // Handle a global trigger 878 | if ( !element ) { 879 | var g = this.global[type]; 880 | if ( g ) 881 | for ( var i = 0; i < g.length; i++ ) 882 | this.trigger( type, data, g[i] ); 883 | 884 | // Handle triggering a single element 885 | } else if ( element["on" + type] ) { 886 | // Pass along a fake event 887 | data.unshift( this.fix({ type: type, target: element }) ); 888 | 889 | // Trigger the event 890 | element["on" + type].apply( element, data ); 891 | } 892 | }, 893 | 894 | handle: function(event) { 895 | if ( typeof jQuery == "undefined" ) return; 896 | 897 | event = event || jQuery.event.fix( window.event ); 898 | 899 | // If no correct event was found, fail 900 | if ( !event ) return; 901 | 902 | var returnValue = true; 903 | 904 | var c = this.events[event.type]; 905 | 906 | for ( var j in c ) { 907 | if ( c[j].apply( this, [event] ) === false ) { 908 | event.preventDefault(); 909 | event.stopPropagation(); 910 | returnValue = false; 911 | } 912 | } 913 | 914 | return returnValue; 915 | }, 916 | 917 | fix: function(event) { 918 | if ( event ) { 919 | event.preventDefault = function() { 920 | this.returnValue = false; 921 | }; 922 | 923 | event.stopPropagation = function() { 924 | this.cancelBubble = true; 925 | }; 926 | } 927 | 928 | return event; 929 | } 930 | 931 | } 932 | }); 933 | 934 | new function() { 935 | var b = navigator.userAgent.toLowerCase(); 936 | 937 | // Figure out what browser is being used 938 | jQuery.browser = { 939 | safari: /webkit/.test(b), 940 | opera: /opera/.test(b), 941 | msie: /msie/.test(b) && !/opera/.test(b), 942 | mozilla: /mozilla/.test(b) && !/compatible/.test(b) 943 | }; 944 | 945 | // Check to see if the W3C box model is being used 946 | jQuery.boxModel = !jQuery.browser.msie || document.compatMode == "CSS1Compat"; 947 | }; 948 | 949 | jQuery.macros = { 950 | to: { 951 | appendTo: "append", 952 | prependTo: "prepend", 953 | insertBefore: "before", 954 | insertAfter: "after" 955 | }, 956 | 957 | 958 | css: "width,height,top,left,position,float,overflow,color,background".split(","), 959 | 960 | filter: [ "eq", "lt", "gt", "contains" ], 961 | 962 | attr: { 963 | 964 | val: "value", 965 | 966 | html: "innerHTML", 967 | 968 | id: null, 969 | 970 | title: null, 971 | 972 | name: null, 973 | 974 | href: null, 975 | 976 | src: null, 977 | 978 | rel: null 979 | }, 980 | 981 | axis: { 982 | 983 | parent: "a.parentNode", 984 | 985 | ancestors: jQuery.parents, 986 | 987 | parents: jQuery.parents, 988 | 989 | next: "jQuery.sibling(a).next", 990 | 991 | prev: "jQuery.sibling(a).prev", 992 | 993 | siblings: jQuery.sibling, 994 | 995 | children: "a.childNodes" 996 | }, 997 | 998 | each: { 999 | 1000 | removeAttr: function( key ) { 1001 | this.removeAttribute( key ); 1002 | }, 1003 | show: function(){ 1004 | this.style.display = this.oldblock ? this.oldblock : ""; 1005 | if ( jQuery.css(this,"display") == "none" ) 1006 | this.style.display = "block"; 1007 | }, 1008 | hide: function(){ 1009 | this.oldblock = this.oldblock || jQuery.css(this,"display"); 1010 | if ( this.oldblock == "none" ) 1011 | this.oldblock = "block"; 1012 | this.style.display = "none"; 1013 | }, 1014 | toggle: function(){ 1015 | $(this)[ $(this).is(":hidden") ? "show" : "hide" ].apply( $(this), arguments ); 1016 | }, 1017 | addClass: function(c){ 1018 | jQuery.className.add(this,c); 1019 | }, 1020 | removeClass: function(c){ 1021 | jQuery.className.remove(this,c); 1022 | }, 1023 | toggleClass: function( c ){ 1024 | jQuery.className[ jQuery.className.has(this,c) ? "remove" : "add" ](this,c); 1025 | }, 1026 | 1027 | remove: function(a){ 1028 | if ( !a || jQuery.filter( [this], a ).r ) 1029 | this.parentNode.removeChild( this ); 1030 | }, 1031 | empty: function(){ 1032 | while ( this.firstChild ) 1033 | this.removeChild( this.firstChild ); 1034 | }, 1035 | bind: function( type, fn ) { 1036 | if ( fn.constructor == String ) 1037 | fn = new Function("e", ( !fn.indexOf(".") ? "$(this)" : "return " ) + fn); 1038 | jQuery.event.add( this, type, fn ); 1039 | }, 1040 | 1041 | unbind: function( type, fn ) { 1042 | jQuery.event.remove( this, type, fn ); 1043 | }, 1044 | trigger: function( type, data ) { 1045 | jQuery.event.trigger( type, data, this ); 1046 | } 1047 | } 1048 | }; 1049 | 1050 | jQuery.init();jQuery.fn.extend({ 1051 | 1052 | // We're overriding the old toggle function, so 1053 | // remember it for later 1054 | _toggle: jQuery.fn.toggle, 1055 | toggle: function(a,b) { 1056 | // If two functions are passed in, we're 1057 | // toggling on a click 1058 | return a && b && a.constructor == Function && b.constructor == Function ? this.click(function(e){ 1059 | // Figure out which function to execute 1060 | this.last = this.last == a ? b : a; 1061 | 1062 | // Make sure that clicks stop 1063 | e.preventDefault(); 1064 | 1065 | // and execute the function 1066 | return this.last.apply( this, [e] ) || false; 1067 | }) : 1068 | 1069 | // Otherwise, execute the old toggle function 1070 | this._toggle.apply( this, arguments ); 1071 | }, 1072 | 1073 | hover: function(f,g) { 1074 | 1075 | // A private function for haandling mouse 'hovering' 1076 | function handleHover(e) { 1077 | // Check if mouse(over|out) are still within the same parent element 1078 | var p = (e.type == "mouseover" ? e.fromElement : e.toElement) || e.relatedTarget; 1079 | 1080 | // Traverse up the tree 1081 | while ( p && p != this ) p = p.parentNode; 1082 | 1083 | // If we actually just moused on to a sub-element, ignore it 1084 | if ( p == this ) return false; 1085 | 1086 | // Execute the right function 1087 | return (e.type == "mouseover" ? f : g).apply(this, [e]); 1088 | } 1089 | 1090 | // Bind the function to the two event listeners 1091 | return this.mouseover(handleHover).mouseout(handleHover); 1092 | }, 1093 | ready: function(f) { 1094 | // If the DOM is already ready 1095 | if ( jQuery.isReady ) 1096 | // Execute the function immediately 1097 | f.apply( document ); 1098 | 1099 | // Otherwise, remember the function for later 1100 | else { 1101 | // Add the function to the wait list 1102 | jQuery.readyList.push( f ); 1103 | } 1104 | 1105 | return this; 1106 | } 1107 | }); 1108 | 1109 | jQuery.extend({ 1110 | /* 1111 | * All the code that makes DOM Ready work nicely. 1112 | */ 1113 | isReady: false, 1114 | readyList: [], 1115 | 1116 | // Handle when the DOM is ready 1117 | ready: function() { 1118 | // Make sure that the DOM is not already loaded 1119 | if ( !jQuery.isReady ) { 1120 | // Remember that the DOM is ready 1121 | jQuery.isReady = true; 1122 | 1123 | // If there are functions bound, to execute 1124 | if ( jQuery.readyList ) { 1125 | // Execute all of them 1126 | for ( var i = 0; i < jQuery.readyList.length; i++ ) 1127 | jQuery.readyList[i].apply( document ); 1128 | 1129 | // Reset the list of functions 1130 | jQuery.readyList = null; 1131 | } 1132 | } 1133 | } 1134 | }); 1135 | 1136 | new function(){ 1137 | 1138 | var e = ("blur,focus,load,resize,scroll,unload,click,dblclick," + 1139 | "mousedown,mouseup,mousemove,mouseover,mouseout,change,reset,select," + 1140 | "submit,keydown,keypress,keyup,error").split(","); 1141 | 1142 | // Go through all the event names, but make sure that 1143 | // it is enclosed properly 1144 | for ( var i = 0; i < e.length; i++ ) new function(){ 1145 | 1146 | var o = e[i]; 1147 | 1148 | // Handle event binding 1149 | jQuery.fn[o] = function(f){ 1150 | return f ? this.bind(o, f) : this.trigger(o); 1151 | }; 1152 | 1153 | // Handle event unbinding 1154 | jQuery.fn["un"+o] = function(f){ return this.unbind(o, f); }; 1155 | 1156 | // Finally, handle events that only fire once 1157 | jQuery.fn["one"+o] = function(f){ 1158 | // Attach the event listener 1159 | return this.each(function(){ 1160 | 1161 | var count = 0; 1162 | 1163 | // Add the event 1164 | jQuery.event.add( this, o, function(e){ 1165 | // If this function has already been executed, stop 1166 | if ( count++ ) return; 1167 | 1168 | // And execute the bound function 1169 | return f.apply(this, [e]); 1170 | }); 1171 | }); 1172 | }; 1173 | 1174 | }; 1175 | 1176 | // If Mozilla is used 1177 | if ( jQuery.browser.mozilla || jQuery.browser.opera ) { 1178 | // Use the handy event callback 1179 | document.addEventListener( "DOMContentLoaded", jQuery.ready, false ); 1180 | 1181 | // If IE is used, use the excellent hack by Matthias Miller 1182 | // http://www.outofhanwell.com/blog/index.php?title=the_window_onload_problem_revisited 1183 | } else if ( jQuery.browser.msie ) { 1184 | 1185 | // Only works if you document.write() it 1186 | document.write("<\/script>"); 1188 | 1189 | // Use the defer script hack 1190 | var script = document.getElementById("__ie_init"); 1191 | script.onreadystatechange = function() { 1192 | if ( this.readyState == "complete" ) 1193 | jQuery.ready(); 1194 | }; 1195 | 1196 | // Clear from memory 1197 | script = null; 1198 | 1199 | // If Safari is used 1200 | } else if ( jQuery.browser.safari ) { 1201 | // Continually check to see if the document.readyState is valid 1202 | jQuery.safariTimer = setInterval(function(){ 1203 | // loaded and complete are both valid states 1204 | if ( document.readyState == "loaded" || 1205 | document.readyState == "complete" ) { 1206 | 1207 | // If either one are found, remove the timer 1208 | clearInterval( jQuery.safariTimer ); 1209 | jQuery.safariTimer = null; 1210 | 1211 | // and execute any waiting functions 1212 | jQuery.ready(); 1213 | } 1214 | }, 10); 1215 | } 1216 | 1217 | // A fallback to window.onload, that will always work 1218 | jQuery.event.add( window, "load", jQuery.ready ); 1219 | 1220 | }; 1221 | jQuery.fn.extend({ 1222 | 1223 | // overwrite the old show method 1224 | _show: jQuery.fn.show, 1225 | 1226 | show: function(speed,callback){ 1227 | return speed ? this.animate({ 1228 | height: "show", width: "show", opacity: "show" 1229 | }, speed, callback) : this._show(); 1230 | }, 1231 | 1232 | // Overwrite the old hide method 1233 | _hide: jQuery.fn.hide, 1234 | 1235 | hide: function(speed,callback){ 1236 | return speed ? this.animate({ 1237 | height: "hide", width: "hide", opacity: "hide" 1238 | }, speed, callback) : this._hide(); 1239 | }, 1240 | 1241 | slideDown: function(speed,callback){ 1242 | return this.animate({height: "show"}, speed, callback); 1243 | }, 1244 | 1245 | slideUp: function(speed,callback){ 1246 | return this.animate({height: "hide"}, speed, callback); 1247 | }, 1248 | 1249 | slideToggle: function(speed,callback){ 1250 | return this.each(function(){ 1251 | var state = $(this).is(":hidden") ? "show" : "hide"; 1252 | $(this).animate({height: state}, speed, callback); 1253 | }); 1254 | }, 1255 | 1256 | fadeIn: function(speed,callback){ 1257 | return this.animate({opacity: "show"}, speed, callback); 1258 | }, 1259 | 1260 | fadeOut: function(speed,callback){ 1261 | return this.animate({opacity: "hide"}, speed, callback); 1262 | }, 1263 | 1264 | fadeTo: function(speed,to,callback){ 1265 | return this.animate({opacity: to}, speed, callback); 1266 | }, 1267 | animate: function(prop,speed,callback) { 1268 | return this.queue(function(){ 1269 | 1270 | this.curAnim = prop; 1271 | 1272 | for ( var p in prop ) { 1273 | var e = new jQuery.fx( this, jQuery.speed(speed,callback), p ); 1274 | if ( prop[p].constructor == Number ) 1275 | e.custom( e.cur(), prop[p] ); 1276 | else 1277 | e[ prop[p] ]( prop ); 1278 | } 1279 | 1280 | }); 1281 | }, 1282 | queue: function(type,fn){ 1283 | if ( !fn ) { 1284 | fn = type; 1285 | type = "fx"; 1286 | } 1287 | 1288 | return this.each(function(){ 1289 | if ( !this.queue ) 1290 | this.queue = {}; 1291 | 1292 | if ( !this.queue[type] ) 1293 | this.queue[type] = []; 1294 | 1295 | this.queue[type].push( fn ); 1296 | 1297 | if ( this.queue[type].length == 1 ) 1298 | fn.apply(this); 1299 | }); 1300 | } 1301 | 1302 | }); 1303 | 1304 | jQuery.extend({ 1305 | 1306 | setAuto: function(e,p) { 1307 | if ( e.notAuto ) return; 1308 | 1309 | if ( p == "height" && e.scrollHeight != parseInt(jQuery.curCSS(e,p)) ) return; 1310 | if ( p == "width" && e.scrollWidth != parseInt(jQuery.curCSS(e,p)) ) return; 1311 | 1312 | // Remember the original height 1313 | var a = e.style[p]; 1314 | 1315 | // Figure out the size of the height right now 1316 | var o = jQuery.curCSS(e,p,1); 1317 | 1318 | if ( p == "height" && e.scrollHeight != o || 1319 | p == "width" && e.scrollWidth != o ) return; 1320 | 1321 | // Set the height to auto 1322 | e.style[p] = e.currentStyle ? "" : "auto"; 1323 | 1324 | // See what the size of "auto" is 1325 | var n = jQuery.curCSS(e,p,1); 1326 | 1327 | // Revert back to the original size 1328 | if ( o != n && n != "auto" ) { 1329 | e.style[p] = a; 1330 | e.notAuto = true; 1331 | } 1332 | }, 1333 | 1334 | speed: function(s,o) { 1335 | o = o || {}; 1336 | 1337 | if ( o.constructor == Function ) 1338 | o = { complete: o }; 1339 | 1340 | var ss = { slow: 600, fast: 200 }; 1341 | o.duration = (s && s.constructor == Number ? s : ss[s]) || 400; 1342 | 1343 | // Queueing 1344 | o.oldComplete = o.complete; 1345 | o.complete = function(){ 1346 | jQuery.dequeue(this, "fx"); 1347 | if ( o.oldComplete && o.oldComplete.constructor == Function ) 1348 | o.oldComplete.apply( this ); 1349 | }; 1350 | 1351 | return o; 1352 | }, 1353 | 1354 | queue: {}, 1355 | 1356 | dequeue: function(elem,type){ 1357 | type = type || "fx"; 1358 | 1359 | if ( elem.queue && elem.queue[type] ) { 1360 | // Remove self 1361 | elem.queue[type].shift(); 1362 | 1363 | // Get next function 1364 | var f = elem.queue[type][0]; 1365 | 1366 | if ( f ) f.apply( elem ); 1367 | } 1368 | }, 1369 | 1370 | /* 1371 | * I originally wrote fx() as a clone of moo.fx and in the process 1372 | * of making it small in size the code became illegible to sane 1373 | * people. You've been warned. 1374 | */ 1375 | 1376 | fx: function( elem, options, prop ){ 1377 | 1378 | var z = this; 1379 | 1380 | // The users options 1381 | z.o = { 1382 | duration: options.duration || 400, 1383 | complete: options.complete, 1384 | step: options.step 1385 | }; 1386 | 1387 | // The element 1388 | z.el = elem; 1389 | 1390 | // The styles 1391 | var y = z.el.style; 1392 | 1393 | // Simple function for setting a style value 1394 | z.a = function(){ 1395 | if ( options.step ) 1396 | options.step.apply( elem, [ z.now ] ); 1397 | 1398 | if ( prop == "opacity" ) { 1399 | if (z.now == 1) z.now = 0.9999; 1400 | if (window.ActiveXObject) 1401 | y.filter = "alpha(opacity=" + z.now*100 + ")"; 1402 | else 1403 | y.opacity = z.now; 1404 | 1405 | // My hate for IE will never die 1406 | } else if ( parseInt(z.now) ) 1407 | y[prop] = parseInt(z.now) + "px"; 1408 | 1409 | y.display = "block"; 1410 | }; 1411 | 1412 | // Figure out the maximum number to run to 1413 | z.max = function(){ 1414 | return parseFloat( jQuery.css(z.el,prop) ); 1415 | }; 1416 | 1417 | // Get the current size 1418 | z.cur = function(){ 1419 | var r = parseFloat( jQuery.curCSS(z.el, prop) ); 1420 | return r && r > -10000 ? r : z.max(); 1421 | }; 1422 | 1423 | // Start an animation from one number to another 1424 | z.custom = function(from,to){ 1425 | z.startTime = (new Date()).getTime(); 1426 | z.now = from; 1427 | z.a(); 1428 | 1429 | z.timer = setInterval(function(){ 1430 | z.step(from, to); 1431 | }, 13); 1432 | }; 1433 | 1434 | // Simple 'show' function 1435 | z.show = function( p ){ 1436 | if ( !z.el.orig ) z.el.orig = {}; 1437 | 1438 | // Remember where we started, so that we can go back to it later 1439 | z.el.orig[prop] = this.cur(); 1440 | 1441 | z.custom( 0, z.el.orig[prop] ); 1442 | 1443 | // Stupid IE, look what you made me do 1444 | if ( prop != "opacity" ) 1445 | y[prop] = "1px"; 1446 | }; 1447 | 1448 | // Simple 'hide' function 1449 | z.hide = function(){ 1450 | if ( !z.el.orig ) z.el.orig = {}; 1451 | 1452 | // Remember where we started, so that we can go back to it later 1453 | z.el.orig[prop] = this.cur(); 1454 | 1455 | z.o.hide = true; 1456 | 1457 | // Begin the animation 1458 | z.custom(z.el.orig[prop], 0); 1459 | }; 1460 | 1461 | // IE has trouble with opacity if it does not have layout 1462 | if ( jQuery.browser.msie && !z.el.currentStyle.hasLayout ) 1463 | y.zoom = "1"; 1464 | 1465 | // Remember the overflow of the element 1466 | if ( !z.el.oldOverlay ) 1467 | z.el.oldOverflow = jQuery.css( z.el, "overflow" ); 1468 | 1469 | // Make sure that nothing sneaks out 1470 | y.overflow = "hidden"; 1471 | 1472 | // Each step of an animation 1473 | z.step = function(firstNum, lastNum){ 1474 | var t = (new Date()).getTime(); 1475 | 1476 | if (t > z.o.duration + z.startTime) { 1477 | // Stop the timer 1478 | clearInterval(z.timer); 1479 | z.timer = null; 1480 | 1481 | z.now = lastNum; 1482 | z.a(); 1483 | 1484 | z.el.curAnim[ prop ] = true; 1485 | 1486 | var done = true; 1487 | for ( var i in z.el.curAnim ) 1488 | if ( z.el.curAnim[i] !== true ) 1489 | done = false; 1490 | 1491 | if ( done ) { 1492 | // Reset the overflow 1493 | y.overflow = z.el.oldOverflow; 1494 | 1495 | // Hide the element if the "hide" operation was done 1496 | if ( z.o.hide ) 1497 | y.display = 'none'; 1498 | 1499 | // Reset the property, if the item has been hidden 1500 | if ( z.o.hide ) { 1501 | for ( var p in z.el.curAnim ) { 1502 | y[ p ] = z.el.orig[p] + ( p == "opacity" ? "" : "px" ); 1503 | 1504 | // set its height and/or width to auto 1505 | if ( p == 'height' || p == 'width' ) 1506 | jQuery.setAuto( z.el, p ); 1507 | } 1508 | } 1509 | } 1510 | 1511 | // If a callback was provided, execute it 1512 | if( done && z.o.complete && z.o.complete.constructor == Function ) 1513 | // Execute the complete function 1514 | z.o.complete.apply( z.el ); 1515 | } else { 1516 | // Figure out where in the animation we are and set the number 1517 | var p = (t - this.startTime) / z.o.duration; 1518 | z.now = ((-Math.cos(p*Math.PI)/2) + 0.5) * (lastNum-firstNum) + firstNum; 1519 | 1520 | // Perform the next step of the animation 1521 | z.a(); 1522 | } 1523 | }; 1524 | 1525 | } 1526 | 1527 | }); 1528 | // AJAX Plugin 1529 | // Docs Here: 1530 | // http://jquery.com/docs/ajax/ 1531 | jQuery.fn.loadIfModified = function( url, params, callback ) { 1532 | this.load( url, params, callback, 1 ); 1533 | }; 1534 | 1535 | jQuery.fn.load = function( url, params, callback, ifModified ) { 1536 | if ( url.constructor == Function ) 1537 | return this.bind("load", url); 1538 | 1539 | callback = callback || function(){}; 1540 | 1541 | // Default to a GET request 1542 | var type = "GET"; 1543 | 1544 | // If the second parameter was provided 1545 | if ( params ) { 1546 | // If it's a function 1547 | if ( params.constructor == Function ) { 1548 | // We assume that it's the callback 1549 | callback = params; 1550 | params = null; 1551 | 1552 | // Otherwise, build a param string 1553 | } else { 1554 | params = jQuery.param( params ); 1555 | type = "POST"; 1556 | } 1557 | } 1558 | 1559 | var self = this; 1560 | 1561 | // Request the remote document 1562 | jQuery.ajax( type, url, params,function(res, status){ 1563 | 1564 | if ( status == "success" || !ifModified && status == "notmodified" ) { 1565 | // Inject the HTML into all the matched elements 1566 | self.html(res.responseText).each( callback, [res.responseText, status] ); 1567 | 1568 | // Execute all the scripts inside of the newly-injected HTML 1569 | $("script", self).each(function(){ 1570 | if ( this.src ) 1571 | $.getScript( this.src ); 1572 | else 1573 | eval.call( window, this.text || this.textContent || this.innerHTML || "" ); 1574 | }); 1575 | } else 1576 | callback.apply( self, [res.responseText, status] ); 1577 | 1578 | }, ifModified); 1579 | 1580 | return this; 1581 | }; 1582 | 1583 | // If IE is used, create a wrapper for the XMLHttpRequest object 1584 | if ( jQuery.browser.msie ) 1585 | XMLHttpRequest = function(){ 1586 | return new ActiveXObject( 1587 | navigator.userAgent.indexOf("MSIE 5") >= 0 ? 1588 | "Microsoft.XMLHTTP" : "Msxml2.XMLHTTP" 1589 | ); 1590 | }; 1591 | 1592 | // Attach a bunch of functions for handling common AJAX events 1593 | new function(){ 1594 | var e = "ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess".split(','); 1595 | 1596 | for ( var i = 0; i < e.length; i++ ) new function(){ 1597 | var o = e[i]; 1598 | jQuery.fn[o] = function(f){ 1599 | return this.bind(o, f); 1600 | }; 1601 | }; 1602 | }; 1603 | 1604 | jQuery.extend({ 1605 | get: function( url, data, callback, type, ifModified ) { 1606 | if ( data.constructor == Function ) { 1607 | type = callback; 1608 | callback = data; 1609 | data = null; 1610 | } 1611 | 1612 | if ( data ) url += "?" + jQuery.param(data); 1613 | 1614 | // Build and start the HTTP Request 1615 | jQuery.ajax( "GET", url, null, function(r, status) { 1616 | if ( callback ) callback( jQuery.httpData(r,type), status ); 1617 | }, ifModified); 1618 | }, 1619 | 1620 | getIfModified: function( url, data, callback, type ) { 1621 | jQuery.get(url, data, callback, type, 1); 1622 | }, 1623 | 1624 | getScript: function( url, data, callback ) { 1625 | jQuery.get(url, data, callback, "script"); 1626 | }, 1627 | post: function( url, data, callback, type ) { 1628 | // Build and start the HTTP Request 1629 | jQuery.ajax( "POST", url, jQuery.param(data), function(r, status) { 1630 | if ( callback ) callback( jQuery.httpData(r,type), status ); 1631 | }); 1632 | }, 1633 | 1634 | // timeout (ms) 1635 | timeout: 0, 1636 | 1637 | ajaxTimeout: function(timeout) { 1638 | jQuery.timeout = timeout; 1639 | }, 1640 | 1641 | // Last-Modified header cache for next request 1642 | lastModified: {}, 1643 | ajax: function( type, url, data, ret, ifModified ) { 1644 | // If only a single argument was passed in, 1645 | // assume that it is a object of key/value pairs 1646 | if ( !url ) { 1647 | ret = type.complete; 1648 | var success = type.success; 1649 | var error = type.error; 1650 | data = type.data; 1651 | url = type.url; 1652 | type = type.type; 1653 | } 1654 | 1655 | // Watch for a new set of requests 1656 | if ( ! jQuery.active++ ) 1657 | jQuery.event.trigger( "ajaxStart" ); 1658 | 1659 | var requestDone = false; 1660 | 1661 | // Create the request object 1662 | var xml = new XMLHttpRequest(); 1663 | 1664 | // Open the socket 1665 | xml.open(type || "GET", url, true); 1666 | 1667 | // Set the correct header, if data is being sent 1668 | if ( data ) 1669 | xml.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); 1670 | 1671 | // Set the If-Modified-Since header, if ifModified mode. 1672 | if ( ifModified ) 1673 | xml.setRequestHeader("If-Modified-Since", 1674 | jQuery.lastModified[url] || "Thu, 01 Jan 1970 00:00:00 GMT" ); 1675 | 1676 | // Set header so calling script knows that it's an XMLHttpRequest 1677 | xml.setRequestHeader("X-Requested-With", "XMLHttpRequest"); 1678 | 1679 | // Make sure the browser sends the right content length 1680 | if ( xml.overrideMimeType ) 1681 | xml.setRequestHeader("Connection", "close"); 1682 | 1683 | // Wait for a response to come back 1684 | var onreadystatechange = function(istimeout){ 1685 | // The transfer is complete and the data is available, or the request timed out 1686 | if ( xml && (xml.readyState == 4 || istimeout == "timeout") ) { 1687 | requestDone = true; 1688 | 1689 | var status = jQuery.httpSuccess( xml ) && istimeout != "timeout" ? 1690 | ifModified && jQuery.httpNotModified( xml, url ) ? "notmodified" : "success" : "error"; 1691 | 1692 | // Make sure that the request was successful or notmodified 1693 | if ( status != "error" ) { 1694 | // Cache Last-Modified header, if ifModified mode. 1695 | var modRes = xml.getResponseHeader("Last-Modified"); 1696 | if ( ifModified && modRes ) jQuery.lastModified[url] = modRes; 1697 | 1698 | // If a local callback was specified, fire it 1699 | if ( success ) success( xml, status ); 1700 | 1701 | // Fire the global callback 1702 | jQuery.event.trigger( "ajaxSuccess" ); 1703 | 1704 | // Otherwise, the request was not successful 1705 | } else { 1706 | // If a local callback was specified, fire it 1707 | if ( error ) error( xml, status ); 1708 | 1709 | // Fire the global callback 1710 | jQuery.event.trigger( "ajaxError" ); 1711 | } 1712 | 1713 | // The request was completed 1714 | jQuery.event.trigger( "ajaxComplete" ); 1715 | 1716 | // Handle the global AJAX counter 1717 | if ( ! --jQuery.active ) 1718 | jQuery.event.trigger( "ajaxStop" ); 1719 | 1720 | // Process result 1721 | if ( ret ) ret(xml, status); 1722 | 1723 | // Stop memory leaks 1724 | xml.onreadystatechange = function(){}; 1725 | xml = null; 1726 | 1727 | } 1728 | }; 1729 | xml.onreadystatechange = onreadystatechange; 1730 | 1731 | // Timeout checker 1732 | if(jQuery.timeout > 0) 1733 | setTimeout(function(){ 1734 | // Check to see if the request is still happening 1735 | if (xml) { 1736 | // Cancel the request 1737 | xml.abort(); 1738 | 1739 | if ( !requestDone ) onreadystatechange( "timeout" ); 1740 | 1741 | // Clear from memory 1742 | xml = null; 1743 | } 1744 | }, jQuery.timeout); 1745 | 1746 | // Send the data 1747 | xml.send(data); 1748 | }, 1749 | 1750 | // Counter for holding the number of active queries 1751 | active: 0, 1752 | 1753 | // Determines if an XMLHttpRequest was successful or not 1754 | httpSuccess: function(r) { 1755 | try { 1756 | return !r.status && location.protocol == "file:" || 1757 | ( r.status >= 200 && r.status < 300 ) || r.status == 304 || 1758 | jQuery.browser.safari && r.status == undefined; 1759 | } catch(e){} 1760 | 1761 | return false; 1762 | }, 1763 | 1764 | // Determines if an XMLHttpRequest returns NotModified 1765 | httpNotModified: function(xml, url) { 1766 | try { 1767 | var xmlRes = xml.getResponseHeader("Last-Modified"); 1768 | 1769 | // Firefox always returns 200. check Last-Modified date 1770 | return xml.status == 304 || xmlRes == jQuery.lastModified[url] || 1771 | jQuery.browser.safari && xml.status == undefined; 1772 | } catch(e){} 1773 | 1774 | return false; 1775 | }, 1776 | 1777 | // Get the data out of an XMLHttpRequest. 1778 | // Return parsed XML if content-type header is "xml" and type is "xml" or omitted, 1779 | // otherwise return plain text. 1780 | httpData: function(r,type) { 1781 | var ct = r.getResponseHeader("content-type"); 1782 | var data = !type && ct && ct.indexOf("xml") >= 0; 1783 | data = type == "xml" || data ? r.responseXML : r.responseText; 1784 | 1785 | // If the type is "script", eval it 1786 | if ( type == "script" ) eval.call( window, data ); 1787 | 1788 | return data; 1789 | }, 1790 | 1791 | // Serialize an array of form elements or a set of 1792 | // key/values into a query string 1793 | param: function(a) { 1794 | var s = []; 1795 | 1796 | // If an array was passed in, assume that it is an array 1797 | // of form elements 1798 | if ( a.constructor == Array ) { 1799 | // Serialize the form elements 1800 | for ( var i = 0; i < a.length; i++ ) 1801 | s.push( a[i].name + "=" + encodeURIComponent( a[i].value ) ); 1802 | 1803 | // Otherwise, assume that it's an object of key/value pairs 1804 | } else { 1805 | // Serialize the key/values 1806 | for ( var j in a ) 1807 | s.push( j + "=" + encodeURIComponent( a[j] ) ); 1808 | } 1809 | 1810 | // Return the resulting serialization 1811 | return s.join("&"); 1812 | } 1813 | 1814 | }); 1815 | -------------------------------------------------------------------------------- /external/json2.js: -------------------------------------------------------------------------------- 1 | /* 2 | http://www.JSON.org/json2.js 3 | 2010-08-25 4 | 5 | Public Domain. 6 | 7 | NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. 8 | 9 | See http://www.JSON.org/js.html 10 | 11 | 12 | This code should be minified before deployment. 13 | See http://javascript.crockford.com/jsmin.html 14 | 15 | USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO 16 | NOT CONTROL. 17 | 18 | 19 | This file creates a global JSON object containing two methods: stringify 20 | and parse. 21 | 22 | JSON.stringify(value, replacer, space) 23 | value any JavaScript value, usually an object or array. 24 | 25 | replacer an optional parameter that determines how object 26 | values are stringified for objects. It can be a 27 | function or an array of strings. 28 | 29 | space an optional parameter that specifies the indentation 30 | of nested structures. If it is omitted, the text will 31 | be packed without extra whitespace. If it is a number, 32 | it will specify the number of spaces to indent at each 33 | level. If it is a string (such as '\t' or ' '), 34 | it contains the characters used to indent at each level. 35 | 36 | This method produces a JSON text from a JavaScript value. 37 | 38 | When an object value is found, if the object contains a toJSON 39 | method, its toJSON method will be called and the result will be 40 | stringified. A toJSON method does not serialize: it returns the 41 | value represented by the name/value pair that should be serialized, 42 | or undefined if nothing should be serialized. The toJSON method 43 | will be passed the key associated with the value, and this will be 44 | bound to the value 45 | 46 | For example, this would serialize Dates as ISO strings. 47 | 48 | Date.prototype.toJSON = function (key) { 49 | function f(n) { 50 | // Format integers to have at least two digits. 51 | return n < 10 ? '0' + n : n; 52 | } 53 | 54 | return this.getUTCFullYear() + '-' + 55 | f(this.getUTCMonth() + 1) + '-' + 56 | f(this.getUTCDate()) + 'T' + 57 | f(this.getUTCHours()) + ':' + 58 | f(this.getUTCMinutes()) + ':' + 59 | f(this.getUTCSeconds()) + 'Z'; 60 | }; 61 | 62 | You can provide an optional replacer method. It will be passed the 63 | key and value of each member, with this bound to the containing 64 | object. The value that is returned from your method will be 65 | serialized. If your method returns undefined, then the member will 66 | be excluded from the serialization. 67 | 68 | If the replacer parameter is an array of strings, then it will be 69 | used to select the members to be serialized. It filters the results 70 | such that only members with keys listed in the replacer array are 71 | stringified. 72 | 73 | Values that do not have JSON representations, such as undefined or 74 | functions, will not be serialized. Such values in objects will be 75 | dropped; in arrays they will be replaced with null. You can use 76 | a replacer function to replace those with JSON values. 77 | JSON.stringify(undefined) returns undefined. 78 | 79 | The optional space parameter produces a stringification of the 80 | value that is filled with line breaks and indentation to make it 81 | easier to read. 82 | 83 | If the space parameter is a non-empty string, then that string will 84 | be used for indentation. If the space parameter is a number, then 85 | the indentation will be that many spaces. 86 | 87 | Example: 88 | 89 | text = JSON.stringify(['e', {pluribus: 'unum'}]); 90 | // text is '["e",{"pluribus":"unum"}]' 91 | 92 | 93 | text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t'); 94 | // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]' 95 | 96 | text = JSON.stringify([new Date()], function (key, value) { 97 | return this[key] instanceof Date ? 98 | 'Date(' + this[key] + ')' : value; 99 | }); 100 | // text is '["Date(---current time---)"]' 101 | 102 | 103 | JSON.parse(text, reviver) 104 | This method parses a JSON text to produce an object or array. 105 | It can throw a SyntaxError exception. 106 | 107 | The optional reviver parameter is a function that can filter and 108 | transform the results. It receives each of the keys and values, 109 | and its return value is used instead of the original value. 110 | If it returns what it received, then the structure is not modified. 111 | If it returns undefined then the member is deleted. 112 | 113 | Example: 114 | 115 | // Parse the text. Values that look like ISO date strings will 116 | // be converted to Date objects. 117 | 118 | myData = JSON.parse(text, function (key, value) { 119 | var a; 120 | if (typeof value === 'string') { 121 | a = 122 | /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value); 123 | if (a) { 124 | return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4], 125 | +a[5], +a[6])); 126 | } 127 | } 128 | return value; 129 | }); 130 | 131 | myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) { 132 | var d; 133 | if (typeof value === 'string' && 134 | value.slice(0, 5) === 'Date(' && 135 | value.slice(-1) === ')') { 136 | d = new Date(value.slice(5, -1)); 137 | if (d) { 138 | return d; 139 | } 140 | } 141 | return value; 142 | }); 143 | 144 | 145 | This is a reference implementation. You are free to copy, modify, or 146 | redistribute. 147 | */ 148 | 149 | /*jslint evil: true, strict: false */ 150 | 151 | /*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply, 152 | call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours, 153 | getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join, 154 | lastIndex, length, parse, prototype, push, replace, slice, stringify, 155 | test, toJSON, toString, valueOf 156 | */ 157 | 158 | 159 | // Create a JSON object only if one does not already exist. We create the 160 | // methods in a closure to avoid creating global variables. 161 | 162 | if (!this.JSON) { 163 | this.JSON = {}; 164 | } 165 | 166 | (function () { 167 | 168 | function f(n) { 169 | // Format integers to have at least two digits. 170 | return n < 10 ? '0' + n : n; 171 | } 172 | 173 | if (typeof Date.prototype.toJSON !== 'function') { 174 | 175 | Date.prototype.toJSON = function (key) { 176 | 177 | return isFinite(this.valueOf()) ? 178 | this.getUTCFullYear() + '-' + 179 | f(this.getUTCMonth() + 1) + '-' + 180 | f(this.getUTCDate()) + 'T' + 181 | f(this.getUTCHours()) + ':' + 182 | f(this.getUTCMinutes()) + ':' + 183 | f(this.getUTCSeconds()) + 'Z' : null; 184 | }; 185 | 186 | String.prototype.toJSON = 187 | Number.prototype.toJSON = 188 | Boolean.prototype.toJSON = function (key) { 189 | return this.valueOf(); 190 | }; 191 | } 192 | 193 | var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, 194 | escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, 195 | gap, 196 | indent, 197 | meta = { // table of character substitutions 198 | '\b': '\\b', 199 | '\t': '\\t', 200 | '\n': '\\n', 201 | '\f': '\\f', 202 | '\r': '\\r', 203 | '"' : '\\"', 204 | '\\': '\\\\' 205 | }, 206 | rep; 207 | 208 | 209 | function quote(string) { 210 | 211 | // If the string contains no control characters, no quote characters, and no 212 | // backslash characters, then we can safely slap some quotes around it. 213 | // Otherwise we must also replace the offending characters with safe escape 214 | // sequences. 215 | 216 | escapable.lastIndex = 0; 217 | return escapable.test(string) ? 218 | '"' + string.replace(escapable, function (a) { 219 | var c = meta[a]; 220 | return typeof c === 'string' ? c : 221 | '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); 222 | }) + '"' : 223 | '"' + string + '"'; 224 | } 225 | 226 | 227 | function str(key, holder) { 228 | 229 | // Produce a string from holder[key]. 230 | 231 | var i, // The loop counter. 232 | k, // The member key. 233 | v, // The member value. 234 | length, 235 | mind = gap, 236 | partial, 237 | value = holder[key]; 238 | 239 | // If the value has a toJSON method, call it to obtain a replacement value. 240 | 241 | if (value && typeof value === 'object' && 242 | typeof value.toJSON === 'function') { 243 | value = value.toJSON(key); 244 | } 245 | 246 | // If we were called with a replacer function, then call the replacer to 247 | // obtain a replacement value. 248 | 249 | if (typeof rep === 'function') { 250 | value = rep.call(holder, key, value); 251 | } 252 | 253 | // What happens next depends on the value's type. 254 | 255 | switch (typeof value) { 256 | case 'string': 257 | return quote(value); 258 | 259 | case 'number': 260 | 261 | // JSON numbers must be finite. Encode non-finite numbers as null. 262 | 263 | return isFinite(value) ? String(value) : 'null'; 264 | 265 | case 'boolean': 266 | case 'null': 267 | 268 | // If the value is a boolean or null, convert it to a string. Note: 269 | // typeof null does not produce 'null'. The case is included here in 270 | // the remote chance that this gets fixed someday. 271 | 272 | return String(value); 273 | 274 | // If the type is 'object', we might be dealing with an object or an array or 275 | // null. 276 | 277 | case 'object': 278 | 279 | // Due to a specification blunder in ECMAScript, typeof null is 'object', 280 | // so watch out for that case. 281 | 282 | if (!value) { 283 | return 'null'; 284 | } 285 | 286 | // Make an array to hold the partial results of stringifying this object value. 287 | 288 | gap += indent; 289 | partial = []; 290 | 291 | // Is the value an array? 292 | 293 | if (Object.prototype.toString.apply(value) === '[object Array]') { 294 | 295 | // The value is an array. Stringify every element. Use null as a placeholder 296 | // for non-JSON values. 297 | 298 | length = value.length; 299 | for (i = 0; i < length; i += 1) { 300 | partial[i] = str(i, value) || 'null'; 301 | } 302 | 303 | // Join all of the elements together, separated with commas, and wrap them in 304 | // brackets. 305 | 306 | v = partial.length === 0 ? '[]' : 307 | gap ? '[\n' + gap + 308 | partial.join(',\n' + gap) + '\n' + 309 | mind + ']' : 310 | '[' + partial.join(',') + ']'; 311 | gap = mind; 312 | return v; 313 | } 314 | 315 | // If the replacer is an array, use it to select the members to be stringified. 316 | 317 | if (rep && typeof rep === 'object') { 318 | length = rep.length; 319 | for (i = 0; i < length; i += 1) { 320 | k = rep[i]; 321 | if (typeof k === 'string') { 322 | v = str(k, value); 323 | if (v) { 324 | partial.push(quote(k) + (gap ? ': ' : ':') + v); 325 | } 326 | } 327 | } 328 | } else { 329 | 330 | // Otherwise, iterate through all of the keys in the object. 331 | 332 | for (k in value) { 333 | if (Object.hasOwnProperty.call(value, k)) { 334 | v = str(k, value); 335 | if (v) { 336 | partial.push(quote(k) + (gap ? ': ' : ':') + v); 337 | } 338 | } 339 | } 340 | } 341 | 342 | // Join all of the member texts together, separated with commas, 343 | // and wrap them in braces. 344 | 345 | v = partial.length === 0 ? '{}' : 346 | gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + 347 | mind + '}' : '{' + partial.join(',') + '}'; 348 | gap = mind; 349 | return v; 350 | } 351 | } 352 | 353 | // If the JSON object does not yet have a stringify method, give it one. 354 | 355 | if (typeof JSON.stringify !== 'function') { 356 | JSON.stringify = function (value, replacer, space) { 357 | 358 | // The stringify method takes a value and an optional replacer, and an optional 359 | // space parameter, and returns a JSON text. The replacer can be a function 360 | // that can replace values, or an array of strings that will select the keys. 361 | // A default replacer method can be provided. Use of the space parameter can 362 | // produce text that is more easily readable. 363 | 364 | var i; 365 | gap = ''; 366 | indent = ''; 367 | 368 | // If the space parameter is a number, make an indent string containing that 369 | // many spaces. 370 | 371 | if (typeof space === 'number') { 372 | for (i = 0; i < space; i += 1) { 373 | indent += ' '; 374 | } 375 | 376 | // If the space parameter is a string, it will be used as the indent string. 377 | 378 | } else if (typeof space === 'string') { 379 | indent = space; 380 | } 381 | 382 | // If there is a replacer, it must be a function or an array. 383 | // Otherwise, throw an error. 384 | 385 | rep = replacer; 386 | if (replacer && typeof replacer !== 'function' && 387 | (typeof replacer !== 'object' || 388 | typeof replacer.length !== 'number')) { 389 | throw new Error('JSON.stringify'); 390 | } 391 | 392 | // Make a fake root object containing our value under the key of ''. 393 | // Return the result of stringifying the value. 394 | 395 | return str('', {'': value}); 396 | }; 397 | } 398 | 399 | 400 | // If the JSON object does not yet have a parse method, give it one. 401 | 402 | if (typeof JSON.parse !== 'function') { 403 | JSON.parse = function (text, reviver) { 404 | 405 | // The parse method takes a text and an optional reviver function, and returns 406 | // a JavaScript value if the text is a valid JSON text. 407 | 408 | var j; 409 | 410 | function walk(holder, key) { 411 | 412 | // The walk method is used to recursively walk the resulting structure so 413 | // that modifications can be made. 414 | 415 | var k, v, value = holder[key]; 416 | if (value && typeof value === 'object') { 417 | for (k in value) { 418 | if (Object.hasOwnProperty.call(value, k)) { 419 | v = walk(value, k); 420 | if (v !== undefined) { 421 | value[k] = v; 422 | } else { 423 | delete value[k]; 424 | } 425 | } 426 | } 427 | } 428 | return reviver.call(holder, key, value); 429 | } 430 | 431 | 432 | // Parsing happens in four stages. In the first stage, we replace certain 433 | // Unicode characters with escape sequences. JavaScript handles many characters 434 | // incorrectly, either silently deleting them, or treating them as line endings. 435 | 436 | text = String(text); 437 | cx.lastIndex = 0; 438 | if (cx.test(text)) { 439 | text = text.replace(cx, function (a) { 440 | return '\\u' + 441 | ('0000' + a.charCodeAt(0).toString(16)).slice(-4); 442 | }); 443 | } 444 | 445 | // In the second stage, we run the text against regular expressions that look 446 | // for non-JSON patterns. We are especially concerned with '()' and 'new' 447 | // because they can cause invocation, and '=' because it can cause mutation. 448 | // But just to be safe, we want to reject all unexpected forms. 449 | 450 | // We split the second stage into 4 regexp operations in order to work around 451 | // crippling inefficiencies in IE's and Safari's regexp engines. First we 452 | // replace the JSON backslash pairs with '@' (a non-JSON character). Second, we 453 | // replace all simple value tokens with ']' characters. Third, we delete all 454 | // open brackets that follow a colon or comma or that begin the text. Finally, 455 | // we look to see that the remaining characters are only whitespace or ']' or 456 | // ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval. 457 | 458 | if (/^[\],:{}\s]*$/ 459 | .test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@') 460 | .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']') 461 | .replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) { 462 | 463 | // In the third stage we use the eval function to compile the text into a 464 | // JavaScript structure. The '{' operator is subject to a syntactic ambiguity 465 | // in JavaScript: it can begin a block or an object literal. We wrap the text 466 | // in parens to eliminate the ambiguity. 467 | 468 | j = eval('(' + text + ')'); 469 | 470 | // In the optional fourth stage, we recursively walk the new structure, passing 471 | // each name/value pair to a reviver function for possible transformation. 472 | 473 | return typeof reviver === 'function' ? 474 | walk({'': j}, '') : j; 475 | } 476 | 477 | // If the text is not JSON parseable, then a SyntaxError is thrown. 478 | 479 | throw new SyntaxError('JSON.parse'); 480 | }; 481 | } 482 | }()); 483 | -------------------------------------------------------------------------------- /external/qunit.css: -------------------------------------------------------------------------------- 1 | /** Font Family and Sizes */ 2 | 3 | #qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult { 4 | font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial; 5 | } 6 | 7 | #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; } 8 | #qunit-tests { font-size: smaller; } 9 | 10 | 11 | /** Resets */ 12 | 13 | #qunit-tests, #qunit-tests ol, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult { 14 | margin: 0; 15 | padding: 0; 16 | } 17 | 18 | 19 | /** Header */ 20 | 21 | #qunit-header { 22 | padding: 0.5em 0 0.5em 1em; 23 | 24 | color: #8699a4; 25 | background-color: #0d3349; 26 | 27 | font-size: 1.5em; 28 | line-height: 1em; 29 | font-weight: normal; 30 | 31 | border-radius: 15px 15px 0 0; 32 | -moz-border-radius: 15px 15px 0 0; 33 | -webkit-border-top-right-radius: 15px; 34 | -webkit-border-top-left-radius: 15px; 35 | } 36 | 37 | #qunit-header a { 38 | text-decoration: none; 39 | color: #c2ccd1; 40 | } 41 | 42 | #qunit-header a:hover, 43 | #qunit-header a:focus { 44 | color: #fff; 45 | } 46 | 47 | #qunit-banner { 48 | height: 5px; 49 | } 50 | 51 | #qunit-testrunner-toolbar { 52 | padding: 0.5em 0 0.5em 2em; 53 | color: #5E740B; 54 | background-color: #eee; 55 | } 56 | 57 | #qunit-userAgent { 58 | padding: 0.5em 0 0.5em 2.5em; 59 | background-color: #2b81af; 60 | color: #fff; 61 | text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px; 62 | } 63 | 64 | 65 | /** Tests: Pass/Fail */ 66 | 67 | #qunit-tests { 68 | list-style-position: inside; 69 | } 70 | 71 | #qunit-tests li { 72 | padding: 0.4em 0.5em 0.4em 2.5em; 73 | border-bottom: 1px solid #fff; 74 | list-style-position: inside; 75 | } 76 | 77 | #qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running { 78 | display: none; 79 | } 80 | 81 | #qunit-tests li strong { 82 | cursor: pointer; 83 | } 84 | 85 | #qunit-tests ol { 86 | margin-top: 0.5em; 87 | padding: 0.5em; 88 | 89 | background-color: #fff; 90 | 91 | border-radius: 15px; 92 | -moz-border-radius: 15px; 93 | -webkit-border-radius: 15px; 94 | 95 | box-shadow: inset 0px 2px 13px #999; 96 | -moz-box-shadow: inset 0px 2px 13px #999; 97 | -webkit-box-shadow: inset 0px 2px 13px #999; 98 | } 99 | 100 | #qunit-tests table { 101 | border-collapse: collapse; 102 | margin-top: .2em; 103 | } 104 | 105 | #qunit-tests th { 106 | text-align: right; 107 | vertical-align: top; 108 | padding: 0 .5em 0 0; 109 | } 110 | 111 | #qunit-tests td { 112 | vertical-align: top; 113 | } 114 | 115 | #qunit-tests pre { 116 | margin: 0; 117 | white-space: pre-wrap; 118 | word-wrap: break-word; 119 | } 120 | 121 | #qunit-tests del { 122 | background-color: #e0f2be; 123 | color: #374e0c; 124 | text-decoration: none; 125 | } 126 | 127 | #qunit-tests ins { 128 | background-color: #ffcaca; 129 | color: #500; 130 | text-decoration: none; 131 | } 132 | 133 | /*** Test Counts */ 134 | 135 | #qunit-tests b.counts { color: black; } 136 | #qunit-tests b.passed { color: #5E740B; } 137 | #qunit-tests b.failed { color: #710909; } 138 | 139 | #qunit-tests li li { 140 | margin: 0.5em; 141 | padding: 0.4em 0.5em 0.4em 0.5em; 142 | background-color: #fff; 143 | border-bottom: none; 144 | list-style-position: inside; 145 | } 146 | 147 | /*** Passing Styles */ 148 | 149 | #qunit-tests li li.pass { 150 | color: #5E740B; 151 | background-color: #fff; 152 | border-left: 26px solid #C6E746; 153 | } 154 | 155 | #qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; } 156 | #qunit-tests .pass .test-name { color: #366097; } 157 | 158 | #qunit-tests .pass .test-actual, 159 | #qunit-tests .pass .test-expected { color: #999999; } 160 | 161 | #qunit-banner.qunit-pass { background-color: #C6E746; } 162 | 163 | /*** Failing Styles */ 164 | 165 | #qunit-tests li li.fail { 166 | color: #710909; 167 | background-color: #fff; 168 | border-left: 26px solid #EE5757; 169 | } 170 | 171 | #qunit-tests > li:last-child { 172 | border-radius: 0 0 15px 15px; 173 | -moz-border-radius: 0 0 15px 15px; 174 | -webkit-border-bottom-right-radius: 15px; 175 | -webkit-border-bottom-left-radius: 15px; 176 | } 177 | 178 | #qunit-tests .fail { color: #000000; background-color: #EE5757; } 179 | #qunit-tests .fail .test-name, 180 | #qunit-tests .fail .module-name { color: #000000; } 181 | 182 | #qunit-tests .fail .test-actual { color: #EE5757; } 183 | #qunit-tests .fail .test-expected { color: green; } 184 | 185 | #qunit-banner.qunit-fail { background-color: #EE5757; } 186 | 187 | 188 | /** Result */ 189 | 190 | #qunit-testresult { 191 | padding: 0.5em 0.5em 0.5em 2.5em; 192 | 193 | color: #2b81af; 194 | background-color: #D2E0E6; 195 | 196 | border-bottom: 1px solid white; 197 | } 198 | 199 | /** Fixture */ 200 | 201 | #qunit-fixture { 202 | position: absolute; 203 | top: -10000px; 204 | left: -10000px; 205 | } 206 | -------------------------------------------------------------------------------- /external/qunit.js: -------------------------------------------------------------------------------- 1 | /* 2 | * QUnit - A JavaScript Unit Testing Framework 3 | * 4 | * http://docs.jquery.com/QUnit 5 | * 6 | * Copyright (c) 2011 John Resig, Jörn Zaefferer 7 | * Dual licensed under the MIT (MIT-LICENSE.txt) 8 | * or GPL (GPL-LICENSE.txt) licenses. 9 | */ 10 | 11 | (function(window) { 12 | 13 | var defined = { 14 | setTimeout: typeof window.setTimeout !== "undefined", 15 | sessionStorage: (function() { 16 | try { 17 | return !!sessionStorage.getItem; 18 | } catch(e){ 19 | return false; 20 | } 21 | })() 22 | }; 23 | 24 | var testId = 0; 25 | 26 | var Test = function(name, testName, expected, testEnvironmentArg, async, callback) { 27 | this.name = name; 28 | this.testName = testName; 29 | this.expected = expected; 30 | this.testEnvironmentArg = testEnvironmentArg; 31 | this.async = async; 32 | this.callback = callback; 33 | this.assertions = []; 34 | }; 35 | Test.prototype = { 36 | init: function() { 37 | var tests = id("qunit-tests"); 38 | if (tests) { 39 | var b = document.createElement("strong"); 40 | b.innerHTML = "Running " + this.name; 41 | var li = document.createElement("li"); 42 | li.appendChild( b ); 43 | li.className = "running"; 44 | li.id = this.id = "test-output" + testId++; 45 | tests.appendChild( li ); 46 | } 47 | }, 48 | setup: function() { 49 | if (this.module != config.previousModule) { 50 | if ( config.previousModule ) { 51 | QUnit.moduleDone( { 52 | name: config.previousModule, 53 | failed: config.moduleStats.bad, 54 | passed: config.moduleStats.all - config.moduleStats.bad, 55 | total: config.moduleStats.all 56 | } ); 57 | } 58 | config.previousModule = this.module; 59 | config.moduleStats = { all: 0, bad: 0 }; 60 | QUnit.moduleStart( { 61 | name: this.module 62 | } ); 63 | } 64 | 65 | config.current = this; 66 | this.testEnvironment = extend({ 67 | setup: function() {}, 68 | teardown: function() {} 69 | }, this.moduleTestEnvironment); 70 | if (this.testEnvironmentArg) { 71 | extend(this.testEnvironment, this.testEnvironmentArg); 72 | } 73 | 74 | QUnit.testStart( { 75 | name: this.testName 76 | } ); 77 | 78 | // allow utility functions to access the current test environment 79 | // TODO why?? 80 | QUnit.current_testEnvironment = this.testEnvironment; 81 | 82 | try { 83 | if ( !config.pollution ) { 84 | saveGlobal(); 85 | } 86 | 87 | this.testEnvironment.setup.call(this.testEnvironment); 88 | } catch(e) { 89 | QUnit.ok( false, "Setup failed on " + this.testName + ": " + e.message ); 90 | } 91 | }, 92 | run: function() { 93 | if ( this.async ) { 94 | QUnit.stop(); 95 | } 96 | 97 | if ( config.notrycatch ) { 98 | this.callback.call(this.testEnvironment); 99 | return; 100 | } 101 | try { 102 | this.callback.call(this.testEnvironment); 103 | } catch(e) { 104 | fail("Test " + this.testName + " died, exception and test follows", e, this.callback); 105 | QUnit.ok( false, "Died on test #" + (this.assertions.length + 1) + ": " + e.message + " - " + QUnit.jsDump.parse(e) ); 106 | // else next test will carry the responsibility 107 | saveGlobal(); 108 | 109 | // Restart the tests if they're blocking 110 | if ( config.blocking ) { 111 | start(); 112 | } 113 | } 114 | }, 115 | teardown: function() { 116 | try { 117 | checkPollution(); 118 | this.testEnvironment.teardown.call(this.testEnvironment); 119 | } catch(e) { 120 | QUnit.ok( false, "Teardown failed on " + this.testName + ": " + e.message ); 121 | } 122 | }, 123 | finish: function() { 124 | if ( this.expected && this.expected != this.assertions.length ) { 125 | QUnit.ok( false, "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run" ); 126 | } 127 | 128 | var good = 0, bad = 0, 129 | tests = id("qunit-tests"); 130 | 131 | config.stats.all += this.assertions.length; 132 | config.moduleStats.all += this.assertions.length; 133 | 134 | if ( tests ) { 135 | var ol = document.createElement("ol"); 136 | 137 | for ( var i = 0; i < this.assertions.length; i++ ) { 138 | var assertion = this.assertions[i]; 139 | 140 | var li = document.createElement("li"); 141 | li.className = assertion.result ? "pass" : "fail"; 142 | li.innerHTML = assertion.message || (assertion.result ? "okay" : "failed"); 143 | ol.appendChild( li ); 144 | 145 | if ( assertion.result ) { 146 | good++; 147 | } else { 148 | bad++; 149 | config.stats.bad++; 150 | config.moduleStats.bad++; 151 | } 152 | } 153 | 154 | // store result when possible 155 | QUnit.config.reorder && defined.sessionStorage && sessionStorage.setItem("qunit-" + this.testName, bad); 156 | 157 | if (bad == 0) { 158 | ol.style.display = "none"; 159 | } 160 | 161 | var b = document.createElement("strong"); 162 | b.innerHTML = this.name + " (" + bad + ", " + good + ", " + this.assertions.length + ")"; 163 | 164 | addEvent(b, "click", function() { 165 | var next = b.nextSibling, display = next.style.display; 166 | next.style.display = display === "none" ? "block" : "none"; 167 | }); 168 | 169 | addEvent(b, "dblclick", function(e) { 170 | var target = e && e.target ? e.target : window.event.srcElement; 171 | if ( target.nodeName.toLowerCase() == "span" || target.nodeName.toLowerCase() == "b" ) { 172 | target = target.parentNode; 173 | } 174 | if ( window.location && target.nodeName.toLowerCase() === "strong" ) { 175 | window.location = QUnit.url({ filter: getText([target]).replace(/\(.+\)$/, "").replace(/(^\s*|\s*$)/g, "") }); 176 | } 177 | }); 178 | 179 | var li = id(this.id); 180 | li.className = bad ? "fail" : "pass"; 181 | li.removeChild( li.firstChild ); 182 | li.appendChild( b ); 183 | li.appendChild( ol ); 184 | 185 | } else { 186 | for ( var i = 0; i < this.assertions.length; i++ ) { 187 | if ( !this.assertions[i].result ) { 188 | bad++; 189 | config.stats.bad++; 190 | config.moduleStats.bad++; 191 | } 192 | } 193 | } 194 | 195 | try { 196 | QUnit.reset(); 197 | } catch(e) { 198 | fail("reset() failed, following Test " + this.testName + ", exception and reset fn follows", e, QUnit.reset); 199 | } 200 | 201 | QUnit.testDone( { 202 | name: this.testName, 203 | failed: bad, 204 | passed: this.assertions.length - bad, 205 | total: this.assertions.length 206 | } ); 207 | }, 208 | 209 | queue: function() { 210 | var test = this; 211 | synchronize(function() { 212 | test.init(); 213 | }); 214 | function run() { 215 | // each of these can by async 216 | synchronize(function() { 217 | test.setup(); 218 | }); 219 | synchronize(function() { 220 | test.run(); 221 | }); 222 | synchronize(function() { 223 | test.teardown(); 224 | }); 225 | synchronize(function() { 226 | test.finish(); 227 | }); 228 | } 229 | // defer when previous test run passed, if storage is available 230 | var bad = QUnit.config.reorder && defined.sessionStorage && +sessionStorage.getItem("qunit-" + this.testName); 231 | if (bad) { 232 | run(); 233 | } else { 234 | synchronize(run); 235 | }; 236 | } 237 | 238 | }; 239 | 240 | var QUnit = { 241 | 242 | // call on start of module test to prepend name to all tests 243 | module: function(name, testEnvironment) { 244 | config.currentModule = name; 245 | config.currentModuleTestEnviroment = testEnvironment; 246 | }, 247 | 248 | asyncTest: function(testName, expected, callback) { 249 | if ( arguments.length === 2 ) { 250 | callback = expected; 251 | expected = 0; 252 | } 253 | 254 | QUnit.test(testName, expected, callback, true); 255 | }, 256 | 257 | test: function(testName, expected, callback, async) { 258 | var name = '' + testName + '', testEnvironmentArg; 259 | 260 | if ( arguments.length === 2 ) { 261 | callback = expected; 262 | expected = null; 263 | } 264 | // is 2nd argument a testEnvironment? 265 | if ( expected && typeof expected === 'object') { 266 | testEnvironmentArg = expected; 267 | expected = null; 268 | } 269 | 270 | if ( config.currentModule ) { 271 | name = '' + config.currentModule + ": " + name; 272 | } 273 | 274 | if ( !validTest(config.currentModule + ": " + testName) ) { 275 | return; 276 | } 277 | 278 | var test = new Test(name, testName, expected, testEnvironmentArg, async, callback); 279 | test.module = config.currentModule; 280 | test.moduleTestEnvironment = config.currentModuleTestEnviroment; 281 | test.queue(); 282 | }, 283 | 284 | /** 285 | * Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through. 286 | */ 287 | expect: function(asserts) { 288 | config.current.expected = asserts; 289 | }, 290 | 291 | /** 292 | * Asserts true. 293 | * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" ); 294 | */ 295 | ok: function(a, msg) { 296 | a = !!a; 297 | var details = { 298 | result: a, 299 | message: msg 300 | }; 301 | msg = escapeHtml(msg); 302 | QUnit.log(details); 303 | config.current.assertions.push({ 304 | result: a, 305 | message: msg 306 | }); 307 | }, 308 | 309 | /** 310 | * Checks that the first two arguments are equal, with an optional message. 311 | * Prints out both actual and expected values. 312 | * 313 | * Prefered to ok( actual == expected, message ) 314 | * 315 | * @example equal( format("Received {0} bytes.", 2), "Received 2 bytes." ); 316 | * 317 | * @param Object actual 318 | * @param Object expected 319 | * @param String message (optional) 320 | */ 321 | equal: function(actual, expected, message) { 322 | QUnit.push(expected == actual, actual, expected, message); 323 | }, 324 | 325 | notEqual: function(actual, expected, message) { 326 | QUnit.push(expected != actual, actual, expected, message); 327 | }, 328 | 329 | deepEqual: function(actual, expected, message) { 330 | QUnit.push(QUnit.equiv(actual, expected), actual, expected, message); 331 | }, 332 | 333 | notDeepEqual: function(actual, expected, message) { 334 | QUnit.push(!QUnit.equiv(actual, expected), actual, expected, message); 335 | }, 336 | 337 | strictEqual: function(actual, expected, message) { 338 | QUnit.push(expected === actual, actual, expected, message); 339 | }, 340 | 341 | notStrictEqual: function(actual, expected, message) { 342 | QUnit.push(expected !== actual, actual, expected, message); 343 | }, 344 | 345 | raises: function(block, expected, message) { 346 | var actual, ok = false; 347 | 348 | if (typeof expected === 'string') { 349 | message = expected; 350 | expected = null; 351 | } 352 | 353 | try { 354 | block(); 355 | } catch (e) { 356 | actual = e; 357 | } 358 | 359 | if (actual) { 360 | // we don't want to validate thrown error 361 | if (!expected) { 362 | ok = true; 363 | // expected is a regexp 364 | } else if (QUnit.objectType(expected) === "regexp") { 365 | ok = expected.test(actual); 366 | // expected is a constructor 367 | } else if (actual instanceof expected) { 368 | ok = true; 369 | // expected is a validation function which returns true is validation passed 370 | } else if (expected.call({}, actual) === true) { 371 | ok = true; 372 | } 373 | } 374 | 375 | QUnit.ok(ok, message); 376 | }, 377 | 378 | start: function() { 379 | config.semaphore--; 380 | if (config.semaphore > 0) { 381 | // don't start until equal number of stop-calls 382 | return; 383 | } 384 | if (config.semaphore < 0) { 385 | // ignore if start is called more often then stop 386 | config.semaphore = 0; 387 | } 388 | // A slight delay, to avoid any current callbacks 389 | if ( defined.setTimeout ) { 390 | window.setTimeout(function() { 391 | if ( config.timeout ) { 392 | clearTimeout(config.timeout); 393 | } 394 | 395 | config.blocking = false; 396 | process(); 397 | }, 13); 398 | } else { 399 | config.blocking = false; 400 | process(); 401 | } 402 | }, 403 | 404 | stop: function(timeout) { 405 | config.semaphore++; 406 | config.blocking = true; 407 | 408 | if ( timeout && defined.setTimeout ) { 409 | clearTimeout(config.timeout); 410 | config.timeout = window.setTimeout(function() { 411 | QUnit.ok( false, "Test timed out" ); 412 | QUnit.start(); 413 | }, timeout); 414 | } 415 | }, 416 | 417 | url: function( params ) { 418 | params = extend( extend( {}, QUnit.urlParams ), params ); 419 | var querystring = "?", 420 | key; 421 | for ( key in params ) { 422 | querystring += encodeURIComponent( key ) + "=" + 423 | encodeURIComponent( params[ key ] ) + "&"; 424 | } 425 | return window.location.pathname + querystring.slice( 0, -1 ); 426 | } 427 | }; 428 | 429 | // Backwards compatibility, deprecated 430 | QUnit.equals = QUnit.equal; 431 | QUnit.same = QUnit.deepEqual; 432 | 433 | // Maintain internal state 434 | var config = { 435 | // The queue of tests to run 436 | queue: [], 437 | 438 | // block until document ready 439 | blocking: true, 440 | 441 | // by default, run previously failed tests first 442 | // very useful in combination with "Hide passed tests" checked 443 | reorder: true, 444 | 445 | noglobals: false, 446 | notrycatch: false 447 | }; 448 | 449 | // Load paramaters 450 | (function() { 451 | var location = window.location || { search: "", protocol: "file:" }, 452 | params = location.search.slice( 1 ).split( "&" ), 453 | length = params.length, 454 | urlParams = {}, 455 | current; 456 | 457 | if ( params[ 0 ] ) { 458 | for ( var i = 0; i < length; i++ ) { 459 | current = params[ i ].split( "=" ); 460 | current[ 0 ] = decodeURIComponent( current[ 0 ] ); 461 | // allow just a key to turn on a flag, e.g., test.html?noglobals 462 | current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true; 463 | urlParams[ current[ 0 ] ] = current[ 1 ]; 464 | if ( current[ 0 ] in config ) { 465 | config[ current[ 0 ] ] = current[ 1 ]; 466 | } 467 | } 468 | } 469 | 470 | QUnit.urlParams = urlParams; 471 | config.filter = urlParams.filter; 472 | 473 | // Figure out if we're running the tests from a server or not 474 | QUnit.isLocal = !!(location.protocol === 'file:'); 475 | })(); 476 | 477 | // Expose the API as global variables, unless an 'exports' 478 | // object exists, in that case we assume we're in CommonJS 479 | if ( typeof exports === "undefined" || typeof require === "undefined" ) { 480 | extend(window, QUnit); 481 | window.QUnit = QUnit; 482 | } else { 483 | extend(exports, QUnit); 484 | exports.QUnit = QUnit; 485 | } 486 | 487 | // define these after exposing globals to keep them in these QUnit namespace only 488 | extend(QUnit, { 489 | config: config, 490 | 491 | // Initialize the configuration options 492 | init: function() { 493 | extend(config, { 494 | stats: { all: 0, bad: 0 }, 495 | moduleStats: { all: 0, bad: 0 }, 496 | started: +new Date, 497 | updateRate: 1000, 498 | blocking: false, 499 | autostart: true, 500 | autorun: false, 501 | filter: "", 502 | queue: [], 503 | semaphore: 0 504 | }); 505 | 506 | var tests = id( "qunit-tests" ), 507 | banner = id( "qunit-banner" ), 508 | result = id( "qunit-testresult" ); 509 | 510 | if ( tests ) { 511 | tests.innerHTML = ""; 512 | } 513 | 514 | if ( banner ) { 515 | banner.className = ""; 516 | } 517 | 518 | if ( result ) { 519 | result.parentNode.removeChild( result ); 520 | } 521 | 522 | if ( tests ) { 523 | result = document.createElement( "p" ); 524 | result.id = "qunit-testresult"; 525 | result.className = "result"; 526 | tests.parentNode.insertBefore( result, tests ); 527 | result.innerHTML = 'Running...
 '; 528 | } 529 | }, 530 | 531 | /** 532 | * Resets the test setup. Useful for tests that modify the DOM. 533 | * 534 | * If jQuery is available, uses jQuery's html(), otherwise just innerHTML. 535 | */ 536 | reset: function() { 537 | if ( window.jQuery ) { 538 | jQuery( "#main, #qunit-fixture" ).html( config.fixture ); 539 | } else { 540 | var main = id( 'main' ) || id( 'qunit-fixture' ); 541 | if ( main ) { 542 | main.innerHTML = config.fixture; 543 | } 544 | } 545 | }, 546 | 547 | /** 548 | * Trigger an event on an element. 549 | * 550 | * @example triggerEvent( document.body, "click" ); 551 | * 552 | * @param DOMElement elem 553 | * @param String type 554 | */ 555 | triggerEvent: function( elem, type, event ) { 556 | if ( document.createEvent ) { 557 | event = document.createEvent("MouseEvents"); 558 | event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView, 559 | 0, 0, 0, 0, 0, false, false, false, false, 0, null); 560 | elem.dispatchEvent( event ); 561 | 562 | } else if ( elem.fireEvent ) { 563 | elem.fireEvent("on"+type); 564 | } 565 | }, 566 | 567 | // Safe object type checking 568 | is: function( type, obj ) { 569 | return QUnit.objectType( obj ) == type; 570 | }, 571 | 572 | objectType: function( obj ) { 573 | if (typeof obj === "undefined") { 574 | return "undefined"; 575 | 576 | // consider: typeof null === object 577 | } 578 | if (obj === null) { 579 | return "null"; 580 | } 581 | 582 | var type = Object.prototype.toString.call( obj ) 583 | .match(/^\[object\s(.*)\]$/)[1] || ''; 584 | 585 | switch (type) { 586 | case 'Number': 587 | if (isNaN(obj)) { 588 | return "nan"; 589 | } else { 590 | return "number"; 591 | } 592 | case 'String': 593 | case 'Boolean': 594 | case 'Array': 595 | case 'Date': 596 | case 'RegExp': 597 | case 'Function': 598 | return type.toLowerCase(); 599 | } 600 | if (typeof obj === "object") { 601 | return "object"; 602 | } 603 | return undefined; 604 | }, 605 | 606 | push: function(result, actual, expected, message) { 607 | var details = { 608 | result: result, 609 | message: message, 610 | actual: actual, 611 | expected: expected 612 | }; 613 | 614 | message = escapeHtml(message) || (result ? "okay" : "failed"); 615 | message = '' + message + ""; 616 | expected = escapeHtml(QUnit.jsDump.parse(expected)); 617 | actual = escapeHtml(QUnit.jsDump.parse(actual)); 618 | var output = message + ''; 619 | if (actual != expected) { 620 | output += ''; 621 | output += ''; 622 | } 623 | if (!result) { 624 | var source = sourceFromStacktrace(); 625 | if (source) { 626 | details.source = source; 627 | output += ''; 628 | } 629 | } 630 | output += "
Expected:
' + expected + '
Result:
' + actual + '
Diff:
' + QUnit.diff(expected, actual) +'
Source:
' + source +'
"; 631 | 632 | QUnit.log(details); 633 | 634 | config.current.assertions.push({ 635 | result: !!result, 636 | message: output 637 | }); 638 | }, 639 | 640 | // Logging callbacks; all receive a single argument with the listed properties 641 | // run test/logs.html for any related changes 642 | begin: function() {}, 643 | // done: { failed, passed, total, runtime } 644 | done: function() {}, 645 | // log: { result, actual, expected, message } 646 | log: function() {}, 647 | // testStart: { name } 648 | testStart: function() {}, 649 | // testDone: { name, failed, passed, total } 650 | testDone: function() {}, 651 | // moduleStart: { name } 652 | moduleStart: function() {}, 653 | // moduleDone: { name, failed, passed, total } 654 | moduleDone: function() {} 655 | }); 656 | 657 | if ( typeof document === "undefined" || document.readyState === "complete" ) { 658 | config.autorun = true; 659 | } 660 | 661 | addEvent(window, "load", function() { 662 | QUnit.begin({}); 663 | 664 | // Initialize the config, saving the execution queue 665 | var oldconfig = extend({}, config); 666 | QUnit.init(); 667 | extend(config, oldconfig); 668 | 669 | config.blocking = false; 670 | 671 | var userAgent = id("qunit-userAgent"); 672 | if ( userAgent ) { 673 | userAgent.innerHTML = navigator.userAgent; 674 | } 675 | var banner = id("qunit-header"); 676 | if ( banner ) { 677 | banner.innerHTML = ' ' + banner.innerHTML + ' ' + 678 | '' + 679 | ''; 680 | addEvent( banner, "change", function( event ) { 681 | var params = {}; 682 | params[ event.target.name ] = event.target.checked ? true : undefined; 683 | window.location = QUnit.url( params ); 684 | }); 685 | } 686 | 687 | var toolbar = id("qunit-testrunner-toolbar"); 688 | if ( toolbar ) { 689 | var filter = document.createElement("input"); 690 | filter.type = "checkbox"; 691 | filter.id = "qunit-filter-pass"; 692 | addEvent( filter, "click", function() { 693 | var ol = document.getElementById("qunit-tests"); 694 | if ( filter.checked ) { 695 | ol.className = ol.className + " hidepass"; 696 | } else { 697 | var tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " "; 698 | ol.className = tmp.replace(/ hidepass /, " "); 699 | } 700 | if ( defined.sessionStorage ) { 701 | sessionStorage.setItem("qunit-filter-passed-tests", filter.checked ? "true" : ""); 702 | } 703 | }); 704 | if ( defined.sessionStorage && sessionStorage.getItem("qunit-filter-passed-tests") ) { 705 | filter.checked = true; 706 | var ol = document.getElementById("qunit-tests"); 707 | ol.className = ol.className + " hidepass"; 708 | } 709 | toolbar.appendChild( filter ); 710 | 711 | var label = document.createElement("label"); 712 | label.setAttribute("for", "qunit-filter-pass"); 713 | label.innerHTML = "Hide passed tests"; 714 | toolbar.appendChild( label ); 715 | } 716 | 717 | var main = id('main') || id('qunit-fixture'); 718 | if ( main ) { 719 | config.fixture = main.innerHTML; 720 | } 721 | 722 | if (config.autostart) { 723 | QUnit.start(); 724 | } 725 | }); 726 | 727 | function done() { 728 | config.autorun = true; 729 | 730 | // Log the last module results 731 | if ( config.currentModule ) { 732 | QUnit.moduleDone( { 733 | name: config.currentModule, 734 | failed: config.moduleStats.bad, 735 | passed: config.moduleStats.all - config.moduleStats.bad, 736 | total: config.moduleStats.all 737 | } ); 738 | } 739 | 740 | var banner = id("qunit-banner"), 741 | tests = id("qunit-tests"), 742 | runtime = +new Date - config.started, 743 | passed = config.stats.all - config.stats.bad, 744 | html = [ 745 | 'Tests completed in ', 746 | runtime, 747 | ' milliseconds.
', 748 | '', 749 | passed, 750 | ' tests of ', 751 | config.stats.all, 752 | ' passed, ', 753 | config.stats.bad, 754 | ' failed.' 755 | ].join(''); 756 | 757 | if ( banner ) { 758 | banner.className = (config.stats.bad ? "qunit-fail" : "qunit-pass"); 759 | } 760 | 761 | if ( tests ) { 762 | id( "qunit-testresult" ).innerHTML = html; 763 | } 764 | 765 | QUnit.done( { 766 | failed: config.stats.bad, 767 | passed: passed, 768 | total: config.stats.all, 769 | runtime: runtime 770 | } ); 771 | } 772 | 773 | function validTest( name ) { 774 | var filter = config.filter, 775 | run = false; 776 | 777 | if ( !filter ) { 778 | return true; 779 | } 780 | 781 | not = filter.charAt( 0 ) === "!"; 782 | if ( not ) { 783 | filter = filter.slice( 1 ); 784 | } 785 | 786 | if ( name.indexOf( filter ) !== -1 ) { 787 | return !not; 788 | } 789 | 790 | if ( not ) { 791 | run = true; 792 | } 793 | 794 | return run; 795 | } 796 | 797 | // so far supports only Firefox, Chrome and Opera (buggy) 798 | // could be extended in the future to use something like https://github.com/csnover/TraceKit 799 | function sourceFromStacktrace() { 800 | try { 801 | throw new Error(); 802 | } catch ( e ) { 803 | if (e.stacktrace) { 804 | // Opera 805 | return e.stacktrace.split("\n")[6]; 806 | } else if (e.stack) { 807 | // Firefox, Chrome 808 | return e.stack.split("\n")[4]; 809 | } 810 | } 811 | } 812 | 813 | function escapeHtml(s) { 814 | if (!s) { 815 | return ""; 816 | } 817 | s = s + ""; 818 | return s.replace(/[\&"<>\\]/g, function(s) { 819 | switch(s) { 820 | case "&": return "&"; 821 | case "\\": return "\\\\"; 822 | case '"': return '\"'; 823 | case "<": return "<"; 824 | case ">": return ">"; 825 | default: return s; 826 | } 827 | }); 828 | } 829 | 830 | function synchronize( callback ) { 831 | config.queue.push( callback ); 832 | 833 | if ( config.autorun && !config.blocking ) { 834 | process(); 835 | } 836 | } 837 | 838 | function process() { 839 | var start = (new Date()).getTime(); 840 | 841 | while ( config.queue.length && !config.blocking ) { 842 | if ( config.updateRate <= 0 || (((new Date()).getTime() - start) < config.updateRate) ) { 843 | config.queue.shift()(); 844 | } else { 845 | window.setTimeout( process, 13 ); 846 | break; 847 | } 848 | } 849 | if (!config.blocking && !config.queue.length) { 850 | done(); 851 | } 852 | } 853 | 854 | function saveGlobal() { 855 | config.pollution = []; 856 | 857 | if ( config.noglobals ) { 858 | for ( var key in window ) { 859 | config.pollution.push( key ); 860 | } 861 | } 862 | } 863 | 864 | function checkPollution( name ) { 865 | var old = config.pollution; 866 | saveGlobal(); 867 | 868 | var newGlobals = diff( old, config.pollution ); 869 | if ( newGlobals.length > 0 ) { 870 | ok( false, "Introduced global variable(s): " + newGlobals.join(", ") ); 871 | config.current.expected++; 872 | } 873 | 874 | var deletedGlobals = diff( config.pollution, old ); 875 | if ( deletedGlobals.length > 0 ) { 876 | ok( false, "Deleted global variable(s): " + deletedGlobals.join(", ") ); 877 | config.current.expected++; 878 | } 879 | } 880 | 881 | // returns a new Array with the elements that are in a but not in b 882 | function diff( a, b ) { 883 | var result = a.slice(); 884 | for ( var i = 0; i < result.length; i++ ) { 885 | for ( var j = 0; j < b.length; j++ ) { 886 | if ( result[i] === b[j] ) { 887 | result.splice(i, 1); 888 | i--; 889 | break; 890 | } 891 | } 892 | } 893 | return result; 894 | } 895 | 896 | function fail(message, exception, callback) { 897 | if ( typeof console !== "undefined" && console.error && console.warn ) { 898 | console.error(message); 899 | console.error(exception); 900 | console.warn(callback.toString()); 901 | 902 | } else if ( window.opera && opera.postError ) { 903 | opera.postError(message, exception, callback.toString); 904 | } 905 | } 906 | 907 | function extend(a, b) { 908 | for ( var prop in b ) { 909 | if ( b[prop] === undefined ) { 910 | delete a[prop]; 911 | } else { 912 | a[prop] = b[prop]; 913 | } 914 | } 915 | 916 | return a; 917 | } 918 | 919 | function addEvent(elem, type, fn) { 920 | if ( elem.addEventListener ) { 921 | elem.addEventListener( type, fn, false ); 922 | } else if ( elem.attachEvent ) { 923 | elem.attachEvent( "on" + type, fn ); 924 | } else { 925 | fn(); 926 | } 927 | } 928 | 929 | function id(name) { 930 | return !!(typeof document !== "undefined" && document && document.getElementById) && 931 | document.getElementById( name ); 932 | } 933 | 934 | // Test for equality any JavaScript type. 935 | // Discussions and reference: http://philrathe.com/articles/equiv 936 | // Test suites: http://philrathe.com/tests/equiv 937 | // Author: Philippe Rathé 938 | QUnit.equiv = function () { 939 | 940 | var innerEquiv; // the real equiv function 941 | var callers = []; // stack to decide between skip/abort functions 942 | var parents = []; // stack to avoiding loops from circular referencing 943 | 944 | // Call the o related callback with the given arguments. 945 | function bindCallbacks(o, callbacks, args) { 946 | var prop = QUnit.objectType(o); 947 | if (prop) { 948 | if (QUnit.objectType(callbacks[prop]) === "function") { 949 | return callbacks[prop].apply(callbacks, args); 950 | } else { 951 | return callbacks[prop]; // or undefined 952 | } 953 | } 954 | } 955 | 956 | var callbacks = function () { 957 | 958 | // for string, boolean, number and null 959 | function useStrictEquality(b, a) { 960 | if (b instanceof a.constructor || a instanceof b.constructor) { 961 | // to catch short annotaion VS 'new' annotation of a declaration 962 | // e.g. var i = 1; 963 | // var j = new Number(1); 964 | return a == b; 965 | } else { 966 | return a === b; 967 | } 968 | } 969 | 970 | return { 971 | "string": useStrictEquality, 972 | "boolean": useStrictEquality, 973 | "number": useStrictEquality, 974 | "null": useStrictEquality, 975 | "undefined": useStrictEquality, 976 | 977 | "nan": function (b) { 978 | return isNaN(b); 979 | }, 980 | 981 | "date": function (b, a) { 982 | return QUnit.objectType(b) === "date" && a.valueOf() === b.valueOf(); 983 | }, 984 | 985 | "regexp": function (b, a) { 986 | return QUnit.objectType(b) === "regexp" && 987 | a.source === b.source && // the regex itself 988 | a.global === b.global && // and its modifers (gmi) ... 989 | a.ignoreCase === b.ignoreCase && 990 | a.multiline === b.multiline; 991 | }, 992 | 993 | // - skip when the property is a method of an instance (OOP) 994 | // - abort otherwise, 995 | // initial === would have catch identical references anyway 996 | "function": function () { 997 | var caller = callers[callers.length - 1]; 998 | return caller !== Object && 999 | typeof caller !== "undefined"; 1000 | }, 1001 | 1002 | "array": function (b, a) { 1003 | var i, j, loop; 1004 | var len; 1005 | 1006 | // b could be an object literal here 1007 | if ( ! (QUnit.objectType(b) === "array")) { 1008 | return false; 1009 | } 1010 | 1011 | len = a.length; 1012 | if (len !== b.length) { // safe and faster 1013 | return false; 1014 | } 1015 | 1016 | //track reference to avoid circular references 1017 | parents.push(a); 1018 | for (i = 0; i < len; i++) { 1019 | loop = false; 1020 | for(j=0;j= 0) { 1165 | type = "array"; 1166 | } else { 1167 | type = typeof obj; 1168 | } 1169 | return type; 1170 | }, 1171 | separator:function() { 1172 | return this.multiline ? this.HTML ? '
' : '\n' : this.HTML ? ' ' : ' '; 1173 | }, 1174 | indent:function( extra ) {// extra can be a number, shortcut for increasing-calling-decreasing 1175 | if ( !this.multiline ) 1176 | return ''; 1177 | var chr = this.indentChar; 1178 | if ( this.HTML ) 1179 | chr = chr.replace(/\t/g,' ').replace(/ /g,' '); 1180 | return Array( this._depth_ + (extra||0) ).join(chr); 1181 | }, 1182 | up:function( a ) { 1183 | this._depth_ += a || 1; 1184 | }, 1185 | down:function( a ) { 1186 | this._depth_ -= a || 1; 1187 | }, 1188 | setParser:function( name, parser ) { 1189 | this.parsers[name] = parser; 1190 | }, 1191 | // The next 3 are exposed so you can use them 1192 | quote:quote, 1193 | literal:literal, 1194 | join:join, 1195 | // 1196 | _depth_: 1, 1197 | // This is the list of parsers, to modify them, use jsDump.setParser 1198 | parsers:{ 1199 | window: '[Window]', 1200 | document: '[Document]', 1201 | error:'[ERROR]', //when no parser is found, shouldn't happen 1202 | unknown: '[Unknown]', 1203 | 'null':'null', 1204 | 'undefined':'undefined', 1205 | 'function':function( fn ) { 1206 | var ret = 'function', 1207 | name = 'name' in fn ? fn.name : (reName.exec(fn)||[])[1];//functions never have name in IE 1208 | if ( name ) 1209 | ret += ' ' + name; 1210 | ret += '('; 1211 | 1212 | ret = [ ret, QUnit.jsDump.parse( fn, 'functionArgs' ), '){'].join(''); 1213 | return join( ret, QUnit.jsDump.parse(fn,'functionCode'), '}' ); 1214 | }, 1215 | array: array, 1216 | nodelist: array, 1217 | arguments: array, 1218 | object:function( map ) { 1219 | var ret = [ ]; 1220 | QUnit.jsDump.up(); 1221 | for ( var key in map ) 1222 | ret.push( QUnit.jsDump.parse(key,'key') + ': ' + QUnit.jsDump.parse(map[key]) ); 1223 | QUnit.jsDump.down(); 1224 | return join( '{', ret, '}' ); 1225 | }, 1226 | node:function( node ) { 1227 | var open = QUnit.jsDump.HTML ? '<' : '<', 1228 | close = QUnit.jsDump.HTML ? '>' : '>'; 1229 | 1230 | var tag = node.nodeName.toLowerCase(), 1231 | ret = open + tag; 1232 | 1233 | for ( var a in QUnit.jsDump.DOMAttrs ) { 1234 | var val = node[QUnit.jsDump.DOMAttrs[a]]; 1235 | if ( val ) 1236 | ret += ' ' + a + '=' + QUnit.jsDump.parse( val, 'attribute' ); 1237 | } 1238 | return ret + close + open + '/' + tag + close; 1239 | }, 1240 | functionArgs:function( fn ) {//function calls it internally, it's the arguments part of the function 1241 | var l = fn.length; 1242 | if ( !l ) return ''; 1243 | 1244 | var args = Array(l); 1245 | while ( l-- ) 1246 | args[l] = String.fromCharCode(97+l);//97 is 'a' 1247 | return ' ' + args.join(', ') + ' '; 1248 | }, 1249 | key:quote, //object calls it internally, the key part of an item in a map 1250 | functionCode:'[code]', //function calls it internally, it's the content of the function 1251 | attribute:quote, //node calls it internally, it's an html attribute value 1252 | string:quote, 1253 | date:quote, 1254 | regexp:literal, //regex 1255 | number:literal, 1256 | 'boolean':literal 1257 | }, 1258 | DOMAttrs:{//attributes to dump from nodes, name=>realName 1259 | id:'id', 1260 | name:'name', 1261 | 'class':'className' 1262 | }, 1263 | HTML:false,//if true, entities are escaped ( <, >, \t, space and \n ) 1264 | indentChar:' ',//indentation unit 1265 | multiline:true //if true, items in a collection, are separated by a \n, else just a space. 1266 | }; 1267 | 1268 | return jsDump; 1269 | })(); 1270 | 1271 | // from Sizzle.js 1272 | function getText( elems ) { 1273 | var ret = "", elem; 1274 | 1275 | for ( var i = 0; elems[i]; i++ ) { 1276 | elem = elems[i]; 1277 | 1278 | // Get the text from text nodes and CDATA nodes 1279 | if ( elem.nodeType === 3 || elem.nodeType === 4 ) { 1280 | ret += elem.nodeValue; 1281 | 1282 | // Traverse everything else, except comment nodes 1283 | } else if ( elem.nodeType !== 8 ) { 1284 | ret += getText( elem.childNodes ); 1285 | } 1286 | } 1287 | 1288 | return ret; 1289 | }; 1290 | 1291 | /* 1292 | * Javascript Diff Algorithm 1293 | * By John Resig (http://ejohn.org/) 1294 | * Modified by Chu Alan "sprite" 1295 | * 1296 | * Released under the MIT license. 1297 | * 1298 | * More Info: 1299 | * http://ejohn.org/projects/javascript-diff-algorithm/ 1300 | * 1301 | * Usage: QUnit.diff(expected, actual) 1302 | * 1303 | * QUnit.diff("the quick brown fox jumped over", "the quick fox jumps over") == "the quick brown fox jumped jumps over" 1304 | */ 1305 | QUnit.diff = (function() { 1306 | function diff(o, n){ 1307 | var ns = new Object(); 1308 | var os = new Object(); 1309 | 1310 | for (var i = 0; i < n.length; i++) { 1311 | if (ns[n[i]] == null) 1312 | ns[n[i]] = { 1313 | rows: new Array(), 1314 | o: null 1315 | }; 1316 | ns[n[i]].rows.push(i); 1317 | } 1318 | 1319 | for (var i = 0; i < o.length; i++) { 1320 | if (os[o[i]] == null) 1321 | os[o[i]] = { 1322 | rows: new Array(), 1323 | n: null 1324 | }; 1325 | os[o[i]].rows.push(i); 1326 | } 1327 | 1328 | for (var i in ns) { 1329 | if (ns[i].rows.length == 1 && typeof(os[i]) != "undefined" && os[i].rows.length == 1) { 1330 | n[ns[i].rows[0]] = { 1331 | text: n[ns[i].rows[0]], 1332 | row: os[i].rows[0] 1333 | }; 1334 | o[os[i].rows[0]] = { 1335 | text: o[os[i].rows[0]], 1336 | row: ns[i].rows[0] 1337 | }; 1338 | } 1339 | } 1340 | 1341 | for (var i = 0; i < n.length - 1; i++) { 1342 | if (n[i].text != null && n[i + 1].text == null && n[i].row + 1 < o.length && o[n[i].row + 1].text == null && 1343 | n[i + 1] == o[n[i].row + 1]) { 1344 | n[i + 1] = { 1345 | text: n[i + 1], 1346 | row: n[i].row + 1 1347 | }; 1348 | o[n[i].row + 1] = { 1349 | text: o[n[i].row + 1], 1350 | row: i + 1 1351 | }; 1352 | } 1353 | } 1354 | 1355 | for (var i = n.length - 1; i > 0; i--) { 1356 | if (n[i].text != null && n[i - 1].text == null && n[i].row > 0 && o[n[i].row - 1].text == null && 1357 | n[i - 1] == o[n[i].row - 1]) { 1358 | n[i - 1] = { 1359 | text: n[i - 1], 1360 | row: n[i].row - 1 1361 | }; 1362 | o[n[i].row - 1] = { 1363 | text: o[n[i].row - 1], 1364 | row: i - 1 1365 | }; 1366 | } 1367 | } 1368 | 1369 | return { 1370 | o: o, 1371 | n: n 1372 | }; 1373 | } 1374 | 1375 | return function(o, n){ 1376 | o = o.replace(/\s+$/, ''); 1377 | n = n.replace(/\s+$/, ''); 1378 | var out = diff(o == "" ? [] : o.split(/\s+/), n == "" ? [] : n.split(/\s+/)); 1379 | 1380 | var str = ""; 1381 | 1382 | var oSpace = o.match(/\s+/g); 1383 | if (oSpace == null) { 1384 | oSpace = [" "]; 1385 | } 1386 | else { 1387 | oSpace.push(" "); 1388 | } 1389 | var nSpace = n.match(/\s+/g); 1390 | if (nSpace == null) { 1391 | nSpace = [" "]; 1392 | } 1393 | else { 1394 | nSpace.push(" "); 1395 | } 1396 | 1397 | if (out.n.length == 0) { 1398 | for (var i = 0; i < out.o.length; i++) { 1399 | str += '' + out.o[i] + oSpace[i] + ""; 1400 | } 1401 | } 1402 | else { 1403 | if (out.n[0].text == null) { 1404 | for (n = 0; n < out.o.length && out.o[n].text == null; n++) { 1405 | str += '' + out.o[n] + oSpace[n] + ""; 1406 | } 1407 | } 1408 | 1409 | for (var i = 0; i < out.n.length; i++) { 1410 | if (out.n[i].text == null) { 1411 | str += '' + out.n[i] + nSpace[i] + ""; 1412 | } 1413 | else { 1414 | var pre = ""; 1415 | 1416 | for (n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++) { 1417 | pre += '' + out.o[n] + oSpace[n] + ""; 1418 | } 1419 | str += " " + out.n[i].text + nSpace[i] + pre; 1420 | } 1421 | } 1422 | } 1423 | 1424 | return str; 1425 | }; 1426 | })(); 1427 | 1428 | })(this); 1429 | -------------------------------------------------------------------------------- /jquery.jsoncookie.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * jQuery JSON Cookie 3 | * 4 | * Copyright 2011 appendTo LLC. (http://appendto.com/team) 5 | * Dual licensed under the MIT or GPL licenses. 6 | * http://appendto.com/open-source-licenses 7 | * 8 | * http://github.com/appendto/jquery-jsoncookie 9 | */ 10 | (function( $ ) { 11 | 12 | var encode = encodeURIComponent, 13 | decode = decodeURIComponent; 14 | 15 | function now() { 16 | return (new Date()).getTime(); 17 | } 18 | 19 | $.cookie = function( key, value, options ) { 20 | options = $.extend( {}, options ); 21 | var expires = options.expires, 22 | result = value; 23 | 24 | // get all cookies 25 | if ( !key ) { 26 | result = {}; 27 | $.each( document.cookie.split( "; " ), function( i, cookie ) { 28 | if ( !cookie ) { 29 | return; 30 | } 31 | var parts = cookie.split( "=" ); 32 | result[ decode( parts[ 0 ] ) ] = JSON.parse( decode( parts[ 1 ] ) ); 33 | }); 34 | return result; 35 | } 36 | 37 | // get/set a specific cookie 38 | key = encode( key ); 39 | if ( value === undefined ) { 40 | result = new RegExp( "(?:^|; )" + key + "=([^;]*)" ).exec( document.cookie ); 41 | return result && JSON.parse( decode( result[ 1 ] ) ); 42 | } else { 43 | if ( value === null ) { 44 | expires = -1; 45 | } 46 | if ( typeof expires === "number" ) { 47 | expires = new Date( now() + expires ); 48 | } 49 | 50 | document.cookie = [ 51 | key, "=", encode( JSON.stringify( value ) ), 52 | expires ? "; expires=" + expires.toUTCString() : "", 53 | options.path ? "; path=" + options.path : "", 54 | options.domain ? "; domain=" + options.domain : "", 55 | options.secure ? "; secure" : "" 56 | ].join( "" ); 57 | } 58 | 59 | return result; 60 | }; 61 | 62 | // support test 63 | if ( $.support ) { 64 | (function() { 65 | var test = "jsoncookie" + now(); 66 | $.cookie( test, test ); 67 | $.support.cookie = $.cookie( test ) === test; 68 | $.cookie( test, null ); 69 | }() ); 70 | } 71 | 72 | }( jQuery ) ); 73 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # jQuery JSON Cookie 2 | 3 | Cookies are the most widely available form of persistent client-side storage. 4 | Unfortunately there's no built-in support for storing structured data inside of one. 5 | That's where the jsoncookie plugin comes in; 6 | this plugin allows you to store any data that can be represented via JSON. 7 | This means that you can store objects, arrays, strings, numbers, and booleans 8 | and get the data back exactly as you expect. 9 | (Standard cookie size limitations of 4K still exist) 10 | 11 | ## Usage 12 | 13 | $.cookie( string key, mixed value [, hash options ] ) 14 | 15 | Stores a value for a given key. 16 | 17 | * `key`: Identifier for the value being stored. 18 | * `value`: The value to store. The value can be anything that can be serialized as JSON. 19 | * [`options`]: A set of key/value pairs that relate to settings for storing the value (see Options section below). 20 | 21 |   22 | 23 | $.cookie( string key ) 24 | 25 | Gets a stored value based on the key. 26 | 27 | $.cookie() 28 | 29 | Gets a hash of all stored values. 30 | 31 | ### Options 32 | 33 | * `expires` Duration in milliseconds that the cookie should exist. 34 | * `domain` Limit which pages can access the cookie based on the (sub)domain. Defaults to the current domain. 35 | * `path` Limit which pages can access the cookie based on the path. Defaulst to the current path. 36 | * `secure` Boolean. Whether to limit the cookie to only be sent over secure connections. 37 | 38 | --- 39 | 40 | This plugin requires the [JSON object](https://developer.mozilla.org/En/Using_native_JSON) to exist. For support in older browsers, you'll need to include [json2.js](https://github.com/douglascrockford/JSON-js). 41 | 42 | For more information on cookies, see the [MDN documentation](https://developer.mozilla.org/en/document.cookie). 43 | 44 | Chrome doesn't support cookies for local files unless you start it with the --enable-file-cookies flag. -------------------------------------------------------------------------------- /test/jquery.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 3 | var parts = document.location.search.slice( 1 ).split( "&" ), 4 | length = parts.length, 5 | i = 0, 6 | current, 7 | version, 8 | url; 9 | 10 | for ( ; i < length; i++ ) { 11 | current = parts[ i ].split( "=" ); 12 | if ( current[ 0 ] === "jquery" ) { 13 | version = current[ 1 ]; 14 | break; 15 | } 16 | } 17 | 18 | if ( version === "git" ) { 19 | url = "http://code.jquery.com/jquery-git.js"; 20 | } else { 21 | url = "../external/jquery-" + ( version || "1.6.1" ) + ".js"; 22 | } 23 | 24 | document.write( "" ); 25 | 26 | }() ); 27 | -------------------------------------------------------------------------------- /test/test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | jQuery JSON Cookie Test Suite 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |

jQuery JSON Cookie Test Suite

15 |

16 |
17 |

18 |
    19 | 20 | 21 | -------------------------------------------------------------------------------- /test/unit.js: -------------------------------------------------------------------------------- 1 | var lifecycle = { 2 | setup: function() { 3 | var expires = new Date( 0 ).toUTCString(); 4 | $.each( document.cookie.split( "; " ), function( i, cookie ) { 5 | if ( !cookie ) { 6 | return; 7 | } 8 | var key = cookie.split( "=" )[ 0 ]; 9 | document.cookie = key + "=; expires=" + expires; 10 | }); 11 | } 12 | }; 13 | 14 | module( "cookie", lifecycle ); 15 | 16 | test( "miss", function() { 17 | expect( 1 ); 18 | equal( $.cookie( "test" ), null ); 19 | }); 20 | 21 | test( "string", function() { 22 | expect( 2 ); 23 | $.cookie( "test", "hello" ); 24 | equal( document.cookie, "test=%22hello%22", "stored" ) 25 | strictEqual( $.cookie( "test" ), "hello", "retrieved" ); 26 | }); 27 | 28 | test( "number", function() { 29 | expect( 2 ); 30 | $.cookie( "test", 5 ); 31 | equal( document.cookie, "test=5", "stored" ) 32 | strictEqual( $.cookie( "test" ), 5, "retrieved" ); 33 | }); 34 | 35 | test( "boolean", function() { 36 | expect( 2 ); 37 | $.cookie( "test", true ); 38 | equal( document.cookie, "test=true", "stored" ) 39 | strictEqual( $.cookie( "test" ), true, "retrieved" ); 40 | }); 41 | 42 | test( "array", function() { 43 | expect( 2 ); 44 | $.cookie( "test", [ "a", 2 ] ); 45 | equal( document.cookie, "test=%5B%22a%22%2C2%5D", "stored" ) 46 | deepEqual( $.cookie( "test" ), [ "a", 2 ], "retrieved" ); 47 | }); 48 | 49 | test( "object", function() { 50 | expect( 2 ); 51 | $.cookie( "test", { it: "works" } ); 52 | equal( document.cookie, "test=%7B%22it%22%3A%22works%22%7D", "stored" ) 53 | deepEqual( $.cookie( "test" ), { it: "works" }, "retrieved" ); 54 | }); 55 | 56 | test( "delete", function() { 57 | expect( 2 ); 58 | $.cookie( "test", "val" ); 59 | equal( $.cookie( "test" ), "val", "stored" ); 60 | $.cookie( "test", null ); 61 | equal( $.cookie( "test" ), null, "cleared" ); 62 | }); 63 | 64 | test( "get all", function() { 65 | expect( 1 ); 66 | $.cookie( "foo", "bar" ); 67 | $.cookie( "baz", [ "qux" ] ); 68 | deepEqual( $.cookie(), { 69 | foo: "bar", 70 | baz: [ "qux" ] 71 | }); 72 | }); 73 | --------------------------------------------------------------------------------