Codebase list node-ast-types / aa41062
Imported Upstream version 0.8.13 Julien Puydt 8 years ago
26 changed file(s) with 17813 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
0 node_modules
0 /node_modules
1 /test
0 language: node_js
1 node_js:
2 - "4.0"
3 - "iojs"
4 - "0.12"
5 - "0.11"
6 - "0.10"
7 - "0.8"
8 - "0.6"
9
10 sudo: false
11
12 before_install:
13 npm install -g npm@'>=1.4.3'
14
15 matrix:
16 allow_failures:
17 - node_js: "0.8"
18 - node_js: "0.6"
0 Copyright (c) 2013 Ben Newman <bn@cs.stanford.edu>
1
2 Permission is hereby granted, free of charge, to any person obtaining
3 a copy of this software and associated documentation files (the
4 "Software"), to deal in the Software without restriction, including
5 without limitation the rights to use, copy, modify, merge, publish,
6 distribute, sublicense, and/or sell copies of the Software, and to
7 permit persons to whom the Software is furnished to do so, subject to
8 the following conditions:
9
10 The above copyright notice and this permission notice shall be
11 included in all copies or substantial portions of the Software.
12
13 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
14 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
15 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
16 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
17 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
18 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
19 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
0 AST Types
1 ===
2
3 This module provides an efficient, modular,
4 [Esprima](https://github.com/ariya/esprima)-compatible implementation of
5 the [abstract syntax
6 tree](http://en.wikipedia.org/wiki/Abstract_syntax_tree) type hierarchy
7 pioneered by the [Mozilla Parser
8 API](https://developer.mozilla.org/en-US/docs/SpiderMonkey/Parser_API).
9
10 [![Build Status](https://travis-ci.org/benjamn/ast-types.png?branch=master)](https://travis-ci.org/benjamn/ast-types)
11
12 Installation
13 ---
14
15 From NPM:
16
17 npm install ast-types
18
19 From GitHub:
20
21 cd path/to/node_modules
22 git clone git://github.com/benjamn/ast-types.git
23 cd ast-types
24 npm install .
25
26 Basic Usage
27 ---
28 ```js
29 var assert = require("assert");
30 var n = require("ast-types").namedTypes;
31 var b = require("ast-types").builders;
32
33 var fooId = b.identifier("foo");
34 var ifFoo = b.ifStatement(fooId, b.blockStatement([
35 b.expressionStatement(b.callExpression(fooId, []))
36 ]));
37
38 assert.ok(n.IfStatement.check(ifFoo));
39 assert.ok(n.Statement.check(ifFoo));
40 assert.ok(n.Node.check(ifFoo));
41
42 assert.ok(n.BlockStatement.check(ifFoo.consequent));
43 assert.strictEqual(
44 ifFoo.consequent.body[0].expression.arguments.length,
45 0);
46
47 assert.strictEqual(ifFoo.test, fooId);
48 assert.ok(n.Expression.check(ifFoo.test));
49 assert.ok(n.Identifier.check(ifFoo.test));
50 assert.ok(!n.Statement.check(ifFoo.test));
51 ```
52
53 AST Traversal
54 ---
55
56 Because it understands the AST type system so thoroughly, this library
57 is able to provide excellent node iteration and traversal mechanisms.
58
59 If you want complete control over the traversal, and all you need is a way
60 of enumerating the known fields of your AST nodes and getting their
61 values, you may be interested in the primitives `getFieldNames` and
62 `getFieldValue`:
63 ```js
64 var types = require("ast-types");
65 var partialFunExpr = { type: "FunctionExpression" };
66
67 // Even though partialFunExpr doesn't actually contain all the fields that
68 // are expected for a FunctionExpression, types.getFieldNames knows:
69 console.log(types.getFieldNames(partialFunExpr));
70 // [ 'type', 'id', 'params', 'body', 'generator', 'expression',
71 // 'defaults', 'rest', 'async' ]
72
73 // For fields that have default values, types.getFieldValue will return
74 // the default if the field is not actually defined.
75 console.log(types.getFieldValue(partialFunExpr, "generator"));
76 // false
77 ```
78
79 Two more low-level helper functions, `eachField` and `someField`, are
80 defined in terms of `getFieldNames` and `getFieldValue`:
81 ```js
82 // Iterate over all defined fields of an object, including those missing
83 // or undefined, passing each field name and effective value (as returned
84 // by getFieldValue) to the callback. If the object has no corresponding
85 // Def, the callback will never be called.
86 exports.eachField = function(object, callback, context) {
87 getFieldNames(object).forEach(function(name) {
88 callback.call(this, name, getFieldValue(object, name));
89 }, context);
90 };
91
92 // Similar to eachField, except that iteration stops as soon as the
93 // callback returns a truthy value. Like Array.prototype.some, the final
94 // result is either true or false to indicates whether the callback
95 // returned true for any element or not.
96 exports.someField = function(object, callback, context) {
97 return getFieldNames(object).some(function(name) {
98 return callback.call(this, name, getFieldValue(object, name));
99 }, context);
100 };
101 ```
102
103 So here's how you might make a copy of an AST node:
104 ```js
105 var copy = {};
106 require("ast-types").eachField(node, function(name, value) {
107 // Note that undefined fields will be visited too, according to
108 // the rules associated with node.type, and default field values
109 // will be substituted if appropriate.
110 copy[name] = value;
111 })
112 ```
113
114 But that's not all! You can also easily visit entire syntax trees using
115 the powerful `types.visit` abstraction.
116
117 Here's a trivial example of how you might assert that `arguments.callee`
118 is never used in `ast`:
119 ```js
120 var assert = require("assert");
121 var types = require("ast-types");
122 var n = types.namedTypes;
123
124 types.visit(ast, {
125 // This method will be called for any node with .type "MemberExpression":
126 visitMemberExpression: function(path) {
127 // Visitor methods receive a single argument, a NodePath object
128 // wrapping the node of interest.
129 var node = path.node;
130
131 if (n.Identifier.check(node.object) &&
132 node.object.name === "arguments" &&
133 n.Identifier.check(node.property)) {
134 assert.notStrictEqual(node.property.name, "callee");
135 }
136
137 // It's your responsibility to call this.traverse with some
138 // NodePath object (usually the one passed into the visitor
139 // method) before the visitor method returns, or return false to
140 // indicate that the traversal need not continue any further down
141 // this subtree.
142 this.traverse(path);
143 }
144 });
145 ```
146
147 Here's a slightly more involved example of transforming `...rest`
148 parameters into browser-runnable ES5 JavaScript:
149
150 ```js
151 var b = types.builders;
152
153 // Reuse the same AST structure for Array.prototype.slice.call.
154 var sliceExpr = b.memberExpression(
155 b.memberExpression(
156 b.memberExpression(
157 b.identifier("Array"),
158 b.identifier("prototype"),
159 false
160 ),
161 b.identifier("slice"),
162 false
163 ),
164 b.identifier("call"),
165 false
166 );
167
168 types.visit(ast, {
169 // This method will be called for any node whose type is a subtype of
170 // Function (e.g., FunctionDeclaration, FunctionExpression, and
171 // ArrowFunctionExpression). Note that types.visit precomputes a
172 // lookup table from every known type to the appropriate visitor
173 // method to call for nodes of that type, so the dispatch takes
174 // constant time.
175 visitFunction: function(path) {
176 // Visitor methods receive a single argument, a NodePath object
177 // wrapping the node of interest.
178 var node = path.node;
179
180 // It's your responsibility to call this.traverse with some
181 // NodePath object (usually the one passed into the visitor
182 // method) before the visitor method returns, or return false to
183 // indicate that the traversal need not continue any further down
184 // this subtree. An assertion will fail if you forget, which is
185 // awesome, because it means you will never again make the
186 // disastrous mistake of forgetting to traverse a subtree. Also
187 // cool: because you can call this method at any point in the
188 // visitor method, it's up to you whether your traversal is
189 // pre-order, post-order, or both!
190 this.traverse(path);
191
192 // This traversal is only concerned with Function nodes that have
193 // rest parameters.
194 if (!node.rest) {
195 return;
196 }
197
198 // For the purposes of this example, we won't worry about functions
199 // with Expression bodies.
200 n.BlockStatement.assert(node.body);
201
202 // Use types.builders to build a variable declaration of the form
203 //
204 // var rest = Array.prototype.slice.call(arguments, n);
205 //
206 // where `rest` is the name of the rest parameter, and `n` is a
207 // numeric literal specifying the number of named parameters the
208 // function takes.
209 var restVarDecl = b.variableDeclaration("var", [
210 b.variableDeclarator(
211 node.rest,
212 b.callExpression(sliceExpr, [
213 b.identifier("arguments"),
214 b.literal(node.params.length)
215 ])
216 )
217 ]);
218
219 // Similar to doing node.body.body.unshift(restVarDecl), except
220 // that the other NodePath objects wrapping body statements will
221 // have their indexes updated to accommodate the new statement.
222 path.get("body", "body").unshift(restVarDecl);
223
224 // Nullify node.rest now that we have simulated the behavior of
225 // the rest parameter using ordinary JavaScript.
226 path.get("rest").replace(null);
227
228 // There's nothing wrong with doing node.rest = null, but I wanted
229 // to point out that the above statement has the same effect.
230 assert.strictEqual(node.rest, null);
231 }
232 });
233 ```
234
235 Here's how you might use `types.visit` to implement a function that
236 determines if a given function node refers to `this`:
237
238 ```js
239 function usesThis(funcNode) {
240 n.Function.assert(funcNode);
241 var result = false;
242
243 types.visit(funcNode, {
244 visitThisExpression: function(path) {
245 result = true;
246
247 // The quickest way to terminate the traversal is to call
248 // this.abort(), which throws a special exception (instanceof
249 // this.AbortRequest) that will be caught in the top-level
250 // types.visit method, so you don't have to worry about
251 // catching the exception yourself.
252 this.abort();
253 },
254
255 visitFunction: function(path) {
256 // ThisExpression nodes in nested scopes don't count as `this`
257 // references for the original function node, so we can safely
258 // avoid traversing this subtree.
259 return false;
260 },
261
262 visitCallExpression: function(path) {
263 var node = path.node;
264
265 // If the function contains CallExpression nodes involving
266 // super, those expressions will implicitly depend on the
267 // value of `this`, even though they do not explicitly contain
268 // any ThisExpression nodes.
269 if (this.isSuperCallExpression(node)) {
270 result = true;
271 this.abort(); // Throws AbortRequest exception.
272 }
273
274 this.traverse(path);
275 },
276
277 // Yes, you can define arbitrary helper methods.
278 isSuperCallExpression: function(callExpr) {
279 n.CallExpression.assert(callExpr);
280 return this.isSuperIdentifier(callExpr.callee)
281 || this.isSuperMemberExpression(callExpr.callee);
282 },
283
284 // And even helper helper methods!
285 isSuperIdentifier: function(node) {
286 return n.Identifier.check(node.callee)
287 && node.callee.name === "super";
288 },
289
290 isSuperMemberExpression: function(node) {
291 return n.MemberExpression.check(node.callee)
292 && n.Identifier.check(node.callee.object)
293 && node.callee.object.name === "super";
294 }
295 });
296
297 return result;
298 }
299 ```
300
301 As you might guess, when an `AbortRequest` is thrown from a subtree, the
302 exception will propagate from the corresponding calls to `this.traverse`
303 in the ancestor visitor methods. If you decide you want to cancel the
304 request, simply catch the exception and call its `.cancel()` method. The
305 rest of the subtree beneath the `try`-`catch` block will be abandoned, but
306 the remaining siblings of the ancestor node will still be visited.
307
308 NodePath
309 ---
310
311 The `NodePath` object passed to visitor methods is a wrapper around an AST
312 node, and it serves to provide access to the chain of ancestor objects
313 (all the way back to the root of the AST) and scope information.
314
315 In general, `path.node` refers to the wrapped node, `path.parent.node`
316 refers to the nearest `Node` ancestor, `path.parent.parent.node` to the
317 grandparent, and so on.
318
319 Note that `path.node` may not be a direct property value of
320 `path.parent.node`; for instance, it might be the case that `path.node` is
321 an element of an array that is a direct child of the parent node:
322 ```js
323 path.node === path.parent.node.elements[3]
324 ```
325 in which case you should know that `path.parentPath` provides
326 finer-grained access to the complete path of objects (not just the `Node`
327 ones) from the root of the AST:
328 ```js
329 // In reality, path.parent is the grandparent of path:
330 path.parentPath.parentPath === path.parent
331
332 // The path.parentPath object wraps the elements array (note that we use
333 // .value because the elements array is not a Node):
334 path.parentPath.value === path.parent.node.elements
335
336 // The path.node object is the fourth element in that array:
337 path.parentPath.value[3] === path.node
338
339 // Unlike path.node and path.value, which are synonyms because path.node
340 // is a Node object, path.parentPath.node is distinct from
341 // path.parentPath.value, because the elements array is not a
342 // Node. Instead, path.parentPath.node refers to the closest ancestor
343 // Node, which happens to be the same as path.parent.node:
344 path.parentPath.node === path.parent.node
345
346 // The path is named for its index in the elements array:
347 path.name === 3
348
349 // Likewise, path.parentPath is named for the property by which
350 // path.parent.node refers to it:
351 path.parentPath.name === "elements"
352
353 // Putting it all together, we can follow the chain of object references
354 // from path.parent.node all the way to path.node by accessing each
355 // property by name:
356 path.parent.node[path.parentPath.name][path.name] === path.node
357 ```
358
359 These `NodePath` objects are created during the traversal without
360 modifying the AST nodes themselves, so it's not a problem if the same node
361 appears more than once in the AST (like `Array.prototype.slice.call` in
362 the example above), because it will be visited with a distict `NodePath`
363 each time it appears.
364
365 Child `NodePath` objects are created lazily, by calling the `.get` method
366 of a parent `NodePath` object:
367 ```js
368 // If a NodePath object for the elements array has never been created
369 // before, it will be created here and cached in the future:
370 path.get("elements").get(3).value === path.value.elements[3]
371
372 // Alternatively, you can pass multiple property names to .get instead of
373 // chaining multiple .get calls:
374 path.get("elements", 0).value === path.value.elements[0]
375 ```
376
377 `NodePath` objects support a number of useful methods:
378 ```js
379 // Replace one node with another node:
380 var fifth = path.get("elements", 4);
381 fifth.replace(newNode);
382
383 // Now do some stuff that might rearrange the list, and this replacement
384 // remains safe:
385 fifth.replace(newerNode);
386
387 // Replace the third element in an array with two new nodes:
388 path.get("elements", 2).replace(
389 b.identifier("foo"),
390 b.thisExpression()
391 );
392
393 // Remove a node and its parent if it would leave a redundant AST node:
394 //e.g. var t = 1, y =2; removing the `t` and `y` declarators results in `var undefined`.
395 path.prune(); //returns the closest parent `NodePath`.
396
397 // Remove a node from a list of nodes:
398 path.get("elements", 3).replace();
399
400 // Add three new nodes to the beginning of a list of nodes:
401 path.get("elements").unshift(a, b, c);
402
403 // Remove and return the first node in a list of nodes:
404 path.get("elements").shift();
405
406 // Push two new nodes onto the end of a list of nodes:
407 path.get("elements").push(d, e);
408
409 // Remove and return the last node in a list of nodes:
410 path.get("elements").pop();
411
412 // Insert a new node before/after the seventh node in a list of nodes:
413 var seventh = path.get("elements", 6);
414 seventh.insertBefore(newNode);
415 seventh.insertAfter(newNode);
416
417 // Insert a new element at index 5 in a list of nodes:
418 path.get("elements").insertAt(5, newNode);
419 ```
420
421 Scope
422 ---
423
424 The object exposed as `path.scope` during AST traversals provides
425 information about variable and function declarations in the scope that
426 contains `path.node`. See [scope.js](lib/scope.js) for its public
427 interface, which currently includes `.isGlobal`, `.getGlobalScope()`,
428 `.depth`, `.declares(name)`, `.lookup(name)`, and `.getBindings()`.
429
430 Custom AST Node Types
431 ---
432
433 The `ast-types` module was designed to be extended. To that end, it
434 provides a readable, declarative syntax for specifying new AST node types,
435 based primarily upon the `require("ast-types").Type.def` function:
436 ```js
437 var types = require("ast-types");
438 var def = types.Type.def;
439 var string = types.builtInTypes.string;
440 var b = types.builders;
441
442 // Suppose you need a named File type to wrap your Programs.
443 def("File")
444 .bases("Node")
445 .build("name", "program")
446 .field("name", string)
447 .field("program", def("Program"));
448
449 // Prevent further modifications to the File type (and any other
450 // types newly introduced by def(...)).
451 types.finalize();
452
453 // The b.file builder function is now available. It expects two
454 // arguments, as named by .build("name", "program") above.
455 var main = b.file("main.js", b.program([
456 // Pointless program contents included for extra color.
457 b.functionDeclaration(b.identifier("succ"), [
458 b.identifier("x")
459 ], b.blockStatement([
460 b.returnStatement(
461 b.binaryExpression(
462 "+", b.identifier("x"), b.literal(1)
463 )
464 )
465 ]))
466 ]));
467
468 assert.strictEqual(main.name, "main.js");
469 assert.strictEqual(main.program.body[0].params[0].name, "x");
470 // etc.
471
472 // If you pass the wrong type of arguments, or fail to pass enough
473 // arguments, an AssertionError will be thrown.
474
475 b.file(b.blockStatement([]));
476 // ==> AssertionError: {"body":[],"type":"BlockStatement","loc":null} does not match type string
477
478 b.file("lib/types.js", b.thisExpression());
479 // ==> AssertionError: {"type":"ThisExpression","loc":null} does not match type Program
480 ```
481 The `def` syntax is used to define all the default AST node types found in
482 [core.js](def/core.js),
483 [es6.js](def/es6.js),
484 [mozilla.js](def/mozilla.js),
485 [e4x.js](def/e4x.js), and
486 [fb-harmony.js](def/fb-harmony.js), so you have
487 no shortage of examples to learn from.
0 require("./es7");
1
2 var types = require("../lib/types");
3 var defaults = require("../lib/shared").defaults;
4 var def = types.Type.def;
5 var or = types.Type.or;
6
7 def("Noop")
8 .bases("Node")
9 .build();
10
11 def("DoExpression")
12 .bases("Expression")
13 .build("body")
14 .field("body", [def("Statement")]);
15
16 def("Super")
17 .bases("Expression")
18 .build();
19
20 def("BindExpression")
21 .bases("Expression")
22 .build("object", "callee")
23 .field("object", or(def("Expression"), null))
24 .field("callee", def("Expression"));
25
26 def("Decorator")
27 .bases("Node")
28 .build("expression")
29 .field("expression", def("Expression"));
30
31 def("Property")
32 .field("decorators",
33 or([def("Decorator")], null),
34 defaults["null"]);
35
36 def("MethodDefinition")
37 .field("decorators",
38 or([def("Decorator")], null),
39 defaults["null"]);
40
41 def("MetaProperty")
42 .bases("Expression")
43 .build("meta", "property")
44 .field("meta", def("Identifier"))
45 .field("property", def("Identifier"));
46
47 def("ParenthesizedExpression")
48 .bases("Expression")
49 .build("expression")
50 .field("expression", def("Expression"));
51
52 def("ImportSpecifier")
53 .bases("ModuleSpecifier")
54 .build("imported", "local")
55 .field("imported", def("Identifier"));
56
57 def("ImportDefaultSpecifier")
58 .bases("ModuleSpecifier")
59 .build("local");
60
61 def("ImportNamespaceSpecifier")
62 .bases("ModuleSpecifier")
63 .build("local");
64
65 def("ExportDefaultDeclaration")
66 .bases("Declaration")
67 .build("declaration")
68 .field("declaration", or(def("Declaration"), def("Expression")));
69
70 def("ExportNamedDeclaration")
71 .bases("Declaration")
72 .build("declaration", "specifiers", "source")
73 .field("declaration", or(def("Declaration"), null))
74 .field("specifiers", [def("ExportSpecifier")], defaults.emptyArray)
75 .field("source", or(def("Literal"), null), defaults["null"]);
76
77 def("ExportSpecifier")
78 .bases("ModuleSpecifier")
79 .build("local", "exported")
80 .field("exported", def("Identifier"));
81
82 def("ExportNamespaceSpecifier")
83 .bases("Specifier")
84 .build("exported")
85 .field("exported", def("Identifier"));
86
87 def("ExportDefaultSpecifier")
88 .bases("Specifier")
89 .build("exported")
90 .field("exported", def("Identifier"));
91
92 def("ExportAllDeclaration")
93 .bases("Declaration")
94 .build("exported", "source")
95 .field("exported", or(def("Identifier"), null))
96 .field("source", def("Literal"));
97
98 def("CommentBlock")
99 .bases("Comment")
100 .build("value", /*optional:*/ "leading", "trailing");
101
102 def("CommentLine")
103 .bases("Comment")
104 .build("value", /*optional:*/ "leading", "trailing");
0 var types = require("../lib/types");
1 var Type = types.Type;
2 var def = Type.def;
3 var or = Type.or;
4 var shared = require("../lib/shared");
5 var defaults = shared.defaults;
6 var geq = shared.geq;
7
8 // Abstract supertype of all syntactic entities that are allowed to have a
9 // .loc field.
10 def("Printable")
11 .field("loc", or(
12 def("SourceLocation"),
13 null
14 ), defaults["null"], true);
15
16 def("Node")
17 .bases("Printable")
18 .field("type", String)
19 .field("comments", or(
20 [def("Comment")],
21 null
22 ), defaults["null"], true);
23
24 def("SourceLocation")
25 .build("start", "end", "source")
26 .field("start", def("Position"))
27 .field("end", def("Position"))
28 .field("source", or(String, null), defaults["null"]);
29
30 def("Position")
31 .build("line", "column")
32 .field("line", geq(1))
33 .field("column", geq(0));
34
35 def("File")
36 .bases("Node")
37 .build("program")
38 .field("program", def("Program"));
39
40 def("Program")
41 .bases("Node")
42 .build("body")
43 .field("body", [def("Statement")]);
44
45 def("Function")
46 .bases("Node")
47 .field("id", or(def("Identifier"), null), defaults["null"])
48 .field("params", [def("Pattern")])
49 .field("body", def("BlockStatement"));
50
51 def("Statement").bases("Node");
52
53 // The empty .build() here means that an EmptyStatement can be constructed
54 // (i.e. it's not abstract) but that it needs no arguments.
55 def("EmptyStatement").bases("Statement").build();
56
57 def("BlockStatement")
58 .bases("Statement")
59 .build("body")
60 .field("body", [def("Statement")]);
61
62 // TODO Figure out how to silently coerce Expressions to
63 // ExpressionStatements where a Statement was expected.
64 def("ExpressionStatement")
65 .bases("Statement")
66 .build("expression")
67 .field("expression", def("Expression"));
68
69 def("IfStatement")
70 .bases("Statement")
71 .build("test", "consequent", "alternate")
72 .field("test", def("Expression"))
73 .field("consequent", def("Statement"))
74 .field("alternate", or(def("Statement"), null), defaults["null"]);
75
76 def("LabeledStatement")
77 .bases("Statement")
78 .build("label", "body")
79 .field("label", def("Identifier"))
80 .field("body", def("Statement"));
81
82 def("BreakStatement")
83 .bases("Statement")
84 .build("label")
85 .field("label", or(def("Identifier"), null), defaults["null"]);
86
87 def("ContinueStatement")
88 .bases("Statement")
89 .build("label")
90 .field("label", or(def("Identifier"), null), defaults["null"]);
91
92 def("WithStatement")
93 .bases("Statement")
94 .build("object", "body")
95 .field("object", def("Expression"))
96 .field("body", def("Statement"));
97
98 def("SwitchStatement")
99 .bases("Statement")
100 .build("discriminant", "cases", "lexical")
101 .field("discriminant", def("Expression"))
102 .field("cases", [def("SwitchCase")])
103 .field("lexical", Boolean, defaults["false"]);
104
105 def("ReturnStatement")
106 .bases("Statement")
107 .build("argument")
108 .field("argument", or(def("Expression"), null));
109
110 def("ThrowStatement")
111 .bases("Statement")
112 .build("argument")
113 .field("argument", def("Expression"));
114
115 def("TryStatement")
116 .bases("Statement")
117 .build("block", "handler", "finalizer")
118 .field("block", def("BlockStatement"))
119 .field("handler", or(def("CatchClause"), null), function() {
120 return this.handlers && this.handlers[0] || null;
121 })
122 .field("handlers", [def("CatchClause")], function() {
123 return this.handler ? [this.handler] : [];
124 }, true) // Indicates this field is hidden from eachField iteration.
125 .field("guardedHandlers", [def("CatchClause")], defaults.emptyArray)
126 .field("finalizer", or(def("BlockStatement"), null), defaults["null"]);
127
128 def("CatchClause")
129 .bases("Node")
130 .build("param", "guard", "body")
131 .field("param", def("Pattern"))
132 .field("guard", or(def("Expression"), null), defaults["null"])
133 .field("body", def("BlockStatement"));
134
135 def("WhileStatement")
136 .bases("Statement")
137 .build("test", "body")
138 .field("test", def("Expression"))
139 .field("body", def("Statement"));
140
141 def("DoWhileStatement")
142 .bases("Statement")
143 .build("body", "test")
144 .field("body", def("Statement"))
145 .field("test", def("Expression"));
146
147 def("ForStatement")
148 .bases("Statement")
149 .build("init", "test", "update", "body")
150 .field("init", or(
151 def("VariableDeclaration"),
152 def("Expression"),
153 null))
154 .field("test", or(def("Expression"), null))
155 .field("update", or(def("Expression"), null))
156 .field("body", def("Statement"));
157
158 def("ForInStatement")
159 .bases("Statement")
160 .build("left", "right", "body")
161 .field("left", or(
162 def("VariableDeclaration"),
163 def("Expression")))
164 .field("right", def("Expression"))
165 .field("body", def("Statement"));
166
167 def("DebuggerStatement").bases("Statement").build();
168
169 def("Declaration").bases("Statement");
170
171 def("FunctionDeclaration")
172 .bases("Function", "Declaration")
173 .build("id", "params", "body")
174 .field("id", def("Identifier"));
175
176 def("FunctionExpression")
177 .bases("Function", "Expression")
178 .build("id", "params", "body");
179
180 def("VariableDeclaration")
181 .bases("Declaration")
182 .build("kind", "declarations")
183 .field("kind", or("var", "let", "const"))
184 .field("declarations", [def("VariableDeclarator")]);
185
186 def("VariableDeclarator")
187 .bases("Node")
188 .build("id", "init")
189 .field("id", def("Pattern"))
190 .field("init", or(def("Expression"), null));
191
192 // TODO Are all Expressions really Patterns?
193 def("Expression").bases("Node", "Pattern");
194
195 def("ThisExpression").bases("Expression").build();
196
197 def("ArrayExpression")
198 .bases("Expression")
199 .build("elements")
200 .field("elements", [or(def("Expression"), null)]);
201
202 def("ObjectExpression")
203 .bases("Expression")
204 .build("properties")
205 .field("properties", [def("Property")]);
206
207 // TODO Not in the Mozilla Parser API, but used by Esprima.
208 def("Property")
209 .bases("Node") // Want to be able to visit Property Nodes.
210 .build("kind", "key", "value")
211 .field("kind", or("init", "get", "set"))
212 .field("key", or(def("Literal"), def("Identifier")))
213 .field("value", def("Expression"));
214
215 def("SequenceExpression")
216 .bases("Expression")
217 .build("expressions")
218 .field("expressions", [def("Expression")]);
219
220 var UnaryOperator = or(
221 "-", "+", "!", "~",
222 "typeof", "void", "delete");
223
224 def("UnaryExpression")
225 .bases("Expression")
226 .build("operator", "argument", "prefix")
227 .field("operator", UnaryOperator)
228 .field("argument", def("Expression"))
229 // Esprima doesn't bother with this field, presumably because it's
230 // always true for unary operators.
231 .field("prefix", Boolean, defaults["true"]);
232
233 var BinaryOperator = or(
234 "==", "!=", "===", "!==",
235 "<", "<=", ">", ">=",
236 "<<", ">>", ">>>",
237 "+", "-", "*", "/", "%",
238 "&", // TODO Missing from the Parser API.
239 "|", "^", "in",
240 "instanceof", "..");
241
242 def("BinaryExpression")
243 .bases("Expression")
244 .build("operator", "left", "right")
245 .field("operator", BinaryOperator)
246 .field("left", def("Expression"))
247 .field("right", def("Expression"));
248
249 var AssignmentOperator = or(
250 "=", "+=", "-=", "*=", "/=", "%=",
251 "<<=", ">>=", ">>>=",
252 "|=", "^=", "&=");
253
254 def("AssignmentExpression")
255 .bases("Expression")
256 .build("operator", "left", "right")
257 .field("operator", AssignmentOperator)
258 .field("left", def("Pattern"))
259 .field("right", def("Expression"));
260
261 var UpdateOperator = or("++", "--");
262
263 def("UpdateExpression")
264 .bases("Expression")
265 .build("operator", "argument", "prefix")
266 .field("operator", UpdateOperator)
267 .field("argument", def("Expression"))
268 .field("prefix", Boolean);
269
270 var LogicalOperator = or("||", "&&");
271
272 def("LogicalExpression")
273 .bases("Expression")
274 .build("operator", "left", "right")
275 .field("operator", LogicalOperator)
276 .field("left", def("Expression"))
277 .field("right", def("Expression"));
278
279 def("ConditionalExpression")
280 .bases("Expression")
281 .build("test", "consequent", "alternate")
282 .field("test", def("Expression"))
283 .field("consequent", def("Expression"))
284 .field("alternate", def("Expression"));
285
286 def("NewExpression")
287 .bases("Expression")
288 .build("callee", "arguments")
289 .field("callee", def("Expression"))
290 // The Mozilla Parser API gives this type as [or(def("Expression"),
291 // null)], but null values don't really make sense at the call site.
292 // TODO Report this nonsense.
293 .field("arguments", [def("Expression")]);
294
295 def("CallExpression")
296 .bases("Expression")
297 .build("callee", "arguments")
298 .field("callee", def("Expression"))
299 // See comment for NewExpression above.
300 .field("arguments", [def("Expression")]);
301
302 def("MemberExpression")
303 .bases("Expression")
304 .build("object", "property", "computed")
305 .field("object", def("Expression"))
306 .field("property", or(def("Identifier"), def("Expression")))
307 .field("computed", Boolean, defaults["false"]);
308
309 def("Pattern").bases("Node");
310
311 def("SwitchCase")
312 .bases("Node")
313 .build("test", "consequent")
314 .field("test", or(def("Expression"), null))
315 .field("consequent", [def("Statement")]);
316
317 def("Identifier")
318 // But aren't Expressions and Patterns already Nodes? TODO Report this.
319 .bases("Node", "Expression", "Pattern")
320 .build("name")
321 .field("name", String);
322
323 def("Literal")
324 // But aren't Expressions already Nodes? TODO Report this.
325 .bases("Node", "Expression")
326 .build("value")
327 .field("value", or(String, Boolean, null, Number, RegExp))
328 .field("regex", or({
329 pattern: String,
330 flags: String
331 }, null), function() {
332 if (this.value instanceof RegExp) {
333 var flags = "";
334
335 if (this.value.ignoreCase) flags += "i";
336 if (this.value.multiline) flags += "m";
337 if (this.value.global) flags += "g";
338
339 return {
340 pattern: this.value.source,
341 flags: flags
342 };
343 }
344
345 return null;
346 });
347
348 // Abstract (non-buildable) comment supertype. Not a Node.
349 def("Comment")
350 .bases("Printable")
351 .field("value", String)
352 // A .leading comment comes before the node, whereas a .trailing
353 // comment comes after it. These two fields should not both be true,
354 // but they might both be false when the comment falls inside a node
355 // and the node has no children for the comment to lead or trail,
356 // e.g. { /*dangling*/ }.
357 .field("leading", Boolean, defaults["true"])
358 .field("trailing", Boolean, defaults["false"]);
0 require("./core");
1 var types = require("../lib/types");
2 var def = types.Type.def;
3 var or = types.Type.or;
4
5 // Note that none of these types are buildable because the Mozilla Parser
6 // API doesn't specify any builder functions, and nobody uses E4X anymore.
7
8 def("XMLDefaultDeclaration")
9 .bases("Declaration")
10 .field("namespace", def("Expression"));
11
12 def("XMLAnyName").bases("Expression");
13
14 def("XMLQualifiedIdentifier")
15 .bases("Expression")
16 .field("left", or(def("Identifier"), def("XMLAnyName")))
17 .field("right", or(def("Identifier"), def("Expression")))
18 .field("computed", Boolean);
19
20 def("XMLFunctionQualifiedIdentifier")
21 .bases("Expression")
22 .field("right", or(def("Identifier"), def("Expression")))
23 .field("computed", Boolean);
24
25 def("XMLAttributeSelector")
26 .bases("Expression")
27 .field("attribute", def("Expression"));
28
29 def("XMLFilterExpression")
30 .bases("Expression")
31 .field("left", def("Expression"))
32 .field("right", def("Expression"));
33
34 def("XMLElement")
35 .bases("XML", "Expression")
36 .field("contents", [def("XML")]);
37
38 def("XMLList")
39 .bases("XML", "Expression")
40 .field("contents", [def("XML")]);
41
42 def("XML").bases("Node");
43
44 def("XMLEscape")
45 .bases("XML")
46 .field("expression", def("Expression"));
47
48 def("XMLText")
49 .bases("XML")
50 .field("text", String);
51
52 def("XMLStartTag")
53 .bases("XML")
54 .field("contents", [def("XML")]);
55
56 def("XMLEndTag")
57 .bases("XML")
58 .field("contents", [def("XML")]);
59
60 def("XMLPointTag")
61 .bases("XML")
62 .field("contents", [def("XML")]);
63
64 def("XMLName")
65 .bases("XML")
66 .field("contents", or(String, [def("XML")]));
67
68 def("XMLAttribute")
69 .bases("XML")
70 .field("value", String);
71
72 def("XMLCdata")
73 .bases("XML")
74 .field("contents", String);
75
76 def("XMLComment")
77 .bases("XML")
78 .field("contents", String);
79
80 def("XMLProcessingInstruction")
81 .bases("XML")
82 .field("target", String)
83 .field("contents", or(String, null));
0 require("./core");
1 var types = require("../lib/types");
2 var def = types.Type.def;
3 var or = types.Type.or;
4 var defaults = require("../lib/shared").defaults;
5
6 def("Function")
7 .field("generator", Boolean, defaults["false"])
8 .field("expression", Boolean, defaults["false"])
9 .field("defaults", [or(def("Expression"), null)], defaults.emptyArray)
10 // TODO This could be represented as a RestElement in .params.
11 .field("rest", or(def("Identifier"), null), defaults["null"]);
12
13 // The ESTree way of representing a ...rest parameter.
14 def("RestElement")
15 .bases("Pattern")
16 .build("argument")
17 .field("argument", def("Pattern"));
18
19 def("SpreadElementPattern")
20 .bases("Pattern")
21 .build("argument")
22 .field("argument", def("Pattern"));
23
24 def("FunctionDeclaration")
25 .build("id", "params", "body", "generator", "expression");
26
27 def("FunctionExpression")
28 .build("id", "params", "body", "generator", "expression");
29
30 // The Parser API calls this ArrowExpression, but Esprima and all other
31 // actual parsers use ArrowFunctionExpression.
32 def("ArrowFunctionExpression")
33 .bases("Function", "Expression")
34 .build("params", "body", "expression")
35 // The forced null value here is compatible with the overridden
36 // definition of the "id" field in the Function interface.
37 .field("id", null, defaults["null"])
38 // Arrow function bodies are allowed to be expressions.
39 .field("body", or(def("BlockStatement"), def("Expression")))
40 // The current spec forbids arrow generators, so I have taken the
41 // liberty of enforcing that. TODO Report this.
42 .field("generator", false, defaults["false"]);
43
44 def("YieldExpression")
45 .bases("Expression")
46 .build("argument", "delegate")
47 .field("argument", or(def("Expression"), null))
48 .field("delegate", Boolean, defaults["false"]);
49
50 def("GeneratorExpression")
51 .bases("Expression")
52 .build("body", "blocks", "filter")
53 .field("body", def("Expression"))
54 .field("blocks", [def("ComprehensionBlock")])
55 .field("filter", or(def("Expression"), null));
56
57 def("ComprehensionExpression")
58 .bases("Expression")
59 .build("body", "blocks", "filter")
60 .field("body", def("Expression"))
61 .field("blocks", [def("ComprehensionBlock")])
62 .field("filter", or(def("Expression"), null));
63
64 def("ComprehensionBlock")
65 .bases("Node")
66 .build("left", "right", "each")
67 .field("left", def("Pattern"))
68 .field("right", def("Expression"))
69 .field("each", Boolean);
70
71 def("Property")
72 .field("key", or(def("Literal"), def("Identifier"), def("Expression")))
73 .field("value", or(def("Expression"), def("Pattern")))
74 .field("method", Boolean, defaults["false"])
75 .field("shorthand", Boolean, defaults["false"])
76 .field("computed", Boolean, defaults["false"]);
77
78 def("PropertyPattern")
79 .bases("Pattern")
80 .build("key", "pattern")
81 .field("key", or(def("Literal"), def("Identifier"), def("Expression")))
82 .field("pattern", def("Pattern"))
83 .field("computed", Boolean, defaults["false"]);
84
85 def("ObjectPattern")
86 .bases("Pattern")
87 .build("properties")
88 .field("properties", [or(def("PropertyPattern"), def("Property"))]);
89
90 def("ArrayPattern")
91 .bases("Pattern")
92 .build("elements")
93 .field("elements", [or(def("Pattern"), null)]);
94
95 def("MethodDefinition")
96 .bases("Declaration")
97 .build("kind", "key", "value", "static")
98 .field("kind", or("constructor", "method", "get", "set"))
99 .field("key", or(def("Literal"), def("Identifier"), def("Expression")))
100 .field("value", def("Function"))
101 .field("computed", Boolean, defaults["false"])
102 .field("static", Boolean, defaults["false"]);
103
104 def("SpreadElement")
105 .bases("Node")
106 .build("argument")
107 .field("argument", def("Expression"));
108
109 def("ArrayExpression")
110 .field("elements", [or(
111 def("Expression"),
112 def("SpreadElement"),
113 def("RestElement"),
114 null
115 )]);
116
117 def("NewExpression")
118 .field("arguments", [or(def("Expression"), def("SpreadElement"))]);
119
120 def("CallExpression")
121 .field("arguments", [or(def("Expression"), def("SpreadElement"))]);
122
123 // Note: this node type is *not* an AssignmentExpression with a Pattern on
124 // the left-hand side! The existing AssignmentExpression type already
125 // supports destructuring assignments. AssignmentPattern nodes may appear
126 // wherever a Pattern is allowed, and the right-hand side represents a
127 // default value to be destructured against the left-hand side, if no
128 // value is otherwise provided. For example: default parameter values.
129 def("AssignmentPattern")
130 .bases("Pattern")
131 .build("left", "right")
132 .field("left", def("Pattern"))
133 .field("right", def("Expression"));
134
135 var ClassBodyElement = or(
136 def("MethodDefinition"),
137 def("VariableDeclarator"),
138 def("ClassPropertyDefinition"),
139 def("ClassProperty")
140 );
141
142 def("ClassProperty")
143 .bases("Declaration")
144 .build("key")
145 .field("key", or(def("Literal"), def("Identifier"), def("Expression")))
146 .field("computed", Boolean, defaults["false"]);
147
148 def("ClassPropertyDefinition") // static property
149 .bases("Declaration")
150 .build("definition")
151 // Yes, Virginia, circular definitions are permitted.
152 .field("definition", ClassBodyElement);
153
154 def("ClassBody")
155 .bases("Declaration")
156 .build("body")
157 .field("body", [ClassBodyElement]);
158
159 def("ClassDeclaration")
160 .bases("Declaration")
161 .build("id", "body", "superClass")
162 .field("id", or(def("Identifier"), null))
163 .field("body", def("ClassBody"))
164 .field("superClass", or(def("Expression"), null), defaults["null"]);
165
166 def("ClassExpression")
167 .bases("Expression")
168 .build("id", "body", "superClass")
169 .field("id", or(def("Identifier"), null), defaults["null"])
170 .field("body", def("ClassBody"))
171 .field("superClass", or(def("Expression"), null), defaults["null"])
172 .field("implements", [def("ClassImplements")], defaults.emptyArray);
173
174 def("ClassImplements")
175 .bases("Node")
176 .build("id")
177 .field("id", def("Identifier"))
178 .field("superClass", or(def("Expression"), null), defaults["null"]);
179
180 // Specifier and ModuleSpecifier are abstract non-standard types
181 // introduced for definitional convenience.
182 def("Specifier").bases("Node");
183
184 // This supertype is shared/abused by both def/babel.js and
185 // def/esprima.js. In the future, it will be possible to load only one set
186 // of definitions appropriate for a given parser, but until then we must
187 // rely on default functions to reconcile the conflicting AST formats.
188 def("ModuleSpecifier")
189 .bases("Specifier")
190 // This local field is used by Babel/Acorn. It should not technically
191 // be optional in the Babel/Acorn AST format, but it must be optional
192 // in the Esprima AST format.
193 .field("local", or(def("Identifier"), null), defaults["null"])
194 // The id and name fields are used by Esprima. The id field should not
195 // technically be optional in the Esprima AST format, but it must be
196 // optional in the Babel/Acorn AST format.
197 .field("id", or(def("Identifier"), null), defaults["null"])
198 .field("name", or(def("Identifier"), null), defaults["null"]);
199
200 def("TaggedTemplateExpression")
201 .bases("Expression")
202 .build("tag", "quasi")
203 .field("tag", def("Expression"))
204 .field("quasi", def("TemplateLiteral"));
205
206 def("TemplateLiteral")
207 .bases("Expression")
208 .build("quasis", "expressions")
209 .field("quasis", [def("TemplateElement")])
210 .field("expressions", [def("Expression")]);
211
212 def("TemplateElement")
213 .bases("Node")
214 .build("value", "tail")
215 .field("value", {"cooked": String, "raw": String})
216 .field("tail", Boolean);
0 require("./es6");
1
2 var types = require("../lib/types");
3 var def = types.Type.def;
4 var or = types.Type.or;
5 var builtin = types.builtInTypes;
6 var defaults = require("../lib/shared").defaults;
7
8 def("Function")
9 .field("async", Boolean, defaults["false"]);
10
11 def("SpreadProperty")
12 .bases("Node")
13 .build("argument")
14 .field("argument", def("Expression"));
15
16 def("ObjectExpression")
17 .field("properties", [or(def("Property"), def("SpreadProperty"))]);
18
19 def("SpreadPropertyPattern")
20 .bases("Pattern")
21 .build("argument")
22 .field("argument", def("Pattern"));
23
24 def("ObjectPattern")
25 .field("properties", [or(
26 def("Property"),
27 def("PropertyPattern"),
28 def("SpreadPropertyPattern")
29 )]);
30
31 def("AwaitExpression")
32 .bases("Expression")
33 .build("argument", "all")
34 .field("argument", or(def("Expression"), null))
35 .field("all", Boolean, defaults["false"]);
0 require("./es7");
1
2 var types = require("../lib/types");
3 var defaults = require("../lib/shared").defaults;
4 var def = types.Type.def;
5 var or = types.Type.or;
6
7 def("VariableDeclaration")
8 .field("declarations", [or(
9 def("VariableDeclarator"),
10 def("Identifier") // Esprima deviation.
11 )]);
12
13 def("Property")
14 .field("value", or(
15 def("Expression"),
16 def("Pattern") // Esprima deviation.
17 ));
18
19 def("ArrayPattern")
20 .field("elements", [or(
21 def("Pattern"),
22 def("SpreadElement"),
23 null
24 )]);
25
26 def("ObjectPattern")
27 .field("properties", [or(
28 def("Property"),
29 def("PropertyPattern"),
30 def("SpreadPropertyPattern"),
31 def("SpreadProperty") // Used by Esprima.
32 )]);
33
34 // Like ModuleSpecifier, except type:"ExportSpecifier" and buildable.
35 // export {<id [as name]>} [from ...];
36 def("ExportSpecifier")
37 .bases("ModuleSpecifier")
38 .build("id", "name");
39
40 // export <*> from ...;
41 def("ExportBatchSpecifier")
42 .bases("Specifier")
43 .build();
44
45 // Like ModuleSpecifier, except type:"ImportSpecifier" and buildable.
46 // import {<id [as name]>} from ...;
47 def("ImportSpecifier")
48 .bases("ModuleSpecifier")
49 .build("id", "name");
50
51 // import <* as id> from ...;
52 def("ImportNamespaceSpecifier")
53 .bases("ModuleSpecifier")
54 .build("id");
55
56 // import <id> from ...;
57 def("ImportDefaultSpecifier")
58 .bases("ModuleSpecifier")
59 .build("id");
60
61 def("ExportDeclaration")
62 .bases("Declaration")
63 .build("default", "declaration", "specifiers", "source")
64 .field("default", Boolean)
65 .field("declaration", or(
66 def("Declaration"),
67 def("Expression"), // Implies default.
68 null
69 ))
70 .field("specifiers", [or(
71 def("ExportSpecifier"),
72 def("ExportBatchSpecifier")
73 )], defaults.emptyArray)
74 .field("source", or(
75 def("Literal"),
76 null
77 ), defaults["null"]);
78
79 def("ImportDeclaration")
80 .bases("Declaration")
81 .build("specifiers", "source")
82 .field("specifiers", [or(
83 def("ImportSpecifier"),
84 def("ImportNamespaceSpecifier"),
85 def("ImportDefaultSpecifier")
86 )], defaults.emptyArray)
87 .field("source", def("Literal"));
88
89 def("Block")
90 .bases("Comment")
91 .build("value", /*optional:*/ "leading", "trailing");
92
93 def("Line")
94 .bases("Comment")
95 .build("value", /*optional:*/ "leading", "trailing");
0 require("./es7");
1
2 var types = require("../lib/types");
3 var def = types.Type.def;
4 var or = types.Type.or;
5 var defaults = require("../lib/shared").defaults;
6
7 def("JSXAttribute")
8 .bases("Node")
9 .build("name", "value")
10 .field("name", or(def("JSXIdentifier"), def("JSXNamespacedName")))
11 .field("value", or(
12 def("Literal"), // attr="value"
13 def("JSXExpressionContainer"), // attr={value}
14 null // attr= or just attr
15 ), defaults["null"]);
16
17 def("JSXIdentifier")
18 .bases("Identifier")
19 .build("name")
20 .field("name", String);
21
22 def("JSXNamespacedName")
23 .bases("Node")
24 .build("namespace", "name")
25 .field("namespace", def("JSXIdentifier"))
26 .field("name", def("JSXIdentifier"));
27
28 def("JSXMemberExpression")
29 .bases("MemberExpression")
30 .build("object", "property")
31 .field("object", or(def("JSXIdentifier"), def("JSXMemberExpression")))
32 .field("property", def("JSXIdentifier"))
33 .field("computed", Boolean, defaults.false);
34
35 var JSXElementName = or(
36 def("JSXIdentifier"),
37 def("JSXNamespacedName"),
38 def("JSXMemberExpression")
39 );
40
41 def("JSXSpreadAttribute")
42 .bases("Node")
43 .build("argument")
44 .field("argument", def("Expression"));
45
46 var JSXAttributes = [or(
47 def("JSXAttribute"),
48 def("JSXSpreadAttribute")
49 )];
50
51 def("JSXExpressionContainer")
52 .bases("Expression")
53 .build("expression")
54 .field("expression", def("Expression"));
55
56 def("JSXElement")
57 .bases("Expression")
58 .build("openingElement", "closingElement", "children")
59 .field("openingElement", def("JSXOpeningElement"))
60 .field("closingElement", or(def("JSXClosingElement"), null), defaults["null"])
61 .field("children", [or(
62 def("JSXElement"),
63 def("JSXExpressionContainer"),
64 def("JSXText"),
65 def("Literal") // TODO Esprima should return JSXText instead.
66 )], defaults.emptyArray)
67 .field("name", JSXElementName, function() {
68 // Little-known fact: the `this` object inside a default function
69 // is none other than the partially-built object itself, and any
70 // fields initialized directly from builder function arguments
71 // (like openingElement, closingElement, and children) are
72 // guaranteed to be available.
73 return this.openingElement.name;
74 }, true) // hidden from traversal
75 .field("selfClosing", Boolean, function() {
76 return this.openingElement.selfClosing;
77 }, true) // hidden from traversal
78 .field("attributes", JSXAttributes, function() {
79 return this.openingElement.attributes;
80 }, true); // hidden from traversal
81
82 def("JSXOpeningElement")
83 .bases("Node") // TODO Does this make sense? Can't really be an JSXElement.
84 .build("name", "attributes", "selfClosing")
85 .field("name", JSXElementName)
86 .field("attributes", JSXAttributes, defaults.emptyArray)
87 .field("selfClosing", Boolean, defaults["false"]);
88
89 def("JSXClosingElement")
90 .bases("Node") // TODO Same concern.
91 .build("name")
92 .field("name", JSXElementName);
93
94 def("JSXText")
95 .bases("Literal")
96 .build("value")
97 .field("value", String);
98
99 def("JSXEmptyExpression").bases("Expression").build();
100
101 // Type Annotations
102 def("Type").bases("Node");
103
104 def("AnyTypeAnnotation")
105 .bases("Type")
106 .build();
107
108 def("MixedTypeAnnotation")
109 .bases("Type")
110 .build();
111
112 def("VoidTypeAnnotation")
113 .bases("Type")
114 .build();
115
116 def("NumberTypeAnnotation")
117 .bases("Type")
118 .build();
119
120 def("NumberLiteralTypeAnnotation")
121 .bases("Type")
122 .build("value", "raw")
123 .field("value", Number)
124 .field("raw", String);
125
126 def("StringTypeAnnotation")
127 .bases("Type")
128 .build();
129
130 def("StringLiteralTypeAnnotation")
131 .bases("Type")
132 .build("value", "raw")
133 .field("value", String)
134 .field("raw", String);
135
136 def("BooleanTypeAnnotation")
137 .bases("Type")
138 .build();
139
140 def("BooleanLiteralTypeAnnotation")
141 .bases("Type")
142 .build("value", "raw")
143 .field("value", Boolean)
144 .field("raw", String);
145
146 def("TypeAnnotation")
147 .bases("Node")
148 .build("typeAnnotation")
149 .field("typeAnnotation", def("Type"));
150
151 def("NullableTypeAnnotation")
152 .bases("Type")
153 .build("typeAnnotation")
154 .field("typeAnnotation", def("Type"));
155
156 def("FunctionTypeAnnotation")
157 .bases("Type")
158 .build("params", "returnType", "rest", "typeParameters")
159 .field("params", [def("FunctionTypeParam")])
160 .field("returnType", def("Type"))
161 .field("rest", or(def("FunctionTypeParam"), null))
162 .field("typeParameters", or(def("TypeParameterDeclaration"), null));
163
164 def("FunctionTypeParam")
165 .bases("Node")
166 .build("name", "typeAnnotation", "optional")
167 .field("name", def("Identifier"))
168 .field("typeAnnotation", def("Type"))
169 .field("optional", Boolean);
170
171 def("ArrayTypeAnnotation")
172 .bases("Type")
173 .build("elementType")
174 .field("elementType", def("Type"));
175
176 def("ObjectTypeAnnotation")
177 .bases("Type")
178 .build("properties")
179 .field("properties", [def("ObjectTypeProperty")])
180 .field("indexers", [def("ObjectTypeIndexer")], defaults.emptyArray)
181 .field("callProperties",
182 [def("ObjectTypeCallProperty")],
183 defaults.emptyArray);
184
185 def("ObjectTypeProperty")
186 .bases("Node")
187 .build("key", "value", "optional")
188 .field("key", or(def("Literal"), def("Identifier")))
189 .field("value", def("Type"))
190 .field("optional", Boolean);
191
192 def("ObjectTypeIndexer")
193 .bases("Node")
194 .build("id", "key", "value")
195 .field("id", def("Identifier"))
196 .field("key", def("Type"))
197 .field("value", def("Type"));
198
199 def("ObjectTypeCallProperty")
200 .bases("Node")
201 .build("value")
202 .field("value", def("FunctionTypeAnnotation"))
203 .field("static", Boolean, false);
204
205 def("QualifiedTypeIdentifier")
206 .bases("Node")
207 .build("qualification", "id")
208 .field("qualification",
209 or(def("Identifier"),
210 def("QualifiedTypeIdentifier")))
211 .field("id", def("Identifier"));
212
213 def("GenericTypeAnnotation")
214 .bases("Type")
215 .build("id", "typeParameters")
216 .field("id", or(def("Identifier"), def("QualifiedTypeIdentifier")))
217 .field("typeParameters", or(def("TypeParameterInstantiation"), null));
218
219 def("MemberTypeAnnotation")
220 .bases("Type")
221 .build("object", "property")
222 .field("object", def("Identifier"))
223 .field("property",
224 or(def("MemberTypeAnnotation"),
225 def("GenericTypeAnnotation")));
226
227 def("UnionTypeAnnotation")
228 .bases("Type")
229 .build("types")
230 .field("types", [def("Type")]);
231
232 def("IntersectionTypeAnnotation")
233 .bases("Type")
234 .build("types")
235 .field("types", [def("Type")]);
236
237 def("TypeofTypeAnnotation")
238 .bases("Type")
239 .build("argument")
240 .field("argument", def("Type"));
241
242 def("Identifier")
243 .field("typeAnnotation", or(def("TypeAnnotation"), null), defaults["null"]);
244
245 def("TypeParameterDeclaration")
246 .bases("Node")
247 .build("params")
248 .field("params", [def("Identifier")]);
249
250 def("TypeParameterInstantiation")
251 .bases("Node")
252 .build("params")
253 .field("params", [def("Type")]);
254
255 def("Function")
256 .field("returnType",
257 or(def("TypeAnnotation"), null),
258 defaults["null"])
259 .field("typeParameters",
260 or(def("TypeParameterDeclaration"), null),
261 defaults["null"]);
262
263 def("ClassProperty")
264 .build("key", "value", "typeAnnotation", "static")
265 .field("value", or(def("Expression"), null))
266 .field("typeAnnotation", or(def("TypeAnnotation"), null))
267 .field("static", Boolean, defaults["false"]);
268
269 def("ClassImplements")
270 .field("typeParameters",
271 or(def("TypeParameterInstantiation"), null),
272 defaults["null"]);
273
274 def("InterfaceDeclaration")
275 .bases("Statement")
276 .build("id", "body", "extends")
277 .field("id", def("Identifier"))
278 .field("typeParameters",
279 or(def("TypeParameterDeclaration"), null),
280 defaults["null"])
281 .field("body", def("ObjectTypeAnnotation"))
282 .field("extends", [def("InterfaceExtends")]);
283
284 def("InterfaceExtends")
285 .bases("Node")
286 .build("id")
287 .field("id", def("Identifier"))
288 .field("typeParameters", or(def("TypeParameterInstantiation"), null));
289
290 def("TypeAlias")
291 .bases("Declaration")
292 .build("id", "typeParameters", "right")
293 .field("id", def("Identifier"))
294 .field("typeParameters", or(def("TypeParameterDeclaration"), null))
295 .field("right", def("Type"));
296
297 def("TypeCastExpression")
298 .bases("Expression")
299 .build("expression", "typeAnnotation")
300 .field("expression", def("Expression"))
301 .field("typeAnnotation", def("TypeAnnotation"));
302
303 def("TupleTypeAnnotation")
304 .bases("Type")
305 .build("types")
306 .field("types", [def("Type")]);
307
308 def("DeclareVariable")
309 .bases("Statement")
310 .build("id")
311 .field("id", def("Identifier"));
312
313 def("DeclareFunction")
314 .bases("Statement")
315 .build("id")
316 .field("id", def("Identifier"));
317
318 def("DeclareClass")
319 .bases("InterfaceDeclaration")
320 .build("id");
321
322 def("DeclareModule")
323 .bases("Statement")
324 .build("id", "body")
325 .field("id", or(def("Identifier"), def("Literal")))
326 .field("body", def("BlockStatement"));
0 require("./core");
1 var types = require("../lib/types");
2 var def = types.Type.def;
3 var or = types.Type.or;
4 var shared = require("../lib/shared");
5 var geq = shared.geq;
6 var defaults = shared.defaults;
7
8 def("Function")
9 // SpiderMonkey allows expression closures: function(x) x+1
10 .field("body", or(def("BlockStatement"), def("Expression")));
11
12 def("ForInStatement")
13 .build("left", "right", "body", "each")
14 .field("each", Boolean, defaults["false"]);
15
16 def("ForOfStatement")
17 .bases("Statement")
18 .build("left", "right", "body")
19 .field("left", or(
20 def("VariableDeclaration"),
21 def("Expression")))
22 .field("right", def("Expression"))
23 .field("body", def("Statement"));
24
25 def("LetStatement")
26 .bases("Statement")
27 .build("head", "body")
28 // TODO Deviating from the spec by reusing VariableDeclarator here.
29 .field("head", [def("VariableDeclarator")])
30 .field("body", def("Statement"));
31
32 def("LetExpression")
33 .bases("Expression")
34 .build("head", "body")
35 // TODO Deviating from the spec by reusing VariableDeclarator here.
36 .field("head", [def("VariableDeclarator")])
37 .field("body", def("Expression"));
38
39 def("GraphExpression")
40 .bases("Expression")
41 .build("index", "expression")
42 .field("index", geq(0))
43 .field("expression", def("Literal"));
44
45 def("GraphIndexExpression")
46 .bases("Expression")
47 .build("index")
48 .field("index", geq(0));
0 var types = require("../main");
1 var getFieldNames = types.getFieldNames;
2 var getFieldValue = types.getFieldValue;
3 var isArray = types.builtInTypes.array;
4 var isObject = types.builtInTypes.object;
5 var isDate = types.builtInTypes.Date;
6 var isRegExp = types.builtInTypes.RegExp;
7 var hasOwn = Object.prototype.hasOwnProperty;
8
9 function astNodesAreEquivalent(a, b, problemPath) {
10 if (isArray.check(problemPath)) {
11 problemPath.length = 0;
12 } else {
13 problemPath = null;
14 }
15
16 return areEquivalent(a, b, problemPath);
17 }
18
19 astNodesAreEquivalent.assert = function(a, b) {
20 var problemPath = [];
21 if (!astNodesAreEquivalent(a, b, problemPath)) {
22 if (problemPath.length === 0) {
23 if (a !== b) {
24 throw new Error("Nodes must be equal");
25 }
26 } else {
27 throw new Error(
28 "Nodes differ in the following path: " +
29 problemPath.map(subscriptForProperty).join("")
30 );
31 }
32 }
33 };
34
35 function subscriptForProperty(property) {
36 if (/[_$a-z][_$a-z0-9]*/i.test(property)) {
37 return "." + property;
38 }
39 return "[" + JSON.stringify(property) + "]";
40 }
41
42 function areEquivalent(a, b, problemPath) {
43 if (a === b) {
44 return true;
45 }
46
47 if (isArray.check(a)) {
48 return arraysAreEquivalent(a, b, problemPath);
49 }
50
51 if (isObject.check(a)) {
52 return objectsAreEquivalent(a, b, problemPath);
53 }
54
55 if (isDate.check(a)) {
56 return isDate.check(b) && (+a === +b);
57 }
58
59 if (isRegExp.check(a)) {
60 return isRegExp.check(b) && (
61 a.source === b.source &&
62 a.global === b.global &&
63 a.multiline === b.multiline &&
64 a.ignoreCase === b.ignoreCase
65 );
66 }
67
68 return a == b;
69 }
70
71 function arraysAreEquivalent(a, b, problemPath) {
72 isArray.assert(a);
73 var aLength = a.length;
74
75 if (!isArray.check(b) || b.length !== aLength) {
76 if (problemPath) {
77 problemPath.push("length");
78 }
79 return false;
80 }
81
82 for (var i = 0; i < aLength; ++i) {
83 if (problemPath) {
84 problemPath.push(i);
85 }
86
87 if (i in a !== i in b) {
88 return false;
89 }
90
91 if (!areEquivalent(a[i], b[i], problemPath)) {
92 return false;
93 }
94
95 if (problemPath) {
96 var problemPathTail = problemPath.pop();
97 if (problemPathTail !== i) {
98 throw new Error("" + problemPathTail);
99 }
100 }
101 }
102
103 return true;
104 }
105
106 function objectsAreEquivalent(a, b, problemPath) {
107 isObject.assert(a);
108 if (!isObject.check(b)) {
109 return false;
110 }
111
112 // Fast path for a common property of AST nodes.
113 if (a.type !== b.type) {
114 if (problemPath) {
115 problemPath.push("type");
116 }
117 return false;
118 }
119
120 var aNames = getFieldNames(a);
121 var aNameCount = aNames.length;
122
123 var bNames = getFieldNames(b);
124 var bNameCount = bNames.length;
125
126 if (aNameCount === bNameCount) {
127 for (var i = 0; i < aNameCount; ++i) {
128 var name = aNames[i];
129 var aChild = getFieldValue(a, name);
130 var bChild = getFieldValue(b, name);
131
132 if (problemPath) {
133 problemPath.push(name);
134 }
135
136 if (!areEquivalent(aChild, bChild, problemPath)) {
137 return false;
138 }
139
140 if (problemPath) {
141 var problemPathTail = problemPath.pop();
142 if (problemPathTail !== name) {
143 throw new Error("" + problemPathTail);
144 }
145 }
146 }
147
148 return true;
149 }
150
151 if (!problemPath) {
152 return false;
153 }
154
155 // Since aNameCount !== bNameCount, we need to find some name that's
156 // missing in aNames but present in bNames, or vice-versa.
157
158 var seenNames = Object.create(null);
159
160 for (i = 0; i < aNameCount; ++i) {
161 seenNames[aNames[i]] = true;
162 }
163
164 for (i = 0; i < bNameCount; ++i) {
165 name = bNames[i];
166
167 if (!hasOwn.call(seenNames, name)) {
168 problemPath.push(name);
169 return false;
170 }
171
172 delete seenNames[name];
173 }
174
175 for (name in seenNames) {
176 problemPath.push(name);
177 break;
178 }
179
180 return false;
181 }
182
183 module.exports = astNodesAreEquivalent;
0 var types = require("./types");
1 var n = types.namedTypes;
2 var b = types.builders;
3 var isNumber = types.builtInTypes.number;
4 var isArray = types.builtInTypes.array;
5 var Path = require("./path");
6 var Scope = require("./scope");
7
8 function NodePath(value, parentPath, name) {
9 if (!(this instanceof NodePath)) {
10 throw new Error("NodePath constructor cannot be invoked without 'new'");
11 }
12 Path.call(this, value, parentPath, name);
13 }
14
15 var NPp = NodePath.prototype = Object.create(Path.prototype, {
16 constructor: {
17 value: NodePath,
18 enumerable: false,
19 writable: true,
20 configurable: true
21 }
22 });
23
24 Object.defineProperties(NPp, {
25 node: {
26 get: function() {
27 Object.defineProperty(this, "node", {
28 configurable: true, // Enable deletion.
29 value: this._computeNode()
30 });
31
32 return this.node;
33 }
34 },
35
36 parent: {
37 get: function() {
38 Object.defineProperty(this, "parent", {
39 configurable: true, // Enable deletion.
40 value: this._computeParent()
41 });
42
43 return this.parent;
44 }
45 },
46
47 scope: {
48 get: function() {
49 Object.defineProperty(this, "scope", {
50 configurable: true, // Enable deletion.
51 value: this._computeScope()
52 });
53
54 return this.scope;
55 }
56 }
57 });
58
59 NPp.replace = function() {
60 delete this.node;
61 delete this.parent;
62 delete this.scope;
63 return Path.prototype.replace.apply(this, arguments);
64 };
65
66 NPp.prune = function() {
67 var remainingNodePath = this.parent;
68
69 this.replace();
70
71 return cleanUpNodesAfterPrune(remainingNodePath);
72 };
73
74 // The value of the first ancestor Path whose value is a Node.
75 NPp._computeNode = function() {
76 var value = this.value;
77 if (n.Node.check(value)) {
78 return value;
79 }
80
81 var pp = this.parentPath;
82 return pp && pp.node || null;
83 };
84
85 // The first ancestor Path whose value is a Node distinct from this.node.
86 NPp._computeParent = function() {
87 var value = this.value;
88 var pp = this.parentPath;
89
90 if (!n.Node.check(value)) {
91 while (pp && !n.Node.check(pp.value)) {
92 pp = pp.parentPath;
93 }
94
95 if (pp) {
96 pp = pp.parentPath;
97 }
98 }
99
100 while (pp && !n.Node.check(pp.value)) {
101 pp = pp.parentPath;
102 }
103
104 return pp || null;
105 };
106
107 // The closest enclosing scope that governs this node.
108 NPp._computeScope = function() {
109 var value = this.value;
110 var pp = this.parentPath;
111 var scope = pp && pp.scope;
112
113 if (n.Node.check(value) &&
114 Scope.isEstablishedBy(value)) {
115 scope = new Scope(this, scope);
116 }
117
118 return scope || null;
119 };
120
121 NPp.getValueProperty = function(name) {
122 return types.getFieldValue(this.value, name);
123 };
124
125 /**
126 * Determine whether this.node needs to be wrapped in parentheses in order
127 * for a parser to reproduce the same local AST structure.
128 *
129 * For instance, in the expression `(1 + 2) * 3`, the BinaryExpression
130 * whose operator is "+" needs parentheses, because `1 + 2 * 3` would
131 * parse differently.
132 *
133 * If assumeExpressionContext === true, we don't worry about edge cases
134 * like an anonymous FunctionExpression appearing lexically first in its
135 * enclosing statement and thus needing parentheses to avoid being parsed
136 * as a FunctionDeclaration with a missing name.
137 */
138 NPp.needsParens = function(assumeExpressionContext) {
139 var pp = this.parentPath;
140 if (!pp) {
141 return false;
142 }
143
144 var node = this.value;
145
146 // Only expressions need parentheses.
147 if (!n.Expression.check(node)) {
148 return false;
149 }
150
151 // Identifiers never need parentheses.
152 if (node.type === "Identifier") {
153 return false;
154 }
155
156 while (!n.Node.check(pp.value)) {
157 pp = pp.parentPath;
158 if (!pp) {
159 return false;
160 }
161 }
162
163 var parent = pp.value;
164
165 switch (node.type) {
166 case "UnaryExpression":
167 case "SpreadElement":
168 case "SpreadProperty":
169 return parent.type === "MemberExpression"
170 && this.name === "object"
171 && parent.object === node;
172
173 case "BinaryExpression":
174 case "LogicalExpression":
175 switch (parent.type) {
176 case "CallExpression":
177 return this.name === "callee"
178 && parent.callee === node;
179
180 case "UnaryExpression":
181 case "SpreadElement":
182 case "SpreadProperty":
183 return true;
184
185 case "MemberExpression":
186 return this.name === "object"
187 && parent.object === node;
188
189 case "BinaryExpression":
190 case "LogicalExpression":
191 var po = parent.operator;
192 var pp = PRECEDENCE[po];
193 var no = node.operator;
194 var np = PRECEDENCE[no];
195
196 if (pp > np) {
197 return true;
198 }
199
200 if (pp === np && this.name === "right") {
201 if (parent.right !== node) {
202 throw new Error("Nodes must be equal");
203 }
204 return true;
205 }
206
207 default:
208 return false;
209 }
210
211 case "SequenceExpression":
212 switch (parent.type) {
213 case "ForStatement":
214 // Although parentheses wouldn't hurt around sequence
215 // expressions in the head of for loops, traditional style
216 // dictates that e.g. i++, j++ should not be wrapped with
217 // parentheses.
218 return false;
219
220 case "ExpressionStatement":
221 return this.name !== "expression";
222
223 default:
224 // Otherwise err on the side of overparenthesization, adding
225 // explicit exceptions above if this proves overzealous.
226 return true;
227 }
228
229 case "YieldExpression":
230 switch (parent.type) {
231 case "BinaryExpression":
232 case "LogicalExpression":
233 case "UnaryExpression":
234 case "SpreadElement":
235 case "SpreadProperty":
236 case "CallExpression":
237 case "MemberExpression":
238 case "NewExpression":
239 case "ConditionalExpression":
240 case "YieldExpression":
241 return true;
242
243 default:
244 return false;
245 }
246
247 case "Literal":
248 return parent.type === "MemberExpression"
249 && isNumber.check(node.value)
250 && this.name === "object"
251 && parent.object === node;
252
253 case "AssignmentExpression":
254 case "ConditionalExpression":
255 switch (parent.type) {
256 case "UnaryExpression":
257 case "SpreadElement":
258 case "SpreadProperty":
259 case "BinaryExpression":
260 case "LogicalExpression":
261 return true;
262
263 case "CallExpression":
264 return this.name === "callee"
265 && parent.callee === node;
266
267 case "ConditionalExpression":
268 return this.name === "test"
269 && parent.test === node;
270
271 case "MemberExpression":
272 return this.name === "object"
273 && parent.object === node;
274
275 default:
276 return false;
277 }
278
279 default:
280 if (parent.type === "NewExpression" &&
281 this.name === "callee" &&
282 parent.callee === node) {
283 return containsCallExpression(node);
284 }
285 }
286
287 if (assumeExpressionContext !== true &&
288 !this.canBeFirstInStatement() &&
289 this.firstInStatement())
290 return true;
291
292 return false;
293 };
294
295 function isBinary(node) {
296 return n.BinaryExpression.check(node)
297 || n.LogicalExpression.check(node);
298 }
299
300 function isUnaryLike(node) {
301 return n.UnaryExpression.check(node)
302 // I considered making SpreadElement and SpreadProperty subtypes
303 // of UnaryExpression, but they're not really Expression nodes.
304 || (n.SpreadElement && n.SpreadElement.check(node))
305 || (n.SpreadProperty && n.SpreadProperty.check(node));
306 }
307
308 var PRECEDENCE = {};
309 [["||"],
310 ["&&"],
311 ["|"],
312 ["^"],
313 ["&"],
314 ["==", "===", "!=", "!=="],
315 ["<", ">", "<=", ">=", "in", "instanceof"],
316 [">>", "<<", ">>>"],
317 ["+", "-"],
318 ["*", "/", "%"]
319 ].forEach(function(tier, i) {
320 tier.forEach(function(op) {
321 PRECEDENCE[op] = i;
322 });
323 });
324
325 function containsCallExpression(node) {
326 if (n.CallExpression.check(node)) {
327 return true;
328 }
329
330 if (isArray.check(node)) {
331 return node.some(containsCallExpression);
332 }
333
334 if (n.Node.check(node)) {
335 return types.someField(node, function(name, child) {
336 return containsCallExpression(child);
337 });
338 }
339
340 return false;
341 }
342
343 NPp.canBeFirstInStatement = function() {
344 var node = this.node;
345 return !n.FunctionExpression.check(node)
346 && !n.ObjectExpression.check(node);
347 };
348
349 NPp.firstInStatement = function() {
350 return firstInStatement(this);
351 };
352
353 function firstInStatement(path) {
354 for (var node, parent; path.parent; path = path.parent) {
355 node = path.node;
356 parent = path.parent.node;
357
358 if (n.BlockStatement.check(parent) &&
359 path.parent.name === "body" &&
360 path.name === 0) {
361 if (parent.body[0] !== node) {
362 throw new Error("Nodes must be equal");
363 }
364 return true;
365 }
366
367 if (n.ExpressionStatement.check(parent) &&
368 path.name === "expression") {
369 if (parent.expression !== node) {
370 throw new Error("Nodes must be equal");
371 }
372 return true;
373 }
374
375 if (n.SequenceExpression.check(parent) &&
376 path.parent.name === "expressions" &&
377 path.name === 0) {
378 if (parent.expressions[0] !== node) {
379 throw new Error("Nodes must be equal");
380 }
381 continue;
382 }
383
384 if (n.CallExpression.check(parent) &&
385 path.name === "callee") {
386 if (parent.callee !== node) {
387 throw new Error("Nodes must be equal");
388 }
389 continue;
390 }
391
392 if (n.MemberExpression.check(parent) &&
393 path.name === "object") {
394 if (parent.object !== node) {
395 throw new Error("Nodes must be equal");
396 }
397 continue;
398 }
399
400 if (n.ConditionalExpression.check(parent) &&
401 path.name === "test") {
402 if (parent.test !== node) {
403 throw new Error("Nodes must be equal");
404 }
405 continue;
406 }
407
408 if (isBinary(parent) &&
409 path.name === "left") {
410 if (parent.left !== node) {
411 throw new Error("Nodes must be equal");
412 }
413 continue;
414 }
415
416 if (n.UnaryExpression.check(parent) &&
417 !parent.prefix &&
418 path.name === "argument") {
419 if (parent.argument !== node) {
420 throw new Error("Nodes must be equal");
421 }
422 continue;
423 }
424
425 return false;
426 }
427
428 return true;
429 }
430
431 /**
432 * Pruning certain nodes will result in empty or incomplete nodes, here we clean those nodes up.
433 */
434 function cleanUpNodesAfterPrune(remainingNodePath) {
435 if (n.VariableDeclaration.check(remainingNodePath.node)) {
436 var declarations = remainingNodePath.get('declarations').value;
437 if (!declarations || declarations.length === 0) {
438 return remainingNodePath.prune();
439 }
440 } else if (n.ExpressionStatement.check(remainingNodePath.node)) {
441 if (!remainingNodePath.get('expression').value) {
442 return remainingNodePath.prune();
443 }
444 } else if (n.IfStatement.check(remainingNodePath.node)) {
445 cleanUpIfStatementAfterPrune(remainingNodePath);
446 }
447
448 return remainingNodePath;
449 }
450
451 function cleanUpIfStatementAfterPrune(ifStatement) {
452 var testExpression = ifStatement.get('test').value;
453 var alternate = ifStatement.get('alternate').value;
454 var consequent = ifStatement.get('consequent').value;
455
456 if (!consequent && !alternate) {
457 var testExpressionStatement = b.expressionStatement(testExpression);
458
459 ifStatement.replace(testExpressionStatement);
460 } else if (!consequent && alternate) {
461 var negatedTestExpression = b.unaryExpression('!', testExpression, true);
462
463 if (n.UnaryExpression.check(testExpression) && testExpression.operator === '!') {
464 negatedTestExpression = testExpression.argument;
465 }
466
467 ifStatement.get("test").replace(negatedTestExpression);
468 ifStatement.get("consequent").replace(alternate);
469 ifStatement.get("alternate").replace();
470 }
471 }
472
473 module.exports = NodePath;
0 var types = require("./types");
1 var NodePath = require("./node-path");
2 var Printable = types.namedTypes.Printable;
3 var isArray = types.builtInTypes.array;
4 var isObject = types.builtInTypes.object;
5 var isFunction = types.builtInTypes.function;
6 var hasOwn = Object.prototype.hasOwnProperty;
7 var undefined;
8
9 function PathVisitor() {
10 if (!(this instanceof PathVisitor)) {
11 throw new Error(
12 "PathVisitor constructor cannot be invoked without 'new'"
13 );
14 }
15
16 // Permanent state.
17 this._reusableContextStack = [];
18
19 this._methodNameTable = computeMethodNameTable(this);
20 this._shouldVisitComments =
21 hasOwn.call(this._methodNameTable, "Block") ||
22 hasOwn.call(this._methodNameTable, "Line");
23
24 this.Context = makeContextConstructor(this);
25
26 // State reset every time PathVisitor.prototype.visit is called.
27 this._visiting = false;
28 this._changeReported = false;
29 }
30
31 function computeMethodNameTable(visitor) {
32 var typeNames = Object.create(null);
33
34 for (var methodName in visitor) {
35 if (/^visit[A-Z]/.test(methodName)) {
36 typeNames[methodName.slice("visit".length)] = true;
37 }
38 }
39
40 var supertypeTable = types.computeSupertypeLookupTable(typeNames);
41 var methodNameTable = Object.create(null);
42
43 var typeNames = Object.keys(supertypeTable);
44 var typeNameCount = typeNames.length;
45 for (var i = 0; i < typeNameCount; ++i) {
46 var typeName = typeNames[i];
47 methodName = "visit" + supertypeTable[typeName];
48 if (isFunction.check(visitor[methodName])) {
49 methodNameTable[typeName] = methodName;
50 }
51 }
52
53 return methodNameTable;
54 }
55
56 PathVisitor.fromMethodsObject = function fromMethodsObject(methods) {
57 if (methods instanceof PathVisitor) {
58 return methods;
59 }
60
61 if (!isObject.check(methods)) {
62 // An empty visitor?
63 return new PathVisitor;
64 }
65
66 function Visitor() {
67 if (!(this instanceof Visitor)) {
68 throw new Error(
69 "Visitor constructor cannot be invoked without 'new'"
70 );
71 }
72 PathVisitor.call(this);
73 }
74
75 var Vp = Visitor.prototype = Object.create(PVp);
76 Vp.constructor = Visitor;
77
78 extend(Vp, methods);
79 extend(Visitor, PathVisitor);
80
81 isFunction.assert(Visitor.fromMethodsObject);
82 isFunction.assert(Visitor.visit);
83
84 return new Visitor;
85 };
86
87 function extend(target, source) {
88 for (var property in source) {
89 if (hasOwn.call(source, property)) {
90 target[property] = source[property];
91 }
92 }
93
94 return target;
95 }
96
97 PathVisitor.visit = function visit(node, methods) {
98 return PathVisitor.fromMethodsObject(methods).visit(node);
99 };
100
101 var PVp = PathVisitor.prototype;
102
103 PVp.visit = function() {
104 if (this._visiting) {
105 throw new Error(
106 "Recursively calling visitor.visit(path) resets visitor state. " +
107 "Try this.visit(path) or this.traverse(path) instead."
108 );
109 }
110
111 // Private state that needs to be reset before every traversal.
112 this._visiting = true;
113 this._changeReported = false;
114 this._abortRequested = false;
115
116 var argc = arguments.length;
117 var args = new Array(argc)
118 for (var i = 0; i < argc; ++i) {
119 args[i] = arguments[i];
120 }
121
122 if (!(args[0] instanceof NodePath)) {
123 args[0] = new NodePath({ root: args[0] }).get("root");
124 }
125
126 // Called with the same arguments as .visit.
127 this.reset.apply(this, args);
128
129 try {
130 var root = this.visitWithoutReset(args[0]);
131 var didNotThrow = true;
132 } finally {
133 this._visiting = false;
134
135 if (!didNotThrow && this._abortRequested) {
136 // If this.visitWithoutReset threw an exception and
137 // this._abortRequested was set to true, return the root of
138 // the AST instead of letting the exception propagate, so that
139 // client code does not have to provide a try-catch block to
140 // intercept the AbortRequest exception. Other kinds of
141 // exceptions will propagate without being intercepted and
142 // rethrown by a catch block, so their stacks will accurately
143 // reflect the original throwing context.
144 return args[0].value;
145 }
146 }
147
148 return root;
149 };
150
151 PVp.AbortRequest = function AbortRequest() {};
152 PVp.abort = function() {
153 var visitor = this;
154 visitor._abortRequested = true;
155 var request = new visitor.AbortRequest();
156
157 // If you decide to catch this exception and stop it from propagating,
158 // make sure to call its cancel method to avoid silencing other
159 // exceptions that might be thrown later in the traversal.
160 request.cancel = function() {
161 visitor._abortRequested = false;
162 };
163
164 throw request;
165 };
166
167 PVp.reset = function(path/*, additional arguments */) {
168 // Empty stub; may be reassigned or overridden by subclasses.
169 };
170
171 PVp.visitWithoutReset = function(path) {
172 if (this instanceof this.Context) {
173 // Since this.Context.prototype === this, there's a chance we
174 // might accidentally call context.visitWithoutReset. If that
175 // happens, re-invoke the method against context.visitor.
176 return this.visitor.visitWithoutReset(path);
177 }
178
179 if (!(path instanceof NodePath)) {
180 throw new Error("");
181 }
182
183 var value = path.value;
184
185 var methodName = value &&
186 typeof value === "object" &&
187 typeof value.type === "string" &&
188 this._methodNameTable[value.type];
189
190 if (methodName) {
191 var context = this.acquireContext(path);
192 try {
193 return context.invokeVisitorMethod(methodName);
194 } finally {
195 this.releaseContext(context);
196 }
197
198 } else {
199 // If there was no visitor method to call, visit the children of
200 // this node generically.
201 return visitChildren(path, this);
202 }
203 };
204
205 function visitChildren(path, visitor) {
206 if (!(path instanceof NodePath)) {
207 throw new Error("");
208 }
209 if (!(visitor instanceof PathVisitor)) {
210 throw new Error("");
211 }
212
213 var value = path.value;
214
215 if (isArray.check(value)) {
216 path.each(visitor.visitWithoutReset, visitor);
217 } else if (!isObject.check(value)) {
218 // No children to visit.
219 } else {
220 var childNames = types.getFieldNames(value);
221
222 // The .comments field of the Node type is hidden, so we only
223 // visit it if the visitor defines visitBlock or visitLine, and
224 // value.comments is defined.
225 if (visitor._shouldVisitComments &&
226 value.comments &&
227 childNames.indexOf("comments") < 0) {
228 childNames.push("comments");
229 }
230
231 var childCount = childNames.length;
232 var childPaths = [];
233
234 for (var i = 0; i < childCount; ++i) {
235 var childName = childNames[i];
236 if (!hasOwn.call(value, childName)) {
237 value[childName] = types.getFieldValue(value, childName);
238 }
239 childPaths.push(path.get(childName));
240 }
241
242 for (var i = 0; i < childCount; ++i) {
243 visitor.visitWithoutReset(childPaths[i]);
244 }
245 }
246
247 return path.value;
248 }
249
250 PVp.acquireContext = function(path) {
251 if (this._reusableContextStack.length === 0) {
252 return new this.Context(path);
253 }
254 return this._reusableContextStack.pop().reset(path);
255 };
256
257 PVp.releaseContext = function(context) {
258 if (!(context instanceof this.Context)) {
259 throw new Error("");
260 }
261 this._reusableContextStack.push(context);
262 context.currentPath = null;
263 };
264
265 PVp.reportChanged = function() {
266 this._changeReported = true;
267 };
268
269 PVp.wasChangeReported = function() {
270 return this._changeReported;
271 };
272
273 function makeContextConstructor(visitor) {
274 function Context(path) {
275 if (!(this instanceof Context)) {
276 throw new Error("");
277 }
278 if (!(this instanceof PathVisitor)) {
279 throw new Error("");
280 }
281 if (!(path instanceof NodePath)) {
282 throw new Error("");
283 }
284
285 Object.defineProperty(this, "visitor", {
286 value: visitor,
287 writable: false,
288 enumerable: true,
289 configurable: false
290 });
291
292 this.currentPath = path;
293 this.needToCallTraverse = true;
294
295 Object.seal(this);
296 }
297
298 if (!(visitor instanceof PathVisitor)) {
299 throw new Error("");
300 }
301
302 // Note that the visitor object is the prototype of Context.prototype,
303 // so all visitor methods are inherited by context objects.
304 var Cp = Context.prototype = Object.create(visitor);
305
306 Cp.constructor = Context;
307 extend(Cp, sharedContextProtoMethods);
308
309 return Context;
310 }
311
312 // Every PathVisitor has a different this.Context constructor and
313 // this.Context.prototype object, but those prototypes can all use the
314 // same reset, invokeVisitorMethod, and traverse function objects.
315 var sharedContextProtoMethods = Object.create(null);
316
317 sharedContextProtoMethods.reset =
318 function reset(path) {
319 if (!(this instanceof this.Context)) {
320 throw new Error("");
321 }
322 if (!(path instanceof NodePath)) {
323 throw new Error("");
324 }
325
326 this.currentPath = path;
327 this.needToCallTraverse = true;
328
329 return this;
330 };
331
332 sharedContextProtoMethods.invokeVisitorMethod =
333 function invokeVisitorMethod(methodName) {
334 if (!(this instanceof this.Context)) {
335 throw new Error("");
336 }
337 if (!(this.currentPath instanceof NodePath)) {
338 throw new Error("");
339 }
340
341 var result = this.visitor[methodName].call(this, this.currentPath);
342
343 if (result === false) {
344 // Visitor methods return false to indicate that they have handled
345 // their own traversal needs, and we should not complain if
346 // this.needToCallTraverse is still true.
347 this.needToCallTraverse = false;
348
349 } else if (result !== undefined) {
350 // Any other non-undefined value returned from the visitor method
351 // is interpreted as a replacement value.
352 this.currentPath = this.currentPath.replace(result)[0];
353
354 if (this.needToCallTraverse) {
355 // If this.traverse still hasn't been called, visit the
356 // children of the replacement node.
357 this.traverse(this.currentPath);
358 }
359 }
360
361 if (this.needToCallTraverse !== false) {
362 throw new Error(
363 "Must either call this.traverse or return false in " + methodName
364 );
365 }
366
367 var path = this.currentPath;
368 return path && path.value;
369 };
370
371 sharedContextProtoMethods.traverse =
372 function traverse(path, newVisitor) {
373 if (!(this instanceof this.Context)) {
374 throw new Error("");
375 }
376 if (!(path instanceof NodePath)) {
377 throw new Error("");
378 }
379 if (!(this.currentPath instanceof NodePath)) {
380 throw new Error("");
381 }
382
383 this.needToCallTraverse = false;
384
385 return visitChildren(path, PathVisitor.fromMethodsObject(
386 newVisitor || this.visitor
387 ));
388 };
389
390 sharedContextProtoMethods.visit =
391 function visit(path, newVisitor) {
392 if (!(this instanceof this.Context)) {
393 throw new Error("");
394 }
395 if (!(path instanceof NodePath)) {
396 throw new Error("");
397 }
398 if (!(this.currentPath instanceof NodePath)) {
399 throw new Error("");
400 }
401
402 this.needToCallTraverse = false;
403
404 return PathVisitor.fromMethodsObject(
405 newVisitor || this.visitor
406 ).visitWithoutReset(path);
407 };
408
409 sharedContextProtoMethods.reportChanged = function reportChanged() {
410 this.visitor.reportChanged();
411 };
412
413 sharedContextProtoMethods.abort = function abort() {
414 this.needToCallTraverse = false;
415 this.visitor.abort();
416 };
417
418 module.exports = PathVisitor;
0 var Op = Object.prototype;
1 var hasOwn = Op.hasOwnProperty;
2 var types = require("./types");
3 var isArray = types.builtInTypes.array;
4 var isNumber = types.builtInTypes.number;
5 var Ap = Array.prototype;
6 var slice = Ap.slice;
7 var map = Ap.map;
8
9 function Path(value, parentPath, name) {
10 if (!(this instanceof Path)) {
11 throw new Error("Path constructor cannot be invoked without 'new'");
12 }
13
14 if (parentPath) {
15 if (!(parentPath instanceof Path)) {
16 throw new Error("");
17 }
18 } else {
19 parentPath = null;
20 name = null;
21 }
22
23 // The value encapsulated by this Path, generally equal to
24 // parentPath.value[name] if we have a parentPath.
25 this.value = value;
26
27 // The immediate parent Path of this Path.
28 this.parentPath = parentPath;
29
30 // The name of the property of parentPath.value through which this
31 // Path's value was reached.
32 this.name = name;
33
34 // Calling path.get("child") multiple times always returns the same
35 // child Path object, for both performance and consistency reasons.
36 this.__childCache = null;
37 }
38
39 var Pp = Path.prototype;
40
41 function getChildCache(path) {
42 // Lazily create the child cache. This also cheapens cache
43 // invalidation, since you can just reset path.__childCache to null.
44 return path.__childCache || (path.__childCache = Object.create(null));
45 }
46
47 function getChildPath(path, name) {
48 var cache = getChildCache(path);
49 var actualChildValue = path.getValueProperty(name);
50 var childPath = cache[name];
51 if (!hasOwn.call(cache, name) ||
52 // Ensure consistency between cache and reality.
53 childPath.value !== actualChildValue) {
54 childPath = cache[name] = new path.constructor(
55 actualChildValue, path, name
56 );
57 }
58 return childPath;
59 }
60
61 // This method is designed to be overridden by subclasses that need to
62 // handle missing properties, etc.
63 Pp.getValueProperty = function getValueProperty(name) {
64 return this.value[name];
65 };
66
67 Pp.get = function get(name) {
68 var path = this;
69 var names = arguments;
70 var count = names.length;
71
72 for (var i = 0; i < count; ++i) {
73 path = getChildPath(path, names[i]);
74 }
75
76 return path;
77 };
78
79 Pp.each = function each(callback, context) {
80 var childPaths = [];
81 var len = this.value.length;
82 var i = 0;
83
84 // Collect all the original child paths before invoking the callback.
85 for (var i = 0; i < len; ++i) {
86 if (hasOwn.call(this.value, i)) {
87 childPaths[i] = this.get(i);
88 }
89 }
90
91 // Invoke the callback on just the original child paths, regardless of
92 // any modifications made to the array by the callback. I chose these
93 // semantics over cleverly invoking the callback on new elements because
94 // this way is much easier to reason about.
95 context = context || this;
96 for (i = 0; i < len; ++i) {
97 if (hasOwn.call(childPaths, i)) {
98 callback.call(context, childPaths[i]);
99 }
100 }
101 };
102
103 Pp.map = function map(callback, context) {
104 var result = [];
105
106 this.each(function(childPath) {
107 result.push(callback.call(this, childPath));
108 }, context);
109
110 return result;
111 };
112
113 Pp.filter = function filter(callback, context) {
114 var result = [];
115
116 this.each(function(childPath) {
117 if (callback.call(this, childPath)) {
118 result.push(childPath);
119 }
120 }, context);
121
122 return result;
123 };
124
125 function emptyMoves() {}
126 function getMoves(path, offset, start, end) {
127 isArray.assert(path.value);
128
129 if (offset === 0) {
130 return emptyMoves;
131 }
132
133 var length = path.value.length;
134 if (length < 1) {
135 return emptyMoves;
136 }
137
138 var argc = arguments.length;
139 if (argc === 2) {
140 start = 0;
141 end = length;
142 } else if (argc === 3) {
143 start = Math.max(start, 0);
144 end = length;
145 } else {
146 start = Math.max(start, 0);
147 end = Math.min(end, length);
148 }
149
150 isNumber.assert(start);
151 isNumber.assert(end);
152
153 var moves = Object.create(null);
154 var cache = getChildCache(path);
155
156 for (var i = start; i < end; ++i) {
157 if (hasOwn.call(path.value, i)) {
158 var childPath = path.get(i);
159 if (childPath.name !== i) {
160 throw new Error("");
161 }
162 var newIndex = i + offset;
163 childPath.name = newIndex;
164 moves[newIndex] = childPath;
165 delete cache[i];
166 }
167 }
168
169 delete cache.length;
170
171 return function() {
172 for (var newIndex in moves) {
173 var childPath = moves[newIndex];
174 if (childPath.name !== +newIndex) {
175 throw new Error("");
176 }
177 cache[newIndex] = childPath;
178 path.value[newIndex] = childPath.value;
179 }
180 };
181 }
182
183 Pp.shift = function shift() {
184 var move = getMoves(this, -1);
185 var result = this.value.shift();
186 move();
187 return result;
188 };
189
190 Pp.unshift = function unshift(node) {
191 var move = getMoves(this, arguments.length);
192 var result = this.value.unshift.apply(this.value, arguments);
193 move();
194 return result;
195 };
196
197 Pp.push = function push(node) {
198 isArray.assert(this.value);
199 delete getChildCache(this).length
200 return this.value.push.apply(this.value, arguments);
201 };
202
203 Pp.pop = function pop() {
204 isArray.assert(this.value);
205 var cache = getChildCache(this);
206 delete cache[this.value.length - 1];
207 delete cache.length;
208 return this.value.pop();
209 };
210
211 Pp.insertAt = function insertAt(index, node) {
212 var argc = arguments.length;
213 var move = getMoves(this, argc - 1, index);
214 if (move === emptyMoves) {
215 return this;
216 }
217
218 index = Math.max(index, 0);
219
220 for (var i = 1; i < argc; ++i) {
221 this.value[index + i - 1] = arguments[i];
222 }
223
224 move();
225
226 return this;
227 };
228
229 Pp.insertBefore = function insertBefore(node) {
230 var pp = this.parentPath;
231 var argc = arguments.length;
232 var insertAtArgs = [this.name];
233 for (var i = 0; i < argc; ++i) {
234 insertAtArgs.push(arguments[i]);
235 }
236 return pp.insertAt.apply(pp, insertAtArgs);
237 };
238
239 Pp.insertAfter = function insertAfter(node) {
240 var pp = this.parentPath;
241 var argc = arguments.length;
242 var insertAtArgs = [this.name + 1];
243 for (var i = 0; i < argc; ++i) {
244 insertAtArgs.push(arguments[i]);
245 }
246 return pp.insertAt.apply(pp, insertAtArgs);
247 };
248
249 function repairRelationshipWithParent(path) {
250 if (!(path instanceof Path)) {
251 throw new Error("");
252 }
253
254 var pp = path.parentPath;
255 if (!pp) {
256 // Orphan paths have no relationship to repair.
257 return path;
258 }
259
260 var parentValue = pp.value;
261 var parentCache = getChildCache(pp);
262
263 // Make sure parentCache[path.name] is populated.
264 if (parentValue[path.name] === path.value) {
265 parentCache[path.name] = path;
266 } else if (isArray.check(parentValue)) {
267 // Something caused path.name to become out of date, so attempt to
268 // recover by searching for path.value in parentValue.
269 var i = parentValue.indexOf(path.value);
270 if (i >= 0) {
271 parentCache[path.name = i] = path;
272 }
273 } else {
274 // If path.value disagrees with parentValue[path.name], and
275 // path.name is not an array index, let path.value become the new
276 // parentValue[path.name] and update parentCache accordingly.
277 parentValue[path.name] = path.value;
278 parentCache[path.name] = path;
279 }
280
281 if (parentValue[path.name] !== path.value) {
282 throw new Error("");
283 }
284 if (path.parentPath.get(path.name) !== path) {
285 throw new Error("");
286 }
287
288 return path;
289 }
290
291 Pp.replace = function replace(replacement) {
292 var results = [];
293 var parentValue = this.parentPath.value;
294 var parentCache = getChildCache(this.parentPath);
295 var count = arguments.length;
296
297 repairRelationshipWithParent(this);
298
299 if (isArray.check(parentValue)) {
300 var originalLength = parentValue.length;
301 var move = getMoves(this.parentPath, count - 1, this.name + 1);
302
303 var spliceArgs = [this.name, 1];
304 for (var i = 0; i < count; ++i) {
305 spliceArgs.push(arguments[i]);
306 }
307
308 var splicedOut = parentValue.splice.apply(parentValue, spliceArgs);
309
310 if (splicedOut[0] !== this.value) {
311 throw new Error("");
312 }
313 if (parentValue.length !== (originalLength - 1 + count)) {
314 throw new Error("");
315 }
316
317 move();
318
319 if (count === 0) {
320 delete this.value;
321 delete parentCache[this.name];
322 this.__childCache = null;
323
324 } else {
325 if (parentValue[this.name] !== replacement) {
326 throw new Error("");
327 }
328
329 if (this.value !== replacement) {
330 this.value = replacement;
331 this.__childCache = null;
332 }
333
334 for (i = 0; i < count; ++i) {
335 results.push(this.parentPath.get(this.name + i));
336 }
337
338 if (results[0] !== this) {
339 throw new Error("");
340 }
341 }
342
343 } else if (count === 1) {
344 if (this.value !== replacement) {
345 this.__childCache = null;
346 }
347 this.value = parentValue[this.name] = replacement;
348 results.push(this);
349
350 } else if (count === 0) {
351 delete parentValue[this.name];
352 delete this.value;
353 this.__childCache = null;
354
355 // Leave this path cached as parentCache[this.name], even though
356 // it no longer has a value defined.
357
358 } else {
359 throw new Error("Could not replace path");
360 }
361
362 return results;
363 };
364
365 module.exports = Path;
0 var types = require("./types");
1 var Type = types.Type;
2 var namedTypes = types.namedTypes;
3 var Node = namedTypes.Node;
4 var Expression = namedTypes.Expression;
5 var isArray = types.builtInTypes.array;
6 var hasOwn = Object.prototype.hasOwnProperty;
7 var b = types.builders;
8
9 function Scope(path, parentScope) {
10 if (!(this instanceof Scope)) {
11 throw new Error("Scope constructor cannot be invoked without 'new'");
12 }
13 if (!(path instanceof require("./node-path"))) {
14 throw new Error("");
15 }
16 ScopeType.assert(path.value);
17
18 var depth;
19
20 if (parentScope) {
21 if (!(parentScope instanceof Scope)) {
22 throw new Error("");
23 }
24 depth = parentScope.depth + 1;
25 } else {
26 parentScope = null;
27 depth = 0;
28 }
29
30 Object.defineProperties(this, {
31 path: { value: path },
32 node: { value: path.value },
33 isGlobal: { value: !parentScope, enumerable: true },
34 depth: { value: depth },
35 parent: { value: parentScope },
36 bindings: { value: {} }
37 });
38 }
39
40 var scopeTypes = [
41 // Program nodes introduce global scopes.
42 namedTypes.Program,
43
44 // Function is the supertype of FunctionExpression,
45 // FunctionDeclaration, ArrowExpression, etc.
46 namedTypes.Function,
47
48 // In case you didn't know, the caught parameter shadows any variable
49 // of the same name in an outer scope.
50 namedTypes.CatchClause
51 ];
52
53 var ScopeType = Type.or.apply(Type, scopeTypes);
54
55 Scope.isEstablishedBy = function(node) {
56 return ScopeType.check(node);
57 };
58
59 var Sp = Scope.prototype;
60
61 // Will be overridden after an instance lazily calls scanScope.
62 Sp.didScan = false;
63
64 Sp.declares = function(name) {
65 this.scan();
66 return hasOwn.call(this.bindings, name);
67 };
68
69 Sp.declareTemporary = function(prefix) {
70 if (prefix) {
71 if (!/^[a-z$_]/i.test(prefix)) {
72 throw new Error("");
73 }
74 } else {
75 prefix = "t$";
76 }
77
78 // Include this.depth in the name to make sure the name does not
79 // collide with any variables in nested/enclosing scopes.
80 prefix += this.depth.toString(36) + "$";
81
82 this.scan();
83
84 var index = 0;
85 while (this.declares(prefix + index)) {
86 ++index;
87 }
88
89 var name = prefix + index;
90 return this.bindings[name] = types.builders.identifier(name);
91 };
92
93 Sp.injectTemporary = function(identifier, init) {
94 identifier || (identifier = this.declareTemporary());
95
96 var bodyPath = this.path.get("body");
97 if (namedTypes.BlockStatement.check(bodyPath.value)) {
98 bodyPath = bodyPath.get("body");
99 }
100
101 bodyPath.unshift(
102 b.variableDeclaration(
103 "var",
104 [b.variableDeclarator(identifier, init || null)]
105 )
106 );
107
108 return identifier;
109 };
110
111 Sp.scan = function(force) {
112 if (force || !this.didScan) {
113 for (var name in this.bindings) {
114 // Empty out this.bindings, just in cases.
115 delete this.bindings[name];
116 }
117 scanScope(this.path, this.bindings);
118 this.didScan = true;
119 }
120 };
121
122 Sp.getBindings = function () {
123 this.scan();
124 return this.bindings;
125 };
126
127 function scanScope(path, bindings) {
128 var node = path.value;
129 ScopeType.assert(node);
130
131 if (namedTypes.CatchClause.check(node)) {
132 // A catch clause establishes a new scope but the only variable
133 // bound in that scope is the catch parameter. Any other
134 // declarations create bindings in the outer scope.
135 addPattern(path.get("param"), bindings);
136
137 } else {
138 recursiveScanScope(path, bindings);
139 }
140 }
141
142 function recursiveScanScope(path, bindings) {
143 var node = path.value;
144
145 if (path.parent &&
146 namedTypes.FunctionExpression.check(path.parent.node) &&
147 path.parent.node.id) {
148 addPattern(path.parent.get("id"), bindings);
149 }
150
151 if (!node) {
152 // None of the remaining cases matter if node is falsy.
153
154 } else if (isArray.check(node)) {
155 path.each(function(childPath) {
156 recursiveScanChild(childPath, bindings);
157 });
158
159 } else if (namedTypes.Function.check(node)) {
160 path.get("params").each(function(paramPath) {
161 addPattern(paramPath, bindings);
162 });
163
164 recursiveScanChild(path.get("body"), bindings);
165
166 } else if (namedTypes.VariableDeclarator.check(node)) {
167 addPattern(path.get("id"), bindings);
168 recursiveScanChild(path.get("init"), bindings);
169
170 } else if (node.type === "ImportSpecifier" ||
171 node.type === "ImportNamespaceSpecifier" ||
172 node.type === "ImportDefaultSpecifier") {
173 addPattern(
174 // Esprima used to use the .name field to refer to the local
175 // binding identifier for ImportSpecifier nodes, but .id for
176 // ImportNamespaceSpecifier and ImportDefaultSpecifier nodes.
177 // ESTree/Acorn/ESpree use .local for all three node types.
178 path.get(node.local ? "local" :
179 node.name ? "name" : "id"),
180 bindings
181 );
182
183 } else if (Node.check(node) && !Expression.check(node)) {
184 types.eachField(node, function(name, child) {
185 var childPath = path.get(name);
186 if (childPath.value !== child) {
187 throw new Error("");
188 }
189 recursiveScanChild(childPath, bindings);
190 });
191 }
192 }
193
194 function recursiveScanChild(path, bindings) {
195 var node = path.value;
196
197 if (!node || Expression.check(node)) {
198 // Ignore falsy values and Expressions.
199
200 } else if (namedTypes.FunctionDeclaration.check(node)) {
201 addPattern(path.get("id"), bindings);
202
203 } else if (namedTypes.ClassDeclaration &&
204 namedTypes.ClassDeclaration.check(node)) {
205 addPattern(path.get("id"), bindings);
206
207 } else if (ScopeType.check(node)) {
208 if (namedTypes.CatchClause.check(node)) {
209 var catchParamName = node.param.name;
210 var hadBinding = hasOwn.call(bindings, catchParamName);
211
212 // Any declarations that occur inside the catch body that do
213 // not have the same name as the catch parameter should count
214 // as bindings in the outer scope.
215 recursiveScanScope(path.get("body"), bindings);
216
217 // If a new binding matching the catch parameter name was
218 // created while scanning the catch body, ignore it because it
219 // actually refers to the catch parameter and not the outer
220 // scope that we're currently scanning.
221 if (!hadBinding) {
222 delete bindings[catchParamName];
223 }
224 }
225
226 } else {
227 recursiveScanScope(path, bindings);
228 }
229 }
230
231 function addPattern(patternPath, bindings) {
232 var pattern = patternPath.value;
233 namedTypes.Pattern.assert(pattern);
234
235 if (namedTypes.Identifier.check(pattern)) {
236 if (hasOwn.call(bindings, pattern.name)) {
237 bindings[pattern.name].push(patternPath);
238 } else {
239 bindings[pattern.name] = [patternPath];
240 }
241
242 } else if (namedTypes.ObjectPattern &&
243 namedTypes.ObjectPattern.check(pattern)) {
244 patternPath.get('properties').each(function(propertyPath) {
245 var property = propertyPath.value;
246 if (namedTypes.Pattern.check(property)) {
247 addPattern(propertyPath, bindings);
248 } else if (namedTypes.Property.check(property)) {
249 addPattern(propertyPath.get('value'), bindings);
250 } else if (namedTypes.SpreadProperty &&
251 namedTypes.SpreadProperty.check(property)) {
252 addPattern(propertyPath.get('argument'), bindings);
253 }
254 });
255
256 } else if (namedTypes.ArrayPattern &&
257 namedTypes.ArrayPattern.check(pattern)) {
258 patternPath.get('elements').each(function(elementPath) {
259 var element = elementPath.value;
260 if (namedTypes.Pattern.check(element)) {
261 addPattern(elementPath, bindings);
262 } else if (namedTypes.SpreadElement &&
263 namedTypes.SpreadElement.check(element)) {
264 addPattern(elementPath.get("argument"), bindings);
265 }
266 });
267
268 } else if (namedTypes.PropertyPattern &&
269 namedTypes.PropertyPattern.check(pattern)) {
270 addPattern(patternPath.get('pattern'), bindings);
271
272 } else if ((namedTypes.SpreadElementPattern &&
273 namedTypes.SpreadElementPattern.check(pattern)) ||
274 (namedTypes.SpreadPropertyPattern &&
275 namedTypes.SpreadPropertyPattern.check(pattern))) {
276 addPattern(patternPath.get('argument'), bindings);
277 }
278 }
279
280 Sp.lookup = function(name) {
281 for (var scope = this; scope; scope = scope.parent)
282 if (scope.declares(name))
283 break;
284 return scope;
285 };
286
287 Sp.getGlobalScope = function() {
288 var scope = this;
289 while (!scope.isGlobal)
290 scope = scope.parent;
291 return scope;
292 };
293
294 module.exports = Scope;
0 var types = require("../lib/types");
1 var Type = types.Type;
2 var builtin = types.builtInTypes;
3 var isNumber = builtin.number;
4
5 // An example of constructing a new type with arbitrary constraints from
6 // an existing type.
7 exports.geq = function(than) {
8 return new Type(function(value) {
9 return isNumber.check(value) && value >= than;
10 }, isNumber + " >= " + than);
11 };
12
13 // Default value-returning functions that may optionally be passed as a
14 // third argument to Def.prototype.field.
15 exports.defaults = {
16 // Functions were used because (among other reasons) that's the most
17 // elegant way to allow for the emptyArray one always to give a new
18 // array instance.
19 "null": function() { return null },
20 "emptyArray": function() { return [] },
21 "false": function() { return false },
22 "true": function() { return true },
23 "undefined": function() {}
24 };
25
26 var naiveIsPrimitive = Type.or(
27 builtin.string,
28 builtin.number,
29 builtin.boolean,
30 builtin.null,
31 builtin.undefined
32 );
33
34 exports.isPrimitive = new Type(function(value) {
35 if (value === null)
36 return true;
37 var type = typeof value;
38 return !(type === "object" ||
39 type === "function");
40 }, naiveIsPrimitive.toString());
0 var Ap = Array.prototype;
1 var slice = Ap.slice;
2 var map = Ap.map;
3 var each = Ap.forEach;
4 var Op = Object.prototype;
5 var objToStr = Op.toString;
6 var funObjStr = objToStr.call(function(){});
7 var strObjStr = objToStr.call("");
8 var hasOwn = Op.hasOwnProperty;
9
10 // A type is an object with a .check method that takes a value and returns
11 // true or false according to whether the value matches the type.
12
13 function Type(check, name) {
14 var self = this;
15 if (!(self instanceof Type)) {
16 throw new Error("Type constructor cannot be invoked without 'new'");
17 }
18
19 // Unfortunately we can't elegantly reuse isFunction and isString,
20 // here, because this code is executed while defining those types.
21 if (objToStr.call(check) !== funObjStr) {
22 throw new Error(check + " is not a function");
23 }
24
25 // The `name` parameter can be either a function or a string.
26 var nameObjStr = objToStr.call(name);
27 if (!(nameObjStr === funObjStr ||
28 nameObjStr === strObjStr)) {
29 throw new Error(name + " is neither a function nor a string");
30 }
31
32 Object.defineProperties(self, {
33 name: { value: name },
34 check: {
35 value: function(value, deep) {
36 var result = check.call(self, value, deep);
37 if (!result && deep && objToStr.call(deep) === funObjStr)
38 deep(self, value);
39 return result;
40 }
41 }
42 });
43 }
44
45 var Tp = Type.prototype;
46
47 // Throughout this file we use Object.defineProperty to prevent
48 // redefinition of exported properties.
49 exports.Type = Type;
50
51 // Like .check, except that failure triggers an AssertionError.
52 Tp.assert = function(value, deep) {
53 if (!this.check(value, deep)) {
54 var str = shallowStringify(value);
55 throw new Error(str + " does not match type " + this);
56 }
57 return true;
58 };
59
60 function shallowStringify(value) {
61 if (isObject.check(value))
62 return "{" + Object.keys(value).map(function(key) {
63 return key + ": " + value[key];
64 }).join(", ") + "}";
65
66 if (isArray.check(value))
67 return "[" + value.map(shallowStringify).join(", ") + "]";
68
69 return JSON.stringify(value);
70 }
71
72 Tp.toString = function() {
73 var name = this.name;
74
75 if (isString.check(name))
76 return name;
77
78 if (isFunction.check(name))
79 return name.call(this) + "";
80
81 return name + " type";
82 };
83
84 var builtInCtorFns = [];
85 var builtInCtorTypes = [];
86 var builtInTypes = {};
87 exports.builtInTypes = builtInTypes;
88
89 function defBuiltInType(example, name) {
90 var objStr = objToStr.call(example);
91
92 var type = new Type(function(value) {
93 return objToStr.call(value) === objStr;
94 }, name);
95
96 builtInTypes[name] = type;
97
98 if (example && typeof example.constructor === "function") {
99 builtInCtorFns.push(example.constructor);
100 builtInCtorTypes.push(type);
101 }
102
103 return type;
104 }
105
106 // These types check the underlying [[Class]] attribute of the given
107 // value, rather than using the problematic typeof operator. Note however
108 // that no subtyping is considered; so, for instance, isObject.check
109 // returns false for [], /./, new Date, and null.
110 var isString = defBuiltInType("truthy", "string");
111 var isFunction = defBuiltInType(function(){}, "function");
112 var isArray = defBuiltInType([], "array");
113 var isObject = defBuiltInType({}, "object");
114 var isRegExp = defBuiltInType(/./, "RegExp");
115 var isDate = defBuiltInType(new Date, "Date");
116 var isNumber = defBuiltInType(3, "number");
117 var isBoolean = defBuiltInType(true, "boolean");
118 var isNull = defBuiltInType(null, "null");
119 var isUndefined = defBuiltInType(void 0, "undefined");
120
121 // There are a number of idiomatic ways of expressing types, so this
122 // function serves to coerce them all to actual Type objects. Note that
123 // providing the name argument is not necessary in most cases.
124 function toType(from, name) {
125 // The toType function should of course be idempotent.
126 if (from instanceof Type)
127 return from;
128
129 // The Def type is used as a helper for constructing compound
130 // interface types for AST nodes.
131 if (from instanceof Def)
132 return from.type;
133
134 // Support [ElemType] syntax.
135 if (isArray.check(from))
136 return Type.fromArray(from);
137
138 // Support { someField: FieldType, ... } syntax.
139 if (isObject.check(from))
140 return Type.fromObject(from);
141
142 if (isFunction.check(from)) {
143 var bicfIndex = builtInCtorFns.indexOf(from);
144 if (bicfIndex >= 0) {
145 return builtInCtorTypes[bicfIndex];
146 }
147
148 // If isFunction.check(from), and from is not a built-in
149 // constructor, assume from is a binary predicate function we can
150 // use to define the type.
151 return new Type(from, name);
152 }
153
154 // As a last resort, toType returns a type that matches any value that
155 // is === from. This is primarily useful for literal values like
156 // toType(null), but it has the additional advantage of allowing
157 // toType to be a total function.
158 return new Type(function(value) {
159 return value === from;
160 }, isUndefined.check(name) ? function() {
161 return from + "";
162 } : name);
163 }
164
165 // Returns a type that matches the given value iff any of type1, type2,
166 // etc. match the value.
167 Type.or = function(/* type1, type2, ... */) {
168 var types = [];
169 var len = arguments.length;
170 for (var i = 0; i < len; ++i)
171 types.push(toType(arguments[i]));
172
173 return new Type(function(value, deep) {
174 for (var i = 0; i < len; ++i)
175 if (types[i].check(value, deep))
176 return true;
177 return false;
178 }, function() {
179 return types.join(" | ");
180 });
181 };
182
183 Type.fromArray = function(arr) {
184 if (!isArray.check(arr)) {
185 throw new Error("");
186 }
187 if (arr.length !== 1) {
188 throw new Error("only one element type is permitted for typed arrays");
189 }
190 return toType(arr[0]).arrayOf();
191 };
192
193 Tp.arrayOf = function() {
194 var elemType = this;
195 return new Type(function(value, deep) {
196 return isArray.check(value) && value.every(function(elem) {
197 return elemType.check(elem, deep);
198 });
199 }, function() {
200 return "[" + elemType + "]";
201 });
202 };
203
204 Type.fromObject = function(obj) {
205 var fields = Object.keys(obj).map(function(name) {
206 return new Field(name, obj[name]);
207 });
208
209 return new Type(function(value, deep) {
210 return isObject.check(value) && fields.every(function(field) {
211 return field.type.check(value[field.name], deep);
212 });
213 }, function() {
214 return "{ " + fields.join(", ") + " }";
215 });
216 };
217
218 function Field(name, type, defaultFn, hidden) {
219 var self = this;
220
221 if (!(self instanceof Field)) {
222 throw new Error("Field constructor cannot be invoked without 'new'");
223 }
224 isString.assert(name);
225
226 type = toType(type);
227
228 var properties = {
229 name: { value: name },
230 type: { value: type },
231 hidden: { value: !!hidden }
232 };
233
234 if (isFunction.check(defaultFn)) {
235 properties.defaultFn = { value: defaultFn };
236 }
237
238 Object.defineProperties(self, properties);
239 }
240
241 var Fp = Field.prototype;
242
243 Fp.toString = function() {
244 return JSON.stringify(this.name) + ": " + this.type;
245 };
246
247 Fp.getValue = function(obj) {
248 var value = obj[this.name];
249
250 if (!isUndefined.check(value))
251 return value;
252
253 if (this.defaultFn)
254 value = this.defaultFn.call(obj);
255
256 return value;
257 };
258
259 // Define a type whose name is registered in a namespace (the defCache) so
260 // that future definitions will return the same type given the same name.
261 // In particular, this system allows for circular and forward definitions.
262 // The Def object d returned from Type.def may be used to configure the
263 // type d.type by calling methods such as d.bases, d.build, and d.field.
264 Type.def = function(typeName) {
265 isString.assert(typeName);
266 return hasOwn.call(defCache, typeName)
267 ? defCache[typeName]
268 : defCache[typeName] = new Def(typeName);
269 };
270
271 // In order to return the same Def instance every time Type.def is called
272 // with a particular name, those instances need to be stored in a cache.
273 var defCache = Object.create(null);
274
275 function Def(typeName) {
276 var self = this;
277 if (!(self instanceof Def)) {
278 throw new Error("Def constructor cannot be invoked without 'new'");
279 }
280
281 Object.defineProperties(self, {
282 typeName: { value: typeName },
283 baseNames: { value: [] },
284 ownFields: { value: Object.create(null) },
285
286 // These two are populated during finalization.
287 allSupertypes: { value: Object.create(null) }, // Includes own typeName.
288 supertypeList: { value: [] }, // Linear inheritance hierarchy.
289 allFields: { value: Object.create(null) }, // Includes inherited fields.
290 fieldNames: { value: [] }, // Non-hidden keys of allFields.
291
292 type: {
293 value: new Type(function(value, deep) {
294 return self.check(value, deep);
295 }, typeName)
296 }
297 });
298 }
299
300 Def.fromValue = function(value) {
301 if (value && typeof value === "object") {
302 var type = value.type;
303 if (typeof type === "string" &&
304 hasOwn.call(defCache, type)) {
305 var d = defCache[type];
306 if (d.finalized) {
307 return d;
308 }
309 }
310 }
311
312 return null;
313 };
314
315 var Dp = Def.prototype;
316
317 Dp.isSupertypeOf = function(that) {
318 if (that instanceof Def) {
319 if (this.finalized !== true ||
320 that.finalized !== true) {
321 throw new Error("");
322 }
323 return hasOwn.call(that.allSupertypes, this.typeName);
324 } else {
325 throw new Error(that + " is not a Def");
326 }
327 };
328
329 // Note that the list returned by this function is a copy of the internal
330 // supertypeList, *without* the typeName itself as the first element.
331 exports.getSupertypeNames = function(typeName) {
332 if (!hasOwn.call(defCache, typeName)) {
333 throw new Error("");
334 }
335 var d = defCache[typeName];
336 if (d.finalized !== true) {
337 throw new Error("");
338 }
339 return d.supertypeList.slice(1);
340 };
341
342 // Returns an object mapping from every known type in the defCache to the
343 // most specific supertype whose name is an own property of the candidates
344 // object.
345 exports.computeSupertypeLookupTable = function(candidates) {
346 var table = {};
347 var typeNames = Object.keys(defCache);
348 var typeNameCount = typeNames.length;
349
350 for (var i = 0; i < typeNameCount; ++i) {
351 var typeName = typeNames[i];
352 var d = defCache[typeName];
353 if (d.finalized !== true) {
354 throw new Error("" + typeName);
355 }
356 for (var j = 0; j < d.supertypeList.length; ++j) {
357 var superTypeName = d.supertypeList[j];
358 if (hasOwn.call(candidates, superTypeName)) {
359 table[typeName] = superTypeName;
360 break;
361 }
362 }
363 }
364
365 return table;
366 };
367
368 Dp.checkAllFields = function(value, deep) {
369 var allFields = this.allFields;
370 if (this.finalized !== true) {
371 throw new Error("" + this.typeName);
372 }
373
374 function checkFieldByName(name) {
375 var field = allFields[name];
376 var type = field.type;
377 var child = field.getValue(value);
378 return type.check(child, deep);
379 }
380
381 return isObject.check(value)
382 && Object.keys(allFields).every(checkFieldByName);
383 };
384
385 Dp.check = function(value, deep) {
386 if (this.finalized !== true) {
387 throw new Error(
388 "prematurely checking unfinalized type " + this.typeName
389 );
390 }
391
392 // A Def type can only match an object value.
393 if (!isObject.check(value))
394 return false;
395
396 var vDef = Def.fromValue(value);
397 if (!vDef) {
398 // If we couldn't infer the Def associated with the given value,
399 // and we expected it to be a SourceLocation or a Position, it was
400 // probably just missing a "type" field (because Esprima does not
401 // assign a type property to such nodes). Be optimistic and let
402 // this.checkAllFields make the final decision.
403 if (this.typeName === "SourceLocation" ||
404 this.typeName === "Position") {
405 return this.checkAllFields(value, deep);
406 }
407
408 // Calling this.checkAllFields for any other type of node is both
409 // bad for performance and way too forgiving.
410 return false;
411 }
412
413 // If checking deeply and vDef === this, then we only need to call
414 // checkAllFields once. Calling checkAllFields is too strict when deep
415 // is false, because then we only care about this.isSupertypeOf(vDef).
416 if (deep && vDef === this)
417 return this.checkAllFields(value, deep);
418
419 // In most cases we rely exclusively on isSupertypeOf to make O(1)
420 // subtyping determinations. This suffices in most situations outside
421 // of unit tests, since interface conformance is checked whenever new
422 // instances are created using builder functions.
423 if (!this.isSupertypeOf(vDef))
424 return false;
425
426 // The exception is when deep is true; then, we recursively check all
427 // fields.
428 if (!deep)
429 return true;
430
431 // Use the more specific Def (vDef) to perform the deep check, but
432 // shallow-check fields defined by the less specific Def (this).
433 return vDef.checkAllFields(value, deep)
434 && this.checkAllFields(value, false);
435 };
436
437 Dp.bases = function() {
438 var args = slice.call(arguments);
439 var bases = this.baseNames;
440
441 if (this.finalized) {
442 if (args.length !== bases.length) {
443 throw new Error("");
444 }
445 for (var i = 0; i < args.length; i++) {
446 if (args[i] !== bases[i]) {
447 throw new Error("");
448 }
449 }
450 return this;
451 }
452
453 args.forEach(function(baseName) {
454 isString.assert(baseName);
455
456 // This indexOf lookup may be O(n), but the typical number of base
457 // names is very small, and indexOf is a native Array method.
458 if (bases.indexOf(baseName) < 0)
459 bases.push(baseName);
460 });
461
462 return this; // For chaining.
463 };
464
465 // False by default until .build(...) is called on an instance.
466 Object.defineProperty(Dp, "buildable", { value: false });
467
468 var builders = {};
469 exports.builders = builders;
470
471 // This object is used as prototype for any node created by a builder.
472 var nodePrototype = {};
473
474 // Call this function to define a new method to be shared by all AST
475 // nodes. The replaced method (if any) is returned for easy wrapping.
476 exports.defineMethod = function(name, func) {
477 var old = nodePrototype[name];
478
479 // Pass undefined as func to delete nodePrototype[name].
480 if (isUndefined.check(func)) {
481 delete nodePrototype[name];
482
483 } else {
484 isFunction.assert(func);
485
486 Object.defineProperty(nodePrototype, name, {
487 enumerable: true, // For discoverability.
488 configurable: true, // For delete proto[name].
489 value: func
490 });
491 }
492
493 return old;
494 };
495
496 var isArrayOfString = isString.arrayOf();
497
498 // Calling the .build method of a Def simultaneously marks the type as
499 // buildable (by defining builders[getBuilderName(typeName)]) and
500 // specifies the order of arguments that should be passed to the builder
501 // function to create an instance of the type.
502 Dp.build = function(/* param1, param2, ... */) {
503 var self = this;
504
505 var newBuildParams = slice.call(arguments);
506 isArrayOfString.assert(newBuildParams);
507
508 // Calling Def.prototype.build multiple times has the effect of merely
509 // redefining this property.
510 Object.defineProperty(self, "buildParams", {
511 value: newBuildParams,
512 writable: false,
513 enumerable: false,
514 configurable: true
515 });
516
517 if (self.buildable) {
518 // If this Def is already buildable, update self.buildParams and
519 // continue using the old builder function.
520 return self;
521 }
522
523 // Every buildable type will have its "type" field filled in
524 // automatically. This includes types that are not subtypes of Node,
525 // like SourceLocation, but that seems harmless (TODO?).
526 self.field("type", String, function() { return self.typeName });
527
528 // Override Dp.buildable for this Def instance.
529 Object.defineProperty(self, "buildable", { value: true });
530
531 Object.defineProperty(builders, getBuilderName(self.typeName), {
532 enumerable: true,
533
534 value: function() {
535 var args = arguments;
536 var argc = args.length;
537 var built = Object.create(nodePrototype);
538
539 if (!self.finalized) {
540 throw new Error(
541 "attempting to instantiate unfinalized type " +
542 self.typeName
543 );
544 }
545
546 function add(param, i) {
547 if (hasOwn.call(built, param))
548 return;
549
550 var all = self.allFields;
551 if (!hasOwn.call(all, param)) {
552 throw new Error("" + param);
553 }
554
555 var field = all[param];
556 var type = field.type;
557 var value;
558
559 if (isNumber.check(i) && i < argc) {
560 value = args[i];
561 } else if (field.defaultFn) {
562 // Expose the partially-built object to the default
563 // function as its `this` object.
564 value = field.defaultFn.call(built);
565 } else {
566 var message = "no value or default function given for field " +
567 JSON.stringify(param) + " of " + self.typeName + "(" +
568 self.buildParams.map(function(name) {
569 return all[name];
570 }).join(", ") + ")";
571 throw new Error(message);
572 }
573
574 if (!type.check(value)) {
575 throw new Error(
576 shallowStringify(value) +
577 " does not match field " + field +
578 " of type " + self.typeName
579 );
580 }
581
582 // TODO Could attach getters and setters here to enforce
583 // dynamic type safety.
584 built[param] = value;
585 }
586
587 self.buildParams.forEach(function(param, i) {
588 add(param, i);
589 });
590
591 Object.keys(self.allFields).forEach(function(param) {
592 add(param); // Use the default value.
593 });
594
595 // Make sure that the "type" field was filled automatically.
596 if (built.type !== self.typeName) {
597 throw new Error("");
598 }
599
600 return built;
601 }
602 });
603
604 return self; // For chaining.
605 };
606
607 function getBuilderName(typeName) {
608 return typeName.replace(/^[A-Z]+/, function(upperCasePrefix) {
609 var len = upperCasePrefix.length;
610 switch (len) {
611 case 0: return "";
612 // If there's only one initial capital letter, just lower-case it.
613 case 1: return upperCasePrefix.toLowerCase();
614 default:
615 // If there's more than one initial capital letter, lower-case
616 // all but the last one, so that XMLDefaultDeclaration (for
617 // example) becomes xmlDefaultDeclaration.
618 return upperCasePrefix.slice(
619 0, len - 1).toLowerCase() +
620 upperCasePrefix.charAt(len - 1);
621 }
622 });
623 }
624 exports.getBuilderName = getBuilderName;
625
626 function getStatementBuilderName(typeName) {
627 typeName = getBuilderName(typeName);
628 return typeName.replace(/(Expression)?$/, "Statement");
629 }
630 exports.getStatementBuilderName = getStatementBuilderName;
631
632 // The reason fields are specified using .field(...) instead of an object
633 // literal syntax is somewhat subtle: the object literal syntax would
634 // support only one key and one value, but with .field(...) we can pass
635 // any number of arguments to specify the field.
636 Dp.field = function(name, type, defaultFn, hidden) {
637 if (this.finalized) {
638 console.error("Ignoring attempt to redefine field " +
639 JSON.stringify(name) + " of finalized type " +
640 JSON.stringify(this.typeName));
641 return this;
642 }
643 this.ownFields[name] = new Field(name, type, defaultFn, hidden);
644 return this; // For chaining.
645 };
646
647 var namedTypes = {};
648 exports.namedTypes = namedTypes;
649
650 // Like Object.keys, but aware of what fields each AST type should have.
651 function getFieldNames(object) {
652 var d = Def.fromValue(object);
653 if (d) {
654 return d.fieldNames.slice(0);
655 }
656
657 if ("type" in object) {
658 throw new Error(
659 "did not recognize object of type " +
660 JSON.stringify(object.type)
661 );
662 }
663
664 return Object.keys(object);
665 }
666 exports.getFieldNames = getFieldNames;
667
668 // Get the value of an object property, taking object.type and default
669 // functions into account.
670 function getFieldValue(object, fieldName) {
671 var d = Def.fromValue(object);
672 if (d) {
673 var field = d.allFields[fieldName];
674 if (field) {
675 return field.getValue(object);
676 }
677 }
678
679 return object[fieldName];
680 }
681 exports.getFieldValue = getFieldValue;
682
683 // Iterate over all defined fields of an object, including those missing
684 // or undefined, passing each field name and effective value (as returned
685 // by getFieldValue) to the callback. If the object has no corresponding
686 // Def, the callback will never be called.
687 exports.eachField = function(object, callback, context) {
688 getFieldNames(object).forEach(function(name) {
689 callback.call(this, name, getFieldValue(object, name));
690 }, context);
691 };
692
693 // Similar to eachField, except that iteration stops as soon as the
694 // callback returns a truthy value. Like Array.prototype.some, the final
695 // result is either true or false to indicates whether the callback
696 // returned true for any element or not.
697 exports.someField = function(object, callback, context) {
698 return getFieldNames(object).some(function(name) {
699 return callback.call(this, name, getFieldValue(object, name));
700 }, context);
701 };
702
703 // This property will be overridden as true by individual Def instances
704 // when they are finalized.
705 Object.defineProperty(Dp, "finalized", { value: false });
706
707 Dp.finalize = function() {
708 var self = this;
709
710 // It's not an error to finalize a type more than once, but only the
711 // first call to .finalize does anything.
712 if (!self.finalized) {
713 var allFields = self.allFields;
714 var allSupertypes = self.allSupertypes;
715
716 self.baseNames.forEach(function(name) {
717 var def = defCache[name];
718 if (def instanceof Def) {
719 def.finalize();
720 extend(allFields, def.allFields);
721 extend(allSupertypes, def.allSupertypes);
722 } else {
723 var message = "unknown supertype name " +
724 JSON.stringify(name) +
725 " for subtype " +
726 JSON.stringify(self.typeName);
727 throw new Error(message);
728 }
729 });
730
731 // TODO Warn if fields are overridden with incompatible types.
732 extend(allFields, self.ownFields);
733 allSupertypes[self.typeName] = self;
734
735 self.fieldNames.length = 0;
736 for (var fieldName in allFields) {
737 if (hasOwn.call(allFields, fieldName) &&
738 !allFields[fieldName].hidden) {
739 self.fieldNames.push(fieldName);
740 }
741 }
742
743 // Types are exported only once they have been finalized.
744 Object.defineProperty(namedTypes, self.typeName, {
745 enumerable: true,
746 value: self.type
747 });
748
749 Object.defineProperty(self, "finalized", { value: true });
750
751 // A linearization of the inheritance hierarchy.
752 populateSupertypeList(self.typeName, self.supertypeList);
753
754 if (self.buildable && self.supertypeList.lastIndexOf("Expression") >= 0) {
755 wrapExpressionBuilderWithStatement(self.typeName);
756 }
757 }
758 };
759
760 // Adds an additional builder for Expression subtypes
761 // that wraps the built Expression in an ExpressionStatements.
762 function wrapExpressionBuilderWithStatement(typeName) {
763 var wrapperName = getStatementBuilderName(typeName);
764
765 // skip if the builder already exists
766 if (builders[wrapperName]) return;
767
768 // the builder function to wrap with builders.ExpressionStatement
769 var wrapped = builders[getBuilderName(typeName)];
770
771 // skip if there is nothing to wrap
772 if (!wrapped) return;
773
774 builders[wrapperName] = function() {
775 return builders.expressionStatement(wrapped.apply(builders, arguments));
776 };
777 }
778
779 function populateSupertypeList(typeName, list) {
780 list.length = 0;
781 list.push(typeName);
782
783 var lastSeen = Object.create(null);
784
785 for (var pos = 0; pos < list.length; ++pos) {
786 typeName = list[pos];
787 var d = defCache[typeName];
788 if (d.finalized !== true) {
789 throw new Error("");
790 }
791
792 // If we saw typeName earlier in the breadth-first traversal,
793 // delete the last-seen occurrence.
794 if (hasOwn.call(lastSeen, typeName)) {
795 delete list[lastSeen[typeName]];
796 }
797
798 // Record the new index of the last-seen occurrence of typeName.
799 lastSeen[typeName] = pos;
800
801 // Enqueue the base names of this type.
802 list.push.apply(list, d.baseNames);
803 }
804
805 // Compaction loop to remove array holes.
806 for (var to = 0, from = to, len = list.length; from < len; ++from) {
807 if (hasOwn.call(list, from)) {
808 list[to++] = list[from];
809 }
810 }
811
812 list.length = to;
813 }
814
815 function extend(into, from) {
816 Object.keys(from).forEach(function(name) {
817 into[name] = from[name];
818 });
819
820 return into;
821 };
822
823 exports.finalize = function() {
824 Object.keys(defCache).forEach(function(name) {
825 defCache[name].finalize();
826 });
827 };
0 var types = require("./lib/types");
1
2 // This core module of AST types captures ES5 as it is parsed today by
3 // git://github.com/ariya/esprima.git#master.
4 require("./def/core");
5
6 // Feel free to add to or remove from this list of extension modules to
7 // configure the precise type hierarchy that you need.
8 require("./def/es6");
9 require("./def/es7");
10 require("./def/mozilla");
11 require("./def/e4x");
12 require("./def/fb-harmony");
13 require("./def/esprima");
14 require("./def/babel");
15
16 types.finalize();
17
18 exports.Type = types.Type;
19 exports.builtInTypes = types.builtInTypes;
20 exports.namedTypes = types.namedTypes;
21 exports.builders = types.builders;
22 exports.defineMethod = types.defineMethod;
23 exports.getFieldNames = types.getFieldNames;
24 exports.getFieldValue = types.getFieldValue;
25 exports.eachField = types.eachField;
26 exports.someField = types.someField;
27 exports.getSupertypeNames = types.getSupertypeNames;
28 exports.astNodesAreEquivalent = require("./lib/equiv");
29 exports.finalize = types.finalize;
30 exports.NodePath = require("./lib/node-path");
31 exports.PathVisitor = require("./lib/path-visitor");
32 exports.visit = exports.PathVisitor.visit;
0 {
1 "author": "Ben Newman <bn@cs.stanford.edu>",
2 "name": "ast-types",
3 "description": "Esprima-compatible implementation of the Mozilla JS Parser API",
4 "keywords": [
5 "ast",
6 "abstract syntax tree",
7 "hierarchy",
8 "mozilla",
9 "spidermonkey",
10 "parser api",
11 "esprima",
12 "types",
13 "type system",
14 "type checking",
15 "dynamic types",
16 "parsing",
17 "transformation",
18 "syntax"
19 ],
20 "version": "0.8.13",
21 "homepage": "http://github.com/benjamn/ast-types",
22 "repository": {
23 "type": "git",
24 "url": "git://github.com/benjamn/ast-types.git"
25 },
26 "license": "MIT",
27 "main": "main.js",
28 "scripts": {
29 "test": "mocha --reporter spec --full-trace test/run.js"
30 },
31 "dependencies": {},
32 "devDependencies": {
33 "babel-core": "^5.6.15",
34 "esprima": "~1.2.2",
35 "esprima-fb": "~14001.1.0-dev-harmony-fb",
36 "mocha": "~2.2.5"
37 },
38 "engines": {
39 "node": ">= 0.8"
40 }
41 }
0 // Backbone.js 1.0.0
1
2 // (c) 2010-2013 Jeremy Ashkenas, DocumentCloud Inc.
3 // (c) 2011-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
4 // Backbone may be freely distributed under the MIT license.
5 // For all details and documentation:
6 // http://backbonejs.org
7
8 (function(){
9
10 // Initial Setup
11 // -------------
12
13 // Save a reference to the global object (`window` in the browser, `exports`
14 // on the server).
15 var root = this;
16
17 // Save the previous value of the `Backbone` variable, so that it can be
18 // restored later on, if `noConflict` is used.
19 var previousBackbone = root.Backbone;
20
21 // Create local references to array methods we'll want to use later.
22 var array = [];
23 var push = array.push;
24 var slice = array.slice;
25 var splice = array.splice;
26
27 // The top-level namespace. All public Backbone classes and modules will
28 // be attached to this. Exported for both the browser and the server.
29 var Backbone;
30 if (typeof exports !== 'undefined') {
31 Backbone = exports;
32 } else {
33 Backbone = root.Backbone = {};
34 }
35
36 // Current version of the library. Keep in sync with `package.json`.
37 Backbone.VERSION = '1.0.0';
38
39 // Require Underscore, if we're on the server, and it's not already present.
40 var _ = root._;
41 if (!_ && (typeof require !== 'undefined')) _ = require('underscore');
42
43 // For Backbone's purposes, jQuery, Zepto, Ender, or My Library (kidding) owns
44 // the `$` variable.
45 Backbone.$ = root.jQuery || root.Zepto || root.ender || root.$;
46
47 // Runs Backbone.js in *noConflict* mode, returning the `Backbone` variable
48 // to its previous owner. Returns a reference to this Backbone object.
49 Backbone.noConflict = function() {
50 root.Backbone = previousBackbone;
51 return this;
52 };
53
54 // Turn on `emulateHTTP` to support legacy HTTP servers. Setting this option
55 // will fake `"PUT"` and `"DELETE"` requests via the `_method` parameter and
56 // set a `X-Http-Method-Override` header.
57 Backbone.emulateHTTP = false;
58
59 // Turn on `emulateJSON` to support legacy servers that can't deal with direct
60 // `application/json` requests ... will encode the body as
61 // `application/x-www-form-urlencoded` instead and will send the model in a
62 // form param named `model`.
63 Backbone.emulateJSON = false;
64
65 // Backbone.Events
66 // ---------------
67
68 // A module that can be mixed in to *any object* in order to provide it with
69 // custom events. You may bind with `on` or remove with `off` callback
70 // functions to an event; `trigger`-ing an event fires all callbacks in
71 // succession.
72 //
73 // var object = {};
74 // _.extend(object, Backbone.Events);
75 // object.on('expand', function(){ alert('expanded'); });
76 // object.trigger('expand');
77 //
78 var Events = Backbone.Events = {
79
80 // Bind an event to a `callback` function. Passing `"all"` will bind
81 // the callback to all events fired.
82 on: function(name, callback, context) {
83 if (!eventsApi(this, 'on', name, [callback, context]) || !callback) return this;
84 this._events || (this._events = {});
85 var events = this._events[name] || (this._events[name] = []);
86 events.push({callback: callback, context: context, ctx: context || this});
87 return this;
88 },
89
90 // Bind an event to only be triggered a single time. After the first time
91 // the callback is invoked, it will be removed.
92 once: function(name, callback, context) {
93 if (!eventsApi(this, 'once', name, [callback, context]) || !callback) return this;
94 var self = this;
95 var once = _.once(function() {
96 self.off(name, once);
97 callback.apply(this, arguments);
98 });
99 once._callback = callback;
100 return this.on(name, once, context);
101 },
102
103 // Remove one or many callbacks. If `context` is null, removes all
104 // callbacks with that function. If `callback` is null, removes all
105 // callbacks for the event. If `name` is null, removes all bound
106 // callbacks for all events.
107 off: function(name, callback, context) {
108 var retain, ev, events, names, i, l, j, k;
109 if (!this._events || !eventsApi(this, 'off', name, [callback, context])) return this;
110 if (!name && !callback && !context) {
111 this._events = {};
112 return this;
113 }
114
115 names = name ? [name] : _.keys(this._events);
116 for (i = 0, l = names.length; i < l; i++) {
117 name = names[i];
118 if (events = this._events[name]) {
119 this._events[name] = retain = [];
120 if (callback || context) {
121 for (j = 0, k = events.length; j < k; j++) {
122 ev = events[j];
123 if ((callback && callback !== ev.callback && callback !== ev.callback._callback) ||
124 (context && context !== ev.context)) {
125 retain.push(ev);
126 }
127 }
128 }
129 if (!retain.length) delete this._events[name];
130 }
131 }
132
133 return this;
134 },
135
136 // Trigger one or many events, firing all bound callbacks. Callbacks are
137 // passed the same arguments as `trigger` is, apart from the event name
138 // (unless you're listening on `"all"`, which will cause your callback to
139 // receive the true name of the event as the first argument).
140 trigger: function(name) {
141 if (!this._events) return this;
142 var args = slice.call(arguments, 1);
143 if (!eventsApi(this, 'trigger', name, args)) return this;
144 var events = this._events[name];
145 var allEvents = this._events.all;
146 if (events) triggerEvents(events, args);
147 if (allEvents) triggerEvents(allEvents, arguments);
148 return this;
149 },
150
151 // Tell this object to stop listening to either specific events ... or
152 // to every object it's currently listening to.
153 stopListening: function(obj, name, callback) {
154 var listeners = this._listeners;
155 if (!listeners) return this;
156 var deleteListener = !name && !callback;
157 if (typeof name === 'object') callback = this;
158 if (obj) (listeners = {})[obj._listenerId] = obj;
159 for (var id in listeners) {
160 listeners[id].off(name, callback, this);
161 if (deleteListener) delete this._listeners[id];
162 }
163 return this;
164 }
165
166 };
167
168 // Regular expression used to split event strings.
169 var eventSplitter = /\s+/;
170
171 // Implement fancy features of the Events API such as multiple event
172 // names `"change blur"` and jQuery-style event maps `{change: action}`
173 // in terms of the existing API.
174 var eventsApi = function(obj, action, name, rest) {
175 if (!name) return true;
176
177 // Handle event maps.
178 if (typeof name === 'object') {
179 for (var key in name) {
180 obj[action].apply(obj, [key, name[key]].concat(rest));
181 }
182 return false;
183 }
184
185 // Handle space separated event names.
186 if (eventSplitter.test(name)) {
187 var names = name.split(eventSplitter);
188 for (var i = 0, l = names.length; i < l; i++) {
189 obj[action].apply(obj, [names[i]].concat(rest));
190 }
191 return false;
192 }
193
194 return true;
195 };
196
197 // A difficult-to-believe, but optimized internal dispatch function for
198 // triggering events. Tries to keep the usual cases speedy (most internal
199 // Backbone events have 3 arguments).
200 var triggerEvents = function(events, args) {
201 var ev, i = -1, l = events.length, a1 = args[0], a2 = args[1], a3 = args[2];
202 switch (args.length) {
203 case 0: while (++i < l) (ev = events[i]).callback.call(ev.ctx); return;
204 case 1: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1); return;
205 case 2: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2); return;
206 case 3: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2, a3); return;
207 default: while (++i < l) (ev = events[i]).callback.apply(ev.ctx, args);
208 }
209 };
210
211 var listenMethods = {listenTo: 'on', listenToOnce: 'once'};
212
213 // Inversion-of-control versions of `on` and `once`. Tell *this* object to
214 // listen to an event in another object ... keeping track of what it's
215 // listening to.
216 _.each(listenMethods, function(implementation, method) {
217 Events[method] = function(obj, name, callback) {
218 var listeners = this._listeners || (this._listeners = {});
219 var id = obj._listenerId || (obj._listenerId = _.uniqueId('l'));
220 listeners[id] = obj;
221 if (typeof name === 'object') callback = this;
222 obj[implementation](name, callback, this);
223 return this;
224 };
225 });
226
227 // Aliases for backwards compatibility.
228 Events.bind = Events.on;
229 Events.unbind = Events.off;
230
231 // Allow the `Backbone` object to serve as a global event bus, for folks who
232 // want global "pubsub" in a convenient place.
233 _.extend(Backbone, Events);
234
235 // Backbone.Model
236 // --------------
237
238 // Backbone **Models** are the basic data object in the framework --
239 // frequently representing a row in a table in a database on your server.
240 // A discrete chunk of data and a bunch of useful, related methods for
241 // performing computations and transformations on that data.
242
243 // Create a new model with the specified attributes. A client id (`cid`)
244 // is automatically generated and assigned for you.
245 var Model = Backbone.Model = function(attributes, options) {
246 var defaults;
247 var attrs = attributes || {};
248 options || (options = {});
249 this.cid = _.uniqueId('c');
250 this.attributes = {};
251 if (options.collection) this.collection = options.collection;
252 if (options.parse) attrs = this.parse(attrs, options) || {};
253 options._attrs = attrs;
254 if (defaults = _.result(this, 'defaults')) {
255 attrs = _.defaults({}, attrs, defaults);
256 }
257 this.set(attrs, options);
258 this.changed = {};
259 this.initialize.apply(this, arguments);
260 };
261
262 // Attach all inheritable methods to the Model prototype.
263 _.extend(Model.prototype, Events, {
264
265 // A hash of attributes whose current and previous value differ.
266 changed: null,
267
268 // The value returned during the last failed validation.
269 validationError: null,
270
271 // The default name for the JSON `id` attribute is `"id"`. MongoDB and
272 // CouchDB users may want to set this to `"_id"`.
273 idAttribute: 'id',
274
275 // Initialize is an empty function by default. Override it with your own
276 // initialization logic.
277 initialize: function(){},
278
279 // Return a copy of the model's `attributes` object.
280 toJSON: function(options) {
281 return _.clone(this.attributes);
282 },
283
284 // Proxy `Backbone.sync` by default -- but override this if you need
285 // custom syncing semantics for *this* particular model.
286 sync: function() {
287 return Backbone.sync.apply(this, arguments);
288 },
289
290 // Get the value of an attribute.
291 get: function(attr) {
292 return this.attributes[attr];
293 },
294
295 // Get the HTML-escaped value of an attribute.
296 escape: function(attr) {
297 return _.escape(this.get(attr));
298 },
299
300 // Returns `true` if the attribute contains a value that is not null
301 // or undefined.
302 has: function(attr) {
303 return this.get(attr) != null;
304 },
305
306 // Set a hash of model attributes on the object, firing `"change"`. This is
307 // the core primitive operation of a model, updating the data and notifying
308 // anyone who needs to know about the change in state. The heart of the beast.
309 set: function(key, val, options) {
310 var attr, attrs, unset, changes, silent, changing, prev, current;
311 if (key == null) return this;
312
313 // Handle both `"key", value` and `{key: value}` -style arguments.
314 if (typeof key === 'object') {
315 attrs = key;
316 options = val;
317 } else {
318 (attrs = {})[key] = val;
319 }
320
321 options || (options = {});
322
323 // Run validation.
324 if (!this._validate(attrs, options)) return false;
325
326 // Extract attributes and options.
327 unset = options.unset;
328 silent = options.silent;
329 changes = [];
330 changing = this._changing;
331 this._changing = true;
332
333 if (!changing) {
334 this._previousAttributes = _.clone(this.attributes);
335 this.changed = {};
336 }
337 current = this.attributes, prev = this._previousAttributes;
338
339 // Check for changes of `id`.
340 if (this.idAttribute in attrs) this.id = attrs[this.idAttribute];
341
342 // For each `set` attribute, update or delete the current value.
343 for (attr in attrs) {
344 val = attrs[attr];
345 if (!_.isEqual(current[attr], val)) changes.push(attr);
346 if (!_.isEqual(prev[attr], val)) {
347 this.changed[attr] = val;
348 } else {
349 delete this.changed[attr];
350 }
351 unset ? delete current[attr] : current[attr] = val;
352 }
353
354 // Trigger all relevant attribute changes.
355 if (!silent) {
356 if (changes.length) this._pending = true;
357 for (var i = 0, l = changes.length; i < l; i++) {
358 this.trigger('change:' + changes[i], this, current[changes[i]], options);
359 }
360 }
361
362 // You might be wondering why there's a `while` loop here. Changes can
363 // be recursively nested within `"change"` events.
364 if (changing) return this;
365 if (!silent) {
366 while (this._pending) {
367 this._pending = false;
368 this.trigger('change', this, options);
369 }
370 }
371 this._pending = false;
372 this._changing = false;
373 return this;
374 },
375
376 // Remove an attribute from the model, firing `"change"`. `unset` is a noop
377 // if the attribute doesn't exist.
378 unset: function(attr, options) {
379 return this.set(attr, void 0, _.extend({}, options, {unset: true}));
380 },
381
382 // Clear all attributes on the model, firing `"change"`.
383 clear: function(options) {
384 var attrs = {};
385 for (var key in this.attributes) attrs[key] = void 0;
386 return this.set(attrs, _.extend({}, options, {unset: true}));
387 },
388
389 // Determine if the model has changed since the last `"change"` event.
390 // If you specify an attribute name, determine if that attribute has changed.
391 hasChanged: function(attr) {
392 if (attr == null) return !_.isEmpty(this.changed);
393 return _.has(this.changed, attr);
394 },
395
396 // Return an object containing all the attributes that have changed, or
397 // false if there are no changed attributes. Useful for determining what
398 // parts of a view need to be updated and/or what attributes need to be
399 // persisted to the server. Unset attributes will be set to undefined.
400 // You can also pass an attributes object to diff against the model,
401 // determining if there *would be* a change.
402 changedAttributes: function(diff) {
403 if (!diff) return this.hasChanged() ? _.clone(this.changed) : false;
404 var val, changed = false;
405 var old = this._changing ? this._previousAttributes : this.attributes;
406 for (var attr in diff) {
407 if (_.isEqual(old[attr], (val = diff[attr]))) continue;
408 (changed || (changed = {}))[attr] = val;
409 }
410 return changed;
411 },
412
413 // Get the previous value of an attribute, recorded at the time the last
414 // `"change"` event was fired.
415 previous: function(attr) {
416 if (attr == null || !this._previousAttributes) return null;
417 return this._previousAttributes[attr];
418 },
419
420 // Get all of the attributes of the model at the time of the previous
421 // `"change"` event.
422 previousAttributes: function() {
423 return _.clone(this._previousAttributes);
424 },
425
426 // Fetch the model from the server. If the server's representation of the
427 // model differs from its current attributes, they will be overridden,
428 // triggering a `"change"` event.
429 fetch: function(options) {
430 options = options ? _.clone(options) : {};
431 if (options.parse === void 0) options.parse = true;
432 var model = this;
433 var success = options.success;
434 options.success = function(resp) {
435 if (!model.set(model.parse(resp, options), options)) return false;
436 if (success) success(model, resp, options);
437 model.trigger('sync', model, resp, options);
438 };
439 wrapError(this, options);
440 return this.sync('read', this, options);
441 },
442
443 // Set a hash of model attributes, and sync the model to the server.
444 // If the server returns an attributes hash that differs, the model's
445 // state will be `set` again.
446 save: function(key, val, options) {
447 var attrs, method, xhr, attributes = this.attributes;
448
449 // Handle both `"key", value` and `{key: value}` -style arguments.
450 if (key == null || typeof key === 'object') {
451 attrs = key;
452 options = val;
453 } else {
454 (attrs = {})[key] = val;
455 }
456
457 options = _.extend({validate: true}, options);
458
459 // If we're not waiting and attributes exist, save acts as
460 // `set(attr).save(null, opts)` with validation. Otherwise, check if
461 // the model will be valid when the attributes, if any, are set.
462 if (attrs && !options.wait) {
463 if (!this.set(attrs, options)) return false;
464 } else {
465 if (!this._validate(attrs, options)) return false;
466 }
467
468 // Set temporary attributes if `{wait: true}`.
469 if (attrs && options.wait) {
470 this.attributes = _.extend({}, attributes, attrs);
471 }
472
473 // After a successful server-side save, the client is (optionally)
474 // updated with the server-side state.
475 if (options.parse === void 0) options.parse = true;
476 var model = this;
477 var success = options.success;
478 options.success = function(resp) {
479 // Ensure attributes are restored during synchronous saves.
480 model.attributes = attributes;
481 var serverAttrs = model.parse(resp, options);
482 if (options.wait) serverAttrs = _.extend(attrs || {}, serverAttrs);
483 if (_.isObject(serverAttrs) && !model.set(serverAttrs, options)) {
484 return false;
485 }
486 if (success) success(model, resp, options);
487 model.trigger('sync', model, resp, options);
488 };
489 wrapError(this, options);
490
491 method = this.isNew() ? 'create' : (options.patch ? 'patch' : 'update');
492 if (method === 'patch') options.attrs = attrs;
493 xhr = this.sync(method, this, options);
494
495 // Restore attributes.
496 if (attrs && options.wait) this.attributes = attributes;
497
498 return xhr;
499 },
500
501 // Destroy this model on the server if it was already persisted.
502 // Optimistically removes the model from its collection, if it has one.
503 // If `wait: true` is passed, waits for the server to respond before removal.
504 destroy: function(options) {
505 options = options ? _.clone(options) : {};
506 var model = this;
507 var success = options.success;
508
509 var destroy = function() {
510 model.trigger('destroy', model, model.collection, options);
511 };
512
513 options.success = function(resp) {
514 if (options.wait || model.isNew()) destroy();
515 if (success) success(model, resp, options);
516 if (!model.isNew()) model.trigger('sync', model, resp, options);
517 };
518
519 if (this.isNew()) {
520 options.success();
521 return false;
522 }
523 wrapError(this, options);
524
525 var xhr = this.sync('delete', this, options);
526 if (!options.wait) destroy();
527 return xhr;
528 },
529
530 // Default URL for the model's representation on the server -- if you're
531 // using Backbone's restful methods, override this to change the endpoint
532 // that will be called.
533 url: function() {
534 var base = _.result(this, 'urlRoot') || _.result(this.collection, 'url') || urlError();
535 if (this.isNew()) return base;
536 return base + (base.charAt(base.length - 1) === '/' ? '' : '/') + encodeURIComponent(this.id);
537 },
538
539 // **parse** converts a response into the hash of attributes to be `set` on
540 // the model. The default implementation is just to pass the response along.
541 parse: function(resp, options) {
542 return resp;
543 },
544
545 // Create a new model with identical attributes to this one.
546 clone: function() {
547 return new this.constructor(this.attributes);
548 },
549
550 // A model is new if it has never been saved to the server, and lacks an id.
551 isNew: function() {
552 return this.id == null;
553 },
554
555 // Check if the model is currently in a valid state.
556 isValid: function(options) {
557 return this._validate({}, _.extend(options || {}, { validate: true }));
558 },
559
560 // Run validation against the next complete set of model attributes,
561 // returning `true` if all is well. Otherwise, fire an `"invalid"` event.
562 _validate: function(attrs, options) {
563 if (!options.validate || !this.validate) return true;
564 attrs = _.extend({}, this.attributes, attrs);
565 var error = this.validationError = this.validate(attrs, options) || null;
566 if (!error) return true;
567 this.trigger('invalid', this, error, _.extend(options || {}, {validationError: error}));
568 return false;
569 }
570
571 });
572
573 // Underscore methods that we want to implement on the Model.
574 var modelMethods = ['keys', 'values', 'pairs', 'invert', 'pick', 'omit'];
575
576 // Mix in each Underscore method as a proxy to `Model#attributes`.
577 _.each(modelMethods, function(method) {
578 Model.prototype[method] = function() {
579 var args = slice.call(arguments);
580 args.unshift(this.attributes);
581 return _[method].apply(_, args);
582 };
583 });
584
585 // Backbone.Collection
586 // -------------------
587
588 // If models tend to represent a single row of data, a Backbone Collection is
589 // more analagous to a table full of data ... or a small slice or page of that
590 // table, or a collection of rows that belong together for a particular reason
591 // -- all of the messages in this particular folder, all of the documents
592 // belonging to this particular author, and so on. Collections maintain
593 // indexes of their models, both in order, and for lookup by `id`.
594
595 // Create a new **Collection**, perhaps to contain a specific type of `model`.
596 // If a `comparator` is specified, the Collection will maintain
597 // its models in sort order, as they're added and removed.
598 var Collection = Backbone.Collection = function(models, options) {
599 options || (options = {});
600 if (options.model) this.model = options.model;
601 if (options.comparator !== void 0) this.comparator = options.comparator;
602 this._reset();
603 this.initialize.apply(this, arguments);
604 if (models) this.reset(models, _.extend({silent: true}, options));
605 };
606
607 // Default options for `Collection#set`.
608 var setOptions = {add: true, remove: true, merge: true};
609 var addOptions = {add: true, merge: false, remove: false};
610
611 // Define the Collection's inheritable methods.
612 _.extend(Collection.prototype, Events, {
613
614 // The default model for a collection is just a **Backbone.Model**.
615 // This should be overridden in most cases.
616 model: Model,
617
618 // Initialize is an empty function by default. Override it with your own
619 // initialization logic.
620 initialize: function(){},
621
622 // The JSON representation of a Collection is an array of the
623 // models' attributes.
624 toJSON: function(options) {
625 return this.map(function(model){ return model.toJSON(options); });
626 },
627
628 // Proxy `Backbone.sync` by default.
629 sync: function() {
630 return Backbone.sync.apply(this, arguments);
631 },
632
633 // Add a model, or list of models to the set.
634 add: function(models, options) {
635 return this.set(models, _.defaults(options || {}, addOptions));
636 },
637
638 // Remove a model, or a list of models from the set.
639 remove: function(models, options) {
640 models = _.isArray(models) ? models.slice() : [models];
641 options || (options = {});
642 var i, l, index, model;
643 for (i = 0, l = models.length; i < l; i++) {
644 model = this.get(models[i]);
645 if (!model) continue;
646 delete this._byId[model.id];
647 delete this._byId[model.cid];
648 index = this.indexOf(model);
649 this.models.splice(index, 1);
650 this.length--;
651 if (!options.silent) {
652 options.index = index;
653 model.trigger('remove', model, this, options);
654 }
655 this._removeReference(model);
656 }
657 return this;
658 },
659
660 // Update a collection by `set`-ing a new list of models, adding new ones,
661 // removing models that are no longer present, and merging models that
662 // already exist in the collection, as necessary. Similar to **Model#set**,
663 // the core operation for updating the data contained by the collection.
664 set: function(models, options) {
665 options = _.defaults(options || {}, setOptions);
666 if (options.parse) models = this.parse(models, options);
667 if (!_.isArray(models)) models = models ? [models] : [];
668 var i, l, model, attrs, existing, sort;
669 var at = options.at;
670 var sortable = this.comparator && (at == null) && options.sort !== false;
671 var sortAttr = _.isString(this.comparator) ? this.comparator : null;
672 var toAdd = [], toRemove = [], modelMap = {};
673 var add = options.add, merge = options.merge, remove = options.remove;
674 var order = !sortable && add && remove ? [] : false;
675
676 // Turn bare objects into model references, and prevent invalid models
677 // from being added.
678 for (i = 0, l = models.length; i < l; i++) {
679 if (!(model = this._prepareModel(attrs = models[i], options))) continue;
680
681 // If a duplicate is found, prevent it from being added and
682 // optionally merge it into the existing model.
683 if (existing = this.get(model)) {
684 if (remove) modelMap[existing.cid] = true;
685 if (merge) {
686 attrs = attrs === model ? model.attributes : options._attrs;
687 existing.set(attrs, options);
688 if (sortable && !sort && existing.hasChanged(sortAttr)) sort = true;
689 }
690
691 // This is a new model, push it to the `toAdd` list.
692 } else if (add) {
693 toAdd.push(model);
694
695 // Listen to added models' events, and index models for lookup by
696 // `id` and by `cid`.
697 model.on('all', this._onModelEvent, this);
698 this._byId[model.cid] = model;
699 if (model.id != null) this._byId[model.id] = model;
700 }
701 if (order) order.push(existing || model);
702 }
703
704 // Remove nonexistent models if appropriate.
705 if (remove) {
706 for (i = 0, l = this.length; i < l; ++i) {
707 if (!modelMap[(model = this.models[i]).cid]) toRemove.push(model);
708 }
709 if (toRemove.length) this.remove(toRemove, options);
710 }
711
712 // See if sorting is needed, update `length` and splice in new models.
713 if (toAdd.length || (order && order.length)) {
714 if (sortable) sort = true;
715 this.length += toAdd.length;
716 if (at != null) {
717 splice.apply(this.models, [at, 0].concat(toAdd));
718 } else {
719 if (order) this.models.length = 0;
720 push.apply(this.models, order || toAdd);
721 }
722 }
723
724 // Silently sort the collection if appropriate.
725 if (sort) this.sort({silent: true});
726
727 if (options.silent) return this;
728
729 // Trigger `add` events.
730 for (i = 0, l = toAdd.length; i < l; i++) {
731 (model = toAdd[i]).trigger('add', model, this, options);
732 }
733
734 // Trigger `sort` if the collection was sorted.
735 if (sort || (order && order.length)) this.trigger('sort', this, options);
736 return this;
737 },
738
739 // When you have more items than you want to add or remove individually,
740 // you can reset the entire set with a new list of models, without firing
741 // any granular `add` or `remove` events. Fires `reset` when finished.
742 // Useful for bulk operations and optimizations.
743 reset: function(models, options) {
744 options || (options = {});
745 for (var i = 0, l = this.models.length; i < l; i++) {
746 this._removeReference(this.models[i]);
747 }
748 options.previousModels = this.models;
749 this._reset();
750 this.add(models, _.extend({silent: true}, options));
751 if (!options.silent) this.trigger('reset', this, options);
752 return this;
753 },
754
755 // Add a model to the end of the collection.
756 push: function(model, options) {
757 model = this._prepareModel(model, options);
758 this.add(model, _.extend({at: this.length}, options));
759 return model;
760 },
761
762 // Remove a model from the end of the collection.
763 pop: function(options) {
764 var model = this.at(this.length - 1);
765 this.remove(model, options);
766 return model;
767 },
768
769 // Add a model to the beginning of the collection.
770 unshift: function(model, options) {
771 model = this._prepareModel(model, options);
772 this.add(model, _.extend({at: 0}, options));
773 return model;
774 },
775
776 // Remove a model from the beginning of the collection.
777 shift: function(options) {
778 var model = this.at(0);
779 this.remove(model, options);
780 return model;
781 },
782
783 // Slice out a sub-array of models from the collection.
784 slice: function() {
785 return slice.apply(this.models, arguments);
786 },
787
788 // Get a model from the set by id.
789 get: function(obj) {
790 if (obj == null) return void 0;
791 return this._byId[obj.id != null ? obj.id : obj.cid || obj];
792 },
793
794 // Get the model at the given index.
795 at: function(index) {
796 return this.models[index];
797 },
798
799 // Return models with matching attributes. Useful for simple cases of
800 // `filter`.
801 where: function(attrs, first) {
802 if (_.isEmpty(attrs)) return first ? void 0 : [];
803 return this[first ? 'find' : 'filter'](function(model) {
804 for (var key in attrs) {
805 if (attrs[key] !== model.get(key)) return false;
806 }
807 return true;
808 });
809 },
810
811 // Return the first model with matching attributes. Useful for simple cases
812 // of `find`.
813 findWhere: function(attrs) {
814 return this.where(attrs, true);
815 },
816
817 // Force the collection to re-sort itself. You don't need to call this under
818 // normal circumstances, as the set will maintain sort order as each item
819 // is added.
820 sort: function(options) {
821 if (!this.comparator) throw new Error('Cannot sort a set without a comparator');
822 options || (options = {});
823
824 // Run sort based on type of `comparator`.
825 if (_.isString(this.comparator) || this.comparator.length === 1) {
826 this.models = this.sortBy(this.comparator, this);
827 } else {
828 this.models.sort(_.bind(this.comparator, this));
829 }
830
831 if (!options.silent) this.trigger('sort', this, options);
832 return this;
833 },
834
835 // Figure out the smallest index at which a model should be inserted so as
836 // to maintain order.
837 sortedIndex: function(model, value, context) {
838 value || (value = this.comparator);
839 var iterator = _.isFunction(value) ? value : function(model) {
840 return model.get(value);
841 };
842 return _.sortedIndex(this.models, model, iterator, context);
843 },
844
845 // Pluck an attribute from each model in the collection.
846 pluck: function(attr) {
847 return _.invoke(this.models, 'get', attr);
848 },
849
850 // Fetch the default set of models for this collection, resetting the
851 // collection when they arrive. If `reset: true` is passed, the response
852 // data will be passed through the `reset` method instead of `set`.
853 fetch: function(options) {
854 options = options ? _.clone(options) : {};
855 if (options.parse === void 0) options.parse = true;
856 var success = options.success;
857 var collection = this;
858 options.success = function(resp) {
859 var method = options.reset ? 'reset' : 'set';
860 collection[method](resp, options);
861 if (success) success(collection, resp, options);
862 collection.trigger('sync', collection, resp, options);
863 };
864 wrapError(this, options);
865 return this.sync('read', this, options);
866 },
867
868 // Create a new instance of a model in this collection. Add the model to the
869 // collection immediately, unless `wait: true` is passed, in which case we
870 // wait for the server to agree.
871 create: function(model, options) {
872 options = options ? _.clone(options) : {};
873 if (!(model = this._prepareModel(model, options))) return false;
874 if (!options.wait) this.add(model, options);
875 var collection = this;
876 var success = options.success;
877 options.success = function(resp) {
878 if (options.wait) collection.add(model, options);
879 if (success) success(model, resp, options);
880 };
881 model.save(null, options);
882 return model;
883 },
884
885 // **parse** converts a response into a list of models to be added to the
886 // collection. The default implementation is just to pass it through.
887 parse: function(resp, options) {
888 return resp;
889 },
890
891 // Create a new collection with an identical list of models as this one.
892 clone: function() {
893 return new this.constructor(this.models);
894 },
895
896 // Private method to reset all internal state. Called when the collection
897 // is first initialized or reset.
898 _reset: function() {
899 this.length = 0;
900 this.models = [];
901 this._byId = {};
902 },
903
904 // Prepare a hash of attributes (or other model) to be added to this
905 // collection.
906 _prepareModel: function(attrs, options) {
907 if (attrs instanceof Model) {
908 if (!attrs.collection) attrs.collection = this;
909 return attrs;
910 }
911 options || (options = {});
912 options.collection = this;
913 var model = new this.model(attrs, options);
914 if (!model._validate(attrs, options)) {
915 this.trigger('invalid', this, attrs, options);
916 return false;
917 }
918 return model;
919 },
920
921 // Internal method to sever a model's ties to a collection.
922 _removeReference: function(model) {
923 if (this === model.collection) delete model.collection;
924 model.off('all', this._onModelEvent, this);
925 },
926
927 // Internal method called every time a model in the set fires an event.
928 // Sets need to update their indexes when models change ids. All other
929 // events simply proxy through. "add" and "remove" events that originate
930 // in other collections are ignored.
931 _onModelEvent: function(event, model, collection, options) {
932 if ((event === 'add' || event === 'remove') && collection !== this) return;
933 if (event === 'destroy') this.remove(model, options);
934 if (model && event === 'change:' + model.idAttribute) {
935 delete this._byId[model.previous(model.idAttribute)];
936 if (model.id != null) this._byId[model.id] = model;
937 }
938 this.trigger.apply(this, arguments);
939 }
940
941 });
942
943 // Underscore methods that we want to implement on the Collection.
944 // 90% of the core usefulness of Backbone Collections is actually implemented
945 // right here:
946 var methods = ['forEach', 'each', 'map', 'collect', 'reduce', 'foldl',
947 'inject', 'reduceRight', 'foldr', 'find', 'detect', 'filter', 'select',
948 'reject', 'every', 'all', 'some', 'any', 'include', 'contains', 'invoke',
949 'max', 'min', 'toArray', 'size', 'first', 'head', 'take', 'initial', 'rest',
950 'tail', 'drop', 'last', 'without', 'indexOf', 'shuffle', 'lastIndexOf',
951 'isEmpty', 'chain'];
952
953 // Mix in each Underscore method as a proxy to `Collection#models`.
954 _.each(methods, function(method) {
955 Collection.prototype[method] = function() {
956 var args = slice.call(arguments);
957 args.unshift(this.models);
958 return _[method].apply(_, args);
959 };
960 });
961
962 // Underscore methods that take a property name as an argument.
963 var attributeMethods = ['groupBy', 'countBy', 'sortBy'];
964
965 // Use attributes instead of properties.
966 _.each(attributeMethods, function(method) {
967 Collection.prototype[method] = function(value, context) {
968 var iterator = _.isFunction(value) ? value : function(model) {
969 return model.get(value);
970 };
971 return _[method](this.models, iterator, context);
972 };
973 });
974
975 // Backbone.View
976 // -------------
977
978 // Backbone Views are almost more convention than they are actual code. A View
979 // is simply a JavaScript object that represents a logical chunk of UI in the
980 // DOM. This might be a single item, an entire list, a sidebar or panel, or
981 // even the surrounding frame which wraps your whole app. Defining a chunk of
982 // UI as a **View** allows you to define your DOM events declaratively, without
983 // having to worry about render order ... and makes it easy for the view to
984 // react to specific changes in the state of your models.
985
986 // Options with special meaning *(e.g. model, collection, id, className)* are
987 // attached directly to the view. See `viewOptions` for an exhaustive
988 // list.
989
990 // Creating a Backbone.View creates its initial element outside of the DOM,
991 // if an existing element is not provided...
992 var View = Backbone.View = function(options) {
993 this.cid = _.uniqueId('view');
994 options || (options = {});
995 _.extend(this, _.pick(options, viewOptions));
996 this._ensureElement();
997 this.initialize.apply(this, arguments);
998 this.delegateEvents();
999 };
1000
1001 // Cached regex to split keys for `delegate`.
1002 var delegateEventSplitter = /^(\S+)\s*(.*)$/;
1003
1004 // List of view options to be merged as properties.
1005 var viewOptions = ['model', 'collection', 'el', 'id', 'attributes', 'className', 'tagName', 'events'];
1006
1007 // Set up all inheritable **Backbone.View** properties and methods.
1008 _.extend(View.prototype, Events, {
1009
1010 // The default `tagName` of a View's element is `"div"`.
1011 tagName: 'div',
1012
1013 // jQuery delegate for element lookup, scoped to DOM elements within the
1014 // current view. This should be prefered to global lookups where possible.
1015 $: function(selector) {
1016 return this.$el.find(selector);
1017 },
1018
1019 // Initialize is an empty function by default. Override it with your own
1020 // initialization logic.
1021 initialize: function(){},
1022
1023 // **render** is the core function that your view should override, in order
1024 // to populate its element (`this.el`), with the appropriate HTML. The
1025 // convention is for **render** to always return `this`.
1026 render: function() {
1027 return this;
1028 },
1029
1030 // Remove this view by taking the element out of the DOM, and removing any
1031 // applicable Backbone.Events listeners.
1032 remove: function() {
1033 this.$el.remove();
1034 this.stopListening();
1035 return this;
1036 },
1037
1038 // Change the view's element (`this.el` property), including event
1039 // re-delegation.
1040 setElement: function(element, delegate) {
1041 if (this.$el) this.undelegateEvents();
1042 this.$el = element instanceof Backbone.$ ? element : Backbone.$(element);
1043 this.el = this.$el[0];
1044 if (delegate !== false) this.delegateEvents();
1045 return this;
1046 },
1047
1048 // Set callbacks, where `this.events` is a hash of
1049 //
1050 // *{"event selector": "callback"}*
1051 //
1052 // {
1053 // 'mousedown .title': 'edit',
1054 // 'click .button': 'save'
1055 // 'click .open': function(e) { ... }
1056 // }
1057 //
1058 // pairs. Callbacks will be bound to the view, with `this` set properly.
1059 // Uses event delegation for efficiency.
1060 // Omitting the selector binds the event to `this.el`.
1061 // This only works for delegate-able events: not `focus`, `blur`, and
1062 // not `change`, `submit`, and `reset` in Internet Explorer.
1063 delegateEvents: function(events) {
1064 if (!(events || (events = _.result(this, 'events')))) return this;
1065 this.undelegateEvents();
1066 for (var key in events) {
1067 var method = events[key];
1068 if (!_.isFunction(method)) method = this[events[key]];
1069 if (!method) continue;
1070
1071 var match = key.match(delegateEventSplitter);
1072 var eventName = match[1], selector = match[2];
1073 method = _.bind(method, this);
1074 eventName += '.delegateEvents' + this.cid;
1075 if (selector === '') {
1076 this.$el.on(eventName, method);
1077 } else {
1078 this.$el.on(eventName, selector, method);
1079 }
1080 }
1081 return this;
1082 },
1083
1084 // Clears all callbacks previously bound to the view with `delegateEvents`.
1085 // You usually don't need to use this, but may wish to if you have multiple
1086 // Backbone views attached to the same DOM element.
1087 undelegateEvents: function() {
1088 this.$el.off('.delegateEvents' + this.cid);
1089 return this;
1090 },
1091
1092 // Ensure that the View has a DOM element to render into.
1093 // If `this.el` is a string, pass it through `$()`, take the first
1094 // matching element, and re-assign it to `el`. Otherwise, create
1095 // an element from the `id`, `className` and `tagName` properties.
1096 _ensureElement: function() {
1097 if (!this.el) {
1098 var attrs = _.extend({}, _.result(this, 'attributes'));
1099 if (this.id) attrs.id = _.result(this, 'id');
1100 if (this.className) attrs['class'] = _.result(this, 'className');
1101 var $el = Backbone.$('<' + _.result(this, 'tagName') + '>').attr(attrs);
1102 this.setElement($el, false);
1103 } else {
1104 this.setElement(_.result(this, 'el'), false);
1105 }
1106 }
1107
1108 });
1109
1110 // Backbone.sync
1111 // -------------
1112
1113 // Override this function to change the manner in which Backbone persists
1114 // models to the server. You will be passed the type of request, and the
1115 // model in question. By default, makes a RESTful Ajax request
1116 // to the model's `url()`. Some possible customizations could be:
1117 //
1118 // * Use `setTimeout` to batch rapid-fire updates into a single request.
1119 // * Send up the models as XML instead of JSON.
1120 // * Persist models via WebSockets instead of Ajax.
1121 //
1122 // Turn on `Backbone.emulateHTTP` in order to send `PUT` and `DELETE` requests
1123 // as `POST`, with a `_method` parameter containing the true HTTP method,
1124 // as well as all requests with the body as `application/x-www-form-urlencoded`
1125 // instead of `application/json` with the model in a param named `model`.
1126 // Useful when interfacing with server-side languages like **PHP** that make
1127 // it difficult to read the body of `PUT` requests.
1128 Backbone.sync = function(method, model, options) {
1129 var type = methodMap[method];
1130
1131 // Default options, unless specified.
1132 _.defaults(options || (options = {}), {
1133 emulateHTTP: Backbone.emulateHTTP,
1134 emulateJSON: Backbone.emulateJSON
1135 });
1136
1137 // Default JSON-request options.
1138 var params = {type: type, dataType: 'json'};
1139
1140 // Ensure that we have a URL.
1141 if (!options.url) {
1142 params.url = _.result(model, 'url') || urlError();
1143 }
1144
1145 // Ensure that we have the appropriate request data.
1146 if (options.data == null && model && (method === 'create' || method === 'update' || method === 'patch')) {
1147 params.contentType = 'application/json';
1148 params.data = JSON.stringify(options.attrs || model.toJSON(options));
1149 }
1150
1151 // For older servers, emulate JSON by encoding the request into an HTML-form.
1152 if (options.emulateJSON) {
1153 params.contentType = 'application/x-www-form-urlencoded';
1154 params.data = params.data ? {model: params.data} : {};
1155 }
1156
1157 // For older servers, emulate HTTP by mimicking the HTTP method with `_method`
1158 // And an `X-HTTP-Method-Override` header.
1159 if (options.emulateHTTP && (type === 'PUT' || type === 'DELETE' || type === 'PATCH')) {
1160 params.type = 'POST';
1161 if (options.emulateJSON) params.data._method = type;
1162 var beforeSend = options.beforeSend;
1163 options.beforeSend = function(xhr) {
1164 xhr.setRequestHeader('X-HTTP-Method-Override', type);
1165 if (beforeSend) return beforeSend.apply(this, arguments);
1166 };
1167 }
1168
1169 // Don't process data on a non-GET request.
1170 if (params.type !== 'GET' && !options.emulateJSON) {
1171 params.processData = false;
1172 }
1173
1174 // If we're sending a `PATCH` request, and we're in an old Internet Explorer
1175 // that still has ActiveX enabled by default, override jQuery to use that
1176 // for XHR instead. Remove this line when jQuery supports `PATCH` on IE8.
1177 if (params.type === 'PATCH' && window.ActiveXObject &&
1178 !(window.external && window.external.msActiveXFilteringEnabled)) {
1179 params.xhr = function() {
1180 return new ActiveXObject("Microsoft.XMLHTTP");
1181 };
1182 }
1183
1184 // Make the request, allowing the user to override any Ajax options.
1185 var xhr = options.xhr = Backbone.ajax(_.extend(params, options));
1186 model.trigger('request', model, xhr, options);
1187 return xhr;
1188 };
1189
1190 // Map from CRUD to HTTP for our default `Backbone.sync` implementation.
1191 var methodMap = {
1192 'create': 'POST',
1193 'update': 'PUT',
1194 'patch': 'PATCH',
1195 'delete': 'DELETE',
1196 'read': 'GET'
1197 };
1198
1199 // Set the default implementation of `Backbone.ajax` to proxy through to `$`.
1200 // Override this if you'd like to use a different library.
1201 Backbone.ajax = function() {
1202 return Backbone.$.ajax.apply(Backbone.$, arguments);
1203 };
1204
1205 // Backbone.Router
1206 // ---------------
1207
1208 // Routers map faux-URLs to actions, and fire events when routes are
1209 // matched. Creating a new one sets its `routes` hash, if not set statically.
1210 var Router = Backbone.Router = function(options) {
1211 options || (options = {});
1212 if (options.routes) this.routes = options.routes;
1213 this._bindRoutes();
1214 this.initialize.apply(this, arguments);
1215 };
1216
1217 // Cached regular expressions for matching named param parts and splatted
1218 // parts of route strings.
1219 var optionalParam = /\((.*?)\)/g;
1220 var namedParam = /(\(\?)?:\w+/g;
1221 var splatParam = /\*\w+/g;
1222 var escapeRegExp = /[\-{}\[\]+?.,\\\^$|#\s]/g;
1223
1224 // Set up all inheritable **Backbone.Router** properties and methods.
1225 _.extend(Router.prototype, Events, {
1226
1227 // Initialize is an empty function by default. Override it with your own
1228 // initialization logic.
1229 initialize: function(){},
1230
1231 // Manually bind a single named route to a callback. For example:
1232 //
1233 // this.route('search/:query/p:num', 'search', function(query, num) {
1234 // ...
1235 // });
1236 //
1237 route: function(route, name, callback) {
1238 if (!_.isRegExp(route)) route = this._routeToRegExp(route);
1239 if (_.isFunction(name)) {
1240 callback = name;
1241 name = '';
1242 }
1243 if (!callback) callback = this[name];
1244 var router = this;
1245 Backbone.history.route(route, function(fragment) {
1246 var args = router._extractParameters(route, fragment);
1247 callback && callback.apply(router, args);
1248 router.trigger.apply(router, ['route:' + name].concat(args));
1249 router.trigger('route', name, args);
1250 Backbone.history.trigger('route', router, name, args);
1251 });
1252 return this;
1253 },
1254
1255 // Simple proxy to `Backbone.history` to save a fragment into the history.
1256 navigate: function(fragment, options) {
1257 Backbone.history.navigate(fragment, options);
1258 return this;
1259 },
1260
1261 // Bind all defined routes to `Backbone.history`. We have to reverse the
1262 // order of the routes here to support behavior where the most general
1263 // routes can be defined at the bottom of the route map.
1264 _bindRoutes: function() {
1265 if (!this.routes) return;
1266 this.routes = _.result(this, 'routes');
1267 var route, routes = _.keys(this.routes);
1268 while ((route = routes.pop()) != null) {
1269 this.route(route, this.routes[route]);
1270 }
1271 },
1272
1273 // Convert a route string into a regular expression, suitable for matching
1274 // against the current location hash.
1275 _routeToRegExp: function(route) {
1276 route = route.replace(escapeRegExp, '\\$&')
1277 .replace(optionalParam, '(?:$1)?')
1278 .replace(namedParam, function(match, optional){
1279 return optional ? match : '([^\/]+)';
1280 })
1281 .replace(splatParam, '(.*?)');
1282 return new RegExp('^' + route + '$');
1283 },
1284
1285 // Given a route, and a URL fragment that it matches, return the array of
1286 // extracted decoded parameters. Empty or unmatched parameters will be
1287 // treated as `null` to normalize cross-browser behavior.
1288 _extractParameters: function(route, fragment) {
1289 var params = route.exec(fragment).slice(1);
1290 return _.map(params, function(param) {
1291 return param ? decodeURIComponent(param) : null;
1292 });
1293 }
1294
1295 });
1296
1297 // Backbone.History
1298 // ----------------
1299
1300 // Handles cross-browser history management, based on either
1301 // [pushState](http://diveintohtml5.info/history.html) and real URLs, or
1302 // [onhashchange](https://developer.mozilla.org/en-US/docs/DOM/window.onhashchange)
1303 // and URL fragments. If the browser supports neither (old IE, natch),
1304 // falls back to polling.
1305 var History = Backbone.History = function() {
1306 this.handlers = [];
1307 _.bindAll(this, 'checkUrl');
1308
1309 // Ensure that `History` can be used outside of the browser.
1310 if (typeof window !== 'undefined') {
1311 this.location = window.location;
1312 this.history = window.history;
1313 }
1314 };
1315
1316 // Cached regex for stripping a leading hash/slash and trailing space.
1317 var routeStripper = /^[#\/]|\s+$/g;
1318
1319 // Cached regex for stripping leading and trailing slashes.
1320 var rootStripper = /^\/+|\/+$/g;
1321
1322 // Cached regex for detecting MSIE.
1323 var isExplorer = /msie [\w.]+/;
1324
1325 // Cached regex for removing a trailing slash.
1326 var trailingSlash = /\/$/;
1327
1328 // Has the history handling already been started?
1329 History.started = false;
1330
1331 // Set up all inheritable **Backbone.History** properties and methods.
1332 _.extend(History.prototype, Events, {
1333
1334 // The default interval to poll for hash changes, if necessary, is
1335 // twenty times a second.
1336 interval: 50,
1337
1338 // Gets the true hash value. Cannot use location.hash directly due to bug
1339 // in Firefox where location.hash will always be decoded.
1340 getHash: function(window) {
1341 var match = (window || this).location.href.match(/#(.*)$/);
1342 return match ? match[1] : '';
1343 },
1344
1345 // Get the cross-browser normalized URL fragment, either from the URL,
1346 // the hash, or the override.
1347 getFragment: function(fragment, forcePushState) {
1348 if (fragment == null) {
1349 if (this._hasPushState || !this._wantsHashChange || forcePushState) {
1350 fragment = this.location.pathname;
1351 var root = this.root.replace(trailingSlash, '');
1352 if (!fragment.indexOf(root)) fragment = fragment.substr(root.length);
1353 } else {
1354 fragment = this.getHash();
1355 }
1356 }
1357 return fragment.replace(routeStripper, '');
1358 },
1359
1360 // Start the hash change handling, returning `true` if the current URL matches
1361 // an existing route, and `false` otherwise.
1362 start: function(options) {
1363 if (History.started) throw new Error("Backbone.history has already been started");
1364 History.started = true;
1365
1366 // Figure out the initial configuration. Do we need an iframe?
1367 // Is pushState desired ... is it available?
1368 this.options = _.extend({}, {root: '/'}, this.options, options);
1369 this.root = this.options.root;
1370 this._wantsHashChange = this.options.hashChange !== false;
1371 this._wantsPushState = !!this.options.pushState;
1372 this._hasPushState = !!(this.options.pushState && this.history && this.history.pushState);
1373 var fragment = this.getFragment();
1374 var docMode = document.documentMode;
1375 var oldIE = (isExplorer.exec(navigator.userAgent.toLowerCase()) && (!docMode || docMode <= 7));
1376
1377 // Normalize root to always include a leading and trailing slash.
1378 this.root = ('/' + this.root + '/').replace(rootStripper, '/');
1379
1380 if (oldIE && this._wantsHashChange) {
1381 this.iframe = Backbone.$('<iframe src="javascript:0" tabindex="-1" />').hide().appendTo('body')[0].contentWindow;
1382 this.navigate(fragment);
1383 }
1384
1385 // Depending on whether we're using pushState or hashes, and whether
1386 // 'onhashchange' is supported, determine how we check the URL state.
1387 if (this._hasPushState) {
1388 Backbone.$(window).on('popstate', this.checkUrl);
1389 } else if (this._wantsHashChange && ('onhashchange' in window) && !oldIE) {
1390 Backbone.$(window).on('hashchange', this.checkUrl);
1391 } else if (this._wantsHashChange) {
1392 this._checkUrlInterval = setInterval(this.checkUrl, this.interval);
1393 }
1394
1395 // Determine if we need to change the base url, for a pushState link
1396 // opened by a non-pushState browser.
1397 this.fragment = fragment;
1398 var loc = this.location;
1399 var atRoot = loc.pathname.replace(/[^\/]$/, '$&/') === this.root;
1400
1401 // If we've started off with a route from a `pushState`-enabled browser,
1402 // but we're currently in a browser that doesn't support it...
1403 if (this._wantsHashChange && this._wantsPushState && !this._hasPushState && !atRoot) {
1404 this.fragment = this.getFragment(null, true);
1405 this.location.replace(this.root + this.location.search + '#' + this.fragment);
1406 // Return immediately as browser will do redirect to new url
1407 return true;
1408
1409 // Or if we've started out with a hash-based route, but we're currently
1410 // in a browser where it could be `pushState`-based instead...
1411 } else if (this._wantsPushState && this._hasPushState && atRoot && loc.hash) {
1412 this.fragment = this.getHash().replace(routeStripper, '');
1413 this.history.replaceState({}, document.title, this.root + this.fragment + loc.search);
1414 }
1415
1416 if (!this.options.silent) return this.loadUrl();
1417 },
1418
1419 // Disable Backbone.history, perhaps temporarily. Not useful in a real app,
1420 // but possibly useful for unit testing Routers.
1421 stop: function() {
1422 Backbone.$(window).off('popstate', this.checkUrl).off('hashchange', this.checkUrl);
1423 clearInterval(this._checkUrlInterval);
1424 History.started = false;
1425 },
1426
1427 // Add a route to be tested when the fragment changes. Routes added later
1428 // may override previous routes.
1429 route: function(route, callback) {
1430 this.handlers.unshift({route: route, callback: callback});
1431 },
1432
1433 // Checks the current URL to see if it has changed, and if it has,
1434 // calls `loadUrl`, normalizing across the hidden iframe.
1435 checkUrl: function(e) {
1436 var current = this.getFragment();
1437 if (current === this.fragment && this.iframe) {
1438 current = this.getFragment(this.getHash(this.iframe));
1439 }
1440 if (current === this.fragment) return false;
1441 if (this.iframe) this.navigate(current);
1442 this.loadUrl() || this.loadUrl(this.getHash());
1443 },
1444
1445 // Attempt to load the current URL fragment. If a route succeeds with a
1446 // match, returns `true`. If no defined routes matches the fragment,
1447 // returns `false`.
1448 loadUrl: function(fragmentOverride) {
1449 var fragment = this.fragment = this.getFragment(fragmentOverride);
1450 var matched = _.any(this.handlers, function(handler) {
1451 if (handler.route.test(fragment)) {
1452 handler.callback(fragment);
1453 return true;
1454 }
1455 });
1456 return matched;
1457 },
1458
1459 // Save a fragment into the hash history, or replace the URL state if the
1460 // 'replace' option is passed. You are responsible for properly URL-encoding
1461 // the fragment in advance.
1462 //
1463 // The options object can contain `trigger: true` if you wish to have the
1464 // route callback be fired (not usually desirable), or `replace: true`, if
1465 // you wish to modify the current URL without adding an entry to the history.
1466 navigate: function(fragment, options) {
1467 if (!History.started) return false;
1468 if (!options || options === true) options = {trigger: options};
1469 fragment = this.getFragment(fragment || '');
1470 if (this.fragment === fragment) return;
1471 this.fragment = fragment;
1472 var url = this.root + fragment;
1473
1474 // If pushState is available, we use it to set the fragment as a real URL.
1475 if (this._hasPushState) {
1476 this.history[options.replace ? 'replaceState' : 'pushState']({}, document.title, url);
1477
1478 // If hash changes haven't been explicitly disabled, update the hash
1479 // fragment to store history.
1480 } else if (this._wantsHashChange) {
1481 this._updateHash(this.location, fragment, options.replace);
1482 if (this.iframe && (fragment !== this.getFragment(this.getHash(this.iframe)))) {
1483 // Opening and closing the iframe tricks IE7 and earlier to push a
1484 // history entry on hash-tag change. When replace is true, we don't
1485 // want this.
1486 if(!options.replace) this.iframe.document.open().close();
1487 this._updateHash(this.iframe.location, fragment, options.replace);
1488 }
1489
1490 // If you've told us that you explicitly don't want fallback hashchange-
1491 // based history, then `navigate` becomes a page refresh.
1492 } else {
1493 return this.location.assign(url);
1494 }
1495 if (options.trigger) return this.loadUrl(fragment);
1496 },
1497
1498 // Update the hash location, either replacing the current entry, or adding
1499 // a new one to the browser history.
1500 _updateHash: function(location, fragment, replace) {
1501 if (replace) {
1502 var href = location.href.replace(/(javascript:|#).*$/, '');
1503 location.replace(href + '#' + fragment);
1504 } else {
1505 // Some browsers require that `hash` contains a leading #.
1506 location.hash = '#' + fragment;
1507 }
1508 }
1509
1510 });
1511
1512 // Create the default Backbone.history.
1513 Backbone.history = new History;
1514
1515 // Helpers
1516 // -------
1517
1518 // Helper function to correctly set up the prototype chain, for subclasses.
1519 // Similar to `goog.inherits`, but uses a hash of prototype properties and
1520 // class properties to be extended.
1521 var extend = function(protoProps, staticProps) {
1522 var parent = this;
1523 var child;
1524
1525 // The constructor function for the new subclass is either defined by you
1526 // (the "constructor" property in your `extend` definition), or defaulted
1527 // by us to simply call the parent's constructor.
1528 if (protoProps && _.has(protoProps, 'constructor')) {
1529 child = protoProps.constructor;
1530 } else {
1531 child = function(){ return parent.apply(this, arguments); };
1532 }
1533
1534 // Add static properties to the constructor function, if supplied.
1535 _.extend(child, parent, staticProps);
1536
1537 // Set the prototype chain to inherit from `parent`, without calling
1538 // `parent`'s constructor function.
1539 var Surrogate = function(){ this.constructor = child; };
1540 Surrogate.prototype = parent.prototype;
1541 child.prototype = new Surrogate;
1542
1543 // Add prototype properties (instance properties) to the subclass,
1544 // if supplied.
1545 if (protoProps) _.extend(child.prototype, protoProps);
1546
1547 // Set a convenience property in case the parent's prototype is needed
1548 // later.
1549 child.__super__ = parent.prototype;
1550
1551 return child;
1552 };
1553
1554 // Set up inheritance for the model, collection, router, view and history.
1555 Model.extend = Collection.extend = Router.extend = View.extend = History.extend = extend;
1556
1557 // Throw an error when a URL is needed, and none is supplied.
1558 var urlError = function() {
1559 throw new Error('A "url" property or function must be specified');
1560 };
1561
1562 // Wrap an optional error callback with a fallback error event.
1563 var wrapError = function(model, options) {
1564 var error = options.error;
1565 options.error = function(resp) {
1566 if (error) error(model, resp, options);
1567 model.trigger('error', model, resp, options);
1568 };
1569 };
1570
1571 }).call(this);
0 /*!
1 * jQuery JavaScript Library v1.9.1
2 * http://jquery.com/
3 *
4 * Includes Sizzle.js
5 * http://sizzlejs.com/
6 *
7 * Copyright 2005, 2012 jQuery Foundation, Inc. and other contributors
8 * Released under the MIT license
9 * http://jquery.org/license
10 *
11 * Date: 2013-2-4
12 */
13 (function( window, undefined ) {
14
15 // Can't do this because several apps including ASP.NET trace
16 // the stack via arguments.caller.callee and Firefox dies if
17 // you try to trace through "use strict" call chains. (#13335)
18 // Support: Firefox 18+
19 //"use strict";
20 var
21 // The deferred used on DOM ready
22 readyList,
23
24 // A central reference to the root jQuery(document)
25 rootjQuery,
26
27 // Support: IE<9
28 // For `typeof node.method` instead of `node.method !== undefined`
29 core_strundefined = typeof undefined,
30
31 // Use the correct document accordingly with window argument (sandbox)
32 document = window.document,
33 location = window.location,
34
35 // Map over jQuery in case of overwrite
36 _jQuery = window.jQuery,
37
38 // Map over the $ in case of overwrite
39 _$ = window.$,
40
41 // [[Class]] -> type pairs
42 class2type = {},
43
44 // List of deleted data cache ids, so we can reuse them
45 core_deletedIds = [],
46
47 core_version = "1.9.1",
48
49 // Save a reference to some core methods
50 core_concat = core_deletedIds.concat,
51 core_push = core_deletedIds.push,
52 core_slice = core_deletedIds.slice,
53 core_indexOf = core_deletedIds.indexOf,
54 core_toString = class2type.toString,
55 core_hasOwn = class2type.hasOwnProperty,
56 core_trim = core_version.trim,
57
58 // Define a local copy of jQuery
59 jQuery = function( selector, context ) {
60 // The jQuery object is actually just the init constructor 'enhanced'
61 return new jQuery.fn.init( selector, context, rootjQuery );
62 },
63
64 // Used for matching numbers
65 core_pnum = /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,
66
67 // Used for splitting on whitespace
68 core_rnotwhite = /\S+/g,
69
70 // Make sure we trim BOM and NBSP (here's looking at you, Safari 5.0 and IE)
71 rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,
72
73 // A simple way to check for HTML strings
74 // Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
75 // Strict HTML recognition (#11290: must start with <)
76 rquickExpr = /^(?:(<[\w\W]+>)[^>]*|#([\w-]*))$/,
77
78 // Match a standalone tag
79 rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>|)$/,
80
81 // JSON RegExp
82 rvalidchars = /^[\],:{}\s]*$/,
83 rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g,
84 rvalidescape = /\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,
85 rvalidtokens = /"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g,
86
87 // Matches dashed string for camelizing
88 rmsPrefix = /^-ms-/,
89 rdashAlpha = /-([\da-z])/gi,
90
91 // Used by jQuery.camelCase as callback to replace()
92 fcamelCase = function( all, letter ) {
93 return letter.toUpperCase();
94 },
95
96 // The ready event handler
97 completed = function( event ) {
98
99 // readyState === "complete" is good enough for us to call the dom ready in oldIE
100 if ( document.addEventListener || event.type === "load" || document.readyState === "complete" ) {
101 detach();
102 jQuery.ready();
103 }
104 },
105 // Clean-up method for dom ready events
106 detach = function() {
107 if ( document.addEventListener ) {
108 document.removeEventListener( "DOMContentLoaded", completed, false );
109 window.removeEventListener( "load", completed, false );
110
111 } else {
112 document.detachEvent( "onreadystatechange", completed );
113 window.detachEvent( "onload", completed );
114 }
115 };
116
117 jQuery.fn = jQuery.prototype = {
118 // The current version of jQuery being used
119 jquery: core_version,
120
121 constructor: jQuery,
122 init: function( selector, context, rootjQuery ) {
123 var match, elem;
124
125 // HANDLE: $(""), $(null), $(undefined), $(false)
126 if ( !selector ) {
127 return this;
128 }
129
130 // Handle HTML strings
131 if ( typeof selector === "string" ) {
132 if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
133 // Assume that strings that start and end with <> are HTML and skip the regex check
134 match = [ null, selector, null ];
135
136 } else {
137 match = rquickExpr.exec( selector );
138 }
139
140 // Match html or make sure no context is specified for #id
141 if ( match && (match[1] || !context) ) {
142
143 // HANDLE: $(html) -> $(array)
144 if ( match[1] ) {
145 context = context instanceof jQuery ? context[0] : context;
146
147 // scripts is true for back-compat
148 jQuery.merge( this, jQuery.parseHTML(
149 match[1],
150 context && context.nodeType ? context.ownerDocument || context : document,
151 true
152 ) );
153
154 // HANDLE: $(html, props)
155 if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) {
156 for ( match in context ) {
157 // Properties of context are called as methods if possible
158 if ( jQuery.isFunction( this[ match ] ) ) {
159 this[ match ]( context[ match ] );
160
161 // ...and otherwise set as attributes
162 } else {
163 this.attr( match, context[ match ] );
164 }
165 }
166 }
167
168 return this;
169
170 // HANDLE: $(#id)
171 } else {
172 elem = document.getElementById( match[2] );
173
174 // Check parentNode to catch when Blackberry 4.6 returns
175 // nodes that are no longer in the document #6963
176 if ( elem && elem.parentNode ) {
177 // Handle the case where IE and Opera return items
178 // by name instead of ID
179 if ( elem.id !== match[2] ) {
180 return rootjQuery.find( selector );
181 }
182
183 // Otherwise, we inject the element directly into the jQuery object
184 this.length = 1;
185 this[0] = elem;
186 }
187
188 this.context = document;
189 this.selector = selector;
190 return this;
191 }
192
193 // HANDLE: $(expr, $(...))
194 } else if ( !context || context.jquery ) {
195 return ( context || rootjQuery ).find( selector );
196
197 // HANDLE: $(expr, context)
198 // (which is just equivalent to: $(context).find(expr)
199 } else {
200 return this.constructor( context ).find( selector );
201 }
202
203 // HANDLE: $(DOMElement)
204 } else if ( selector.nodeType ) {
205 this.context = this[0] = selector;
206 this.length = 1;
207 return this;
208
209 // HANDLE: $(function)
210 // Shortcut for document ready
211 } else if ( jQuery.isFunction( selector ) ) {
212 return rootjQuery.ready( selector );
213 }
214
215 if ( selector.selector !== undefined ) {
216 this.selector = selector.selector;
217 this.context = selector.context;
218 }
219
220 return jQuery.makeArray( selector, this );
221 },
222
223 // Start with an empty selector
224 selector: "",
225
226 // The default length of a jQuery object is 0
227 length: 0,
228
229 // The number of elements contained in the matched element set
230 size: function() {
231 return this.length;
232 },
233
234 toArray: function() {
235 return core_slice.call( this );
236 },
237
238 // Get the Nth element in the matched element set OR
239 // Get the whole matched element set as a clean array
240 get: function( num ) {
241 return num == null ?
242
243 // Return a 'clean' array
244 this.toArray() :
245
246 // Return just the object
247 ( num < 0 ? this[ this.length + num ] : this[ num ] );
248 },
249
250 // Take an array of elements and push it onto the stack
251 // (returning the new matched element set)
252 pushStack: function( elems ) {
253
254 // Build a new jQuery matched element set
255 var ret = jQuery.merge( this.constructor(), elems );
256
257 // Add the old object onto the stack (as a reference)
258 ret.prevObject = this;
259 ret.context = this.context;
260
261 // Return the newly-formed element set
262 return ret;
263 },
264
265 // Execute a callback for every element in the matched set.
266 // (You can seed the arguments with an array of args, but this is
267 // only used internally.)
268 each: function( callback, args ) {
269 return jQuery.each( this, callback, args );
270 },
271
272 ready: function( fn ) {
273 // Add the callback
274 jQuery.ready.promise().done( fn );
275
276 return this;
277 },
278
279 slice: function() {
280 return this.pushStack( core_slice.apply( this, arguments ) );
281 },
282
283 first: function() {
284 return this.eq( 0 );
285 },
286
287 last: function() {
288 return this.eq( -1 );
289 },
290
291 eq: function( i ) {
292 var len = this.length,
293 j = +i + ( i < 0 ? len : 0 );
294 return this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] );
295 },
296
297 map: function( callback ) {
298 return this.pushStack( jQuery.map(this, function( elem, i ) {
299 return callback.call( elem, i, elem );
300 }));
301 },
302
303 end: function() {
304 return this.prevObject || this.constructor(null);
305 },
306
307 // For internal use only.
308 // Behaves like an Array's method, not like a jQuery method.
309 push: core_push,
310 sort: [].sort,
311 splice: [].splice
312 };
313
314 // Give the init function the jQuery prototype for later instantiation
315 jQuery.fn.init.prototype = jQuery.fn;
316
317 jQuery.extend = jQuery.fn.extend = function() {
318 var src, copyIsArray, copy, name, options, clone,
319 target = arguments[0] || {},
320 i = 1,
321 length = arguments.length,
322 deep = false;
323
324 // Handle a deep copy situation
325 if ( typeof target === "boolean" ) {
326 deep = target;
327 target = arguments[1] || {};
328 // skip the boolean and the target
329 i = 2;
330 }
331
332 // Handle case when target is a string or something (possible in deep copy)
333 if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
334 target = {};
335 }
336
337 // extend jQuery itself if only one argument is passed
338 if ( length === i ) {
339 target = this;
340 --i;
341 }
342
343 for ( ; i < length; i++ ) {
344 // Only deal with non-null/undefined values
345 if ( (options = arguments[ i ]) != null ) {
346 // Extend the base object
347 for ( name in options ) {
348 src = target[ name ];
349 copy = options[ name ];
350
351 // Prevent never-ending loop
352 if ( target === copy ) {
353 continue;
354 }
355
356 // Recurse if we're merging plain objects or arrays
357 if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
358 if ( copyIsArray ) {
359 copyIsArray = false;
360 clone = src && jQuery.isArray(src) ? src : [];
361
362 } else {
363 clone = src && jQuery.isPlainObject(src) ? src : {};
364 }
365
366 // Never move original objects, clone them
367 target[ name ] = jQuery.extend( deep, clone, copy );
368
369 // Don't bring in undefined values
370 } else if ( copy !== undefined ) {
371 target[ name ] = copy;
372 }
373 }
374 }
375 }
376
377 // Return the modified object
378 return target;
379 };
380
381 jQuery.extend({
382 noConflict: function( deep ) {
383 if ( window.$ === jQuery ) {
384 window.$ = _$;
385 }
386
387 if ( deep && window.jQuery === jQuery ) {
388 window.jQuery = _jQuery;
389 }
390
391 return jQuery;
392 },
393
394 // Is the DOM ready to be used? Set to true once it occurs.
395 isReady: false,
396
397 // A counter to track how many items to wait for before
398 // the ready event fires. See #6781
399 readyWait: 1,
400
401 // Hold (or release) the ready event
402 holdReady: function( hold ) {
403 if ( hold ) {
404 jQuery.readyWait++;
405 } else {
406 jQuery.ready( true );
407 }
408 },
409
410 // Handle when the DOM is ready
411 ready: function( wait ) {
412
413 // Abort if there are pending holds or we're already ready
414 if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
415 return;
416 }
417
418 // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
419 if ( !document.body ) {
420 return setTimeout( jQuery.ready );
421 }
422
423 // Remember that the DOM is ready
424 jQuery.isReady = true;
425
426 // If a normal DOM Ready event fired, decrement, and wait if need be
427 if ( wait !== true && --jQuery.readyWait > 0 ) {
428 return;
429 }
430
431 // If there are functions bound, to execute
432 readyList.resolveWith( document, [ jQuery ] );
433
434 // Trigger any bound ready events
435 if ( jQuery.fn.trigger ) {
436 jQuery( document ).trigger("ready").off("ready");
437 }
438 },
439
440 // See test/unit/core.js for details concerning isFunction.
441 // Since version 1.3, DOM methods and functions like alert
442 // aren't supported. They return false on IE (#2968).
443 isFunction: function( obj ) {
444 return jQuery.type(obj) === "function";
445 },
446
447 isArray: Array.isArray || function( obj ) {
448 return jQuery.type(obj) === "array";
449 },
450
451 isWindow: function( obj ) {
452 return obj != null && obj == obj.window;
453 },
454
455 isNumeric: function( obj ) {
456 return !isNaN( parseFloat(obj) ) && isFinite( obj );
457 },
458
459 type: function( obj ) {
460 if ( obj == null ) {
461 return String( obj );
462 }
463 return typeof obj === "object" || typeof obj === "function" ?
464 class2type[ core_toString.call(obj) ] || "object" :
465 typeof obj;
466 },
467
468 isPlainObject: function( obj ) {
469 // Must be an Object.
470 // Because of IE, we also have to check the presence of the constructor property.
471 // Make sure that DOM nodes and window objects don't pass through, as well
472 if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
473 return false;
474 }
475
476 try {
477 // Not own constructor property must be Object
478 if ( obj.constructor &&
479 !core_hasOwn.call(obj, "constructor") &&
480 !core_hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
481 return false;
482 }
483 } catch ( e ) {
484 // IE8,9 Will throw exceptions on certain host objects #9897
485 return false;
486 }
487
488 // Own properties are enumerated firstly, so to speed up,
489 // if last one is own, then all properties are own.
490
491 var key;
492 for ( key in obj ) {}
493
494 return key === undefined || core_hasOwn.call( obj, key );
495 },
496
497 isEmptyObject: function( obj ) {
498 var name;
499 for ( name in obj ) {
500 return false;
501 }
502 return true;
503 },
504
505 error: function( msg ) {
506 throw new Error( msg );
507 },
508
509 // data: string of html
510 // context (optional): If specified, the fragment will be created in this context, defaults to document
511 // keepScripts (optional): If true, will include scripts passed in the html string
512 parseHTML: function( data, context, keepScripts ) {
513 if ( !data || typeof data !== "string" ) {
514 return null;
515 }
516 if ( typeof context === "boolean" ) {
517 keepScripts = context;
518 context = false;
519 }
520 context = context || document;
521
522 var parsed = rsingleTag.exec( data ),
523 scripts = !keepScripts && [];
524
525 // Single tag
526 if ( parsed ) {
527 return [ context.createElement( parsed[1] ) ];
528 }
529
530 parsed = jQuery.buildFragment( [ data ], context, scripts );
531 if ( scripts ) {
532 jQuery( scripts ).remove();
533 }
534 return jQuery.merge( [], parsed.childNodes );
535 },
536
537 parseJSON: function( data ) {
538 // Attempt to parse using the native JSON parser first
539 if ( window.JSON && window.JSON.parse ) {
540 return window.JSON.parse( data );
541 }
542
543 if ( data === null ) {
544 return data;
545 }
546
547 if ( typeof data === "string" ) {
548
549 // Make sure leading/trailing whitespace is removed (IE can't handle it)
550 data = jQuery.trim( data );
551
552 if ( data ) {
553 // Make sure the incoming data is actual JSON
554 // Logic borrowed from http://json.org/json2.js
555 if ( rvalidchars.test( data.replace( rvalidescape, "@" )
556 .replace( rvalidtokens, "]" )
557 .replace( rvalidbraces, "")) ) {
558
559 return ( new Function( "return " + data ) )();
560 }
561 }
562 }
563
564 jQuery.error( "Invalid JSON: " + data );
565 },
566
567 // Cross-browser xml parsing
568 parseXML: function( data ) {
569 var xml, tmp;
570 if ( !data || typeof data !== "string" ) {
571 return null;
572 }
573 try {
574 if ( window.DOMParser ) { // Standard
575 tmp = new DOMParser();
576 xml = tmp.parseFromString( data , "text/xml" );
577 } else { // IE
578 xml = new ActiveXObject( "Microsoft.XMLDOM" );
579 xml.async = "false";
580 xml.loadXML( data );
581 }
582 } catch( e ) {
583 xml = undefined;
584 }
585 if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) {
586 jQuery.error( "Invalid XML: " + data );
587 }
588 return xml;
589 },
590
591 noop: function() {},
592
593 // Evaluates a script in a global context
594 // Workarounds based on findings by Jim Driscoll
595 // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context
596 globalEval: function( data ) {
597 if ( data && jQuery.trim( data ) ) {
598 // We use execScript on Internet Explorer
599 // We use an anonymous function so that context is window
600 // rather than jQuery in Firefox
601 ( window.execScript || function( data ) {
602 window[ "eval" ].call( window, data );
603 } )( data );
604 }
605 },
606
607 // Convert dashed to camelCase; used by the css and data modules
608 // Microsoft forgot to hump their vendor prefix (#9572)
609 camelCase: function( string ) {
610 return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
611 },
612
613 nodeName: function( elem, name ) {
614 return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
615 },
616
617 // args is for internal usage only
618 each: function( obj, callback, args ) {
619 var value,
620 i = 0,
621 length = obj.length,
622 isArray = isArraylike( obj );
623
624 if ( args ) {
625 if ( isArray ) {
626 for ( ; i < length; i++ ) {
627 value = callback.apply( obj[ i ], args );
628
629 if ( value === false ) {
630 break;
631 }
632 }
633 } else {
634 for ( i in obj ) {
635 value = callback.apply( obj[ i ], args );
636
637 if ( value === false ) {
638 break;
639 }
640 }
641 }
642
643 // A special, fast, case for the most common use of each
644 } else {
645 if ( isArray ) {
646 for ( ; i < length; i++ ) {
647 value = callback.call( obj[ i ], i, obj[ i ] );
648
649 if ( value === false ) {
650 break;
651 }
652 }
653 } else {
654 for ( i in obj ) {
655 value = callback.call( obj[ i ], i, obj[ i ] );
656
657 if ( value === false ) {
658 break;
659 }
660 }
661 }
662 }
663
664 return obj;
665 },
666
667 // Use native String.trim function wherever possible
668 trim: core_trim && !core_trim.call("\uFEFF\xA0") ?
669 function( text ) {
670 return text == null ?
671 "" :
672 core_trim.call( text );
673 } :
674
675 // Otherwise use our own trimming functionality
676 function( text ) {
677 return text == null ?
678 "" :
679 ( text + "" ).replace( rtrim, "" );
680 },
681
682 // results is for internal usage only
683 makeArray: function( arr, results ) {
684 var ret = results || [];
685
686 if ( arr != null ) {
687 if ( isArraylike( Object(arr) ) ) {
688 jQuery.merge( ret,
689 typeof arr === "string" ?
690 [ arr ] : arr
691 );
692 } else {
693 core_push.call( ret, arr );
694 }
695 }
696
697 return ret;
698 },
699
700 inArray: function( elem, arr, i ) {
701 var len;
702
703 if ( arr ) {
704 if ( core_indexOf ) {
705 return core_indexOf.call( arr, elem, i );
706 }
707
708 len = arr.length;
709 i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0;
710
711 for ( ; i < len; i++ ) {
712 // Skip accessing in sparse arrays
713 if ( i in arr && arr[ i ] === elem ) {
714 return i;
715 }
716 }
717 }
718
719 return -1;
720 },
721
722 merge: function( first, second ) {
723 var l = second.length,
724 i = first.length,
725 j = 0;
726
727 if ( typeof l === "number" ) {
728 for ( ; j < l; j++ ) {
729 first[ i++ ] = second[ j ];
730 }
731 } else {
732 while ( second[j] !== undefined ) {
733 first[ i++ ] = second[ j++ ];
734 }
735 }
736
737 first.length = i;
738
739 return first;
740 },
741
742 grep: function( elems, callback, inv ) {
743 var retVal,
744 ret = [],
745 i = 0,
746 length = elems.length;
747 inv = !!inv;
748
749 // Go through the array, only saving the items
750 // that pass the validator function
751 for ( ; i < length; i++ ) {
752 retVal = !!callback( elems[ i ], i );
753 if ( inv !== retVal ) {
754 ret.push( elems[ i ] );
755 }
756 }
757
758 return ret;
759 },
760
761 // arg is for internal usage only
762 map: function( elems, callback, arg ) {
763 var value,
764 i = 0,
765 length = elems.length,
766 isArray = isArraylike( elems ),
767 ret = [];
768
769 // Go through the array, translating each of the items to their
770 if ( isArray ) {
771 for ( ; i < length; i++ ) {
772 value = callback( elems[ i ], i, arg );
773
774 if ( value != null ) {
775 ret[ ret.length ] = value;
776 }
777 }
778
779 // Go through every key on the object,
780 } else {
781 for ( i in elems ) {
782 value = callback( elems[ i ], i, arg );
783
784 if ( value != null ) {
785 ret[ ret.length ] = value;
786 }
787 }
788 }
789
790 // Flatten any nested arrays
791 return core_concat.apply( [], ret );
792 },
793
794 // A global GUID counter for objects
795 guid: 1,
796
797 // Bind a function to a context, optionally partially applying any
798 // arguments.
799 proxy: function( fn, context ) {
800 var args, proxy, tmp;
801
802 if ( typeof context === "string" ) {
803 tmp = fn[ context ];
804 context = fn;
805 fn = tmp;
806 }
807
808 // Quick check to determine if target is callable, in the spec
809 // this throws a TypeError, but we will just return undefined.
810 if ( !jQuery.isFunction( fn ) ) {
811 return undefined;
812 }
813
814 // Simulated bind
815 args = core_slice.call( arguments, 2 );
816 proxy = function() {
817 return fn.apply( context || this, args.concat( core_slice.call( arguments ) ) );
818 };
819
820 // Set the guid of unique handler to the same of original handler, so it can be removed
821 proxy.guid = fn.guid = fn.guid || jQuery.guid++;
822
823 return proxy;
824 },
825
826 // Multifunctional method to get and set values of a collection
827 // The value/s can optionally be executed if it's a function
828 access: function( elems, fn, key, value, chainable, emptyGet, raw ) {
829 var i = 0,
830 length = elems.length,
831 bulk = key == null;
832
833 // Sets many values
834 if ( jQuery.type( key ) === "object" ) {
835 chainable = true;
836 for ( i in key ) {
837 jQuery.access( elems, fn, i, key[i], true, emptyGet, raw );
838 }
839
840 // Sets one value
841 } else if ( value !== undefined ) {
842 chainable = true;
843
844 if ( !jQuery.isFunction( value ) ) {
845 raw = true;
846 }
847
848 if ( bulk ) {
849 // Bulk operations run against the entire set
850 if ( raw ) {
851 fn.call( elems, value );
852 fn = null;
853
854 // ...except when executing function values
855 } else {
856 bulk = fn;
857 fn = function( elem, key, value ) {
858 return bulk.call( jQuery( elem ), value );
859 };
860 }
861 }
862
863 if ( fn ) {
864 for ( ; i < length; i++ ) {
865 fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) );
866 }
867 }
868 }
869
870 return chainable ?
871 elems :
872
873 // Gets
874 bulk ?
875 fn.call( elems ) :
876 length ? fn( elems[0], key ) : emptyGet;
877 },
878
879 now: function() {
880 return ( new Date() ).getTime();
881 }
882 });
883
884 jQuery.ready.promise = function( obj ) {
885 if ( !readyList ) {
886
887 readyList = jQuery.Deferred();
888
889 // Catch cases where $(document).ready() is called after the browser event has already occurred.
890 // we once tried to use readyState "interactive" here, but it caused issues like the one
891 // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15
892 if ( document.readyState === "complete" ) {
893 // Handle it asynchronously to allow scripts the opportunity to delay ready
894 setTimeout( jQuery.ready );
895
896 // Standards-based browsers support DOMContentLoaded
897 } else if ( document.addEventListener ) {
898 // Use the handy event callback
899 document.addEventListener( "DOMContentLoaded", completed, false );
900
901 // A fallback to window.onload, that will always work
902 window.addEventListener( "load", completed, false );
903
904 // If IE event model is used
905 } else {
906 // Ensure firing before onload, maybe late but safe also for iframes
907 document.attachEvent( "onreadystatechange", completed );
908
909 // A fallback to window.onload, that will always work
910 window.attachEvent( "onload", completed );
911
912 // If IE and not a frame
913 // continually check to see if the document is ready
914 var top = false;
915
916 try {
917 top = window.frameElement == null && document.documentElement;
918 } catch(e) {}
919
920 if ( top && top.doScroll ) {
921 (function doScrollCheck() {
922 if ( !jQuery.isReady ) {
923
924 try {
925 // Use the trick by Diego Perini
926 // http://javascript.nwbox.com/IEContentLoaded/
927 top.doScroll("left");
928 } catch(e) {
929 return setTimeout( doScrollCheck, 50 );
930 }
931
932 // detach all dom ready events
933 detach();
934
935 // and execute any waiting functions
936 jQuery.ready();
937 }
938 })();
939 }
940 }
941 }
942 return readyList.promise( obj );
943 };
944
945 // Populate the class2type map
946 jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) {
947 class2type[ "[object " + name + "]" ] = name.toLowerCase();
948 });
949
950 function isArraylike( obj ) {
951 var length = obj.length,
952 type = jQuery.type( obj );
953
954 if ( jQuery.isWindow( obj ) ) {
955 return false;
956 }
957
958 if ( obj.nodeType === 1 && length ) {
959 return true;
960 }
961
962 return type === "array" || type !== "function" &&
963 ( length === 0 ||
964 typeof length === "number" && length > 0 && ( length - 1 ) in obj );
965 }
966
967 // All jQuery objects should point back to these
968 rootjQuery = jQuery(document);
969 // String to Object options format cache
970 var optionsCache = {};
971
972 // Convert String-formatted options into Object-formatted ones and store in cache
973 function createOptions( options ) {
974 var object = optionsCache[ options ] = {};
975 jQuery.each( options.match( core_rnotwhite ) || [], function( _, flag ) {
976 object[ flag ] = true;
977 });
978 return object;
979 }
980
981 /*
982 * Create a callback list using the following parameters:
983 *
984 * options: an optional list of space-separated options that will change how
985 * the callback list behaves or a more traditional option object
986 *
987 * By default a callback list will act like an event callback list and can be
988 * "fired" multiple times.
989 *
990 * Possible options:
991 *
992 * once: will ensure the callback list can only be fired once (like a Deferred)
993 *
994 * memory: will keep track of previous values and will call any callback added
995 * after the list has been fired right away with the latest "memorized"
996 * values (like a Deferred)
997 *
998 * unique: will ensure a callback can only be added once (no duplicate in the list)
999 *
1000 * stopOnFalse: interrupt callings when a callback returns false
1001 *
1002 */
1003 jQuery.Callbacks = function( options ) {
1004
1005 // Convert options from String-formatted to Object-formatted if needed
1006 // (we check in cache first)
1007 options = typeof options === "string" ?
1008 ( optionsCache[ options ] || createOptions( options ) ) :
1009 jQuery.extend( {}, options );
1010
1011 var // Flag to know if list is currently firing
1012 firing,
1013 // Last fire value (for non-forgettable lists)
1014 memory,
1015 // Flag to know if list was already fired
1016 fired,
1017 // End of the loop when firing
1018 firingLength,
1019 // Index of currently firing callback (modified by remove if needed)
1020 firingIndex,
1021 // First callback to fire (used internally by add and fireWith)
1022 firingStart,
1023 // Actual callback list
1024 list = [],
1025 // Stack of fire calls for repeatable lists
1026 stack = !options.once && [],
1027 // Fire callbacks
1028 fire = function( data ) {
1029 memory = options.memory && data;
1030 fired = true;
1031 firingIndex = firingStart || 0;
1032 firingStart = 0;
1033 firingLength = list.length;
1034 firing = true;
1035 for ( ; list && firingIndex < firingLength; firingIndex++ ) {
1036 if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {
1037 memory = false; // To prevent further calls using add
1038 break;
1039 }
1040 }
1041 firing = false;
1042 if ( list ) {
1043 if ( stack ) {
1044 if ( stack.length ) {
1045 fire( stack.shift() );
1046 }
1047 } else if ( memory ) {
1048 list = [];
1049 } else {
1050 self.disable();
1051 }
1052 }
1053 },
1054 // Actual Callbacks object
1055 self = {
1056 // Add a callback or a collection of callbacks to the list
1057 add: function() {
1058 if ( list ) {
1059 // First, we save the current length
1060 var start = list.length;
1061 (function add( args ) {
1062 jQuery.each( args, function( _, arg ) {
1063 var type = jQuery.type( arg );
1064 if ( type === "function" ) {
1065 if ( !options.unique || !self.has( arg ) ) {
1066 list.push( arg );
1067 }
1068 } else if ( arg && arg.length && type !== "string" ) {
1069 // Inspect recursively
1070 add( arg );
1071 }
1072 });
1073 })( arguments );
1074 // Do we need to add the callbacks to the
1075 // current firing batch?
1076 if ( firing ) {
1077 firingLength = list.length;
1078 // With memory, if we're not firing then
1079 // we should call right away
1080 } else if ( memory ) {
1081 firingStart = start;
1082 fire( memory );
1083 }
1084 }
1085 return this;
1086 },
1087 // Remove a callback from the list
1088 remove: function() {
1089 if ( list ) {
1090 jQuery.each( arguments, function( _, arg ) {
1091 var index;
1092 while( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
1093 list.splice( index, 1 );
1094 // Handle firing indexes
1095 if ( firing ) {
1096 if ( index <= firingLength ) {
1097 firingLength--;
1098 }
1099 if ( index <= firingIndex ) {
1100 firingIndex--;
1101 }
1102 }
1103 }
1104 });
1105 }
1106 return this;
1107 },
1108 // Check if a given callback is in the list.
1109 // If no argument is given, return whether or not list has callbacks attached.
1110 has: function( fn ) {
1111 return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length );
1112 },
1113 // Remove all callbacks from the list
1114 empty: function() {
1115 list = [];
1116 return this;
1117 },
1118 // Have the list do nothing anymore
1119 disable: function() {
1120 list = stack = memory = undefined;
1121 return this;
1122 },
1123 // Is it disabled?
1124 disabled: function() {
1125 return !list;
1126 },
1127 // Lock the list in its current state
1128 lock: function() {
1129 stack = undefined;
1130 if ( !memory ) {
1131 self.disable();
1132 }
1133 return this;
1134 },
1135 // Is it locked?
1136 locked: function() {
1137 return !stack;
1138 },
1139 // Call all callbacks with the given context and arguments
1140 fireWith: function( context, args ) {
1141 args = args || [];
1142 args = [ context, args.slice ? args.slice() : args ];
1143 if ( list && ( !fired || stack ) ) {
1144 if ( firing ) {
1145 stack.push( args );
1146 } else {
1147 fire( args );
1148 }
1149 }
1150 return this;
1151 },
1152 // Call all the callbacks with the given arguments
1153 fire: function() {
1154 self.fireWith( this, arguments );
1155 return this;
1156 },
1157 // To know if the callbacks have already been called at least once
1158 fired: function() {
1159 return !!fired;
1160 }
1161 };
1162
1163 return self;
1164 };
1165 jQuery.extend({
1166
1167 Deferred: function( func ) {
1168 var tuples = [
1169 // action, add listener, listener list, final state
1170 [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],
1171 [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],
1172 [ "notify", "progress", jQuery.Callbacks("memory") ]
1173 ],
1174 state = "pending",
1175 promise = {
1176 state: function() {
1177 return state;
1178 },
1179 always: function() {
1180 deferred.done( arguments ).fail( arguments );
1181 return this;
1182 },
1183 then: function( /* fnDone, fnFail, fnProgress */ ) {
1184 var fns = arguments;
1185 return jQuery.Deferred(function( newDefer ) {
1186 jQuery.each( tuples, function( i, tuple ) {
1187 var action = tuple[ 0 ],
1188 fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];
1189 // deferred[ done | fail | progress ] for forwarding actions to newDefer
1190 deferred[ tuple[1] ](function() {
1191 var returned = fn && fn.apply( this, arguments );
1192 if ( returned && jQuery.isFunction( returned.promise ) ) {
1193 returned.promise()
1194 .done( newDefer.resolve )
1195 .fail( newDefer.reject )
1196 .progress( newDefer.notify );
1197 } else {
1198 newDefer[ action + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );
1199 }
1200 });
1201 });
1202 fns = null;
1203 }).promise();
1204 },
1205 // Get a promise for this deferred
1206 // If obj is provided, the promise aspect is added to the object
1207 promise: function( obj ) {
1208 return obj != null ? jQuery.extend( obj, promise ) : promise;
1209 }
1210 },
1211 deferred = {};
1212
1213 // Keep pipe for back-compat
1214 promise.pipe = promise.then;
1215
1216 // Add list-specific methods
1217 jQuery.each( tuples, function( i, tuple ) {
1218 var list = tuple[ 2 ],
1219 stateString = tuple[ 3 ];
1220
1221 // promise[ done | fail | progress ] = list.add
1222 promise[ tuple[1] ] = list.add;
1223
1224 // Handle state
1225 if ( stateString ) {
1226 list.add(function() {
1227 // state = [ resolved | rejected ]
1228 state = stateString;
1229
1230 // [ reject_list | resolve_list ].disable; progress_list.lock
1231 }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );
1232 }
1233
1234 // deferred[ resolve | reject | notify ]
1235 deferred[ tuple[0] ] = function() {
1236 deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments );
1237 return this;
1238 };
1239 deferred[ tuple[0] + "With" ] = list.fireWith;
1240 });
1241
1242 // Make the deferred a promise
1243 promise.promise( deferred );
1244
1245 // Call given func if any
1246 if ( func ) {
1247 func.call( deferred, deferred );
1248 }
1249
1250 // All done!
1251 return deferred;
1252 },
1253
1254 // Deferred helper
1255 when: function( subordinate /* , ..., subordinateN */ ) {
1256 var i = 0,
1257 resolveValues = core_slice.call( arguments ),
1258 length = resolveValues.length,
1259
1260 // the count of uncompleted subordinates
1261 remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,
1262
1263 // the master Deferred. If resolveValues consist of only a single Deferred, just use that.
1264 deferred = remaining === 1 ? subordinate : jQuery.Deferred(),
1265
1266 // Update function for both resolve and progress values
1267 updateFunc = function( i, contexts, values ) {
1268 return function( value ) {
1269 contexts[ i ] = this;
1270 values[ i ] = arguments.length > 1 ? core_slice.call( arguments ) : value;
1271 if( values === progressValues ) {
1272 deferred.notifyWith( contexts, values );
1273 } else if ( !( --remaining ) ) {
1274 deferred.resolveWith( contexts, values );
1275 }
1276 };
1277 },
1278
1279 progressValues, progressContexts, resolveContexts;
1280
1281 // add listeners to Deferred subordinates; treat others as resolved
1282 if ( length > 1 ) {
1283 progressValues = new Array( length );
1284 progressContexts = new Array( length );
1285 resolveContexts = new Array( length );
1286 for ( ; i < length; i++ ) {
1287 if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {
1288 resolveValues[ i ].promise()
1289 .done( updateFunc( i, resolveContexts, resolveValues ) )
1290 .fail( deferred.reject )
1291 .progress( updateFunc( i, progressContexts, progressValues ) );
1292 } else {
1293 --remaining;
1294 }
1295 }
1296 }
1297
1298 // if we're not waiting on anything, resolve the master
1299 if ( !remaining ) {
1300 deferred.resolveWith( resolveContexts, resolveValues );
1301 }
1302
1303 return deferred.promise();
1304 }
1305 });
1306 jQuery.support = (function() {
1307
1308 var support, all, a,
1309 input, select, fragment,
1310 opt, eventName, isSupported, i,
1311 div = document.createElement("div");
1312
1313 // Setup
1314 div.setAttribute( "className", "t" );
1315 div.innerHTML = " <link/><table></table><a href='/a'>a</a><input type='checkbox'/>";
1316
1317 // Support tests won't run in some limited or non-browser environments
1318 all = div.getElementsByTagName("*");
1319 a = div.getElementsByTagName("a")[ 0 ];
1320 if ( !all || !a || !all.length ) {
1321 return {};
1322 }
1323
1324 // First batch of tests
1325 select = document.createElement("select");
1326 opt = select.appendChild( document.createElement("option") );
1327 input = div.getElementsByTagName("input")[ 0 ];
1328
1329 a.style.cssText = "top:1px;float:left;opacity:.5";
1330 support = {
1331 // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7)
1332 getSetAttribute: div.className !== "t",
1333
1334 // IE strips leading whitespace when .innerHTML is used
1335 leadingWhitespace: div.firstChild.nodeType === 3,
1336
1337 // Make sure that tbody elements aren't automatically inserted
1338 // IE will insert them into empty tables
1339 tbody: !div.getElementsByTagName("tbody").length,
1340
1341 // Make sure that link elements get serialized correctly by innerHTML
1342 // This requires a wrapper element in IE
1343 htmlSerialize: !!div.getElementsByTagName("link").length,
1344
1345 // Get the style information from getAttribute
1346 // (IE uses .cssText instead)
1347 style: /top/.test( a.getAttribute("style") ),
1348
1349 // Make sure that URLs aren't manipulated
1350 // (IE normalizes it by default)
1351 hrefNormalized: a.getAttribute("href") === "/a",
1352
1353 // Make sure that element opacity exists
1354 // (IE uses filter instead)
1355 // Use a regex to work around a WebKit issue. See #5145
1356 opacity: /^0.5/.test( a.style.opacity ),
1357
1358 // Verify style float existence
1359 // (IE uses styleFloat instead of cssFloat)
1360 cssFloat: !!a.style.cssFloat,
1361
1362 // Check the default checkbox/radio value ("" on WebKit; "on" elsewhere)
1363 checkOn: !!input.value,
1364
1365 // Make sure that a selected-by-default option has a working selected property.
1366 // (WebKit defaults to false instead of true, IE too, if it's in an optgroup)
1367 optSelected: opt.selected,
1368
1369 // Tests for enctype support on a form (#6743)
1370 enctype: !!document.createElement("form").enctype,
1371
1372 // Makes sure cloning an html5 element does not cause problems
1373 // Where outerHTML is undefined, this still works
1374 html5Clone: document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav></:nav>",
1375
1376 // jQuery.support.boxModel DEPRECATED in 1.8 since we don't support Quirks Mode
1377 boxModel: document.compatMode === "CSS1Compat",
1378
1379 // Will be defined later
1380 deleteExpando: true,
1381 noCloneEvent: true,
1382 inlineBlockNeedsLayout: false,
1383 shrinkWrapBlocks: false,
1384 reliableMarginRight: true,
1385 boxSizingReliable: true,
1386 pixelPosition: false
1387 };
1388
1389 // Make sure checked status is properly cloned
1390 input.checked = true;
1391 support.noCloneChecked = input.cloneNode( true ).checked;
1392
1393 // Make sure that the options inside disabled selects aren't marked as disabled
1394 // (WebKit marks them as disabled)
1395 select.disabled = true;
1396 support.optDisabled = !opt.disabled;
1397
1398 // Support: IE<9
1399 try {
1400 delete div.test;
1401 } catch( e ) {
1402 support.deleteExpando = false;
1403 }
1404
1405 // Check if we can trust getAttribute("value")
1406 input = document.createElement("input");
1407 input.setAttribute( "value", "" );
1408 support.input = input.getAttribute( "value" ) === "";
1409
1410 // Check if an input maintains its value after becoming a radio
1411 input.value = "t";
1412 input.setAttribute( "type", "radio" );
1413 support.radioValue = input.value === "t";
1414
1415 // #11217 - WebKit loses check when the name is after the checked attribute
1416 input.setAttribute( "checked", "t" );
1417 input.setAttribute( "name", "t" );
1418
1419 fragment = document.createDocumentFragment();
1420 fragment.appendChild( input );
1421
1422 // Check if a disconnected checkbox will retain its checked
1423 // value of true after appended to the DOM (IE6/7)
1424 support.appendChecked = input.checked;
1425
1426 // WebKit doesn't clone checked state correctly in fragments
1427 support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked;
1428
1429 // Support: IE<9
1430 // Opera does not clone events (and typeof div.attachEvent === undefined).
1431 // IE9-10 clones events bound via attachEvent, but they don't trigger with .click()
1432 if ( div.attachEvent ) {
1433 div.attachEvent( "onclick", function() {
1434 support.noCloneEvent = false;
1435 });
1436
1437 div.cloneNode( true ).click();
1438 }
1439
1440 // Support: IE<9 (lack submit/change bubble), Firefox 17+ (lack focusin event)
1441 // Beware of CSP restrictions (https://developer.mozilla.org/en/Security/CSP), test/csp.php
1442 for ( i in { submit: true, change: true, focusin: true }) {
1443 div.setAttribute( eventName = "on" + i, "t" );
1444
1445 support[ i + "Bubbles" ] = eventName in window || div.attributes[ eventName ].expando === false;
1446 }
1447
1448 div.style.backgroundClip = "content-box";
1449 div.cloneNode( true ).style.backgroundClip = "";
1450 support.clearCloneStyle = div.style.backgroundClip === "content-box";
1451
1452 // Run tests that need a body at doc ready
1453 jQuery(function() {
1454 var container, marginDiv, tds,
1455 divReset = "padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;",
1456 body = document.getElementsByTagName("body")[0];
1457
1458 if ( !body ) {
1459 // Return for frameset docs that don't have a body
1460 return;
1461 }
1462
1463 container = document.createElement("div");
1464 container.style.cssText = "border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px";
1465
1466 body.appendChild( container ).appendChild( div );
1467
1468 // Support: IE8
1469 // Check if table cells still have offsetWidth/Height when they are set
1470 // to display:none and there are still other visible table cells in a
1471 // table row; if so, offsetWidth/Height are not reliable for use when
1472 // determining if an element has been hidden directly using
1473 // display:none (it is still safe to use offsets if a parent element is
1474 // hidden; don safety goggles and see bug #4512 for more information).
1475 div.innerHTML = "<table><tr><td></td><td>t</td></tr></table>";
1476 tds = div.getElementsByTagName("td");
1477 tds[ 0 ].style.cssText = "padding:0;margin:0;border:0;display:none";
1478 isSupported = ( tds[ 0 ].offsetHeight === 0 );
1479
1480 tds[ 0 ].style.display = "";
1481 tds[ 1 ].style.display = "none";
1482
1483 // Support: IE8
1484 // Check if empty table cells still have offsetWidth/Height
1485 support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 );
1486
1487 // Check box-sizing and margin behavior
1488 div.innerHTML = "";
1489 div.style.cssText = "box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;";
1490 support.boxSizing = ( div.offsetWidth === 4 );
1491 support.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== 1 );
1492
1493 // Use window.getComputedStyle because jsdom on node.js will break without it.
1494 if ( window.getComputedStyle ) {
1495 support.pixelPosition = ( window.getComputedStyle( div, null ) || {} ).top !== "1%";
1496 support.boxSizingReliable = ( window.getComputedStyle( div, null ) || { width: "4px" } ).width === "4px";
1497
1498 // Check if div with explicit width and no margin-right incorrectly
1499 // gets computed margin-right based on width of container. (#3333)
1500 // Fails in WebKit before Feb 2011 nightlies
1501 // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
1502 marginDiv = div.appendChild( document.createElement("div") );
1503 marginDiv.style.cssText = div.style.cssText = divReset;
1504 marginDiv.style.marginRight = marginDiv.style.width = "0";
1505 div.style.width = "1px";
1506
1507 support.reliableMarginRight =
1508 !parseFloat( ( window.getComputedStyle( marginDiv, null ) || {} ).marginRight );
1509 }
1510
1511 if ( typeof div.style.zoom !== core_strundefined ) {
1512 // Support: IE<8
1513 // Check if natively block-level elements act like inline-block
1514 // elements when setting their display to 'inline' and giving
1515 // them layout
1516 div.innerHTML = "";
1517 div.style.cssText = divReset + "width:1px;padding:1px;display:inline;zoom:1";
1518 support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 );
1519
1520 // Support: IE6
1521 // Check if elements with layout shrink-wrap their children
1522 div.style.display = "block";
1523 div.innerHTML = "<div></div>";
1524 div.firstChild.style.width = "5px";
1525 support.shrinkWrapBlocks = ( div.offsetWidth !== 3 );
1526
1527 if ( support.inlineBlockNeedsLayout ) {
1528 // Prevent IE 6 from affecting layout for positioned elements #11048
1529 // Prevent IE from shrinking the body in IE 7 mode #12869
1530 // Support: IE<8
1531 body.style.zoom = 1;
1532 }
1533 }
1534
1535 body.removeChild( container );
1536
1537 // Null elements to avoid leaks in IE
1538 container = div = tds = marginDiv = null;
1539 });
1540
1541 // Null elements to avoid leaks in IE
1542 all = select = fragment = opt = a = input = null;
1543
1544 return support;
1545 })();
1546
1547 var rbrace = /(?:\{[\s\S]*\}|\[[\s\S]*\])$/,
1548 rmultiDash = /([A-Z])/g;
1549
1550 function internalData( elem, name, data, pvt /* Internal Use Only */ ){
1551 if ( !jQuery.acceptData( elem ) ) {
1552 return;
1553 }
1554
1555 var thisCache, ret,
1556 internalKey = jQuery.expando,
1557 getByName = typeof name === "string",
1558
1559 // We have to handle DOM nodes and JS objects differently because IE6-7
1560 // can't GC object references properly across the DOM-JS boundary
1561 isNode = elem.nodeType,
1562
1563 // Only DOM nodes need the global jQuery cache; JS object data is
1564 // attached directly to the object so GC can occur automatically
1565 cache = isNode ? jQuery.cache : elem,
1566
1567 // Only defining an ID for JS objects if its cache already exists allows
1568 // the code to shortcut on the same path as a DOM node with no cache
1569 id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey;
1570
1571 // Avoid doing any more work than we need to when trying to get data on an
1572 // object that has no data at all
1573 if ( (!id || !cache[id] || (!pvt && !cache[id].data)) && getByName && data === undefined ) {
1574 return;
1575 }
1576
1577 if ( !id ) {
1578 // Only DOM nodes need a new unique ID for each element since their data
1579 // ends up in the global cache
1580 if ( isNode ) {
1581 elem[ internalKey ] = id = core_deletedIds.pop() || jQuery.guid++;
1582 } else {
1583 id = internalKey;
1584 }
1585 }
1586
1587 if ( !cache[ id ] ) {
1588 cache[ id ] = {};
1589
1590 // Avoids exposing jQuery metadata on plain JS objects when the object
1591 // is serialized using JSON.stringify
1592 if ( !isNode ) {
1593 cache[ id ].toJSON = jQuery.noop;
1594 }
1595 }
1596
1597 // An object can be passed to jQuery.data instead of a key/value pair; this gets
1598 // shallow copied over onto the existing cache
1599 if ( typeof name === "object" || typeof name === "function" ) {
1600 if ( pvt ) {
1601 cache[ id ] = jQuery.extend( cache[ id ], name );
1602 } else {
1603 cache[ id ].data = jQuery.extend( cache[ id ].data, name );
1604 }
1605 }
1606
1607 thisCache = cache[ id ];
1608
1609 // jQuery data() is stored in a separate object inside the object's internal data
1610 // cache in order to avoid key collisions between internal data and user-defined
1611 // data.
1612 if ( !pvt ) {
1613 if ( !thisCache.data ) {
1614 thisCache.data = {};
1615 }
1616
1617 thisCache = thisCache.data;
1618 }
1619
1620 if ( data !== undefined ) {
1621 thisCache[ jQuery.camelCase( name ) ] = data;
1622 }
1623
1624 // Check for both converted-to-camel and non-converted data property names
1625 // If a data property was specified
1626 if ( getByName ) {
1627
1628 // First Try to find as-is property data
1629 ret = thisCache[ name ];
1630
1631 // Test for null|undefined property data
1632 if ( ret == null ) {
1633
1634 // Try to find the camelCased property
1635 ret = thisCache[ jQuery.camelCase( name ) ];
1636 }
1637 } else {
1638 ret = thisCache;
1639 }
1640
1641 return ret;
1642 }
1643
1644 function internalRemoveData( elem, name, pvt ) {
1645 if ( !jQuery.acceptData( elem ) ) {
1646 return;
1647 }
1648
1649 var i, l, thisCache,
1650 isNode = elem.nodeType,
1651
1652 // See jQuery.data for more information
1653 cache = isNode ? jQuery.cache : elem,
1654 id = isNode ? elem[ jQuery.expando ] : jQuery.expando;
1655
1656 // If there is already no cache entry for this object, there is no
1657 // purpose in continuing
1658 if ( !cache[ id ] ) {
1659 return;
1660 }
1661
1662 if ( name ) {
1663
1664 thisCache = pvt ? cache[ id ] : cache[ id ].data;
1665
1666 if ( thisCache ) {
1667
1668 // Support array or space separated string names for data keys
1669 if ( !jQuery.isArray( name ) ) {
1670
1671 // try the string as a key before any manipulation
1672 if ( name in thisCache ) {
1673 name = [ name ];
1674 } else {
1675
1676 // split the camel cased version by spaces unless a key with the spaces exists
1677 name = jQuery.camelCase( name );
1678 if ( name in thisCache ) {
1679 name = [ name ];
1680 } else {
1681 name = name.split(" ");
1682 }
1683 }
1684 } else {
1685 // If "name" is an array of keys...
1686 // When data is initially created, via ("key", "val") signature,
1687 // keys will be converted to camelCase.
1688 // Since there is no way to tell _how_ a key was added, remove
1689 // both plain key and camelCase key. #12786
1690 // This will only penalize the array argument path.
1691 name = name.concat( jQuery.map( name, jQuery.camelCase ) );
1692 }
1693
1694 for ( i = 0, l = name.length; i < l; i++ ) {
1695 delete thisCache[ name[i] ];
1696 }
1697
1698 // If there is no data left in the cache, we want to continue
1699 // and let the cache object itself get destroyed
1700 if ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) {
1701 return;
1702 }
1703 }
1704 }
1705
1706 // See jQuery.data for more information
1707 if ( !pvt ) {
1708 delete cache[ id ].data;
1709
1710 // Don't destroy the parent cache unless the internal data object
1711 // had been the only thing left in it
1712 if ( !isEmptyDataObject( cache[ id ] ) ) {
1713 return;
1714 }
1715 }
1716
1717 // Destroy the cache
1718 if ( isNode ) {
1719 jQuery.cleanData( [ elem ], true );
1720
1721 // Use delete when supported for expandos or `cache` is not a window per isWindow (#10080)
1722 } else if ( jQuery.support.deleteExpando || cache != cache.window ) {
1723 delete cache[ id ];
1724
1725 // When all else fails, null
1726 } else {
1727 cache[ id ] = null;
1728 }
1729 }
1730
1731 jQuery.extend({
1732 cache: {},
1733
1734 // Unique for each copy of jQuery on the page
1735 // Non-digits removed to match rinlinejQuery
1736 expando: "jQuery" + ( core_version + Math.random() ).replace( /\D/g, "" ),
1737
1738 // The following elements throw uncatchable exceptions if you
1739 // attempt to add expando properties to them.
1740 noData: {
1741 "embed": true,
1742 // Ban all objects except for Flash (which handle expandos)
1743 "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",
1744 "applet": true
1745 },
1746
1747 hasData: function( elem ) {
1748 elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];
1749 return !!elem && !isEmptyDataObject( elem );
1750 },
1751
1752 data: function( elem, name, data ) {
1753 return internalData( elem, name, data );
1754 },
1755
1756 removeData: function( elem, name ) {
1757 return internalRemoveData( elem, name );
1758 },
1759
1760 // For internal use only.
1761 _data: function( elem, name, data ) {
1762 return internalData( elem, name, data, true );
1763 },
1764
1765 _removeData: function( elem, name ) {
1766 return internalRemoveData( elem, name, true );
1767 },
1768
1769 // A method for determining if a DOM node can handle the data expando
1770 acceptData: function( elem ) {
1771 // Do not set data on non-element because it will not be cleared (#8335).
1772 if ( elem.nodeType && elem.nodeType !== 1 && elem.nodeType !== 9 ) {
1773 return false;
1774 }
1775
1776 var noData = elem.nodeName && jQuery.noData[ elem.nodeName.toLowerCase() ];
1777
1778 // nodes accept data unless otherwise specified; rejection can be conditional
1779 return !noData || noData !== true && elem.getAttribute("classid") === noData;
1780 }
1781 });
1782
1783 jQuery.fn.extend({
1784 data: function( key, value ) {
1785 var attrs, name,
1786 elem = this[0],
1787 i = 0,
1788 data = null;
1789
1790 // Gets all values
1791 if ( key === undefined ) {
1792 if ( this.length ) {
1793 data = jQuery.data( elem );
1794
1795 if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) {
1796 attrs = elem.attributes;
1797 for ( ; i < attrs.length; i++ ) {
1798 name = attrs[i].name;
1799
1800 if ( !name.indexOf( "data-" ) ) {
1801 name = jQuery.camelCase( name.slice(5) );
1802
1803 dataAttr( elem, name, data[ name ] );
1804 }
1805 }
1806 jQuery._data( elem, "parsedAttrs", true );
1807 }
1808 }
1809
1810 return data;
1811 }
1812
1813 // Sets multiple values
1814 if ( typeof key === "object" ) {
1815 return this.each(function() {
1816 jQuery.data( this, key );
1817 });
1818 }
1819
1820 return jQuery.access( this, function( value ) {
1821
1822 if ( value === undefined ) {
1823 // Try to fetch any internally stored data first
1824 return elem ? dataAttr( elem, key, jQuery.data( elem, key ) ) : null;
1825 }
1826
1827 this.each(function() {
1828 jQuery.data( this, key, value );
1829 });
1830 }, null, value, arguments.length > 1, null, true );
1831 },
1832
1833 removeData: function( key ) {
1834 return this.each(function() {
1835 jQuery.removeData( this, key );
1836 });
1837 }
1838 });
1839
1840 function dataAttr( elem, key, data ) {
1841 // If nothing was found internally, try to fetch any
1842 // data from the HTML5 data-* attribute
1843 if ( data === undefined && elem.nodeType === 1 ) {
1844
1845 var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase();
1846
1847 data = elem.getAttribute( name );
1848
1849 if ( typeof data === "string" ) {
1850 try {
1851 data = data === "true" ? true :
1852 data === "false" ? false :
1853 data === "null" ? null :
1854 // Only convert to a number if it doesn't change the string
1855 +data + "" === data ? +data :
1856 rbrace.test( data ) ? jQuery.parseJSON( data ) :
1857 data;
1858 } catch( e ) {}
1859
1860 // Make sure we set the data so it isn't changed later
1861 jQuery.data( elem, key, data );
1862
1863 } else {
1864 data = undefined;
1865 }
1866 }
1867
1868 return data;
1869 }
1870
1871 // checks a cache object for emptiness
1872 function isEmptyDataObject( obj ) {
1873 var name;
1874 for ( name in obj ) {
1875
1876 // if the public data object is empty, the private is still empty
1877 if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) {
1878 continue;
1879 }
1880 if ( name !== "toJSON" ) {
1881 return false;
1882 }
1883 }
1884
1885 return true;
1886 }
1887 jQuery.extend({
1888 queue: function( elem, type, data ) {
1889 var queue;
1890
1891 if ( elem ) {
1892 type = ( type || "fx" ) + "queue";
1893 queue = jQuery._data( elem, type );
1894
1895 // Speed up dequeue by getting out quickly if this is just a lookup
1896 if ( data ) {
1897 if ( !queue || jQuery.isArray(data) ) {
1898 queue = jQuery._data( elem, type, jQuery.makeArray(data) );
1899 } else {
1900 queue.push( data );
1901 }
1902 }
1903 return queue || [];
1904 }
1905 },
1906
1907 dequeue: function( elem, type ) {
1908 type = type || "fx";
1909
1910 var queue = jQuery.queue( elem, type ),
1911 startLength = queue.length,
1912 fn = queue.shift(),
1913 hooks = jQuery._queueHooks( elem, type ),
1914 next = function() {
1915 jQuery.dequeue( elem, type );
1916 };
1917
1918 // If the fx queue is dequeued, always remove the progress sentinel
1919 if ( fn === "inprogress" ) {
1920 fn = queue.shift();
1921 startLength--;
1922 }
1923
1924 hooks.cur = fn;
1925 if ( fn ) {
1926
1927 // Add a progress sentinel to prevent the fx queue from being
1928 // automatically dequeued
1929 if ( type === "fx" ) {
1930 queue.unshift( "inprogress" );
1931 }
1932
1933 // clear up the last queue stop function
1934 delete hooks.stop;
1935 fn.call( elem, next, hooks );
1936 }
1937
1938 if ( !startLength && hooks ) {
1939 hooks.empty.fire();
1940 }
1941 },
1942
1943 // not intended for public consumption - generates a queueHooks object, or returns the current one
1944 _queueHooks: function( elem, type ) {
1945 var key = type + "queueHooks";
1946 return jQuery._data( elem, key ) || jQuery._data( elem, key, {
1947 empty: jQuery.Callbacks("once memory").add(function() {
1948 jQuery._removeData( elem, type + "queue" );
1949 jQuery._removeData( elem, key );
1950 })
1951 });
1952 }
1953 });
1954
1955 jQuery.fn.extend({
1956 queue: function( type, data ) {
1957 var setter = 2;
1958
1959 if ( typeof type !== "string" ) {
1960 data = type;
1961 type = "fx";
1962 setter--;
1963 }
1964
1965 if ( arguments.length < setter ) {
1966 return jQuery.queue( this[0], type );
1967 }
1968
1969 return data === undefined ?
1970 this :
1971 this.each(function() {
1972 var queue = jQuery.queue( this, type, data );
1973
1974 // ensure a hooks for this queue
1975 jQuery._queueHooks( this, type );
1976
1977 if ( type === "fx" && queue[0] !== "inprogress" ) {
1978 jQuery.dequeue( this, type );
1979 }
1980 });
1981 },
1982 dequeue: function( type ) {
1983 return this.each(function() {
1984 jQuery.dequeue( this, type );
1985 });
1986 },
1987 // Based off of the plugin by Clint Helfers, with permission.
1988 // http://blindsignals.com/index.php/2009/07/jquery-delay/
1989 delay: function( time, type ) {
1990 time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
1991 type = type || "fx";
1992
1993 return this.queue( type, function( next, hooks ) {
1994 var timeout = setTimeout( next, time );
1995 hooks.stop = function() {
1996 clearTimeout( timeout );
1997 };
1998 });
1999 },
2000 clearQueue: function( type ) {
2001 return this.queue( type || "fx", [] );
2002 },
2003 // Get a promise resolved when queues of a certain type
2004 // are emptied (fx is the type by default)
2005 promise: function( type, obj ) {
2006 var tmp,
2007 count = 1,
2008 defer = jQuery.Deferred(),
2009 elements = this,
2010 i = this.length,
2011 resolve = function() {
2012 if ( !( --count ) ) {
2013 defer.resolveWith( elements, [ elements ] );
2014 }
2015 };
2016
2017 if ( typeof type !== "string" ) {
2018 obj = type;
2019 type = undefined;
2020 }
2021 type = type || "fx";
2022
2023 while( i-- ) {
2024 tmp = jQuery._data( elements[ i ], type + "queueHooks" );
2025 if ( tmp && tmp.empty ) {
2026 count++;
2027 tmp.empty.add( resolve );
2028 }
2029 }
2030 resolve();
2031 return defer.promise( obj );
2032 }
2033 });
2034 var nodeHook, boolHook,
2035 rclass = /[\t\r\n]/g,
2036 rreturn = /\r/g,
2037 rfocusable = /^(?:input|select|textarea|button|object)$/i,
2038 rclickable = /^(?:a|area)$/i,
2039 rboolean = /^(?:checked|selected|autofocus|autoplay|async|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped)$/i,
2040 ruseDefault = /^(?:checked|selected)$/i,
2041 getSetAttribute = jQuery.support.getSetAttribute,
2042 getSetInput = jQuery.support.input;
2043
2044 jQuery.fn.extend({
2045 attr: function( name, value ) {
2046 return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 );
2047 },
2048
2049 removeAttr: function( name ) {
2050 return this.each(function() {
2051 jQuery.removeAttr( this, name );
2052 });
2053 },
2054
2055 prop: function( name, value ) {
2056 return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 );
2057 },
2058
2059 removeProp: function( name ) {
2060 name = jQuery.propFix[ name ] || name;
2061 return this.each(function() {
2062 // try/catch handles cases where IE balks (such as removing a property on window)
2063 try {
2064 this[ name ] = undefined;
2065 delete this[ name ];
2066 } catch( e ) {}
2067 });
2068 },
2069
2070 addClass: function( value ) {
2071 var classes, elem, cur, clazz, j,
2072 i = 0,
2073 len = this.length,
2074 proceed = typeof value === "string" && value;
2075
2076 if ( jQuery.isFunction( value ) ) {
2077 return this.each(function( j ) {
2078 jQuery( this ).addClass( value.call( this, j, this.className ) );
2079 });
2080 }
2081
2082 if ( proceed ) {
2083 // The disjunction here is for better compressibility (see removeClass)
2084 classes = ( value || "" ).match( core_rnotwhite ) || [];
2085
2086 for ( ; i < len; i++ ) {
2087 elem = this[ i ];
2088 cur = elem.nodeType === 1 && ( elem.className ?
2089 ( " " + elem.className + " " ).replace( rclass, " " ) :
2090 " "
2091 );
2092
2093 if ( cur ) {
2094 j = 0;
2095 while ( (clazz = classes[j++]) ) {
2096 if ( cur.indexOf( " " + clazz + " " ) < 0 ) {
2097 cur += clazz + " ";
2098 }
2099 }
2100 elem.className = jQuery.trim( cur );
2101
2102 }
2103 }
2104 }
2105
2106 return this;
2107 },
2108
2109 removeClass: function( value ) {
2110 var classes, elem, cur, clazz, j,
2111 i = 0,
2112 len = this.length,
2113 proceed = arguments.length === 0 || typeof value === "string" && value;
2114
2115 if ( jQuery.isFunction( value ) ) {
2116 return this.each(function( j ) {
2117 jQuery( this ).removeClass( value.call( this, j, this.className ) );
2118 });
2119 }
2120 if ( proceed ) {
2121 classes = ( value || "" ).match( core_rnotwhite ) || [];
2122
2123 for ( ; i < len; i++ ) {
2124 elem = this[ i ];
2125 // This expression is here for better compressibility (see addClass)
2126 cur = elem.nodeType === 1 && ( elem.className ?
2127 ( " " + elem.className + " " ).replace( rclass, " " ) :
2128 ""
2129 );
2130
2131 if ( cur ) {
2132 j = 0;
2133 while ( (clazz = classes[j++]) ) {
2134 // Remove *all* instances
2135 while ( cur.indexOf( " " + clazz + " " ) >= 0 ) {
2136 cur = cur.replace( " " + clazz + " ", " " );
2137 }
2138 }
2139 elem.className = value ? jQuery.trim( cur ) : "";
2140 }
2141 }
2142 }
2143
2144 return this;
2145 },
2146
2147 toggleClass: function( value, stateVal ) {
2148 var type = typeof value,
2149 isBool = typeof stateVal === "boolean";
2150
2151 if ( jQuery.isFunction( value ) ) {
2152 return this.each(function( i ) {
2153 jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );
2154 });
2155 }
2156
2157 return this.each(function() {
2158 if ( type === "string" ) {
2159 // toggle individual class names
2160 var className,
2161 i = 0,
2162 self = jQuery( this ),
2163 state = stateVal,
2164 classNames = value.match( core_rnotwhite ) || [];
2165
2166 while ( (className = classNames[ i++ ]) ) {
2167 // check each className given, space separated list
2168 state = isBool ? state : !self.hasClass( className );
2169 self[ state ? "addClass" : "removeClass" ]( className );
2170 }
2171
2172 // Toggle whole class name
2173 } else if ( type === core_strundefined || type === "boolean" ) {
2174 if ( this.className ) {
2175 // store className if set
2176 jQuery._data( this, "__className__", this.className );
2177 }
2178
2179 // If the element has a class name or if we're passed "false",
2180 // then remove the whole classname (if there was one, the above saved it).
2181 // Otherwise bring back whatever was previously saved (if anything),
2182 // falling back to the empty string if nothing was stored.
2183 this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || "";
2184 }
2185 });
2186 },
2187
2188 hasClass: function( selector ) {
2189 var className = " " + selector + " ",
2190 i = 0,
2191 l = this.length;
2192 for ( ; i < l; i++ ) {
2193 if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) >= 0 ) {
2194 return true;
2195 }
2196 }
2197
2198 return false;
2199 },
2200
2201 val: function( value ) {
2202 var ret, hooks, isFunction,
2203 elem = this[0];
2204
2205 if ( !arguments.length ) {
2206 if ( elem ) {
2207 hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ];
2208
2209 if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) {
2210 return ret;
2211 }
2212
2213 ret = elem.value;
2214
2215 return typeof ret === "string" ?
2216 // handle most common string cases
2217 ret.replace(rreturn, "") :
2218 // handle cases where value is null/undef or number
2219 ret == null ? "" : ret;
2220 }
2221
2222 return;
2223 }
2224
2225 isFunction = jQuery.isFunction( value );
2226
2227 return this.each(function( i ) {
2228 var val,
2229 self = jQuery(this);
2230
2231 if ( this.nodeType !== 1 ) {
2232 return;
2233 }
2234
2235 if ( isFunction ) {
2236 val = value.call( this, i, self.val() );
2237 } else {
2238 val = value;
2239 }
2240
2241 // Treat null/undefined as ""; convert numbers to string
2242 if ( val == null ) {
2243 val = "";
2244 } else if ( typeof val === "number" ) {
2245 val += "";
2246 } else if ( jQuery.isArray( val ) ) {
2247 val = jQuery.map(val, function ( value ) {
2248 return value == null ? "" : value + "";
2249 });
2250 }
2251
2252 hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];
2253
2254 // If set returns undefined, fall back to normal setting
2255 if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) {
2256 this.value = val;
2257 }
2258 });
2259 }
2260 });
2261
2262 jQuery.extend({
2263 valHooks: {
2264 option: {
2265 get: function( elem ) {
2266 // attributes.value is undefined in Blackberry 4.7 but
2267 // uses .value. See #6932
2268 var val = elem.attributes.value;
2269 return !val || val.specified ? elem.value : elem.text;
2270 }
2271 },
2272 select: {
2273 get: function( elem ) {
2274 var value, option,
2275 options = elem.options,
2276 index = elem.selectedIndex,
2277 one = elem.type === "select-one" || index < 0,
2278 values = one ? null : [],
2279 max = one ? index + 1 : options.length,
2280 i = index < 0 ?
2281 max :
2282 one ? index : 0;
2283
2284 // Loop through all the selected options
2285 for ( ; i < max; i++ ) {
2286 option = options[ i ];
2287
2288 // oldIE doesn't update selected after form reset (#2551)
2289 if ( ( option.selected || i === index ) &&
2290 // Don't return options that are disabled or in a disabled optgroup
2291 ( jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null ) &&
2292 ( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) {
2293
2294 // Get the specific value for the option
2295 value = jQuery( option ).val();
2296
2297 // We don't need an array for one selects
2298 if ( one ) {
2299 return value;
2300 }
2301
2302 // Multi-Selects return an array
2303 values.push( value );
2304 }
2305 }
2306
2307 return values;
2308 },
2309
2310 set: function( elem, value ) {
2311 var values = jQuery.makeArray( value );
2312
2313 jQuery(elem).find("option").each(function() {
2314 this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0;
2315 });
2316
2317 if ( !values.length ) {
2318 elem.selectedIndex = -1;
2319 }
2320 return values;
2321 }
2322 }
2323 },
2324
2325 attr: function( elem, name, value ) {
2326 var hooks, notxml, ret,
2327 nType = elem.nodeType;
2328
2329 // don't get/set attributes on text, comment and attribute nodes
2330 if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
2331 return;
2332 }
2333
2334 // Fallback to prop when attributes are not supported
2335 if ( typeof elem.getAttribute === core_strundefined ) {
2336 return jQuery.prop( elem, name, value );
2337 }
2338
2339 notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
2340
2341 // All attributes are lowercase
2342 // Grab necessary hook if one is defined
2343 if ( notxml ) {
2344 name = name.toLowerCase();
2345 hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook );
2346 }
2347
2348 if ( value !== undefined ) {
2349
2350 if ( value === null ) {
2351 jQuery.removeAttr( elem, name );
2352
2353 } else if ( hooks && notxml && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
2354 return ret;
2355
2356 } else {
2357 elem.setAttribute( name, value + "" );
2358 return value;
2359 }
2360
2361 } else if ( hooks && notxml && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
2362 return ret;
2363
2364 } else {
2365
2366 // In IE9+, Flash objects don't have .getAttribute (#12945)
2367 // Support: IE9+
2368 if ( typeof elem.getAttribute !== core_strundefined ) {
2369 ret = elem.getAttribute( name );
2370 }
2371
2372 // Non-existent attributes return null, we normalize to undefined
2373 return ret == null ?
2374 undefined :
2375 ret;
2376 }
2377 },
2378
2379 removeAttr: function( elem, value ) {
2380 var name, propName,
2381 i = 0,
2382 attrNames = value && value.match( core_rnotwhite );
2383
2384 if ( attrNames && elem.nodeType === 1 ) {
2385 while ( (name = attrNames[i++]) ) {
2386 propName = jQuery.propFix[ name ] || name;
2387
2388 // Boolean attributes get special treatment (#10870)
2389 if ( rboolean.test( name ) ) {
2390 // Set corresponding property to false for boolean attributes
2391 // Also clear defaultChecked/defaultSelected (if appropriate) for IE<8
2392 if ( !getSetAttribute && ruseDefault.test( name ) ) {
2393 elem[ jQuery.camelCase( "default-" + name ) ] =
2394 elem[ propName ] = false;
2395 } else {
2396 elem[ propName ] = false;
2397 }
2398
2399 // See #9699 for explanation of this approach (setting first, then removal)
2400 } else {
2401 jQuery.attr( elem, name, "" );
2402 }
2403
2404 elem.removeAttribute( getSetAttribute ? name : propName );
2405 }
2406 }
2407 },
2408
2409 attrHooks: {
2410 type: {
2411 set: function( elem, value ) {
2412 if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) {
2413 // Setting the type on a radio button after the value resets the value in IE6-9
2414 // Reset value to default in case type is set after value during creation
2415 var val = elem.value;
2416 elem.setAttribute( "type", value );
2417 if ( val ) {
2418 elem.value = val;
2419 }
2420 return value;
2421 }
2422 }
2423 }
2424 },
2425
2426 propFix: {
2427 tabindex: "tabIndex",
2428 readonly: "readOnly",
2429 "for": "htmlFor",
2430 "class": "className",
2431 maxlength: "maxLength",
2432 cellspacing: "cellSpacing",
2433 cellpadding: "cellPadding",
2434 rowspan: "rowSpan",
2435 colspan: "colSpan",
2436 usemap: "useMap",
2437 frameborder: "frameBorder",
2438 contenteditable: "contentEditable"
2439 },
2440
2441 prop: function( elem, name, value ) {
2442 var ret, hooks, notxml,
2443 nType = elem.nodeType;
2444
2445 // don't get/set properties on text, comment and attribute nodes
2446 if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
2447 return;
2448 }
2449
2450 notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
2451
2452 if ( notxml ) {
2453 // Fix name and attach hooks
2454 name = jQuery.propFix[ name ] || name;
2455 hooks = jQuery.propHooks[ name ];
2456 }
2457
2458 if ( value !== undefined ) {
2459 if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
2460 return ret;
2461
2462 } else {
2463 return ( elem[ name ] = value );
2464 }
2465
2466 } else {
2467 if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
2468 return ret;
2469
2470 } else {
2471 return elem[ name ];
2472 }
2473 }
2474 },
2475
2476 propHooks: {
2477 tabIndex: {
2478 get: function( elem ) {
2479 // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set
2480 // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
2481 var attributeNode = elem.getAttributeNode("tabindex");
2482
2483 return attributeNode && attributeNode.specified ?
2484 parseInt( attributeNode.value, 10 ) :
2485 rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?
2486 0 :
2487 undefined;
2488 }
2489 }
2490 }
2491 });
2492
2493 // Hook for boolean attributes
2494 boolHook = {
2495 get: function( elem, name ) {
2496 var
2497 // Use .prop to determine if this attribute is understood as boolean
2498 prop = jQuery.prop( elem, name ),
2499
2500 // Fetch it accordingly
2501 attr = typeof prop === "boolean" && elem.getAttribute( name ),
2502 detail = typeof prop === "boolean" ?
2503
2504 getSetInput && getSetAttribute ?
2505 attr != null :
2506 // oldIE fabricates an empty string for missing boolean attributes
2507 // and conflates checked/selected into attroperties
2508 ruseDefault.test( name ) ?
2509 elem[ jQuery.camelCase( "default-" + name ) ] :
2510 !!attr :
2511
2512 // fetch an attribute node for properties not recognized as boolean
2513 elem.getAttributeNode( name );
2514
2515 return detail && detail.value !== false ?
2516 name.toLowerCase() :
2517 undefined;
2518 },
2519 set: function( elem, value, name ) {
2520 if ( value === false ) {
2521 // Remove boolean attributes when set to false
2522 jQuery.removeAttr( elem, name );
2523 } else if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) {
2524 // IE<8 needs the *property* name
2525 elem.setAttribute( !getSetAttribute && jQuery.propFix[ name ] || name, name );
2526
2527 // Use defaultChecked and defaultSelected for oldIE
2528 } else {
2529 elem[ jQuery.camelCase( "default-" + name ) ] = elem[ name ] = true;
2530 }
2531
2532 return name;
2533 }
2534 };
2535
2536 // fix oldIE value attroperty
2537 if ( !getSetInput || !getSetAttribute ) {
2538 jQuery.attrHooks.value = {
2539 get: function( elem, name ) {
2540 var ret = elem.getAttributeNode( name );
2541 return jQuery.nodeName( elem, "input" ) ?
2542
2543 // Ignore the value *property* by using defaultValue
2544 elem.defaultValue :
2545
2546 ret && ret.specified ? ret.value : undefined;
2547 },
2548 set: function( elem, value, name ) {
2549 if ( jQuery.nodeName( elem, "input" ) ) {
2550 // Does not return so that setAttribute is also used
2551 elem.defaultValue = value;
2552 } else {
2553 // Use nodeHook if defined (#1954); otherwise setAttribute is fine
2554 return nodeHook && nodeHook.set( elem, value, name );
2555 }
2556 }
2557 };
2558 }
2559
2560 // IE6/7 do not support getting/setting some attributes with get/setAttribute
2561 if ( !getSetAttribute ) {
2562
2563 // Use this for any attribute in IE6/7
2564 // This fixes almost every IE6/7 issue
2565 nodeHook = jQuery.valHooks.button = {
2566 get: function( elem, name ) {
2567 var ret = elem.getAttributeNode( name );
2568 return ret && ( name === "id" || name === "name" || name === "coords" ? ret.value !== "" : ret.specified ) ?
2569 ret.value :
2570 undefined;
2571 },
2572 set: function( elem, value, name ) {
2573 // Set the existing or create a new attribute node
2574 var ret = elem.getAttributeNode( name );
2575 if ( !ret ) {
2576 elem.setAttributeNode(
2577 (ret = elem.ownerDocument.createAttribute( name ))
2578 );
2579 }
2580
2581 ret.value = value += "";
2582
2583 // Break association with cloned elements by also using setAttribute (#9646)
2584 return name === "value" || value === elem.getAttribute( name ) ?
2585 value :
2586 undefined;
2587 }
2588 };
2589
2590 // Set contenteditable to false on removals(#10429)
2591 // Setting to empty string throws an error as an invalid value
2592 jQuery.attrHooks.contenteditable = {
2593 get: nodeHook.get,
2594 set: function( elem, value, name ) {
2595 nodeHook.set( elem, value === "" ? false : value, name );
2596 }
2597 };
2598
2599 // Set width and height to auto instead of 0 on empty string( Bug #8150 )
2600 // This is for removals
2601 jQuery.each([ "width", "height" ], function( i, name ) {
2602 jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {
2603 set: function( elem, value ) {
2604 if ( value === "" ) {
2605 elem.setAttribute( name, "auto" );
2606 return value;
2607 }
2608 }
2609 });
2610 });
2611 }
2612
2613
2614 // Some attributes require a special call on IE
2615 // http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
2616 if ( !jQuery.support.hrefNormalized ) {
2617 jQuery.each([ "href", "src", "width", "height" ], function( i, name ) {
2618 jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {
2619 get: function( elem ) {
2620 var ret = elem.getAttribute( name, 2 );
2621 return ret == null ? undefined : ret;
2622 }
2623 });
2624 });
2625
2626 // href/src property should get the full normalized URL (#10299/#12915)
2627 jQuery.each([ "href", "src" ], function( i, name ) {
2628 jQuery.propHooks[ name ] = {
2629 get: function( elem ) {
2630 return elem.getAttribute( name, 4 );
2631 }
2632 };
2633 });
2634 }
2635
2636 if ( !jQuery.support.style ) {
2637 jQuery.attrHooks.style = {
2638 get: function( elem ) {
2639 // Return undefined in the case of empty string
2640 // Note: IE uppercases css property names, but if we were to .toLowerCase()
2641 // .cssText, that would destroy case senstitivity in URL's, like in "background"
2642 return elem.style.cssText || undefined;
2643 },
2644 set: function( elem, value ) {
2645 return ( elem.style.cssText = value + "" );
2646 }
2647 };
2648 }
2649
2650 // Safari mis-reports the default selected property of an option
2651 // Accessing the parent's selectedIndex property fixes it
2652 if ( !jQuery.support.optSelected ) {
2653 jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, {
2654 get: function( elem ) {
2655 var parent = elem.parentNode;
2656
2657 if ( parent ) {
2658 parent.selectedIndex;
2659
2660 // Make sure that it also works with optgroups, see #5701
2661 if ( parent.parentNode ) {
2662 parent.parentNode.selectedIndex;
2663 }
2664 }
2665 return null;
2666 }
2667 });
2668 }
2669
2670 // IE6/7 call enctype encoding
2671 if ( !jQuery.support.enctype ) {
2672 jQuery.propFix.enctype = "encoding";
2673 }
2674
2675 // Radios and checkboxes getter/setter
2676 if ( !jQuery.support.checkOn ) {
2677 jQuery.each([ "radio", "checkbox" ], function() {
2678 jQuery.valHooks[ this ] = {
2679 get: function( elem ) {
2680 // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified
2681 return elem.getAttribute("value") === null ? "on" : elem.value;
2682 }
2683 };
2684 });
2685 }
2686 jQuery.each([ "radio", "checkbox" ], function() {
2687 jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], {
2688 set: function( elem, value ) {
2689 if ( jQuery.isArray( value ) ) {
2690 return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 );
2691 }
2692 }
2693 });
2694 });
2695 var rformElems = /^(?:input|select|textarea)$/i,
2696 rkeyEvent = /^key/,
2697 rmouseEvent = /^(?:mouse|contextmenu)|click/,
2698 rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
2699 rtypenamespace = /^([^.]*)(?:\.(.+)|)$/;
2700
2701 function returnTrue() {
2702 return true;
2703 }
2704
2705 function returnFalse() {
2706 return false;
2707 }
2708
2709 /*
2710 * Helper functions for managing events -- not part of the public interface.
2711 * Props to Dean Edwards' addEvent library for many of the ideas.
2712 */
2713 jQuery.event = {
2714
2715 global: {},
2716
2717 add: function( elem, types, handler, data, selector ) {
2718 var tmp, events, t, handleObjIn,
2719 special, eventHandle, handleObj,
2720 handlers, type, namespaces, origType,
2721 elemData = jQuery._data( elem );
2722
2723 // Don't attach events to noData or text/comment nodes (but allow plain objects)
2724 if ( !elemData ) {
2725 return;
2726 }
2727
2728 // Caller can pass in an object of custom data in lieu of the handler
2729 if ( handler.handler ) {
2730 handleObjIn = handler;
2731 handler = handleObjIn.handler;
2732 selector = handleObjIn.selector;
2733 }
2734
2735 // Make sure that the handler has a unique ID, used to find/remove it later
2736 if ( !handler.guid ) {
2737 handler.guid = jQuery.guid++;
2738 }
2739
2740 // Init the element's event structure and main handler, if this is the first
2741 if ( !(events = elemData.events) ) {
2742 events = elemData.events = {};
2743 }
2744 if ( !(eventHandle = elemData.handle) ) {
2745 eventHandle = elemData.handle = function( e ) {
2746 // Discard the second event of a jQuery.event.trigger() and
2747 // when an event is called after a page has unloaded
2748 return typeof jQuery !== core_strundefined && (!e || jQuery.event.triggered !== e.type) ?
2749 jQuery.event.dispatch.apply( eventHandle.elem, arguments ) :
2750 undefined;
2751 };
2752 // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events
2753 eventHandle.elem = elem;
2754 }
2755
2756 // Handle multiple events separated by a space
2757 // jQuery(...).bind("mouseover mouseout", fn);
2758 types = ( types || "" ).match( core_rnotwhite ) || [""];
2759 t = types.length;
2760 while ( t-- ) {
2761 tmp = rtypenamespace.exec( types[t] ) || [];
2762 type = origType = tmp[1];
2763 namespaces = ( tmp[2] || "" ).split( "." ).sort();
2764
2765 // If event changes its type, use the special event handlers for the changed type
2766 special = jQuery.event.special[ type ] || {};
2767
2768 // If selector defined, determine special event api type, otherwise given type
2769 type = ( selector ? special.delegateType : special.bindType ) || type;
2770
2771 // Update special based on newly reset type
2772 special = jQuery.event.special[ type ] || {};
2773
2774 // handleObj is passed to all event handlers
2775 handleObj = jQuery.extend({
2776 type: type,
2777 origType: origType,
2778 data: data,
2779 handler: handler,
2780 guid: handler.guid,
2781 selector: selector,
2782 needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
2783 namespace: namespaces.join(".")
2784 }, handleObjIn );
2785
2786 // Init the event handler queue if we're the first
2787 if ( !(handlers = events[ type ]) ) {
2788 handlers = events[ type ] = [];
2789 handlers.delegateCount = 0;
2790
2791 // Only use addEventListener/attachEvent if the special events handler returns false
2792 if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
2793 // Bind the global event handler to the element
2794 if ( elem.addEventListener ) {
2795 elem.addEventListener( type, eventHandle, false );
2796
2797 } else if ( elem.attachEvent ) {
2798 elem.attachEvent( "on" + type, eventHandle );
2799 }
2800 }
2801 }
2802
2803 if ( special.add ) {
2804 special.add.call( elem, handleObj );
2805
2806 if ( !handleObj.handler.guid ) {
2807 handleObj.handler.guid = handler.guid;
2808 }
2809 }
2810
2811 // Add to the element's handler list, delegates in front
2812 if ( selector ) {
2813 handlers.splice( handlers.delegateCount++, 0, handleObj );
2814 } else {
2815 handlers.push( handleObj );
2816 }
2817
2818 // Keep track of which events have ever been used, for event optimization
2819 jQuery.event.global[ type ] = true;
2820 }
2821
2822 // Nullify elem to prevent memory leaks in IE
2823 elem = null;
2824 },
2825
2826 // Detach an event or set of events from an element
2827 remove: function( elem, types, handler, selector, mappedTypes ) {
2828 var j, handleObj, tmp,
2829 origCount, t, events,
2830 special, handlers, type,
2831 namespaces, origType,
2832 elemData = jQuery.hasData( elem ) && jQuery._data( elem );
2833
2834 if ( !elemData || !(events = elemData.events) ) {
2835 return;
2836 }
2837
2838 // Once for each type.namespace in types; type may be omitted
2839 types = ( types || "" ).match( core_rnotwhite ) || [""];
2840 t = types.length;
2841 while ( t-- ) {
2842 tmp = rtypenamespace.exec( types[t] ) || [];
2843 type = origType = tmp[1];
2844 namespaces = ( tmp[2] || "" ).split( "." ).sort();
2845
2846 // Unbind all events (on this namespace, if provided) for the element
2847 if ( !type ) {
2848 for ( type in events ) {
2849 jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
2850 }
2851 continue;
2852 }
2853
2854 special = jQuery.event.special[ type ] || {};
2855 type = ( selector ? special.delegateType : special.bindType ) || type;
2856 handlers = events[ type ] || [];
2857 tmp = tmp[2] && new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" );
2858
2859 // Remove matching events
2860 origCount = j = handlers.length;
2861 while ( j-- ) {
2862 handleObj = handlers[ j ];
2863
2864 if ( ( mappedTypes || origType === handleObj.origType ) &&
2865 ( !handler || handler.guid === handleObj.guid ) &&
2866 ( !tmp || tmp.test( handleObj.namespace ) ) &&
2867 ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) {
2868 handlers.splice( j, 1 );
2869
2870 if ( handleObj.selector ) {
2871 handlers.delegateCount--;
2872 }
2873 if ( special.remove ) {
2874 special.remove.call( elem, handleObj );
2875 }
2876 }
2877 }
2878
2879 // Remove generic event handler if we removed something and no more handlers exist
2880 // (avoids potential for endless recursion during removal of special event handlers)
2881 if ( origCount && !handlers.length ) {
2882 if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) {
2883 jQuery.removeEvent( elem, type, elemData.handle );
2884 }
2885
2886 delete events[ type ];
2887 }
2888 }
2889
2890 // Remove the expando if it's no longer used
2891 if ( jQuery.isEmptyObject( events ) ) {
2892 delete elemData.handle;
2893
2894 // removeData also checks for emptiness and clears the expando if empty
2895 // so use it instead of delete
2896 jQuery._removeData( elem, "events" );
2897 }
2898 },
2899
2900 trigger: function( event, data, elem, onlyHandlers ) {
2901 var handle, ontype, cur,
2902 bubbleType, special, tmp, i,
2903 eventPath = [ elem || document ],
2904 type = core_hasOwn.call( event, "type" ) ? event.type : event,
2905 namespaces = core_hasOwn.call( event, "namespace" ) ? event.namespace.split(".") : [];
2906
2907 cur = tmp = elem = elem || document;
2908
2909 // Don't do events on text and comment nodes
2910 if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
2911 return;
2912 }
2913
2914 // focus/blur morphs to focusin/out; ensure we're not firing them right now
2915 if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
2916 return;
2917 }
2918
2919 if ( type.indexOf(".") >= 0 ) {
2920 // Namespaced trigger; create a regexp to match event type in handle()
2921 namespaces = type.split(".");
2922 type = namespaces.shift();
2923 namespaces.sort();
2924 }
2925 ontype = type.indexOf(":") < 0 && "on" + type;
2926
2927 // Caller can pass in a jQuery.Event object, Object, or just an event type string
2928 event = event[ jQuery.expando ] ?
2929 event :
2930 new jQuery.Event( type, typeof event === "object" && event );
2931
2932 event.isTrigger = true;
2933 event.namespace = namespaces.join(".");
2934 event.namespace_re = event.namespace ?
2935 new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ) :
2936 null;
2937
2938 // Clean up the event in case it is being reused
2939 event.result = undefined;
2940 if ( !event.target ) {
2941 event.target = elem;
2942 }
2943
2944 // Clone any incoming data and prepend the event, creating the handler arg list
2945 data = data == null ?
2946 [ event ] :
2947 jQuery.makeArray( data, [ event ] );
2948
2949 // Allow special events to draw outside the lines
2950 special = jQuery.event.special[ type ] || {};
2951 if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {
2952 return;
2953 }
2954
2955 // Determine event propagation path in advance, per W3C events spec (#9951)
2956 // Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
2957 if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {
2958
2959 bubbleType = special.delegateType || type;
2960 if ( !rfocusMorph.test( bubbleType + type ) ) {
2961 cur = cur.parentNode;
2962 }
2963 for ( ; cur; cur = cur.parentNode ) {
2964 eventPath.push( cur );
2965 tmp = cur;
2966 }
2967
2968 // Only add window if we got to document (e.g., not plain obj or detached DOM)
2969 if ( tmp === (elem.ownerDocument || document) ) {
2970 eventPath.push( tmp.defaultView || tmp.parentWindow || window );
2971 }
2972 }
2973
2974 // Fire handlers on the event path
2975 i = 0;
2976 while ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) {
2977
2978 event.type = i > 1 ?
2979 bubbleType :
2980 special.bindType || type;
2981
2982 // jQuery handler
2983 handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" );
2984 if ( handle ) {
2985 handle.apply( cur, data );
2986 }
2987
2988 // Native handler
2989 handle = ontype && cur[ ontype ];
2990 if ( handle && jQuery.acceptData( cur ) && handle.apply && handle.apply( cur, data ) === false ) {
2991 event.preventDefault();
2992 }
2993 }
2994 event.type = type;
2995
2996 // If nobody prevented the default action, do it now
2997 if ( !onlyHandlers && !event.isDefaultPrevented() ) {
2998
2999 if ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) &&
3000 !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) {
3001
3002 // Call a native DOM method on the target with the same name name as the event.
3003 // Can't use an .isFunction() check here because IE6/7 fails that test.
3004 // Don't do default actions on window, that's where global variables be (#6170)
3005 if ( ontype && elem[ type ] && !jQuery.isWindow( elem ) ) {
3006
3007 // Don't re-trigger an onFOO event when we call its FOO() method
3008 tmp = elem[ ontype ];
3009
3010 if ( tmp ) {
3011 elem[ ontype ] = null;
3012 }
3013
3014 // Prevent re-triggering of the same event, since we already bubbled it above
3015 jQuery.event.triggered = type;
3016 try {
3017 elem[ type ]();
3018 } catch ( e ) {
3019 // IE<9 dies on focus/blur to hidden element (#1486,#12518)
3020 // only reproducible on winXP IE8 native, not IE9 in IE8 mode
3021 }
3022 jQuery.event.triggered = undefined;
3023
3024 if ( tmp ) {
3025 elem[ ontype ] = tmp;
3026 }
3027 }
3028 }
3029 }
3030
3031 return event.result;
3032 },
3033
3034 dispatch: function( event ) {
3035
3036 // Make a writable jQuery.Event from the native event object
3037 event = jQuery.event.fix( event );
3038
3039 var i, ret, handleObj, matched, j,
3040 handlerQueue = [],
3041 args = core_slice.call( arguments ),
3042 handlers = ( jQuery._data( this, "events" ) || {} )[ event.type ] || [],
3043 special = jQuery.event.special[ event.type ] || {};
3044
3045 // Use the fix-ed jQuery.Event rather than the (read-only) native event
3046 args[0] = event;
3047 event.delegateTarget = this;
3048
3049 // Call the preDispatch hook for the mapped type, and let it bail if desired
3050 if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
3051 return;
3052 }
3053
3054 // Determine handlers
3055 handlerQueue = jQuery.event.handlers.call( this, event, handlers );
3056
3057 // Run delegates first; they may want to stop propagation beneath us
3058 i = 0;
3059 while ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) {
3060 event.currentTarget = matched.elem;
3061
3062 j = 0;
3063 while ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) {
3064
3065 // Triggered event must either 1) have no namespace, or
3066 // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace).
3067 if ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) {
3068
3069 event.handleObj = handleObj;
3070 event.data = handleObj.data;
3071
3072 ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )
3073 .apply( matched.elem, args );
3074
3075 if ( ret !== undefined ) {
3076 if ( (event.result = ret) === false ) {
3077 event.preventDefault();
3078 event.stopPropagation();
3079 }
3080 }
3081 }
3082 }
3083 }
3084
3085 // Call the postDispatch hook for the mapped type
3086 if ( special.postDispatch ) {
3087 special.postDispatch.call( this, event );
3088 }
3089
3090 return event.result;
3091 },
3092
3093 handlers: function( event, handlers ) {
3094 var sel, handleObj, matches, i,
3095 handlerQueue = [],
3096 delegateCount = handlers.delegateCount,
3097 cur = event.target;
3098
3099 // Find delegate handlers
3100 // Black-hole SVG <use> instance trees (#13180)
3101 // Avoid non-left-click bubbling in Firefox (#3861)
3102 if ( delegateCount && cur.nodeType && (!event.button || event.type !== "click") ) {
3103
3104 for ( ; cur != this; cur = cur.parentNode || this ) {
3105
3106 // Don't check non-elements (#13208)
3107 // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)
3108 if ( cur.nodeType === 1 && (cur.disabled !== true || event.type !== "click") ) {
3109 matches = [];
3110 for ( i = 0; i < delegateCount; i++ ) {
3111 handleObj = handlers[ i ];
3112
3113 // Don't conflict with Object.prototype properties (#13203)
3114 sel = handleObj.selector + " ";
3115
3116 if ( matches[ sel ] === undefined ) {
3117 matches[ sel ] = handleObj.needsContext ?
3118 jQuery( sel, this ).index( cur ) >= 0 :
3119 jQuery.find( sel, this, null, [ cur ] ).length;
3120 }
3121 if ( matches[ sel ] ) {
3122 matches.push( handleObj );
3123 }
3124 }
3125 if ( matches.length ) {
3126 handlerQueue.push({ elem: cur, handlers: matches });
3127 }
3128 }
3129 }
3130 }
3131
3132 // Add the remaining (directly-bound) handlers
3133 if ( delegateCount < handlers.length ) {
3134 handlerQueue.push({ elem: this, handlers: handlers.slice( delegateCount ) });
3135 }
3136
3137 return handlerQueue;
3138 },
3139
3140 fix: function( event ) {
3141 if ( event[ jQuery.expando ] ) {
3142 return event;
3143 }
3144
3145 // Create a writable copy of the event object and normalize some properties
3146 var i, prop, copy,
3147 type = event.type,
3148 originalEvent = event,
3149 fixHook = this.fixHooks[ type ];
3150
3151 if ( !fixHook ) {
3152 this.fixHooks[ type ] = fixHook =
3153 rmouseEvent.test( type ) ? this.mouseHooks :
3154 rkeyEvent.test( type ) ? this.keyHooks :
3155 {};
3156 }
3157 copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props;
3158
3159 event = new jQuery.Event( originalEvent );
3160
3161 i = copy.length;
3162 while ( i-- ) {
3163 prop = copy[ i ];
3164 event[ prop ] = originalEvent[ prop ];
3165 }
3166
3167 // Support: IE<9
3168 // Fix target property (#1925)
3169 if ( !event.target ) {
3170 event.target = originalEvent.srcElement || document;
3171 }
3172
3173 // Support: Chrome 23+, Safari?
3174 // Target should not be a text node (#504, #13143)
3175 if ( event.target.nodeType === 3 ) {
3176 event.target = event.target.parentNode;
3177 }
3178
3179 // Support: IE<9
3180 // For mouse/key events, metaKey==false if it's undefined (#3368, #11328)
3181 event.metaKey = !!event.metaKey;
3182
3183 return fixHook.filter ? fixHook.filter( event, originalEvent ) : event;
3184 },
3185
3186 // Includes some event props shared by KeyEvent and MouseEvent
3187 props: "altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),
3188
3189 fixHooks: {},
3190
3191 keyHooks: {
3192 props: "char charCode key keyCode".split(" "),
3193 filter: function( event, original ) {
3194
3195 // Add which for key events
3196 if ( event.which == null ) {
3197 event.which = original.charCode != null ? original.charCode : original.keyCode;
3198 }
3199
3200 return event;
3201 }
3202 },
3203
3204 mouseHooks: {
3205 props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),
3206 filter: function( event, original ) {
3207 var body, eventDoc, doc,
3208 button = original.button,
3209 fromElement = original.fromElement;
3210
3211 // Calculate pageX/Y if missing and clientX/Y available
3212 if ( event.pageX == null && original.clientX != null ) {
3213 eventDoc = event.target.ownerDocument || document;
3214 doc = eventDoc.documentElement;
3215 body = eventDoc.body;
3216
3217 event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 );
3218 event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 );
3219 }
3220
3221 // Add relatedTarget, if necessary
3222 if ( !event.relatedTarget && fromElement ) {
3223 event.relatedTarget = fromElement === event.target ? original.toElement : fromElement;
3224 }
3225
3226 // Add which for click: 1 === left; 2 === middle; 3 === right
3227 // Note: button is not normalized, so don't use it
3228 if ( !event.which && button !== undefined ) {
3229 event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );
3230 }
3231
3232 return event;
3233 }
3234 },
3235
3236 special: {
3237 load: {
3238 // Prevent triggered image.load events from bubbling to window.load
3239 noBubble: true
3240 },
3241 click: {
3242 // For checkbox, fire native event so checked state will be right
3243 trigger: function() {
3244 if ( jQuery.nodeName( this, "input" ) && this.type === "checkbox" && this.click ) {
3245 this.click();
3246 return false;
3247 }
3248 }
3249 },
3250 focus: {
3251 // Fire native event if possible so blur/focus sequence is correct
3252 trigger: function() {
3253 if ( this !== document.activeElement && this.focus ) {
3254 try {
3255 this.focus();
3256 return false;
3257 } catch ( e ) {
3258 // Support: IE<9
3259 // If we error on focus to hidden element (#1486, #12518),
3260 // let .trigger() run the handlers
3261 }
3262 }
3263 },
3264 delegateType: "focusin"
3265 },
3266 blur: {
3267 trigger: function() {
3268 if ( this === document.activeElement && this.blur ) {
3269 this.blur();
3270 return false;
3271 }
3272 },
3273 delegateType: "focusout"
3274 },
3275
3276 beforeunload: {
3277 postDispatch: function( event ) {
3278
3279 // Even when returnValue equals to undefined Firefox will still show alert
3280 if ( event.result !== undefined ) {
3281 event.originalEvent.returnValue = event.result;
3282 }
3283 }
3284 }
3285 },
3286
3287 simulate: function( type, elem, event, bubble ) {
3288 // Piggyback on a donor event to simulate a different one.
3289 // Fake originalEvent to avoid donor's stopPropagation, but if the
3290 // simulated event prevents default then we do the same on the donor.
3291 var e = jQuery.extend(
3292 new jQuery.Event(),
3293 event,
3294 { type: type,
3295 isSimulated: true,
3296 originalEvent: {}
3297 }
3298 );
3299 if ( bubble ) {
3300 jQuery.event.trigger( e, null, elem );
3301 } else {
3302 jQuery.event.dispatch.call( elem, e );
3303 }
3304 if ( e.isDefaultPrevented() ) {
3305 event.preventDefault();
3306 }
3307 }
3308 };
3309
3310 jQuery.removeEvent = document.removeEventListener ?
3311 function( elem, type, handle ) {
3312 if ( elem.removeEventListener ) {
3313 elem.removeEventListener( type, handle, false );
3314 }
3315 } :
3316 function( elem, type, handle ) {
3317 var name = "on" + type;
3318
3319 if ( elem.detachEvent ) {
3320
3321 // #8545, #7054, preventing memory leaks for custom events in IE6-8
3322 // detachEvent needed property on element, by name of that event, to properly expose it to GC
3323 if ( typeof elem[ name ] === core_strundefined ) {
3324 elem[ name ] = null;
3325 }
3326
3327 elem.detachEvent( name, handle );
3328 }
3329 };
3330
3331 jQuery.Event = function( src, props ) {
3332 // Allow instantiation without the 'new' keyword
3333 if ( !(this instanceof jQuery.Event) ) {
3334 return new jQuery.Event( src, props );
3335 }
3336
3337 // Event object
3338 if ( src && src.type ) {
3339 this.originalEvent = src;
3340 this.type = src.type;
3341
3342 // Events bubbling up the document may have been marked as prevented
3343 // by a handler lower down the tree; reflect the correct value.
3344 this.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false ||
3345 src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse;
3346
3347 // Event type
3348 } else {
3349 this.type = src;
3350 }
3351
3352 // Put explicitly provided properties onto the event object
3353 if ( props ) {
3354 jQuery.extend( this, props );
3355 }
3356
3357 // Create a timestamp if incoming event doesn't have one
3358 this.timeStamp = src && src.timeStamp || jQuery.now();
3359
3360 // Mark it as fixed
3361 this[ jQuery.expando ] = true;
3362 };
3363
3364 // jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
3365 // http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
3366 jQuery.Event.prototype = {
3367 isDefaultPrevented: returnFalse,
3368 isPropagationStopped: returnFalse,
3369 isImmediatePropagationStopped: returnFalse,
3370
3371 preventDefault: function() {
3372 var e = this.originalEvent;
3373
3374 this.isDefaultPrevented = returnTrue;
3375 if ( !e ) {
3376 return;
3377 }
3378
3379 // If preventDefault exists, run it on the original event
3380 if ( e.preventDefault ) {
3381 e.preventDefault();
3382
3383 // Support: IE
3384 // Otherwise set the returnValue property of the original event to false
3385 } else {
3386 e.returnValue = false;
3387 }
3388 },
3389 stopPropagation: function() {
3390 var e = this.originalEvent;
3391
3392 this.isPropagationStopped = returnTrue;
3393 if ( !e ) {
3394 return;
3395 }
3396 // If stopPropagation exists, run it on the original event
3397 if ( e.stopPropagation ) {
3398 e.stopPropagation();
3399 }
3400
3401 // Support: IE
3402 // Set the cancelBubble property of the original event to true
3403 e.cancelBubble = true;
3404 },
3405 stopImmediatePropagation: function() {
3406 this.isImmediatePropagationStopped = returnTrue;
3407 this.stopPropagation();
3408 }
3409 };
3410
3411 // Create mouseenter/leave events using mouseover/out and event-time checks
3412 jQuery.each({
3413 mouseenter: "mouseover",
3414 mouseleave: "mouseout"
3415 }, function( orig, fix ) {
3416 jQuery.event.special[ orig ] = {
3417 delegateType: fix,
3418 bindType: fix,
3419
3420 handle: function( event ) {
3421 var ret,
3422 target = this,
3423 related = event.relatedTarget,
3424 handleObj = event.handleObj;
3425
3426 // For mousenter/leave call the handler if related is outside the target.
3427 // NB: No relatedTarget if the mouse left/entered the browser window
3428 if ( !related || (related !== target && !jQuery.contains( target, related )) ) {
3429 event.type = handleObj.origType;
3430 ret = handleObj.handler.apply( this, arguments );
3431 event.type = fix;
3432 }
3433 return ret;
3434 }
3435 };
3436 });
3437
3438 // IE submit delegation
3439 if ( !jQuery.support.submitBubbles ) {
3440
3441 jQuery.event.special.submit = {
3442 setup: function() {
3443 // Only need this for delegated form submit events
3444 if ( jQuery.nodeName( this, "form" ) ) {
3445 return false;
3446 }
3447
3448 // Lazy-add a submit handler when a descendant form may potentially be submitted
3449 jQuery.event.add( this, "click._submit keypress._submit", function( e ) {
3450 // Node name check avoids a VML-related crash in IE (#9807)
3451 var elem = e.target,
3452 form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined;
3453 if ( form && !jQuery._data( form, "submitBubbles" ) ) {
3454 jQuery.event.add( form, "submit._submit", function( event ) {
3455 event._submit_bubble = true;
3456 });
3457 jQuery._data( form, "submitBubbles", true );
3458 }
3459 });
3460 // return undefined since we don't need an event listener
3461 },
3462
3463 postDispatch: function( event ) {
3464 // If form was submitted by the user, bubble the event up the tree
3465 if ( event._submit_bubble ) {
3466 delete event._submit_bubble;
3467 if ( this.parentNode && !event.isTrigger ) {
3468 jQuery.event.simulate( "submit", this.parentNode, event, true );
3469 }
3470 }
3471 },
3472
3473 teardown: function() {
3474 // Only need this for delegated form submit events
3475 if ( jQuery.nodeName( this, "form" ) ) {
3476 return false;
3477 }
3478
3479 // Remove delegated handlers; cleanData eventually reaps submit handlers attached above
3480 jQuery.event.remove( this, "._submit" );
3481 }
3482 };
3483 }
3484
3485 // IE change delegation and checkbox/radio fix
3486 if ( !jQuery.support.changeBubbles ) {
3487
3488 jQuery.event.special.change = {
3489
3490 setup: function() {
3491
3492 if ( rformElems.test( this.nodeName ) ) {
3493 // IE doesn't fire change on a check/radio until blur; trigger it on click
3494 // after a propertychange. Eat the blur-change in special.change.handle.
3495 // This still fires onchange a second time for check/radio after blur.
3496 if ( this.type === "checkbox" || this.type === "radio" ) {
3497 jQuery.event.add( this, "propertychange._change", function( event ) {
3498 if ( event.originalEvent.propertyName === "checked" ) {
3499 this._just_changed = true;
3500 }
3501 });
3502 jQuery.event.add( this, "click._change", function( event ) {
3503 if ( this._just_changed && !event.isTrigger ) {
3504 this._just_changed = false;
3505 }
3506 // Allow triggered, simulated change events (#11500)
3507 jQuery.event.simulate( "change", this, event, true );
3508 });
3509 }
3510 return false;
3511 }
3512 // Delegated event; lazy-add a change handler on descendant inputs
3513 jQuery.event.add( this, "beforeactivate._change", function( e ) {
3514 var elem = e.target;
3515
3516 if ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, "changeBubbles" ) ) {
3517 jQuery.event.add( elem, "change._change", function( event ) {
3518 if ( this.parentNode && !event.isSimulated && !event.isTrigger ) {
3519 jQuery.event.simulate( "change", this.parentNode, event, true );
3520 }
3521 });
3522 jQuery._data( elem, "changeBubbles", true );
3523 }
3524 });
3525 },
3526
3527 handle: function( event ) {
3528 var elem = event.target;
3529
3530 // Swallow native change events from checkbox/radio, we already triggered them above
3531 if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) {
3532 return event.handleObj.handler.apply( this, arguments );
3533 }
3534 },
3535
3536 teardown: function() {
3537 jQuery.event.remove( this, "._change" );
3538
3539 return !rformElems.test( this.nodeName );
3540 }
3541 };
3542 }
3543
3544 // Create "bubbling" focus and blur events
3545 if ( !jQuery.support.focusinBubbles ) {
3546 jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
3547
3548 // Attach a single capturing handler while someone wants focusin/focusout
3549 var attaches = 0,
3550 handler = function( event ) {
3551 jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true );
3552 };
3553
3554 jQuery.event.special[ fix ] = {
3555 setup: function() {
3556 if ( attaches++ === 0 ) {
3557 document.addEventListener( orig, handler, true );
3558 }
3559 },
3560 teardown: function() {
3561 if ( --attaches === 0 ) {
3562 document.removeEventListener( orig, handler, true );
3563 }
3564 }
3565 };
3566 });
3567 }
3568
3569 jQuery.fn.extend({
3570
3571 on: function( types, selector, data, fn, /*INTERNAL*/ one ) {
3572 var type, origFn;
3573
3574 // Types can be a map of types/handlers
3575 if ( typeof types === "object" ) {
3576 // ( types-Object, selector, data )
3577 if ( typeof selector !== "string" ) {
3578 // ( types-Object, data )
3579 data = data || selector;
3580 selector = undefined;
3581 }
3582 for ( type in types ) {
3583 this.on( type, selector, data, types[ type ], one );
3584 }
3585 return this;
3586 }
3587
3588 if ( data == null && fn == null ) {
3589 // ( types, fn )
3590 fn = selector;
3591 data = selector = undefined;
3592 } else if ( fn == null ) {
3593 if ( typeof selector === "string" ) {
3594 // ( types, selector, fn )
3595 fn = data;
3596 data = undefined;
3597 } else {
3598 // ( types, data, fn )
3599 fn = data;
3600 data = selector;
3601 selector = undefined;
3602 }
3603 }
3604 if ( fn === false ) {
3605 fn = returnFalse;
3606 } else if ( !fn ) {
3607 return this;
3608 }
3609
3610 if ( one === 1 ) {
3611 origFn = fn;
3612 fn = function( event ) {
3613 // Can use an empty set, since event contains the info
3614 jQuery().off( event );
3615 return origFn.apply( this, arguments );
3616 };
3617 // Use same guid so caller can remove using origFn
3618 fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
3619 }
3620 return this.each( function() {
3621 jQuery.event.add( this, types, fn, data, selector );
3622 });
3623 },
3624 one: function( types, selector, data, fn ) {
3625 return this.on( types, selector, data, fn, 1 );
3626 },
3627 off: function( types, selector, fn ) {
3628 var handleObj, type;
3629 if ( types && types.preventDefault && types.handleObj ) {
3630 // ( event ) dispatched jQuery.Event
3631 handleObj = types.handleObj;
3632 jQuery( types.delegateTarget ).off(
3633 handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType,
3634 handleObj.selector,
3635 handleObj.handler
3636 );
3637 return this;
3638 }
3639 if ( typeof types === "object" ) {
3640 // ( types-object [, selector] )
3641 for ( type in types ) {
3642 this.off( type, selector, types[ type ] );
3643 }
3644 return this;
3645 }
3646 if ( selector === false || typeof selector === "function" ) {
3647 // ( types [, fn] )
3648 fn = selector;
3649 selector = undefined;
3650 }
3651 if ( fn === false ) {
3652 fn = returnFalse;
3653 }
3654 return this.each(function() {
3655 jQuery.event.remove( this, types, fn, selector );
3656 });
3657 },
3658
3659 bind: function( types, data, fn ) {
3660 return this.on( types, null, data, fn );
3661 },
3662 unbind: function( types, fn ) {
3663 return this.off( types, null, fn );
3664 },
3665
3666 delegate: function( selector, types, data, fn ) {
3667 return this.on( types, selector, data, fn );
3668 },
3669 undelegate: function( selector, types, fn ) {
3670 // ( namespace ) or ( selector, types [, fn] )
3671 return arguments.length === 1 ? this.off( selector, "**" ) : this.off( types, selector || "**", fn );
3672 },
3673
3674 trigger: function( type, data ) {
3675 return this.each(function() {
3676 jQuery.event.trigger( type, data, this );
3677 });
3678 },
3679 triggerHandler: function( type, data ) {
3680 var elem = this[0];
3681 if ( elem ) {
3682 return jQuery.event.trigger( type, data, elem, true );
3683 }
3684 }
3685 });
3686 /*!
3687 * Sizzle CSS Selector Engine
3688 * Copyright 2012 jQuery Foundation and other contributors
3689 * Released under the MIT license
3690 * http://sizzlejs.com/
3691 */
3692 (function( window, undefined ) {
3693
3694 var i,
3695 cachedruns,
3696 Expr,
3697 getText,
3698 isXML,
3699 compile,
3700 hasDuplicate,
3701 outermostContext,
3702
3703 // Local document vars
3704 setDocument,
3705 document,
3706 docElem,
3707 documentIsXML,
3708 rbuggyQSA,
3709 rbuggyMatches,
3710 matches,
3711 contains,
3712 sortOrder,
3713
3714 // Instance-specific data
3715 expando = "sizzle" + -(new Date()),
3716 preferredDoc = window.document,
3717 support = {},
3718 dirruns = 0,
3719 done = 0,
3720 classCache = createCache(),
3721 tokenCache = createCache(),
3722 compilerCache = createCache(),
3723
3724 // General-purpose constants
3725 strundefined = typeof undefined,
3726 MAX_NEGATIVE = 1 << 31,
3727
3728 // Array methods
3729 arr = [],
3730 pop = arr.pop,
3731 push = arr.push,
3732 slice = arr.slice,
3733 // Use a stripped-down indexOf if we can't use a native one
3734 indexOf = arr.indexOf || function( elem ) {
3735 var i = 0,
3736 len = this.length;
3737 for ( ; i < len; i++ ) {
3738 if ( this[i] === elem ) {
3739 return i;
3740 }
3741 }
3742 return -1;
3743 },
3744
3745
3746 // Regular expressions
3747
3748 // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace
3749 whitespace = "[\\x20\\t\\r\\n\\f]",
3750 // http://www.w3.org/TR/css3-syntax/#characters
3751 characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",
3752
3753 // Loosely modeled on CSS identifier characters
3754 // An unquoted value should be a CSS identifier http://www.w3.org/TR/css3-selectors/#attribute-selectors
3755 // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
3756 identifier = characterEncoding.replace( "w", "w#" ),
3757
3758 // Acceptable operators http://www.w3.org/TR/selectors/#attribute-selectors
3759 operators = "([*^$|!~]?=)",
3760 attributes = "\\[" + whitespace + "*(" + characterEncoding + ")" + whitespace +
3761 "*(?:" + operators + whitespace + "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + identifier + ")|)|)" + whitespace + "*\\]",
3762
3763 // Prefer arguments quoted,
3764 // then not containing pseudos/brackets,
3765 // then attribute selectors/non-parenthetical expressions,
3766 // then anything else
3767 // These preferences are here to reduce the number of selectors
3768 // needing tokenize in the PSEUDO preFilter
3769 pseudos = ":(" + characterEncoding + ")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|" + attributes.replace( 3, 8 ) + ")*)|.*)\\)|)",
3770
3771 // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
3772 rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),
3773
3774 rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
3775 rcombinators = new RegExp( "^" + whitespace + "*([\\x20\\t\\r\\n\\f>+~])" + whitespace + "*" ),
3776 rpseudo = new RegExp( pseudos ),
3777 ridentifier = new RegExp( "^" + identifier + "$" ),
3778
3779 matchExpr = {
3780 "ID": new RegExp( "^#(" + characterEncoding + ")" ),
3781 "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ),
3782 "NAME": new RegExp( "^\\[name=['\"]?(" + characterEncoding + ")['\"]?\\]" ),
3783 "TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ),
3784 "ATTR": new RegExp( "^" + attributes ),
3785 "PSEUDO": new RegExp( "^" + pseudos ),
3786 "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace +
3787 "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace +
3788 "*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
3789 // For use in libraries implementing .is()
3790 // We use this for POS matching in `select`
3791 "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" +
3792 whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
3793 },
3794
3795 rsibling = /[\x20\t\r\n\f]*[+~]/,
3796
3797 rnative = /^[^{]+\{\s*\[native code/,
3798
3799 // Easily-parseable/retrievable ID or TAG or CLASS selectors
3800 rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
3801
3802 rinputs = /^(?:input|select|textarea|button)$/i,
3803 rheader = /^h\d$/i,
3804
3805 rescape = /'|\\/g,
3806 rattributeQuotes = /\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,
3807
3808 // CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters
3809 runescape = /\\([\da-fA-F]{1,6}[\x20\t\r\n\f]?|.)/g,
3810 funescape = function( _, escaped ) {
3811 var high = "0x" + escaped - 0x10000;
3812 // NaN means non-codepoint
3813 return high !== high ?
3814 escaped :
3815 // BMP codepoint
3816 high < 0 ?
3817 String.fromCharCode( high + 0x10000 ) :
3818 // Supplemental Plane codepoint (surrogate pair)
3819 String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
3820 };
3821
3822 // Use a stripped-down slice if we can't use a native one
3823 try {
3824 slice.call( preferredDoc.documentElement.childNodes, 0 )[0].nodeType;
3825 } catch ( e ) {
3826 slice = function( i ) {
3827 var elem,
3828 results = [];
3829 while ( (elem = this[i++]) ) {
3830 results.push( elem );
3831 }
3832 return results;
3833 };
3834 }
3835
3836 /**
3837 * For feature detection
3838 * @param {Function} fn The function to test for native support
3839 */
3840 function isNative( fn ) {
3841 return rnative.test( fn + "" );
3842 }
3843
3844 /**
3845 * Create key-value caches of limited size
3846 * @returns {Function(string, Object)} Returns the Object data after storing it on itself with
3847 * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)
3848 * deleting the oldest entry
3849 */
3850 function createCache() {
3851 var cache,
3852 keys = [];
3853
3854 return (cache = function( key, value ) {
3855 // Use (key + " ") to avoid collision with native prototype properties (see Issue #157)
3856 if ( keys.push( key += " " ) > Expr.cacheLength ) {
3857 // Only keep the most recent entries
3858 delete cache[ keys.shift() ];
3859 }
3860 return (cache[ key ] = value);
3861 });
3862 }
3863
3864 /**
3865 * Mark a function for special use by Sizzle
3866 * @param {Function} fn The function to mark
3867 */
3868 function markFunction( fn ) {
3869 fn[ expando ] = true;
3870 return fn;
3871 }
3872
3873 /**
3874 * Support testing using an element
3875 * @param {Function} fn Passed the created div and expects a boolean result
3876 */
3877 function assert( fn ) {
3878 var div = document.createElement("div");
3879
3880 try {
3881 return fn( div );
3882 } catch (e) {
3883 return false;
3884 } finally {
3885 // release memory in IE
3886 div = null;
3887 }
3888 }
3889
3890 function Sizzle( selector, context, results, seed ) {
3891 var match, elem, m, nodeType,
3892 // QSA vars
3893 i, groups, old, nid, newContext, newSelector;
3894
3895 if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {
3896 setDocument( context );
3897 }
3898
3899 context = context || document;
3900 results = results || [];
3901
3902 if ( !selector || typeof selector !== "string" ) {
3903 return results;
3904 }
3905
3906 if ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) {
3907 return [];
3908 }
3909
3910 if ( !documentIsXML && !seed ) {
3911
3912 // Shortcuts
3913 if ( (match = rquickExpr.exec( selector )) ) {
3914 // Speed-up: Sizzle("#ID")
3915 if ( (m = match[1]) ) {
3916 if ( nodeType === 9 ) {
3917 elem = context.getElementById( m );
3918 // Check parentNode to catch when Blackberry 4.6 returns
3919 // nodes that are no longer in the document #6963
3920 if ( elem && elem.parentNode ) {
3921 // Handle the case where IE, Opera, and Webkit return items
3922 // by name instead of ID
3923 if ( elem.id === m ) {
3924 results.push( elem );
3925 return results;
3926 }
3927 } else {
3928 return results;
3929 }
3930 } else {
3931 // Context is not a document
3932 if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) &&
3933 contains( context, elem ) && elem.id === m ) {
3934 results.push( elem );
3935 return results;
3936 }
3937 }
3938
3939 // Speed-up: Sizzle("TAG")
3940 } else if ( match[2] ) {
3941 push.apply( results, slice.call(context.getElementsByTagName( selector ), 0) );
3942 return results;
3943
3944 // Speed-up: Sizzle(".CLASS")
3945 } else if ( (m = match[3]) && support.getByClassName && context.getElementsByClassName ) {
3946 push.apply( results, slice.call(context.getElementsByClassName( m ), 0) );
3947 return results;
3948 }
3949 }
3950
3951 // QSA path
3952 if ( support.qsa && !rbuggyQSA.test(selector) ) {
3953 old = true;
3954 nid = expando;
3955 newContext = context;
3956 newSelector = nodeType === 9 && selector;
3957
3958 // qSA works strangely on Element-rooted queries
3959 // We can work around this by specifying an extra ID on the root
3960 // and working up from there (Thanks to Andrew Dupont for the technique)
3961 // IE 8 doesn't work on object elements
3962 if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
3963 groups = tokenize( selector );
3964
3965 if ( (old = context.getAttribute("id")) ) {
3966 nid = old.replace( rescape, "\\$&" );
3967 } else {
3968 context.setAttribute( "id", nid );
3969 }
3970 nid = "[id='" + nid + "'] ";
3971
3972 i = groups.length;
3973 while ( i-- ) {
3974 groups[i] = nid + toSelector( groups[i] );
3975 }
3976 newContext = rsibling.test( selector ) && context.parentNode || context;
3977 newSelector = groups.join(",");
3978 }
3979
3980 if ( newSelector ) {
3981 try {
3982 push.apply( results, slice.call( newContext.querySelectorAll(
3983 newSelector
3984 ), 0 ) );
3985 return results;
3986 } catch(qsaError) {
3987 } finally {
3988 if ( !old ) {
3989 context.removeAttribute("id");
3990 }
3991 }
3992 }
3993 }
3994 }
3995
3996 // All others
3997 return select( selector.replace( rtrim, "$1" ), context, results, seed );
3998 }
3999
4000 /**
4001 * Detect xml
4002 * @param {Element|Object} elem An element or a document
4003 */
4004 isXML = Sizzle.isXML = function( elem ) {
4005 // documentElement is verified for cases where it doesn't yet exist
4006 // (such as loading iframes in IE - #4833)
4007 var documentElement = elem && (elem.ownerDocument || elem).documentElement;
4008 return documentElement ? documentElement.nodeName !== "HTML" : false;
4009 };
4010
4011 /**
4012 * Sets document-related variables once based on the current document
4013 * @param {Element|Object} [doc] An element or document object to use to set the document
4014 * @returns {Object} Returns the current document
4015 */
4016 setDocument = Sizzle.setDocument = function( node ) {
4017 var doc = node ? node.ownerDocument || node : preferredDoc;
4018
4019 // If no document and documentElement is available, return
4020 if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {
4021 return document;
4022 }
4023
4024 // Set our document
4025 document = doc;
4026 docElem = doc.documentElement;
4027
4028 // Support tests
4029 documentIsXML = isXML( doc );
4030
4031 // Check if getElementsByTagName("*") returns only elements
4032 support.tagNameNoComments = assert(function( div ) {
4033 div.appendChild( doc.createComment("") );
4034 return !div.getElementsByTagName("*").length;
4035 });
4036
4037 // Check if attributes should be retrieved by attribute nodes
4038 support.attributes = assert(function( div ) {
4039 div.innerHTML = "<select></select>";
4040 var type = typeof div.lastChild.getAttribute("multiple");
4041 // IE8 returns a string for some attributes even when not present
4042 return type !== "boolean" && type !== "string";
4043 });
4044
4045 // Check if getElementsByClassName can be trusted
4046 support.getByClassName = assert(function( div ) {
4047 // Opera can't find a second classname (in 9.6)
4048 div.innerHTML = "<div class='hidden e'></div><div class='hidden'></div>";
4049 if ( !div.getElementsByClassName || !div.getElementsByClassName("e").length ) {
4050 return false;
4051 }
4052
4053 // Safari 3.2 caches class attributes and doesn't catch changes
4054 div.lastChild.className = "e";
4055 return div.getElementsByClassName("e").length === 2;
4056 });
4057
4058 // Check if getElementById returns elements by name
4059 // Check if getElementsByName privileges form controls or returns elements by ID
4060 support.getByName = assert(function( div ) {
4061 // Inject content
4062 div.id = expando + 0;
4063 div.innerHTML = "<a name='" + expando + "'></a><div name='" + expando + "'></div>";
4064 docElem.insertBefore( div, docElem.firstChild );
4065
4066 // Test
4067 var pass = doc.getElementsByName &&
4068 // buggy browsers will return fewer than the correct 2
4069 doc.getElementsByName( expando ).length === 2 +
4070 // buggy browsers will return more than the correct 0
4071 doc.getElementsByName( expando + 0 ).length;
4072 support.getIdNotName = !doc.getElementById( expando );
4073
4074 // Cleanup
4075 docElem.removeChild( div );
4076
4077 return pass;
4078 });
4079
4080 // IE6/7 return modified attributes
4081 Expr.attrHandle = assert(function( div ) {
4082 div.innerHTML = "<a href='#'></a>";
4083 return div.firstChild && typeof div.firstChild.getAttribute !== strundefined &&
4084 div.firstChild.getAttribute("href") === "#";
4085 }) ?
4086 {} :
4087 {
4088 "href": function( elem ) {
4089 return elem.getAttribute( "href", 2 );
4090 },
4091 "type": function( elem ) {
4092 return elem.getAttribute("type");
4093 }
4094 };
4095
4096 // ID find and filter
4097 if ( support.getIdNotName ) {
4098 Expr.find["ID"] = function( id, context ) {
4099 if ( typeof context.getElementById !== strundefined && !documentIsXML ) {
4100 var m = context.getElementById( id );
4101 // Check parentNode to catch when Blackberry 4.6 returns
4102 // nodes that are no longer in the document #6963
4103 return m && m.parentNode ? [m] : [];
4104 }
4105 };
4106 Expr.filter["ID"] = function( id ) {
4107 var attrId = id.replace( runescape, funescape );
4108 return function( elem ) {
4109 return elem.getAttribute("id") === attrId;
4110 };
4111 };
4112 } else {
4113 Expr.find["ID"] = function( id, context ) {
4114 if ( typeof context.getElementById !== strundefined && !documentIsXML ) {
4115 var m = context.getElementById( id );
4116
4117 return m ?
4118 m.id === id || typeof m.getAttributeNode !== strundefined && m.getAttributeNode("id").value === id ?
4119 [m] :
4120 undefined :
4121 [];
4122 }
4123 };
4124 Expr.filter["ID"] = function( id ) {
4125 var attrId = id.replace( runescape, funescape );
4126 return function( elem ) {
4127 var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id");
4128 return node && node.value === attrId;
4129 };
4130 };
4131 }
4132
4133 // Tag
4134 Expr.find["TAG"] = support.tagNameNoComments ?
4135 function( tag, context ) {
4136 if ( typeof context.getElementsByTagName !== strundefined ) {
4137 return context.getElementsByTagName( tag );
4138 }
4139 } :
4140 function( tag, context ) {
4141 var elem,
4142 tmp = [],
4143 i = 0,
4144 results = context.getElementsByTagName( tag );
4145
4146 // Filter out possible comments
4147 if ( tag === "*" ) {
4148 while ( (elem = results[i++]) ) {
4149 if ( elem.nodeType === 1 ) {
4150 tmp.push( elem );
4151 }
4152 }
4153
4154 return tmp;
4155 }
4156 return results;
4157 };
4158
4159 // Name
4160 Expr.find["NAME"] = support.getByName && function( tag, context ) {
4161 if ( typeof context.getElementsByName !== strundefined ) {
4162 return context.getElementsByName( name );
4163 }
4164 };
4165
4166 // Class
4167 Expr.find["CLASS"] = support.getByClassName && function( className, context ) {
4168 if ( typeof context.getElementsByClassName !== strundefined && !documentIsXML ) {
4169 return context.getElementsByClassName( className );
4170 }
4171 };
4172
4173 // QSA and matchesSelector support
4174
4175 // matchesSelector(:active) reports false when true (IE9/Opera 11.5)
4176 rbuggyMatches = [];
4177
4178 // qSa(:focus) reports false when true (Chrome 21),
4179 // no need to also add to buggyMatches since matches checks buggyQSA
4180 // A support test would require too much code (would include document ready)
4181 rbuggyQSA = [ ":focus" ];
4182
4183 if ( (support.qsa = isNative(doc.querySelectorAll)) ) {
4184 // Build QSA regex
4185 // Regex strategy adopted from Diego Perini
4186 assert(function( div ) {
4187 // Select is set to empty string on purpose
4188 // This is to test IE's treatment of not explictly
4189 // setting a boolean content attribute,
4190 // since its presence should be enough
4191 // http://bugs.jquery.com/ticket/12359
4192 div.innerHTML = "<select><option selected=''></option></select>";
4193
4194 // IE8 - Some boolean attributes are not treated correctly
4195 if ( !div.querySelectorAll("[selected]").length ) {
4196 rbuggyQSA.push( "\\[" + whitespace + "*(?:checked|disabled|ismap|multiple|readonly|selected|value)" );
4197 }
4198
4199 // Webkit/Opera - :checked should return selected option elements
4200 // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
4201 // IE8 throws error here and will not see later tests
4202 if ( !div.querySelectorAll(":checked").length ) {
4203 rbuggyQSA.push(":checked");
4204 }
4205 });
4206
4207 assert(function( div ) {
4208
4209 // Opera 10-12/IE8 - ^= $= *= and empty values
4210 // Should not select anything
4211 div.innerHTML = "<input type='hidden' i=''/>";
4212 if ( div.querySelectorAll("[i^='']").length ) {
4213 rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:\"\"|'')" );
4214 }
4215
4216 // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
4217 // IE8 throws error here and will not see later tests
4218 if ( !div.querySelectorAll(":enabled").length ) {
4219 rbuggyQSA.push( ":enabled", ":disabled" );
4220 }
4221
4222 // Opera 10-11 does not throw on post-comma invalid pseudos
4223 div.querySelectorAll("*,:x");
4224 rbuggyQSA.push(",.*:");
4225 });
4226 }
4227
4228 if ( (support.matchesSelector = isNative( (matches = docElem.matchesSelector ||
4229 docElem.mozMatchesSelector ||
4230 docElem.webkitMatchesSelector ||
4231 docElem.oMatchesSelector ||
4232 docElem.msMatchesSelector) )) ) {
4233
4234 assert(function( div ) {
4235 // Check to see if it's possible to do matchesSelector
4236 // on a disconnected node (IE 9)
4237 support.disconnectedMatch = matches.call( div, "div" );
4238
4239 // This should fail with an exception
4240 // Gecko does not error, returns false instead
4241 matches.call( div, "[s!='']:x" );
4242 rbuggyMatches.push( "!=", pseudos );
4243 });
4244 }
4245
4246 rbuggyQSA = new RegExp( rbuggyQSA.join("|") );
4247 rbuggyMatches = new RegExp( rbuggyMatches.join("|") );
4248
4249 // Element contains another
4250 // Purposefully does not implement inclusive descendent
4251 // As in, an element does not contain itself
4252 contains = isNative(docElem.contains) || docElem.compareDocumentPosition ?
4253 function( a, b ) {
4254 var adown = a.nodeType === 9 ? a.documentElement : a,
4255 bup = b && b.parentNode;
4256 return a === bup || !!( bup && bup.nodeType === 1 && (
4257 adown.contains ?
4258 adown.contains( bup ) :
4259 a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
4260 ));
4261 } :
4262 function( a, b ) {
4263 if ( b ) {
4264 while ( (b = b.parentNode) ) {
4265 if ( b === a ) {
4266 return true;
4267 }
4268 }
4269 }
4270 return false;
4271 };
4272
4273 // Document order sorting
4274 sortOrder = docElem.compareDocumentPosition ?
4275 function( a, b ) {
4276 var compare;
4277
4278 if ( a === b ) {
4279 hasDuplicate = true;
4280 return 0;
4281 }
4282
4283 if ( (compare = b.compareDocumentPosition && a.compareDocumentPosition && a.compareDocumentPosition( b )) ) {
4284 if ( compare & 1 || a.parentNode && a.parentNode.nodeType === 11 ) {
4285 if ( a === doc || contains( preferredDoc, a ) ) {
4286 return -1;
4287 }
4288 if ( b === doc || contains( preferredDoc, b ) ) {
4289 return 1;
4290 }
4291 return 0;
4292 }
4293 return compare & 4 ? -1 : 1;
4294 }
4295
4296 return a.compareDocumentPosition ? -1 : 1;
4297 } :
4298 function( a, b ) {
4299 var cur,
4300 i = 0,
4301 aup = a.parentNode,
4302 bup = b.parentNode,
4303 ap = [ a ],
4304 bp = [ b ];
4305
4306 // Exit early if the nodes are identical
4307 if ( a === b ) {
4308 hasDuplicate = true;
4309 return 0;
4310
4311 // Parentless nodes are either documents or disconnected
4312 } else if ( !aup || !bup ) {
4313 return a === doc ? -1 :
4314 b === doc ? 1 :
4315 aup ? -1 :
4316 bup ? 1 :
4317 0;
4318
4319 // If the nodes are siblings, we can do a quick check
4320 } else if ( aup === bup ) {
4321 return siblingCheck( a, b );
4322 }
4323
4324 // Otherwise we need full lists of their ancestors for comparison
4325 cur = a;
4326 while ( (cur = cur.parentNode) ) {
4327 ap.unshift( cur );
4328 }
4329 cur = b;
4330 while ( (cur = cur.parentNode) ) {
4331 bp.unshift( cur );
4332 }
4333
4334 // Walk down the tree looking for a discrepancy
4335 while ( ap[i] === bp[i] ) {
4336 i++;
4337 }
4338
4339 return i ?
4340 // Do a sibling check if the nodes have a common ancestor
4341 siblingCheck( ap[i], bp[i] ) :
4342
4343 // Otherwise nodes in our document sort first
4344 ap[i] === preferredDoc ? -1 :
4345 bp[i] === preferredDoc ? 1 :
4346 0;
4347 };
4348
4349 // Always assume the presence of duplicates if sort doesn't
4350 // pass them to our comparison function (as in Google Chrome).
4351 hasDuplicate = false;
4352 [0, 0].sort( sortOrder );
4353 support.detectDuplicates = hasDuplicate;
4354
4355 return document;
4356 };
4357
4358 Sizzle.matches = function( expr, elements ) {
4359 return Sizzle( expr, null, null, elements );
4360 };
4361
4362 Sizzle.matchesSelector = function( elem, expr ) {
4363 // Set document vars if needed
4364 if ( ( elem.ownerDocument || elem ) !== document ) {
4365 setDocument( elem );
4366 }
4367
4368 // Make sure that attribute selectors are quoted
4369 expr = expr.replace( rattributeQuotes, "='$1']" );
4370
4371 // rbuggyQSA always contains :focus, so no need for an existence check
4372 if ( support.matchesSelector && !documentIsXML && (!rbuggyMatches || !rbuggyMatches.test(expr)) && !rbuggyQSA.test(expr) ) {
4373 try {
4374 var ret = matches.call( elem, expr );
4375
4376 // IE 9's matchesSelector returns false on disconnected nodes
4377 if ( ret || support.disconnectedMatch ||
4378 // As well, disconnected nodes are said to be in a document
4379 // fragment in IE 9
4380 elem.document && elem.document.nodeType !== 11 ) {
4381 return ret;
4382 }
4383 } catch(e) {}
4384 }
4385
4386 return Sizzle( expr, document, null, [elem] ).length > 0;
4387 };
4388
4389 Sizzle.contains = function( context, elem ) {
4390 // Set document vars if needed
4391 if ( ( context.ownerDocument || context ) !== document ) {
4392 setDocument( context );
4393 }
4394 return contains( context, elem );
4395 };
4396
4397 Sizzle.attr = function( elem, name ) {
4398 var val;
4399
4400 // Set document vars if needed
4401 if ( ( elem.ownerDocument || elem ) !== document ) {
4402 setDocument( elem );
4403 }
4404
4405 if ( !documentIsXML ) {
4406 name = name.toLowerCase();
4407 }
4408 if ( (val = Expr.attrHandle[ name ]) ) {
4409 return val( elem );
4410 }
4411 if ( documentIsXML || support.attributes ) {
4412 return elem.getAttribute( name );
4413 }
4414 return ( (val = elem.getAttributeNode( name )) || elem.getAttribute( name ) ) && elem[ name ] === true ?
4415 name :
4416 val && val.specified ? val.value : null;
4417 };
4418
4419 Sizzle.error = function( msg ) {
4420 throw new Error( "Syntax error, unrecognized expression: " + msg );
4421 };
4422
4423 // Document sorting and removing duplicates
4424 Sizzle.uniqueSort = function( results ) {
4425 var elem,
4426 duplicates = [],
4427 i = 1,
4428 j = 0;
4429
4430 // Unless we *know* we can detect duplicates, assume their presence
4431 hasDuplicate = !support.detectDuplicates;
4432 results.sort( sortOrder );
4433
4434 if ( hasDuplicate ) {
4435 for ( ; (elem = results[i]); i++ ) {
4436 if ( elem === results[ i - 1 ] ) {
4437 j = duplicates.push( i );
4438 }
4439 }
4440 while ( j-- ) {
4441 results.splice( duplicates[ j ], 1 );
4442 }
4443 }
4444
4445 return results;
4446 };
4447
4448 function siblingCheck( a, b ) {
4449 var cur = b && a,
4450 diff = cur && ( ~b.sourceIndex || MAX_NEGATIVE ) - ( ~a.sourceIndex || MAX_NEGATIVE );
4451
4452 // Use IE sourceIndex if available on both nodes
4453 if ( diff ) {
4454 return diff;
4455 }
4456
4457 // Check if b follows a
4458 if ( cur ) {
4459 while ( (cur = cur.nextSibling) ) {
4460 if ( cur === b ) {
4461 return -1;
4462 }
4463 }
4464 }
4465
4466 return a ? 1 : -1;
4467 }
4468
4469 // Returns a function to use in pseudos for input types
4470 function createInputPseudo( type ) {
4471 return function( elem ) {
4472 var name = elem.nodeName.toLowerCase();
4473 return name === "input" && elem.type === type;
4474 };
4475 }
4476
4477 // Returns a function to use in pseudos for buttons
4478 function createButtonPseudo( type ) {
4479 return function( elem ) {
4480 var name = elem.nodeName.toLowerCase();
4481 return (name === "input" || name === "button") && elem.type === type;
4482 };
4483 }
4484
4485 // Returns a function to use in pseudos for positionals
4486 function createPositionalPseudo( fn ) {
4487 return markFunction(function( argument ) {
4488 argument = +argument;
4489 return markFunction(function( seed, matches ) {
4490 var j,
4491 matchIndexes = fn( [], seed.length, argument ),
4492 i = matchIndexes.length;
4493
4494 // Match elements found at the specified indexes
4495 while ( i-- ) {
4496 if ( seed[ (j = matchIndexes[i]) ] ) {
4497 seed[j] = !(matches[j] = seed[j]);
4498 }
4499 }
4500 });
4501 });
4502 }
4503
4504 /**
4505 * Utility function for retrieving the text value of an array of DOM nodes
4506 * @param {Array|Element} elem
4507 */
4508 getText = Sizzle.getText = function( elem ) {
4509 var node,
4510 ret = "",
4511 i = 0,
4512 nodeType = elem.nodeType;
4513
4514 if ( !nodeType ) {
4515 // If no nodeType, this is expected to be an array
4516 for ( ; (node = elem[i]); i++ ) {
4517 // Do not traverse comment nodes
4518 ret += getText( node );
4519 }
4520 } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
4521 // Use textContent for elements
4522 // innerText usage removed for consistency of new lines (see #11153)
4523 if ( typeof elem.textContent === "string" ) {
4524 return elem.textContent;
4525 } else {
4526 // Traverse its children
4527 for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
4528 ret += getText( elem );
4529 }
4530 }
4531 } else if ( nodeType === 3 || nodeType === 4 ) {
4532 return elem.nodeValue;
4533 }
4534 // Do not include comment or processing instruction nodes
4535
4536 return ret;
4537 };
4538
4539 Expr = Sizzle.selectors = {
4540
4541 // Can be adjusted by the user
4542 cacheLength: 50,
4543
4544 createPseudo: markFunction,
4545
4546 match: matchExpr,
4547
4548 find: {},
4549
4550 relative: {
4551 ">": { dir: "parentNode", first: true },
4552 " ": { dir: "parentNode" },
4553 "+": { dir: "previousSibling", first: true },
4554 "~": { dir: "previousSibling" }
4555 },
4556
4557 preFilter: {
4558 "ATTR": function( match ) {
4559 match[1] = match[1].replace( runescape, funescape );
4560
4561 // Move the given value to match[3] whether quoted or unquoted
4562 match[3] = ( match[4] || match[5] || "" ).replace( runescape, funescape );
4563
4564 if ( match[2] === "~=" ) {
4565 match[3] = " " + match[3] + " ";
4566 }
4567
4568 return match.slice( 0, 4 );
4569 },
4570
4571 "CHILD": function( match ) {
4572 /* matches from matchExpr["CHILD"]
4573 1 type (only|nth|...)
4574 2 what (child|of-type)
4575 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
4576 4 xn-component of xn+y argument ([+-]?\d*n|)
4577 5 sign of xn-component
4578 6 x of xn-component
4579 7 sign of y-component
4580 8 y of y-component
4581 */
4582 match[1] = match[1].toLowerCase();
4583
4584 if ( match[1].slice( 0, 3 ) === "nth" ) {
4585 // nth-* requires argument
4586 if ( !match[3] ) {
4587 Sizzle.error( match[0] );
4588 }
4589
4590 // numeric x and y parameters for Expr.filter.CHILD
4591 // remember that false/true cast respectively to 0/1
4592 match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) );
4593 match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" );
4594
4595 // other types prohibit arguments
4596 } else if ( match[3] ) {
4597 Sizzle.error( match[0] );
4598 }
4599
4600 return match;
4601 },
4602
4603 "PSEUDO": function( match ) {
4604 var excess,
4605 unquoted = !match[5] && match[2];
4606
4607 if ( matchExpr["CHILD"].test( match[0] ) ) {
4608 return null;
4609 }
4610
4611 // Accept quoted arguments as-is
4612 if ( match[4] ) {
4613 match[2] = match[4];
4614
4615 // Strip excess characters from unquoted arguments
4616 } else if ( unquoted && rpseudo.test( unquoted ) &&
4617 // Get excess from tokenize (recursively)
4618 (excess = tokenize( unquoted, true )) &&
4619 // advance to the next closing parenthesis
4620 (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) {
4621
4622 // excess is a negative index
4623 match[0] = match[0].slice( 0, excess );
4624 match[2] = unquoted.slice( 0, excess );
4625 }
4626
4627 // Return only captures needed by the pseudo filter method (type and argument)
4628 return match.slice( 0, 3 );
4629 }
4630 },
4631
4632 filter: {
4633
4634 "TAG": function( nodeName ) {
4635 if ( nodeName === "*" ) {
4636 return function() { return true; };
4637 }
4638
4639 nodeName = nodeName.replace( runescape, funescape ).toLowerCase();
4640 return function( elem ) {
4641 return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
4642 };
4643 },
4644
4645 "CLASS": function( className ) {
4646 var pattern = classCache[ className + " " ];
4647
4648 return pattern ||
4649 (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) &&
4650 classCache( className, function( elem ) {
4651 return pattern.test( elem.className || (typeof elem.getAttribute !== strundefined && elem.getAttribute("class")) || "" );
4652 });
4653 },
4654
4655 "ATTR": function( name, operator, check ) {
4656 return function( elem ) {
4657 var result = Sizzle.attr( elem, name );
4658
4659 if ( result == null ) {
4660 return operator === "!=";
4661 }
4662 if ( !operator ) {
4663 return true;
4664 }
4665
4666 result += "";
4667
4668 return operator === "=" ? result === check :
4669 operator === "!=" ? result !== check :
4670 operator === "^=" ? check && result.indexOf( check ) === 0 :
4671 operator === "*=" ? check && result.indexOf( check ) > -1 :
4672 operator === "$=" ? check && result.slice( -check.length ) === check :
4673 operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 :
4674 operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" :
4675 false;
4676 };
4677 },
4678
4679 "CHILD": function( type, what, argument, first, last ) {
4680 var simple = type.slice( 0, 3 ) !== "nth",
4681 forward = type.slice( -4 ) !== "last",
4682 ofType = what === "of-type";
4683
4684 return first === 1 && last === 0 ?
4685
4686 // Shortcut for :nth-*(n)
4687 function( elem ) {
4688 return !!elem.parentNode;
4689 } :
4690
4691 function( elem, context, xml ) {
4692 var cache, outerCache, node, diff, nodeIndex, start,
4693 dir = simple !== forward ? "nextSibling" : "previousSibling",
4694 parent = elem.parentNode,
4695 name = ofType && elem.nodeName.toLowerCase(),
4696 useCache = !xml && !ofType;
4697
4698 if ( parent ) {
4699
4700 // :(first|last|only)-(child|of-type)
4701 if ( simple ) {
4702 while ( dir ) {
4703 node = elem;
4704 while ( (node = node[ dir ]) ) {
4705 if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) {
4706 return false;
4707 }
4708 }
4709 // Reverse direction for :only-* (if we haven't yet done so)
4710 start = dir = type === "only" && !start && "nextSibling";
4711 }
4712 return true;
4713 }
4714
4715 start = [ forward ? parent.firstChild : parent.lastChild ];
4716
4717 // non-xml :nth-child(...) stores cache data on `parent`
4718 if ( forward && useCache ) {
4719 // Seek `elem` from a previously-cached index
4720 outerCache = parent[ expando ] || (parent[ expando ] = {});
4721 cache = outerCache[ type ] || [];
4722 nodeIndex = cache[0] === dirruns && cache[1];
4723 diff = cache[0] === dirruns && cache[2];
4724 node = nodeIndex && parent.childNodes[ nodeIndex ];
4725
4726 while ( (node = ++nodeIndex && node && node[ dir ] ||
4727
4728 // Fallback to seeking `elem` from the start
4729 (diff = nodeIndex = 0) || start.pop()) ) {
4730
4731 // When found, cache indexes on `parent` and break
4732 if ( node.nodeType === 1 && ++diff && node === elem ) {
4733 outerCache[ type ] = [ dirruns, nodeIndex, diff ];
4734 break;
4735 }
4736 }
4737
4738 // Use previously-cached element index if available
4739 } else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) {
4740 diff = cache[1];
4741
4742 // xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...)
4743 } else {
4744 // Use the same loop as above to seek `elem` from the start
4745 while ( (node = ++nodeIndex && node && node[ dir ] ||
4746 (diff = nodeIndex = 0) || start.pop()) ) {
4747
4748 if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) {
4749 // Cache the index of each encountered element
4750 if ( useCache ) {
4751 (node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ];
4752 }
4753
4754 if ( node === elem ) {
4755 break;
4756 }
4757 }
4758 }
4759 }
4760
4761 // Incorporate the offset, then check against cycle size
4762 diff -= last;
4763 return diff === first || ( diff % first === 0 && diff / first >= 0 );
4764 }
4765 };
4766 },
4767
4768 "PSEUDO": function( pseudo, argument ) {
4769 // pseudo-class names are case-insensitive
4770 // http://www.w3.org/TR/selectors/#pseudo-classes
4771 // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
4772 // Remember that setFilters inherits from pseudos
4773 var args,
4774 fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
4775 Sizzle.error( "unsupported pseudo: " + pseudo );
4776
4777 // The user may use createPseudo to indicate that
4778 // arguments are needed to create the filter function
4779 // just as Sizzle does
4780 if ( fn[ expando ] ) {
4781 return fn( argument );
4782 }
4783
4784 // But maintain support for old signatures
4785 if ( fn.length > 1 ) {
4786 args = [ pseudo, pseudo, "", argument ];
4787 return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
4788 markFunction(function( seed, matches ) {
4789 var idx,
4790 matched = fn( seed, argument ),
4791 i = matched.length;
4792 while ( i-- ) {
4793 idx = indexOf.call( seed, matched[i] );
4794 seed[ idx ] = !( matches[ idx ] = matched[i] );
4795 }
4796 }) :
4797 function( elem ) {
4798 return fn( elem, 0, args );
4799 };
4800 }
4801
4802 return fn;
4803 }
4804 },
4805
4806 pseudos: {
4807 // Potentially complex pseudos
4808 "not": markFunction(function( selector ) {
4809 // Trim the selector passed to compile
4810 // to avoid treating leading and trailing
4811 // spaces as combinators
4812 var input = [],
4813 results = [],
4814 matcher = compile( selector.replace( rtrim, "$1" ) );
4815
4816 return matcher[ expando ] ?
4817 markFunction(function( seed, matches, context, xml ) {
4818 var elem,
4819 unmatched = matcher( seed, null, xml, [] ),
4820 i = seed.length;
4821
4822 // Match elements unmatched by `matcher`
4823 while ( i-- ) {
4824 if ( (elem = unmatched[i]) ) {
4825 seed[i] = !(matches[i] = elem);
4826 }
4827 }
4828 }) :
4829 function( elem, context, xml ) {
4830 input[0] = elem;
4831 matcher( input, null, xml, results );
4832 return !results.pop();
4833 };
4834 }),
4835
4836 "has": markFunction(function( selector ) {
4837 return function( elem ) {
4838 return Sizzle( selector, elem ).length > 0;
4839 };
4840 }),
4841
4842 "contains": markFunction(function( text ) {
4843 return function( elem ) {
4844 return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;
4845 };
4846 }),
4847
4848 // "Whether an element is represented by a :lang() selector
4849 // is based solely on the element's language value
4850 // being equal to the identifier C,
4851 // or beginning with the identifier C immediately followed by "-".
4852 // The matching of C against the element's language value is performed case-insensitively.
4853 // The identifier C does not have to be a valid language name."
4854 // http://www.w3.org/TR/selectors/#lang-pseudo
4855 "lang": markFunction( function( lang ) {
4856 // lang value must be a valid identifider
4857 if ( !ridentifier.test(lang || "") ) {
4858 Sizzle.error( "unsupported lang: " + lang );
4859 }
4860 lang = lang.replace( runescape, funescape ).toLowerCase();
4861 return function( elem ) {
4862 var elemLang;
4863 do {
4864 if ( (elemLang = documentIsXML ?
4865 elem.getAttribute("xml:lang") || elem.getAttribute("lang") :
4866 elem.lang) ) {
4867
4868 elemLang = elemLang.toLowerCase();
4869 return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0;
4870 }
4871 } while ( (elem = elem.parentNode) && elem.nodeType === 1 );
4872 return false;
4873 };
4874 }),
4875
4876 // Miscellaneous
4877 "target": function( elem ) {
4878 var hash = window.location && window.location.hash;
4879 return hash && hash.slice( 1 ) === elem.id;
4880 },
4881
4882 "root": function( elem ) {
4883 return elem === docElem;
4884 },
4885
4886 "focus": function( elem ) {
4887 return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
4888 },
4889
4890 // Boolean properties
4891 "enabled": function( elem ) {
4892 return elem.disabled === false;
4893 },
4894
4895 "disabled": function( elem ) {
4896 return elem.disabled === true;
4897 },
4898
4899 "checked": function( elem ) {
4900 // In CSS3, :checked should return both checked and selected elements
4901 // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
4902 var nodeName = elem.nodeName.toLowerCase();
4903 return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected);
4904 },
4905
4906 "selected": function( elem ) {
4907 // Accessing this property makes selected-by-default
4908 // options in Safari work properly
4909 if ( elem.parentNode ) {
4910 elem.parentNode.selectedIndex;
4911 }
4912
4913 return elem.selected === true;
4914 },
4915
4916 // Contents
4917 "empty": function( elem ) {
4918 // http://www.w3.org/TR/selectors/#empty-pseudo
4919 // :empty is only affected by element nodes and content nodes(including text(3), cdata(4)),
4920 // not comment, processing instructions, or others
4921 // Thanks to Diego Perini for the nodeName shortcut
4922 // Greater than "@" means alpha characters (specifically not starting with "#" or "?")
4923 for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
4924 if ( elem.nodeName > "@" || elem.nodeType === 3 || elem.nodeType === 4 ) {
4925 return false;
4926 }
4927 }
4928 return true;
4929 },
4930
4931 "parent": function( elem ) {
4932 return !Expr.pseudos["empty"]( elem );
4933 },
4934
4935 // Element/input types
4936 "header": function( elem ) {
4937 return rheader.test( elem.nodeName );
4938 },
4939
4940 "input": function( elem ) {
4941 return rinputs.test( elem.nodeName );
4942 },
4943
4944 "button": function( elem ) {
4945 var name = elem.nodeName.toLowerCase();
4946 return name === "input" && elem.type === "button" || name === "button";
4947 },
4948
4949 "text": function( elem ) {
4950 var attr;
4951 // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc)
4952 // use getAttribute instead to test this case
4953 return elem.nodeName.toLowerCase() === "input" &&
4954 elem.type === "text" &&
4955 ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === elem.type );
4956 },
4957
4958 // Position-in-collection
4959 "first": createPositionalPseudo(function() {
4960 return [ 0 ];
4961 }),
4962
4963 "last": createPositionalPseudo(function( matchIndexes, length ) {
4964 return [ length - 1 ];
4965 }),
4966
4967 "eq": createPositionalPseudo(function( matchIndexes, length, argument ) {
4968 return [ argument < 0 ? argument + length : argument ];
4969 }),
4970
4971 "even": createPositionalPseudo(function( matchIndexes, length ) {
4972 var i = 0;
4973 for ( ; i < length; i += 2 ) {
4974 matchIndexes.push( i );
4975 }
4976 return matchIndexes;
4977 }),
4978
4979 "odd": createPositionalPseudo(function( matchIndexes, length ) {
4980 var i = 1;
4981 for ( ; i < length; i += 2 ) {
4982 matchIndexes.push( i );
4983 }
4984 return matchIndexes;
4985 }),
4986
4987 "lt": createPositionalPseudo(function( matchIndexes, length, argument ) {
4988 var i = argument < 0 ? argument + length : argument;
4989 for ( ; --i >= 0; ) {
4990 matchIndexes.push( i );
4991 }
4992 return matchIndexes;
4993 }),
4994
4995 "gt": createPositionalPseudo(function( matchIndexes, length, argument ) {
4996 var i = argument < 0 ? argument + length : argument;
4997 for ( ; ++i < length; ) {
4998 matchIndexes.push( i );
4999 }
5000 return matchIndexes;
5001 })
5002 }
5003 };
5004
5005 // Add button/input type pseudos
5006 for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {
5007 Expr.pseudos[ i ] = createInputPseudo( i );
5008 }
5009 for ( i in { submit: true, reset: true } ) {
5010 Expr.pseudos[ i ] = createButtonPseudo( i );
5011 }
5012
5013 function tokenize( selector, parseOnly ) {
5014 var matched, match, tokens, type,
5015 soFar, groups, preFilters,
5016 cached = tokenCache[ selector + " " ];
5017
5018 if ( cached ) {
5019 return parseOnly ? 0 : cached.slice( 0 );
5020 }
5021
5022 soFar = selector;
5023 groups = [];
5024 preFilters = Expr.preFilter;
5025
5026 while ( soFar ) {
5027
5028 // Comma and first run
5029 if ( !matched || (match = rcomma.exec( soFar )) ) {
5030 if ( match ) {
5031 // Don't consume trailing commas as valid
5032 soFar = soFar.slice( match[0].length ) || soFar;
5033 }
5034 groups.push( tokens = [] );
5035 }
5036
5037 matched = false;
5038
5039 // Combinators
5040 if ( (match = rcombinators.exec( soFar )) ) {
5041 matched = match.shift();
5042 tokens.push( {
5043 value: matched,
5044 // Cast descendant combinators to space
5045 type: match[0].replace( rtrim, " " )
5046 } );
5047 soFar = soFar.slice( matched.length );
5048 }
5049
5050 // Filters
5051 for ( type in Expr.filter ) {
5052 if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||
5053 (match = preFilters[ type ]( match ))) ) {
5054 matched = match.shift();
5055 tokens.push( {
5056 value: matched,
5057 type: type,
5058 matches: match
5059 } );
5060 soFar = soFar.slice( matched.length );
5061 }
5062 }
5063
5064 if ( !matched ) {
5065 break;
5066 }
5067 }
5068
5069 // Return the length of the invalid excess
5070 // if we're just parsing
5071 // Otherwise, throw an error or return tokens
5072 return parseOnly ?
5073 soFar.length :
5074 soFar ?
5075 Sizzle.error( selector ) :
5076 // Cache the tokens
5077 tokenCache( selector, groups ).slice( 0 );
5078 }
5079
5080 function toSelector( tokens ) {
5081 var i = 0,
5082 len = tokens.length,
5083 selector = "";
5084 for ( ; i < len; i++ ) {
5085 selector += tokens[i].value;
5086 }
5087 return selector;
5088 }
5089
5090 function addCombinator( matcher, combinator, base ) {
5091 var dir = combinator.dir,
5092 checkNonElements = base && dir === "parentNode",
5093 doneName = done++;
5094
5095 return combinator.first ?
5096 // Check against closest ancestor/preceding element
5097 function( elem, context, xml ) {
5098 while ( (elem = elem[ dir ]) ) {
5099 if ( elem.nodeType === 1 || checkNonElements ) {
5100 return matcher( elem, context, xml );
5101 }
5102 }
5103 } :
5104
5105 // Check against all ancestor/preceding elements
5106 function( elem, context, xml ) {
5107 var data, cache, outerCache,
5108 dirkey = dirruns + " " + doneName;
5109
5110 // We can't set arbitrary data on XML nodes, so they don't benefit from dir caching
5111 if ( xml ) {
5112 while ( (elem = elem[ dir ]) ) {
5113 if ( elem.nodeType === 1 || checkNonElements ) {
5114 if ( matcher( elem, context, xml ) ) {
5115 return true;
5116 }
5117 }
5118 }
5119 } else {
5120 while ( (elem = elem[ dir ]) ) {
5121 if ( elem.nodeType === 1 || checkNonElements ) {
5122 outerCache = elem[ expando ] || (elem[ expando ] = {});
5123 if ( (cache = outerCache[ dir ]) && cache[0] === dirkey ) {
5124 if ( (data = cache[1]) === true || data === cachedruns ) {
5125 return data === true;
5126 }
5127 } else {
5128 cache = outerCache[ dir ] = [ dirkey ];
5129 cache[1] = matcher( elem, context, xml ) || cachedruns;
5130 if ( cache[1] === true ) {
5131 return true;
5132 }
5133 }
5134 }
5135 }
5136 }
5137 };
5138 }
5139
5140 function elementMatcher( matchers ) {
5141 return matchers.length > 1 ?
5142 function( elem, context, xml ) {
5143 var i = matchers.length;
5144 while ( i-- ) {
5145 if ( !matchers[i]( elem, context, xml ) ) {
5146 return false;
5147 }
5148 }
5149 return true;
5150 } :
5151 matchers[0];
5152 }
5153
5154 function condense( unmatched, map, filter, context, xml ) {
5155 var elem,
5156 newUnmatched = [],
5157 i = 0,
5158 len = unmatched.length,
5159 mapped = map != null;
5160
5161 for ( ; i < len; i++ ) {
5162 if ( (elem = unmatched[i]) ) {
5163 if ( !filter || filter( elem, context, xml ) ) {
5164 newUnmatched.push( elem );
5165 if ( mapped ) {
5166 map.push( i );
5167 }
5168 }
5169 }
5170 }
5171
5172 return newUnmatched;
5173 }
5174
5175 function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
5176 if ( postFilter && !postFilter[ expando ] ) {
5177 postFilter = setMatcher( postFilter );
5178 }
5179 if ( postFinder && !postFinder[ expando ] ) {
5180 postFinder = setMatcher( postFinder, postSelector );
5181 }
5182 return markFunction(function( seed, results, context, xml ) {
5183 var temp, i, elem,
5184 preMap = [],
5185 postMap = [],
5186 preexisting = results.length,
5187
5188 // Get initial elements from seed or context
5189 elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ),
5190
5191 // Prefilter to get matcher input, preserving a map for seed-results synchronization
5192 matcherIn = preFilter && ( seed || !selector ) ?
5193 condense( elems, preMap, preFilter, context, xml ) :
5194 elems,
5195
5196 matcherOut = matcher ?
5197 // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,
5198 postFinder || ( seed ? preFilter : preexisting || postFilter ) ?
5199
5200 // ...intermediate processing is necessary
5201 [] :
5202
5203 // ...otherwise use results directly
5204 results :
5205 matcherIn;
5206
5207 // Find primary matches
5208 if ( matcher ) {
5209 matcher( matcherIn, matcherOut, context, xml );
5210 }
5211
5212 // Apply postFilter
5213 if ( postFilter ) {
5214 temp = condense( matcherOut, postMap );
5215 postFilter( temp, [], context, xml );
5216
5217 // Un-match failing elements by moving them back to matcherIn
5218 i = temp.length;
5219 while ( i-- ) {
5220 if ( (elem = temp[i]) ) {
5221 matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);
5222 }
5223 }
5224 }
5225
5226 if ( seed ) {
5227 if ( postFinder || preFilter ) {
5228 if ( postFinder ) {
5229 // Get the final matcherOut by condensing this intermediate into postFinder contexts
5230 temp = [];
5231 i = matcherOut.length;
5232 while ( i-- ) {
5233 if ( (elem = matcherOut[i]) ) {
5234 // Restore matcherIn since elem is not yet a final match
5235 temp.push( (matcherIn[i] = elem) );
5236 }
5237 }
5238 postFinder( null, (matcherOut = []), temp, xml );
5239 }
5240
5241 // Move matched elements from seed to results to keep them synchronized
5242 i = matcherOut.length;
5243 while ( i-- ) {
5244 if ( (elem = matcherOut[i]) &&
5245 (temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) {
5246
5247 seed[temp] = !(results[temp] = elem);
5248 }
5249 }
5250 }
5251
5252 // Add elements to results, through postFinder if defined
5253 } else {
5254 matcherOut = condense(
5255 matcherOut === results ?
5256 matcherOut.splice( preexisting, matcherOut.length ) :
5257 matcherOut
5258 );
5259 if ( postFinder ) {
5260 postFinder( null, results, matcherOut, xml );
5261 } else {
5262 push.apply( results, matcherOut );
5263 }
5264 }
5265 });
5266 }
5267
5268 function matcherFromTokens( tokens ) {
5269 var checkContext, matcher, j,
5270 len = tokens.length,
5271 leadingRelative = Expr.relative[ tokens[0].type ],
5272 implicitRelative = leadingRelative || Expr.relative[" "],
5273 i = leadingRelative ? 1 : 0,
5274
5275 // The foundational matcher ensures that elements are reachable from top-level context(s)
5276 matchContext = addCombinator( function( elem ) {
5277 return elem === checkContext;
5278 }, implicitRelative, true ),
5279 matchAnyContext = addCombinator( function( elem ) {
5280 return indexOf.call( checkContext, elem ) > -1;
5281 }, implicitRelative, true ),
5282 matchers = [ function( elem, context, xml ) {
5283 return ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
5284 (checkContext = context).nodeType ?
5285 matchContext( elem, context, xml ) :
5286 matchAnyContext( elem, context, xml ) );
5287 } ];
5288
5289 for ( ; i < len; i++ ) {
5290 if ( (matcher = Expr.relative[ tokens[i].type ]) ) {
5291 matchers = [ addCombinator(elementMatcher( matchers ), matcher) ];
5292 } else {
5293 matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );
5294
5295 // Return special upon seeing a positional matcher
5296 if ( matcher[ expando ] ) {
5297 // Find the next relative operator (if any) for proper handling
5298 j = ++i;
5299 for ( ; j < len; j++ ) {
5300 if ( Expr.relative[ tokens[j].type ] ) {
5301 break;
5302 }
5303 }
5304 return setMatcher(
5305 i > 1 && elementMatcher( matchers ),
5306 i > 1 && toSelector( tokens.slice( 0, i - 1 ) ).replace( rtrim, "$1" ),
5307 matcher,
5308 i < j && matcherFromTokens( tokens.slice( i, j ) ),
5309 j < len && matcherFromTokens( (tokens = tokens.slice( j )) ),
5310 j < len && toSelector( tokens )
5311 );
5312 }
5313 matchers.push( matcher );
5314 }
5315 }
5316
5317 return elementMatcher( matchers );
5318 }
5319
5320 function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
5321 // A counter to specify which element is currently being matched
5322 var matcherCachedRuns = 0,
5323 bySet = setMatchers.length > 0,
5324 byElement = elementMatchers.length > 0,
5325 superMatcher = function( seed, context, xml, results, expandContext ) {
5326 var elem, j, matcher,
5327 setMatched = [],
5328 matchedCount = 0,
5329 i = "0",
5330 unmatched = seed && [],
5331 outermost = expandContext != null,
5332 contextBackup = outermostContext,
5333 // We must always have either seed elements or context
5334 elems = seed || byElement && Expr.find["TAG"]( "*", expandContext && context.parentNode || context ),
5335 // Use integer dirruns iff this is the outermost matcher
5336 dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1);
5337
5338 if ( outermost ) {
5339 outermostContext = context !== document && context;
5340 cachedruns = matcherCachedRuns;
5341 }
5342
5343 // Add elements passing elementMatchers directly to results
5344 // Keep `i` a string if there are no elements so `matchedCount` will be "00" below
5345 for ( ; (elem = elems[i]) != null; i++ ) {
5346 if ( byElement && elem ) {
5347 j = 0;
5348 while ( (matcher = elementMatchers[j++]) ) {
5349 if ( matcher( elem, context, xml ) ) {
5350 results.push( elem );
5351 break;
5352 }
5353 }
5354 if ( outermost ) {
5355 dirruns = dirrunsUnique;
5356 cachedruns = ++matcherCachedRuns;
5357 }
5358 }
5359
5360 // Track unmatched elements for set filters
5361 if ( bySet ) {
5362 // They will have gone through all possible matchers
5363 if ( (elem = !matcher && elem) ) {
5364 matchedCount--;
5365 }
5366
5367 // Lengthen the array for every element, matched or not
5368 if ( seed ) {
5369 unmatched.push( elem );
5370 }
5371 }
5372 }
5373
5374 // Apply set filters to unmatched elements
5375 matchedCount += i;
5376 if ( bySet && i !== matchedCount ) {
5377 j = 0;
5378 while ( (matcher = setMatchers[j++]) ) {
5379 matcher( unmatched, setMatched, context, xml );
5380 }
5381
5382 if ( seed ) {
5383 // Reintegrate element matches to eliminate the need for sorting
5384 if ( matchedCount > 0 ) {
5385 while ( i-- ) {
5386 if ( !(unmatched[i] || setMatched[i]) ) {
5387 setMatched[i] = pop.call( results );
5388 }
5389 }
5390 }
5391
5392 // Discard index placeholder values to get only actual matches
5393 setMatched = condense( setMatched );
5394 }
5395
5396 // Add matches to results
5397 push.apply( results, setMatched );
5398
5399 // Seedless set matches succeeding multiple successful matchers stipulate sorting
5400 if ( outermost && !seed && setMatched.length > 0 &&
5401 ( matchedCount + setMatchers.length ) > 1 ) {
5402
5403 Sizzle.uniqueSort( results );
5404 }
5405 }
5406
5407 // Override manipulation of globals by nested matchers
5408 if ( outermost ) {
5409 dirruns = dirrunsUnique;
5410 outermostContext = contextBackup;
5411 }
5412
5413 return unmatched;
5414 };
5415
5416 return bySet ?
5417 markFunction( superMatcher ) :
5418 superMatcher;
5419 }
5420
5421 compile = Sizzle.compile = function( selector, group /* Internal Use Only */ ) {
5422 var i,
5423 setMatchers = [],
5424 elementMatchers = [],
5425 cached = compilerCache[ selector + " " ];
5426
5427 if ( !cached ) {
5428 // Generate a function of recursive functions that can be used to check each element
5429 if ( !group ) {
5430 group = tokenize( selector );
5431 }
5432 i = group.length;
5433 while ( i-- ) {
5434 cached = matcherFromTokens( group[i] );
5435 if ( cached[ expando ] ) {
5436 setMatchers.push( cached );
5437 } else {
5438 elementMatchers.push( cached );
5439 }
5440 }
5441
5442 // Cache the compiled function
5443 cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );
5444 }
5445 return cached;
5446 };
5447
5448 function multipleContexts( selector, contexts, results ) {
5449 var i = 0,
5450 len = contexts.length;
5451 for ( ; i < len; i++ ) {
5452 Sizzle( selector, contexts[i], results );
5453 }
5454 return results;
5455 }
5456
5457 function select( selector, context, results, seed ) {
5458 var i, tokens, token, type, find,
5459 match = tokenize( selector );
5460
5461 if ( !seed ) {
5462 // Try to minimize operations if there is only one group
5463 if ( match.length === 1 ) {
5464
5465 // Take a shortcut and set the context if the root selector is an ID
5466 tokens = match[0] = match[0].slice( 0 );
5467 if ( tokens.length > 2 && (token = tokens[0]).type === "ID" &&
5468 context.nodeType === 9 && !documentIsXML &&
5469 Expr.relative[ tokens[1].type ] ) {
5470
5471 context = Expr.find["ID"]( token.matches[0].replace( runescape, funescape ), context )[0];
5472 if ( !context ) {
5473 return results;
5474 }
5475
5476 selector = selector.slice( tokens.shift().value.length );
5477 }
5478
5479 // Fetch a seed set for right-to-left matching
5480 i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length;
5481 while ( i-- ) {
5482 token = tokens[i];
5483
5484 // Abort if we hit a combinator
5485 if ( Expr.relative[ (type = token.type) ] ) {
5486 break;
5487 }
5488 if ( (find = Expr.find[ type ]) ) {
5489 // Search, expanding context for leading sibling combinators
5490 if ( (seed = find(
5491 token.matches[0].replace( runescape, funescape ),
5492 rsibling.test( tokens[0].type ) && context.parentNode || context
5493 )) ) {
5494
5495 // If seed is empty or no tokens remain, we can return early
5496 tokens.splice( i, 1 );
5497 selector = seed.length && toSelector( tokens );
5498 if ( !selector ) {
5499 push.apply( results, slice.call( seed, 0 ) );
5500 return results;
5501 }
5502
5503 break;
5504 }
5505 }
5506 }
5507 }
5508 }
5509
5510 // Compile and execute a filtering function
5511 // Provide `match` to avoid retokenization if we modified the selector above
5512 compile( selector, match )(
5513 seed,
5514 context,
5515 documentIsXML,
5516 results,
5517 rsibling.test( selector )
5518 );
5519 return results;
5520 }
5521
5522 // Deprecated
5523 Expr.pseudos["nth"] = Expr.pseudos["eq"];
5524
5525 // Easy API for creating new setFilters
5526 function setFilters() {}
5527 Expr.filters = setFilters.prototype = Expr.pseudos;
5528 Expr.setFilters = new setFilters();
5529
5530 // Initialize with the default document
5531 setDocument();
5532
5533 // Override sizzle attribute retrieval
5534 Sizzle.attr = jQuery.attr;
5535 jQuery.find = Sizzle;
5536 jQuery.expr = Sizzle.selectors;
5537 jQuery.expr[":"] = jQuery.expr.pseudos;
5538 jQuery.unique = Sizzle.uniqueSort;
5539 jQuery.text = Sizzle.getText;
5540 jQuery.isXMLDoc = Sizzle.isXML;
5541 jQuery.contains = Sizzle.contains;
5542
5543
5544 })( window );
5545 var runtil = /Until$/,
5546 rparentsprev = /^(?:parents|prev(?:Until|All))/,
5547 isSimple = /^.[^:#\[\.,]*$/,
5548 rneedsContext = jQuery.expr.match.needsContext,
5549 // methods guaranteed to produce a unique set when starting from a unique set
5550 guaranteedUnique = {
5551 children: true,
5552 contents: true,
5553 next: true,
5554 prev: true
5555 };
5556
5557 jQuery.fn.extend({
5558 find: function( selector ) {
5559 var i, ret, self,
5560 len = this.length;
5561
5562 if ( typeof selector !== "string" ) {
5563 self = this;
5564 return this.pushStack( jQuery( selector ).filter(function() {
5565 for ( i = 0; i < len; i++ ) {
5566 if ( jQuery.contains( self[ i ], this ) ) {
5567 return true;
5568 }
5569 }
5570 }) );
5571 }
5572
5573 ret = [];
5574 for ( i = 0; i < len; i++ ) {
5575 jQuery.find( selector, this[ i ], ret );
5576 }
5577
5578 // Needed because $( selector, context ) becomes $( context ).find( selector )
5579 ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret );
5580 ret.selector = ( this.selector ? this.selector + " " : "" ) + selector;
5581 return ret;
5582 },
5583
5584 has: function( target ) {
5585 var i,
5586 targets = jQuery( target, this ),
5587 len = targets.length;
5588
5589 return this.filter(function() {
5590 for ( i = 0; i < len; i++ ) {
5591 if ( jQuery.contains( this, targets[i] ) ) {
5592 return true;
5593 }
5594 }
5595 });
5596 },
5597
5598 not: function( selector ) {
5599 return this.pushStack( winnow(this, selector, false) );
5600 },
5601
5602 filter: function( selector ) {
5603 return this.pushStack( winnow(this, selector, true) );
5604 },
5605
5606 is: function( selector ) {
5607 return !!selector && (
5608 typeof selector === "string" ?
5609 // If this is a positional/relative selector, check membership in the returned set
5610 // so $("p:first").is("p:last") won't return true for a doc with two "p".
5611 rneedsContext.test( selector ) ?
5612 jQuery( selector, this.context ).index( this[0] ) >= 0 :
5613 jQuery.filter( selector, this ).length > 0 :
5614 this.filter( selector ).length > 0 );
5615 },
5616
5617 closest: function( selectors, context ) {
5618 var cur,
5619 i = 0,
5620 l = this.length,
5621 ret = [],
5622 pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ?
5623 jQuery( selectors, context || this.context ) :
5624 0;
5625
5626 for ( ; i < l; i++ ) {
5627 cur = this[i];
5628
5629 while ( cur && cur.ownerDocument && cur !== context && cur.nodeType !== 11 ) {
5630 if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) {
5631 ret.push( cur );
5632 break;
5633 }
5634 cur = cur.parentNode;
5635 }
5636 }
5637
5638 return this.pushStack( ret.length > 1 ? jQuery.unique( ret ) : ret );
5639 },
5640
5641 // Determine the position of an element within
5642 // the matched set of elements
5643 index: function( elem ) {
5644
5645 // No argument, return index in parent
5646 if ( !elem ) {
5647 return ( this[0] && this[0].parentNode ) ? this.first().prevAll().length : -1;
5648 }
5649
5650 // index in selector
5651 if ( typeof elem === "string" ) {
5652 return jQuery.inArray( this[0], jQuery( elem ) );
5653 }
5654
5655 // Locate the position of the desired element
5656 return jQuery.inArray(
5657 // If it receives a jQuery object, the first element is used
5658 elem.jquery ? elem[0] : elem, this );
5659 },
5660
5661 add: function( selector, context ) {
5662 var set = typeof selector === "string" ?
5663 jQuery( selector, context ) :
5664 jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ),
5665 all = jQuery.merge( this.get(), set );
5666
5667 return this.pushStack( jQuery.unique(all) );
5668 },
5669
5670 addBack: function( selector ) {
5671 return this.add( selector == null ?
5672 this.prevObject : this.prevObject.filter(selector)
5673 );
5674 }
5675 });
5676
5677 jQuery.fn.andSelf = jQuery.fn.addBack;
5678
5679 function sibling( cur, dir ) {
5680 do {
5681 cur = cur[ dir ];
5682 } while ( cur && cur.nodeType !== 1 );
5683
5684 return cur;
5685 }
5686
5687 jQuery.each({
5688 parent: function( elem ) {
5689 var parent = elem.parentNode;
5690 return parent && parent.nodeType !== 11 ? parent : null;
5691 },
5692 parents: function( elem ) {
5693 return jQuery.dir( elem, "parentNode" );
5694 },
5695 parentsUntil: function( elem, i, until ) {
5696 return jQuery.dir( elem, "parentNode", until );
5697 },
5698 next: function( elem ) {
5699 return sibling( elem, "nextSibling" );
5700 },
5701 prev: function( elem ) {
5702 return sibling( elem, "previousSibling" );
5703 },
5704 nextAll: function( elem ) {
5705 return jQuery.dir( elem, "nextSibling" );
5706 },
5707 prevAll: function( elem ) {
5708 return jQuery.dir( elem, "previousSibling" );
5709 },
5710 nextUntil: function( elem, i, until ) {
5711 return jQuery.dir( elem, "nextSibling", until );
5712 },
5713 prevUntil: function( elem, i, until ) {
5714 return jQuery.dir( elem, "previousSibling", until );
5715 },
5716 siblings: function( elem ) {
5717 return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem );
5718 },
5719 children: function( elem ) {
5720 return jQuery.sibling( elem.firstChild );
5721 },
5722 contents: function( elem ) {
5723 return jQuery.nodeName( elem, "iframe" ) ?
5724 elem.contentDocument || elem.contentWindow.document :
5725 jQuery.merge( [], elem.childNodes );
5726 }
5727 }, function( name, fn ) {
5728 jQuery.fn[ name ] = function( until, selector ) {
5729 var ret = jQuery.map( this, fn, until );
5730
5731 if ( !runtil.test( name ) ) {
5732 selector = until;
5733 }
5734
5735 if ( selector && typeof selector === "string" ) {
5736 ret = jQuery.filter( selector, ret );
5737 }
5738
5739 ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret;
5740
5741 if ( this.length > 1 && rparentsprev.test( name ) ) {
5742 ret = ret.reverse();
5743 }
5744
5745 return this.pushStack( ret );
5746 };
5747 });
5748
5749 jQuery.extend({
5750 filter: function( expr, elems, not ) {
5751 if ( not ) {
5752 expr = ":not(" + expr + ")";
5753 }
5754
5755 return elems.length === 1 ?
5756 jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] :
5757 jQuery.find.matches(expr, elems);
5758 },
5759
5760 dir: function( elem, dir, until ) {
5761 var matched = [],
5762 cur = elem[ dir ];
5763
5764 while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {
5765 if ( cur.nodeType === 1 ) {
5766 matched.push( cur );
5767 }
5768 cur = cur[dir];
5769 }
5770 return matched;
5771 },
5772
5773 sibling: function( n, elem ) {
5774 var r = [];
5775
5776 for ( ; n; n = n.nextSibling ) {
5777 if ( n.nodeType === 1 && n !== elem ) {
5778 r.push( n );
5779 }
5780 }
5781
5782 return r;
5783 }
5784 });
5785
5786 // Implement the identical functionality for filter and not
5787 function winnow( elements, qualifier, keep ) {
5788
5789 // Can't pass null or undefined to indexOf in Firefox 4
5790 // Set to 0 to skip string check
5791 qualifier = qualifier || 0;
5792
5793 if ( jQuery.isFunction( qualifier ) ) {
5794 return jQuery.grep(elements, function( elem, i ) {
5795 var retVal = !!qualifier.call( elem, i, elem );
5796 return retVal === keep;
5797 });
5798
5799 } else if ( qualifier.nodeType ) {
5800 return jQuery.grep(elements, function( elem ) {
5801 return ( elem === qualifier ) === keep;
5802 });
5803
5804 } else if ( typeof qualifier === "string" ) {
5805 var filtered = jQuery.grep(elements, function( elem ) {
5806 return elem.nodeType === 1;
5807 });
5808
5809 if ( isSimple.test( qualifier ) ) {
5810 return jQuery.filter(qualifier, filtered, !keep);
5811 } else {
5812 qualifier = jQuery.filter( qualifier, filtered );
5813 }
5814 }
5815
5816 return jQuery.grep(elements, function( elem ) {
5817 return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep;
5818 });
5819 }
5820 function createSafeFragment( document ) {
5821 var list = nodeNames.split( "|" ),
5822 safeFrag = document.createDocumentFragment();
5823
5824 if ( safeFrag.createElement ) {
5825 while ( list.length ) {
5826 safeFrag.createElement(
5827 list.pop()
5828 );
5829 }
5830 }
5831 return safeFrag;
5832 }
5833
5834 var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" +
5835 "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",
5836 rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g,
5837 rnoshimcache = new RegExp("<(?:" + nodeNames + ")[\\s/>]", "i"),
5838 rleadingWhitespace = /^\s+/,
5839 rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,
5840 rtagName = /<([\w:]+)/,
5841 rtbody = /<tbody/i,
5842 rhtml = /<|&#?\w+;/,
5843 rnoInnerhtml = /<(?:script|style|link)/i,
5844 manipulation_rcheckableType = /^(?:checkbox|radio)$/i,
5845 // checked="checked" or checked
5846 rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
5847 rscriptType = /^$|\/(?:java|ecma)script/i,
5848 rscriptTypeMasked = /^true\/(.*)/,
5849 rcleanScript = /^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,
5850
5851 // We have to close these tags to support XHTML (#13200)
5852 wrapMap = {
5853 option: [ 1, "<select multiple='multiple'>", "</select>" ],
5854 legend: [ 1, "<fieldset>", "</fieldset>" ],
5855 area: [ 1, "<map>", "</map>" ],
5856 param: [ 1, "<object>", "</object>" ],
5857 thead: [ 1, "<table>", "</table>" ],
5858 tr: [ 2, "<table><tbody>", "</tbody></table>" ],
5859 col: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ],
5860 td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
5861
5862 // IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags,
5863 // unless wrapped in a div with non-breaking characters in front of it.
5864 _default: jQuery.support.htmlSerialize ? [ 0, "", "" ] : [ 1, "X<div>", "</div>" ]
5865 },
5866 safeFragment = createSafeFragment( document ),
5867 fragmentDiv = safeFragment.appendChild( document.createElement("div") );
5868
5869 wrapMap.optgroup = wrapMap.option;
5870 wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
5871 wrapMap.th = wrapMap.td;
5872
5873 jQuery.fn.extend({
5874 text: function( value ) {
5875 return jQuery.access( this, function( value ) {
5876 return value === undefined ?
5877 jQuery.text( this ) :
5878 this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) );
5879 }, null, value, arguments.length );
5880 },
5881
5882 wrapAll: function( html ) {
5883 if ( jQuery.isFunction( html ) ) {
5884 return this.each(function(i) {
5885 jQuery(this).wrapAll( html.call(this, i) );
5886 });
5887 }
5888
5889 if ( this[0] ) {
5890 // The elements to wrap the target around
5891 var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true);
5892
5893 if ( this[0].parentNode ) {
5894 wrap.insertBefore( this[0] );
5895 }
5896
5897 wrap.map(function() {
5898 var elem = this;
5899
5900 while ( elem.firstChild && elem.firstChild.nodeType === 1 ) {
5901 elem = elem.firstChild;
5902 }
5903
5904 return elem;
5905 }).append( this );
5906 }
5907
5908 return this;
5909 },
5910
5911 wrapInner: function( html ) {
5912 if ( jQuery.isFunction( html ) ) {
5913 return this.each(function(i) {
5914 jQuery(this).wrapInner( html.call(this, i) );
5915 });
5916 }
5917
5918 return this.each(function() {
5919 var self = jQuery( this ),
5920 contents = self.contents();
5921
5922 if ( contents.length ) {
5923 contents.wrapAll( html );
5924
5925 } else {
5926 self.append( html );
5927 }
5928 });
5929 },
5930
5931 wrap: function( html ) {
5932 var isFunction = jQuery.isFunction( html );
5933
5934 return this.each(function(i) {
5935 jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html );
5936 });
5937 },
5938
5939 unwrap: function() {
5940 return this.parent().each(function() {
5941 if ( !jQuery.nodeName( this, "body" ) ) {
5942 jQuery( this ).replaceWith( this.childNodes );
5943 }
5944 }).end();
5945 },
5946
5947 append: function() {
5948 return this.domManip(arguments, true, function( elem ) {
5949 if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
5950 this.appendChild( elem );
5951 }
5952 });
5953 },
5954
5955 prepend: function() {
5956 return this.domManip(arguments, true, function( elem ) {
5957 if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
5958 this.insertBefore( elem, this.firstChild );
5959 }
5960 });
5961 },
5962
5963 before: function() {
5964 return this.domManip( arguments, false, function( elem ) {
5965 if ( this.parentNode ) {
5966 this.parentNode.insertBefore( elem, this );
5967 }
5968 });
5969 },
5970
5971 after: function() {
5972 return this.domManip( arguments, false, function( elem ) {
5973 if ( this.parentNode ) {
5974 this.parentNode.insertBefore( elem, this.nextSibling );
5975 }
5976 });
5977 },
5978
5979 // keepData is for internal use only--do not document
5980 remove: function( selector, keepData ) {
5981 var elem,
5982 i = 0;
5983
5984 for ( ; (elem = this[i]) != null; i++ ) {
5985 if ( !selector || jQuery.filter( selector, [ elem ] ).length > 0 ) {
5986 if ( !keepData && elem.nodeType === 1 ) {
5987 jQuery.cleanData( getAll( elem ) );
5988 }
5989
5990 if ( elem.parentNode ) {
5991 if ( keepData && jQuery.contains( elem.ownerDocument, elem ) ) {
5992 setGlobalEval( getAll( elem, "script" ) );
5993 }
5994 elem.parentNode.removeChild( elem );
5995 }
5996 }
5997 }
5998
5999 return this;
6000 },
6001
6002 empty: function() {
6003 var elem,
6004 i = 0;
6005
6006 for ( ; (elem = this[i]) != null; i++ ) {
6007 // Remove element nodes and prevent memory leaks
6008 if ( elem.nodeType === 1 ) {
6009 jQuery.cleanData( getAll( elem, false ) );
6010 }
6011
6012 // Remove any remaining nodes
6013 while ( elem.firstChild ) {
6014 elem.removeChild( elem.firstChild );
6015 }
6016
6017 // If this is a select, ensure that it displays empty (#12336)
6018 // Support: IE<9
6019 if ( elem.options && jQuery.nodeName( elem, "select" ) ) {
6020 elem.options.length = 0;
6021 }
6022 }
6023
6024 return this;
6025 },
6026
6027 clone: function( dataAndEvents, deepDataAndEvents ) {
6028 dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
6029 deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
6030
6031 return this.map( function () {
6032 return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
6033 });
6034 },
6035
6036 html: function( value ) {
6037 return jQuery.access( this, function( value ) {
6038 var elem = this[0] || {},
6039 i = 0,
6040 l = this.length;
6041
6042 if ( value === undefined ) {
6043 return elem.nodeType === 1 ?
6044 elem.innerHTML.replace( rinlinejQuery, "" ) :
6045 undefined;
6046 }
6047
6048 // See if we can take a shortcut and just use innerHTML
6049 if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
6050 ( jQuery.support.htmlSerialize || !rnoshimcache.test( value ) ) &&
6051 ( jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value ) ) &&
6052 !wrapMap[ ( rtagName.exec( value ) || ["", ""] )[1].toLowerCase() ] ) {
6053
6054 value = value.replace( rxhtmlTag, "<$1></$2>" );
6055
6056 try {
6057 for (; i < l; i++ ) {
6058 // Remove element nodes and prevent memory leaks
6059 elem = this[i] || {};
6060 if ( elem.nodeType === 1 ) {
6061 jQuery.cleanData( getAll( elem, false ) );
6062 elem.innerHTML = value;
6063 }
6064 }
6065
6066 elem = 0;
6067
6068 // If using innerHTML throws an exception, use the fallback method
6069 } catch(e) {}
6070 }
6071
6072 if ( elem ) {
6073 this.empty().append( value );
6074 }
6075 }, null, value, arguments.length );
6076 },
6077
6078 replaceWith: function( value ) {
6079 var isFunc = jQuery.isFunction( value );
6080
6081 // Make sure that the elements are removed from the DOM before they are inserted
6082 // this can help fix replacing a parent with child elements
6083 if ( !isFunc && typeof value !== "string" ) {
6084 value = jQuery( value ).not( this ).detach();
6085 }
6086
6087 return this.domManip( [ value ], true, function( elem ) {
6088 var next = this.nextSibling,
6089 parent = this.parentNode;
6090
6091 if ( parent ) {
6092 jQuery( this ).remove();
6093 parent.insertBefore( elem, next );
6094 }
6095 });
6096 },
6097
6098 detach: function( selector ) {
6099 return this.remove( selector, true );
6100 },
6101
6102 domManip: function( args, table, callback ) {
6103
6104 // Flatten any nested arrays
6105 args = core_concat.apply( [], args );
6106
6107 var first, node, hasScripts,
6108 scripts, doc, fragment,
6109 i = 0,
6110 l = this.length,
6111 set = this,
6112 iNoClone = l - 1,
6113 value = args[0],
6114 isFunction = jQuery.isFunction( value );
6115
6116 // We can't cloneNode fragments that contain checked, in WebKit
6117 if ( isFunction || !( l <= 1 || typeof value !== "string" || jQuery.support.checkClone || !rchecked.test( value ) ) ) {
6118 return this.each(function( index ) {
6119 var self = set.eq( index );
6120 if ( isFunction ) {
6121 args[0] = value.call( this, index, table ? self.html() : undefined );
6122 }
6123 self.domManip( args, table, callback );
6124 });
6125 }
6126
6127 if ( l ) {
6128 fragment = jQuery.buildFragment( args, this[ 0 ].ownerDocument, false, this );
6129 first = fragment.firstChild;
6130
6131 if ( fragment.childNodes.length === 1 ) {
6132 fragment = first;
6133 }
6134
6135 if ( first ) {
6136 table = table && jQuery.nodeName( first, "tr" );
6137 scripts = jQuery.map( getAll( fragment, "script" ), disableScript );
6138 hasScripts = scripts.length;
6139
6140 // Use the original fragment for the last item instead of the first because it can end up
6141 // being emptied incorrectly in certain situations (#8070).
6142 for ( ; i < l; i++ ) {
6143 node = fragment;
6144
6145 if ( i !== iNoClone ) {
6146 node = jQuery.clone( node, true, true );
6147
6148 // Keep references to cloned scripts for later restoration
6149 if ( hasScripts ) {
6150 jQuery.merge( scripts, getAll( node, "script" ) );
6151 }
6152 }
6153
6154 callback.call(
6155 table && jQuery.nodeName( this[i], "table" ) ?
6156 findOrAppend( this[i], "tbody" ) :
6157 this[i],
6158 node,
6159 i
6160 );
6161 }
6162
6163 if ( hasScripts ) {
6164 doc = scripts[ scripts.length - 1 ].ownerDocument;
6165
6166 // Reenable scripts
6167 jQuery.map( scripts, restoreScript );
6168
6169 // Evaluate executable scripts on first document insertion
6170 for ( i = 0; i < hasScripts; i++ ) {
6171 node = scripts[ i ];
6172 if ( rscriptType.test( node.type || "" ) &&
6173 !jQuery._data( node, "globalEval" ) && jQuery.contains( doc, node ) ) {
6174
6175 if ( node.src ) {
6176 // Hope ajax is available...
6177 jQuery.ajax({
6178 url: node.src,
6179 type: "GET",
6180 dataType: "script",
6181 async: false,
6182 global: false,
6183 "throws": true
6184 });
6185 } else {
6186 jQuery.globalEval( ( node.text || node.textContent || node.innerHTML || "" ).replace( rcleanScript, "" ) );
6187 }
6188 }
6189 }
6190 }
6191
6192 // Fix #11809: Avoid leaking memory
6193 fragment = first = null;
6194 }
6195 }
6196
6197 return this;
6198 }
6199 });
6200
6201 function findOrAppend( elem, tag ) {
6202 return elem.getElementsByTagName( tag )[0] || elem.appendChild( elem.ownerDocument.createElement( tag ) );
6203 }
6204
6205 // Replace/restore the type attribute of script elements for safe DOM manipulation
6206 function disableScript( elem ) {
6207 var attr = elem.getAttributeNode("type");
6208 elem.type = ( attr && attr.specified ) + "/" + elem.type;
6209 return elem;
6210 }
6211 function restoreScript( elem ) {
6212 var match = rscriptTypeMasked.exec( elem.type );
6213 if ( match ) {
6214 elem.type = match[1];
6215 } else {
6216 elem.removeAttribute("type");
6217 }
6218 return elem;
6219 }
6220
6221 // Mark scripts as having already been evaluated
6222 function setGlobalEval( elems, refElements ) {
6223 var elem,
6224 i = 0;
6225 for ( ; (elem = elems[i]) != null; i++ ) {
6226 jQuery._data( elem, "globalEval", !refElements || jQuery._data( refElements[i], "globalEval" ) );
6227 }
6228 }
6229
6230 function cloneCopyEvent( src, dest ) {
6231
6232 if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) {
6233 return;
6234 }
6235
6236 var type, i, l,
6237 oldData = jQuery._data( src ),
6238 curData = jQuery._data( dest, oldData ),
6239 events = oldData.events;
6240
6241 if ( events ) {
6242 delete curData.handle;
6243 curData.events = {};
6244
6245 for ( type in events ) {
6246 for ( i = 0, l = events[ type ].length; i < l; i++ ) {
6247 jQuery.event.add( dest, type, events[ type ][ i ] );
6248 }
6249 }
6250 }
6251
6252 // make the cloned public data object a copy from the original
6253 if ( curData.data ) {
6254 curData.data = jQuery.extend( {}, curData.data );
6255 }
6256 }
6257
6258 function fixCloneNodeIssues( src, dest ) {
6259 var nodeName, e, data;
6260
6261 // We do not need to do anything for non-Elements
6262 if ( dest.nodeType !== 1 ) {
6263 return;
6264 }
6265
6266 nodeName = dest.nodeName.toLowerCase();
6267
6268 // IE6-8 copies events bound via attachEvent when using cloneNode.
6269 if ( !jQuery.support.noCloneEvent && dest[ jQuery.expando ] ) {
6270 data = jQuery._data( dest );
6271
6272 for ( e in data.events ) {
6273 jQuery.removeEvent( dest, e, data.handle );
6274 }
6275
6276 // Event data gets referenced instead of copied if the expando gets copied too
6277 dest.removeAttribute( jQuery.expando );
6278 }
6279
6280 // IE blanks contents when cloning scripts, and tries to evaluate newly-set text
6281 if ( nodeName === "script" && dest.text !== src.text ) {
6282 disableScript( dest ).text = src.text;
6283 restoreScript( dest );
6284
6285 // IE6-10 improperly clones children of object elements using classid.
6286 // IE10 throws NoModificationAllowedError if parent is null, #12132.
6287 } else if ( nodeName === "object" ) {
6288 if ( dest.parentNode ) {
6289 dest.outerHTML = src.outerHTML;
6290 }
6291
6292 // This path appears unavoidable for IE9. When cloning an object
6293 // element in IE9, the outerHTML strategy above is not sufficient.
6294 // If the src has innerHTML and the destination does not,
6295 // copy the src.innerHTML into the dest.innerHTML. #10324
6296 if ( jQuery.support.html5Clone && ( src.innerHTML && !jQuery.trim(dest.innerHTML) ) ) {
6297 dest.innerHTML = src.innerHTML;
6298 }
6299
6300 } else if ( nodeName === "input" && manipulation_rcheckableType.test( src.type ) ) {
6301 // IE6-8 fails to persist the checked state of a cloned checkbox
6302 // or radio button. Worse, IE6-7 fail to give the cloned element
6303 // a checked appearance if the defaultChecked value isn't also set
6304
6305 dest.defaultChecked = dest.checked = src.checked;
6306
6307 // IE6-7 get confused and end up setting the value of a cloned
6308 // checkbox/radio button to an empty string instead of "on"
6309 if ( dest.value !== src.value ) {
6310 dest.value = src.value;
6311 }
6312
6313 // IE6-8 fails to return the selected option to the default selected
6314 // state when cloning options
6315 } else if ( nodeName === "option" ) {
6316 dest.defaultSelected = dest.selected = src.defaultSelected;
6317
6318 // IE6-8 fails to set the defaultValue to the correct value when
6319 // cloning other types of input fields
6320 } else if ( nodeName === "input" || nodeName === "textarea" ) {
6321 dest.defaultValue = src.defaultValue;
6322 }
6323 }
6324
6325 jQuery.each({
6326 appendTo: "append",
6327 prependTo: "prepend",
6328 insertBefore: "before",
6329 insertAfter: "after",
6330 replaceAll: "replaceWith"
6331 }, function( name, original ) {
6332 jQuery.fn[ name ] = function( selector ) {
6333 var elems,
6334 i = 0,
6335 ret = [],
6336 insert = jQuery( selector ),
6337 last = insert.length - 1;
6338
6339 for ( ; i <= last; i++ ) {
6340 elems = i === last ? this : this.clone(true);
6341 jQuery( insert[i] )[ original ]( elems );
6342
6343 // Modern browsers can apply jQuery collections as arrays, but oldIE needs a .get()
6344 core_push.apply( ret, elems.get() );
6345 }
6346
6347 return this.pushStack( ret );
6348 };
6349 });
6350
6351 function getAll( context, tag ) {
6352 var elems, elem,
6353 i = 0,
6354 found = typeof context.getElementsByTagName !== core_strundefined ? context.getElementsByTagName( tag || "*" ) :
6355 typeof context.querySelectorAll !== core_strundefined ? context.querySelectorAll( tag || "*" ) :
6356 undefined;
6357
6358 if ( !found ) {
6359 for ( found = [], elems = context.childNodes || context; (elem = elems[i]) != null; i++ ) {
6360 if ( !tag || jQuery.nodeName( elem, tag ) ) {
6361 found.push( elem );
6362 } else {
6363 jQuery.merge( found, getAll( elem, tag ) );
6364 }
6365 }
6366 }
6367
6368 return tag === undefined || tag && jQuery.nodeName( context, tag ) ?
6369 jQuery.merge( [ context ], found ) :
6370 found;
6371 }
6372
6373 // Used in buildFragment, fixes the defaultChecked property
6374 function fixDefaultChecked( elem ) {
6375 if ( manipulation_rcheckableType.test( elem.type ) ) {
6376 elem.defaultChecked = elem.checked;
6377 }
6378 }
6379
6380 jQuery.extend({
6381 clone: function( elem, dataAndEvents, deepDataAndEvents ) {
6382 var destElements, node, clone, i, srcElements,
6383 inPage = jQuery.contains( elem.ownerDocument, elem );
6384
6385 if ( jQuery.support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ) {
6386 clone = elem.cloneNode( true );
6387
6388 // IE<=8 does not properly clone detached, unknown element nodes
6389 } else {
6390 fragmentDiv.innerHTML = elem.outerHTML;
6391 fragmentDiv.removeChild( clone = fragmentDiv.firstChild );
6392 }
6393
6394 if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) &&
6395 (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) {
6396
6397 // We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2
6398 destElements = getAll( clone );
6399 srcElements = getAll( elem );
6400
6401 // Fix all IE cloning issues
6402 for ( i = 0; (node = srcElements[i]) != null; ++i ) {
6403 // Ensure that the destination node is not null; Fixes #9587
6404 if ( destElements[i] ) {
6405 fixCloneNodeIssues( node, destElements[i] );
6406 }
6407 }
6408 }
6409
6410 // Copy the events from the original to the clone
6411 if ( dataAndEvents ) {
6412 if ( deepDataAndEvents ) {
6413 srcElements = srcElements || getAll( elem );
6414 destElements = destElements || getAll( clone );
6415
6416 for ( i = 0; (node = srcElements[i]) != null; i++ ) {
6417 cloneCopyEvent( node, destElements[i] );
6418 }
6419 } else {
6420 cloneCopyEvent( elem, clone );
6421 }
6422 }
6423
6424 // Preserve script evaluation history
6425 destElements = getAll( clone, "script" );
6426 if ( destElements.length > 0 ) {
6427 setGlobalEval( destElements, !inPage && getAll( elem, "script" ) );
6428 }
6429
6430 destElements = srcElements = node = null;
6431
6432 // Return the cloned set
6433 return clone;
6434 },
6435
6436 buildFragment: function( elems, context, scripts, selection ) {
6437 var j, elem, contains,
6438 tmp, tag, tbody, wrap,
6439 l = elems.length,
6440
6441 // Ensure a safe fragment
6442 safe = createSafeFragment( context ),
6443
6444 nodes = [],
6445 i = 0;
6446
6447 for ( ; i < l; i++ ) {
6448 elem = elems[ i ];
6449
6450 if ( elem || elem === 0 ) {
6451
6452 // Add nodes directly
6453 if ( jQuery.type( elem ) === "object" ) {
6454 jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );
6455
6456 // Convert non-html into a text node
6457 } else if ( !rhtml.test( elem ) ) {
6458 nodes.push( context.createTextNode( elem ) );
6459
6460 // Convert html into DOM nodes
6461 } else {
6462 tmp = tmp || safe.appendChild( context.createElement("div") );
6463
6464 // Deserialize a standard representation
6465 tag = ( rtagName.exec( elem ) || ["", ""] )[1].toLowerCase();
6466 wrap = wrapMap[ tag ] || wrapMap._default;
6467
6468 tmp.innerHTML = wrap[1] + elem.replace( rxhtmlTag, "<$1></$2>" ) + wrap[2];
6469
6470 // Descend through wrappers to the right content
6471 j = wrap[0];
6472 while ( j-- ) {
6473 tmp = tmp.lastChild;
6474 }
6475
6476 // Manually add leading whitespace removed by IE
6477 if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {
6478 nodes.push( context.createTextNode( rleadingWhitespace.exec( elem )[0] ) );
6479 }
6480
6481 // Remove IE's autoinserted <tbody> from table fragments
6482 if ( !jQuery.support.tbody ) {
6483
6484 // String was a <table>, *may* have spurious <tbody>
6485 elem = tag === "table" && !rtbody.test( elem ) ?
6486 tmp.firstChild :
6487
6488 // String was a bare <thead> or <tfoot>
6489 wrap[1] === "<table>" && !rtbody.test( elem ) ?
6490 tmp :
6491 0;
6492
6493 j = elem && elem.childNodes.length;
6494 while ( j-- ) {
6495 if ( jQuery.nodeName( (tbody = elem.childNodes[j]), "tbody" ) && !tbody.childNodes.length ) {
6496 elem.removeChild( tbody );
6497 }
6498 }
6499 }
6500
6501 jQuery.merge( nodes, tmp.childNodes );
6502
6503 // Fix #12392 for WebKit and IE > 9
6504 tmp.textContent = "";
6505
6506 // Fix #12392 for oldIE
6507 while ( tmp.firstChild ) {
6508 tmp.removeChild( tmp.firstChild );
6509 }
6510
6511 // Remember the top-level container for proper cleanup
6512 tmp = safe.lastChild;
6513 }
6514 }
6515 }
6516
6517 // Fix #11356: Clear elements from fragment
6518 if ( tmp ) {
6519 safe.removeChild( tmp );
6520 }
6521
6522 // Reset defaultChecked for any radios and checkboxes
6523 // about to be appended to the DOM in IE 6/7 (#8060)
6524 if ( !jQuery.support.appendChecked ) {
6525 jQuery.grep( getAll( nodes, "input" ), fixDefaultChecked );
6526 }
6527
6528 i = 0;
6529 while ( (elem = nodes[ i++ ]) ) {
6530
6531 // #4087 - If origin and destination elements are the same, and this is
6532 // that element, do not do anything
6533 if ( selection && jQuery.inArray( elem, selection ) !== -1 ) {
6534 continue;
6535 }
6536
6537 contains = jQuery.contains( elem.ownerDocument, elem );
6538
6539 // Append to fragment
6540 tmp = getAll( safe.appendChild( elem ), "script" );
6541
6542 // Preserve script evaluation history
6543 if ( contains ) {
6544 setGlobalEval( tmp );
6545 }
6546
6547 // Capture executables
6548 if ( scripts ) {
6549 j = 0;
6550 while ( (elem = tmp[ j++ ]) ) {
6551 if ( rscriptType.test( elem.type || "" ) ) {
6552 scripts.push( elem );
6553 }
6554 }
6555 }
6556 }
6557
6558 tmp = null;
6559
6560 return safe;
6561 },
6562
6563 cleanData: function( elems, /* internal */ acceptData ) {
6564 var elem, type, id, data,
6565 i = 0,
6566 internalKey = jQuery.expando,
6567 cache = jQuery.cache,
6568 deleteExpando = jQuery.support.deleteExpando,
6569 special = jQuery.event.special;
6570
6571 for ( ; (elem = elems[i]) != null; i++ ) {
6572
6573 if ( acceptData || jQuery.acceptData( elem ) ) {
6574
6575 id = elem[ internalKey ];
6576 data = id && cache[ id ];
6577
6578 if ( data ) {
6579 if ( data.events ) {
6580 for ( type in data.events ) {
6581 if ( special[ type ] ) {
6582 jQuery.event.remove( elem, type );
6583
6584 // This is a shortcut to avoid jQuery.event.remove's overhead
6585 } else {
6586 jQuery.removeEvent( elem, type, data.handle );
6587 }
6588 }
6589 }
6590
6591 // Remove cache only if it was not already removed by jQuery.event.remove
6592 if ( cache[ id ] ) {
6593
6594 delete cache[ id ];
6595
6596 // IE does not allow us to delete expando properties from nodes,
6597 // nor does it have a removeAttribute function on Document nodes;
6598 // we must handle all of these cases
6599 if ( deleteExpando ) {
6600 delete elem[ internalKey ];
6601
6602 } else if ( typeof elem.removeAttribute !== core_strundefined ) {
6603 elem.removeAttribute( internalKey );
6604
6605 } else {
6606 elem[ internalKey ] = null;
6607 }
6608
6609 core_deletedIds.push( id );
6610 }
6611 }
6612 }
6613 }
6614 }
6615 });
6616 var iframe, getStyles, curCSS,
6617 ralpha = /alpha\([^)]*\)/i,
6618 ropacity = /opacity\s*=\s*([^)]*)/,
6619 rposition = /^(top|right|bottom|left)$/,
6620 // swappable if display is none or starts with table except "table", "table-cell", or "table-caption"
6621 // see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
6622 rdisplayswap = /^(none|table(?!-c[ea]).+)/,
6623 rmargin = /^margin/,
6624 rnumsplit = new RegExp( "^(" + core_pnum + ")(.*)$", "i" ),
6625 rnumnonpx = new RegExp( "^(" + core_pnum + ")(?!px)[a-z%]+$", "i" ),
6626 rrelNum = new RegExp( "^([+-])=(" + core_pnum + ")", "i" ),
6627 elemdisplay = { BODY: "block" },
6628
6629 cssShow = { position: "absolute", visibility: "hidden", display: "block" },
6630 cssNormalTransform = {
6631 letterSpacing: 0,
6632 fontWeight: 400
6633 },
6634
6635 cssExpand = [ "Top", "Right", "Bottom", "Left" ],
6636 cssPrefixes = [ "Webkit", "O", "Moz", "ms" ];
6637
6638 // return a css property mapped to a potentially vendor prefixed property
6639 function vendorPropName( style, name ) {
6640
6641 // shortcut for names that are not vendor prefixed
6642 if ( name in style ) {
6643 return name;
6644 }
6645
6646 // check for vendor prefixed names
6647 var capName = name.charAt(0).toUpperCase() + name.slice(1),
6648 origName = name,
6649 i = cssPrefixes.length;
6650
6651 while ( i-- ) {
6652 name = cssPrefixes[ i ] + capName;
6653 if ( name in style ) {
6654 return name;
6655 }
6656 }
6657
6658 return origName;
6659 }
6660
6661 function isHidden( elem, el ) {
6662 // isHidden might be called from jQuery#filter function;
6663 // in that case, element will be second argument
6664 elem = el || elem;
6665 return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem );
6666 }
6667
6668 function showHide( elements, show ) {
6669 var display, elem, hidden,
6670 values = [],
6671 index = 0,
6672 length = elements.length;
6673
6674 for ( ; index < length; index++ ) {
6675 elem = elements[ index ];
6676 if ( !elem.style ) {
6677 continue;
6678 }
6679
6680 values[ index ] = jQuery._data( elem, "olddisplay" );
6681 display = elem.style.display;
6682 if ( show ) {
6683 // Reset the inline display of this element to learn if it is
6684 // being hidden by cascaded rules or not
6685 if ( !values[ index ] && display === "none" ) {
6686 elem.style.display = "";
6687 }
6688
6689 // Set elements which have been overridden with display: none
6690 // in a stylesheet to whatever the default browser style is
6691 // for such an element
6692 if ( elem.style.display === "" && isHidden( elem ) ) {
6693 values[ index ] = jQuery._data( elem, "olddisplay", css_defaultDisplay(elem.nodeName) );
6694 }
6695 } else {
6696
6697 if ( !values[ index ] ) {
6698 hidden = isHidden( elem );
6699
6700 if ( display && display !== "none" || !hidden ) {
6701 jQuery._data( elem, "olddisplay", hidden ? display : jQuery.css( elem, "display" ) );
6702 }
6703 }
6704 }
6705 }
6706
6707 // Set the display of most of the elements in a second loop
6708 // to avoid the constant reflow
6709 for ( index = 0; index < length; index++ ) {
6710 elem = elements[ index ];
6711 if ( !elem.style ) {
6712 continue;
6713 }
6714 if ( !show || elem.style.display === "none" || elem.style.display === "" ) {
6715 elem.style.display = show ? values[ index ] || "" : "none";
6716 }
6717 }
6718
6719 return elements;
6720 }
6721
6722 jQuery.fn.extend({
6723 css: function( name, value ) {
6724 return jQuery.access( this, function( elem, name, value ) {
6725 var len, styles,
6726 map = {},
6727 i = 0;
6728
6729 if ( jQuery.isArray( name ) ) {
6730 styles = getStyles( elem );
6731 len = name.length;
6732
6733 for ( ; i < len; i++ ) {
6734 map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );
6735 }
6736
6737 return map;
6738 }
6739
6740 return value !== undefined ?
6741 jQuery.style( elem, name, value ) :
6742 jQuery.css( elem, name );
6743 }, name, value, arguments.length > 1 );
6744 },
6745 show: function() {
6746 return showHide( this, true );
6747 },
6748 hide: function() {
6749 return showHide( this );
6750 },
6751 toggle: function( state ) {
6752 var bool = typeof state === "boolean";
6753
6754 return this.each(function() {
6755 if ( bool ? state : isHidden( this ) ) {
6756 jQuery( this ).show();
6757 } else {
6758 jQuery( this ).hide();
6759 }
6760 });
6761 }
6762 });
6763
6764 jQuery.extend({
6765 // Add in style property hooks for overriding the default
6766 // behavior of getting and setting a style property
6767 cssHooks: {
6768 opacity: {
6769 get: function( elem, computed ) {
6770 if ( computed ) {
6771 // We should always get a number back from opacity
6772 var ret = curCSS( elem, "opacity" );
6773 return ret === "" ? "1" : ret;
6774 }
6775 }
6776 }
6777 },
6778
6779 // Exclude the following css properties to add px
6780 cssNumber: {
6781 "columnCount": true,
6782 "fillOpacity": true,
6783 "fontWeight": true,
6784 "lineHeight": true,
6785 "opacity": true,
6786 "orphans": true,
6787 "widows": true,
6788 "zIndex": true,
6789 "zoom": true
6790 },
6791
6792 // Add in properties whose names you wish to fix before
6793 // setting or getting the value
6794 cssProps: {
6795 // normalize float css property
6796 "float": jQuery.support.cssFloat ? "cssFloat" : "styleFloat"
6797 },
6798
6799 // Get and set the style property on a DOM Node
6800 style: function( elem, name, value, extra ) {
6801 // Don't set styles on text and comment nodes
6802 if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
6803 return;
6804 }
6805
6806 // Make sure that we're working with the right name
6807 var ret, type, hooks,
6808 origName = jQuery.camelCase( name ),
6809 style = elem.style;
6810
6811 name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) );
6812
6813 // gets hook for the prefixed version
6814 // followed by the unprefixed version
6815 hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
6816
6817 // Check if we're setting a value
6818 if ( value !== undefined ) {
6819 type = typeof value;
6820
6821 // convert relative number strings (+= or -=) to relative numbers. #7345
6822 if ( type === "string" && (ret = rrelNum.exec( value )) ) {
6823 value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) );
6824 // Fixes bug #9237
6825 type = "number";
6826 }
6827
6828 // Make sure that NaN and null values aren't set. See: #7116
6829 if ( value == null || type === "number" && isNaN( value ) ) {
6830 return;
6831 }
6832
6833 // If a number was passed in, add 'px' to the (except for certain CSS properties)
6834 if ( type === "number" && !jQuery.cssNumber[ origName ] ) {
6835 value += "px";
6836 }
6837
6838 // Fixes #8908, it can be done more correctly by specifing setters in cssHooks,
6839 // but it would mean to define eight (for every problematic property) identical functions
6840 if ( !jQuery.support.clearCloneStyle && value === "" && name.indexOf("background") === 0 ) {
6841 style[ name ] = "inherit";
6842 }
6843
6844 // If a hook was provided, use that value, otherwise just set the specified value
6845 if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) {
6846
6847 // Wrapped to prevent IE from throwing errors when 'invalid' values are provided
6848 // Fixes bug #5509
6849 try {
6850 style[ name ] = value;
6851 } catch(e) {}
6852 }
6853
6854 } else {
6855 // If a hook was provided get the non-computed value from there
6856 if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {
6857 return ret;
6858 }
6859
6860 // Otherwise just get the value from the style object
6861 return style[ name ];
6862 }
6863 },
6864
6865 css: function( elem, name, extra, styles ) {
6866 var num, val, hooks,
6867 origName = jQuery.camelCase( name );
6868
6869 // Make sure that we're working with the right name
6870 name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) );
6871
6872 // gets hook for the prefixed version
6873 // followed by the unprefixed version
6874 hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
6875
6876 // If a hook was provided get the computed value from there
6877 if ( hooks && "get" in hooks ) {
6878 val = hooks.get( elem, true, extra );
6879 }
6880
6881 // Otherwise, if a way to get the computed value exists, use that
6882 if ( val === undefined ) {
6883 val = curCSS( elem, name, styles );
6884 }
6885
6886 //convert "normal" to computed value
6887 if ( val === "normal" && name in cssNormalTransform ) {
6888 val = cssNormalTransform[ name ];
6889 }
6890
6891 // Return, converting to number if forced or a qualifier was provided and val looks numeric
6892 if ( extra === "" || extra ) {
6893 num = parseFloat( val );
6894 return extra === true || jQuery.isNumeric( num ) ? num || 0 : val;
6895 }
6896 return val;
6897 },
6898
6899 // A method for quickly swapping in/out CSS properties to get correct calculations
6900 swap: function( elem, options, callback, args ) {
6901 var ret, name,
6902 old = {};
6903
6904 // Remember the old values, and insert the new ones
6905 for ( name in options ) {
6906 old[ name ] = elem.style[ name ];
6907 elem.style[ name ] = options[ name ];
6908 }
6909
6910 ret = callback.apply( elem, args || [] );
6911
6912 // Revert the old values
6913 for ( name in options ) {
6914 elem.style[ name ] = old[ name ];
6915 }
6916
6917 return ret;
6918 }
6919 });
6920
6921 // NOTE: we've included the "window" in window.getComputedStyle
6922 // because jsdom on node.js will break without it.
6923 if ( window.getComputedStyle ) {
6924 getStyles = function( elem ) {
6925 return window.getComputedStyle( elem, null );
6926 };
6927
6928 curCSS = function( elem, name, _computed ) {
6929 var width, minWidth, maxWidth,
6930 computed = _computed || getStyles( elem ),
6931
6932 // getPropertyValue is only needed for .css('filter') in IE9, see #12537
6933 ret = computed ? computed.getPropertyValue( name ) || computed[ name ] : undefined,
6934 style = elem.style;
6935
6936 if ( computed ) {
6937
6938 if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) {
6939 ret = jQuery.style( elem, name );
6940 }
6941
6942 // A tribute to the "awesome hack by Dean Edwards"
6943 // Chrome < 17 and Safari 5.0 uses "computed value" instead of "used value" for margin-right
6944 // Safari 5.1.7 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels
6945 // this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values
6946 if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) {
6947
6948 // Remember the original values
6949 width = style.width;
6950 minWidth = style.minWidth;
6951 maxWidth = style.maxWidth;
6952
6953 // Put in the new values to get a computed value out
6954 style.minWidth = style.maxWidth = style.width = ret;
6955 ret = computed.width;
6956
6957 // Revert the changed values
6958 style.width = width;
6959 style.minWidth = minWidth;
6960 style.maxWidth = maxWidth;
6961 }
6962 }
6963
6964 return ret;
6965 };
6966 } else if ( document.documentElement.currentStyle ) {
6967 getStyles = function( elem ) {
6968 return elem.currentStyle;
6969 };
6970
6971 curCSS = function( elem, name, _computed ) {
6972 var left, rs, rsLeft,
6973 computed = _computed || getStyles( elem ),
6974 ret = computed ? computed[ name ] : undefined,
6975 style = elem.style;
6976
6977 // Avoid setting ret to empty string here
6978 // so we don't default to auto
6979 if ( ret == null && style && style[ name ] ) {
6980 ret = style[ name ];
6981 }
6982
6983 // From the awesome hack by Dean Edwards
6984 // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
6985
6986 // If we're not dealing with a regular pixel number
6987 // but a number that has a weird ending, we need to convert it to pixels
6988 // but not position css attributes, as those are proportional to the parent element instead
6989 // and we can't measure the parent instead because it might trigger a "stacking dolls" problem
6990 if ( rnumnonpx.test( ret ) && !rposition.test( name ) ) {
6991
6992 // Remember the original values
6993 left = style.left;
6994 rs = elem.runtimeStyle;
6995 rsLeft = rs && rs.left;
6996
6997 // Put in the new values to get a computed value out
6998 if ( rsLeft ) {
6999 rs.left = elem.currentStyle.left;
7000 }
7001 style.left = name === "fontSize" ? "1em" : ret;
7002 ret = style.pixelLeft + "px";
7003
7004 // Revert the changed values
7005 style.left = left;
7006 if ( rsLeft ) {
7007 rs.left = rsLeft;
7008 }
7009 }
7010
7011 return ret === "" ? "auto" : ret;
7012 };
7013 }
7014
7015 function setPositiveNumber( elem, value, subtract ) {
7016 var matches = rnumsplit.exec( value );
7017 return matches ?
7018 // Guard against undefined "subtract", e.g., when used as in cssHooks
7019 Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) :
7020 value;
7021 }
7022
7023 function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
7024 var i = extra === ( isBorderBox ? "border" : "content" ) ?
7025 // If we already have the right measurement, avoid augmentation
7026 4 :
7027 // Otherwise initialize for horizontal or vertical properties
7028 name === "width" ? 1 : 0,
7029
7030 val = 0;
7031
7032 for ( ; i < 4; i += 2 ) {
7033 // both box models exclude margin, so add it if we want it
7034 if ( extra === "margin" ) {
7035 val += jQuery.css( elem, extra + cssExpand[ i ], true, styles );
7036 }
7037
7038 if ( isBorderBox ) {
7039 // border-box includes padding, so remove it if we want content
7040 if ( extra === "content" ) {
7041 val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
7042 }
7043
7044 // at this point, extra isn't border nor margin, so remove border
7045 if ( extra !== "margin" ) {
7046 val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
7047 }
7048 } else {
7049 // at this point, extra isn't content, so add padding
7050 val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
7051
7052 // at this point, extra isn't content nor padding, so add border
7053 if ( extra !== "padding" ) {
7054 val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
7055 }
7056 }
7057 }
7058
7059 return val;
7060 }
7061
7062 function getWidthOrHeight( elem, name, extra ) {
7063
7064 // Start with offset property, which is equivalent to the border-box value
7065 var valueIsBorderBox = true,
7066 val = name === "width" ? elem.offsetWidth : elem.offsetHeight,
7067 styles = getStyles( elem ),
7068 isBorderBox = jQuery.support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box";
7069
7070 // some non-html elements return undefined for offsetWidth, so check for null/undefined
7071 // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285
7072 // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668
7073 if ( val <= 0 || val == null ) {
7074 // Fall back to computed then uncomputed css if necessary
7075 val = curCSS( elem, name, styles );
7076 if ( val < 0 || val == null ) {
7077 val = elem.style[ name ];
7078 }
7079
7080 // Computed unit is not pixels. Stop here and return.
7081 if ( rnumnonpx.test(val) ) {
7082 return val;
7083 }
7084
7085 // we need the check for style in case a browser which returns unreliable values
7086 // for getComputedStyle silently falls back to the reliable elem.style
7087 valueIsBorderBox = isBorderBox && ( jQuery.support.boxSizingReliable || val === elem.style[ name ] );
7088
7089 // Normalize "", auto, and prepare for extra
7090 val = parseFloat( val ) || 0;
7091 }
7092
7093 // use the active box-sizing model to add/subtract irrelevant styles
7094 return ( val +
7095 augmentWidthOrHeight(
7096 elem,
7097 name,
7098 extra || ( isBorderBox ? "border" : "content" ),
7099 valueIsBorderBox,
7100 styles
7101 )
7102 ) + "px";
7103 }
7104
7105 // Try to determine the default display value of an element
7106 function css_defaultDisplay( nodeName ) {
7107 var doc = document,
7108 display = elemdisplay[ nodeName ];
7109
7110 if ( !display ) {
7111 display = actualDisplay( nodeName, doc );
7112
7113 // If the simple way fails, read from inside an iframe
7114 if ( display === "none" || !display ) {
7115 // Use the already-created iframe if possible
7116 iframe = ( iframe ||
7117 jQuery("<iframe frameborder='0' width='0' height='0'/>")
7118 .css( "cssText", "display:block !important" )
7119 ).appendTo( doc.documentElement );
7120
7121 // Always write a new HTML skeleton so Webkit and Firefox don't choke on reuse
7122 doc = ( iframe[0].contentWindow || iframe[0].contentDocument ).document;
7123 doc.write("<!doctype html><html><body>");
7124 doc.close();
7125
7126 display = actualDisplay( nodeName, doc );
7127 iframe.detach();
7128 }
7129
7130 // Store the correct default display
7131 elemdisplay[ nodeName ] = display;
7132 }
7133
7134 return display;
7135 }
7136
7137 // Called ONLY from within css_defaultDisplay
7138 function actualDisplay( name, doc ) {
7139 var elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ),
7140 display = jQuery.css( elem[0], "display" );
7141 elem.remove();
7142 return display;
7143 }
7144
7145 jQuery.each([ "height", "width" ], function( i, name ) {
7146 jQuery.cssHooks[ name ] = {
7147 get: function( elem, computed, extra ) {
7148 if ( computed ) {
7149 // certain elements can have dimension info if we invisibly show them
7150 // however, it must have a current display style that would benefit from this
7151 return elem.offsetWidth === 0 && rdisplayswap.test( jQuery.css( elem, "display" ) ) ?
7152 jQuery.swap( elem, cssShow, function() {
7153 return getWidthOrHeight( elem, name, extra );
7154 }) :
7155 getWidthOrHeight( elem, name, extra );
7156 }
7157 },
7158
7159 set: function( elem, value, extra ) {
7160 var styles = extra && getStyles( elem );
7161 return setPositiveNumber( elem, value, extra ?
7162 augmentWidthOrHeight(
7163 elem,
7164 name,
7165 extra,
7166 jQuery.support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
7167 styles
7168 ) : 0
7169 );
7170 }
7171 };
7172 });
7173
7174 if ( !jQuery.support.opacity ) {
7175 jQuery.cssHooks.opacity = {
7176 get: function( elem, computed ) {
7177 // IE uses filters for opacity
7178 return ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "" ) ?
7179 ( 0.01 * parseFloat( RegExp.$1 ) ) + "" :
7180 computed ? "1" : "";
7181 },
7182
7183 set: function( elem, value ) {
7184 var style = elem.style,
7185 currentStyle = elem.currentStyle,
7186 opacity = jQuery.isNumeric( value ) ? "alpha(opacity=" + value * 100 + ")" : "",
7187 filter = currentStyle && currentStyle.filter || style.filter || "";
7188
7189 // IE has trouble with opacity if it does not have layout
7190 // Force it by setting the zoom level
7191 style.zoom = 1;
7192
7193 // if setting opacity to 1, and no other filters exist - attempt to remove filter attribute #6652
7194 // if value === "", then remove inline opacity #12685
7195 if ( ( value >= 1 || value === "" ) &&
7196 jQuery.trim( filter.replace( ralpha, "" ) ) === "" &&
7197 style.removeAttribute ) {
7198
7199 // Setting style.filter to null, "" & " " still leave "filter:" in the cssText
7200 // if "filter:" is present at all, clearType is disabled, we want to avoid this
7201 // style.removeAttribute is IE Only, but so apparently is this code path...
7202 style.removeAttribute( "filter" );
7203
7204 // if there is no filter style applied in a css rule or unset inline opacity, we are done
7205 if ( value === "" || currentStyle && !currentStyle.filter ) {
7206 return;
7207 }
7208 }
7209
7210 // otherwise, set new filter values
7211 style.filter = ralpha.test( filter ) ?
7212 filter.replace( ralpha, opacity ) :
7213 filter + " " + opacity;
7214 }
7215 };
7216 }
7217
7218 // These hooks cannot be added until DOM ready because the support test
7219 // for it is not run until after DOM ready
7220 jQuery(function() {
7221 if ( !jQuery.support.reliableMarginRight ) {
7222 jQuery.cssHooks.marginRight = {
7223 get: function( elem, computed ) {
7224 if ( computed ) {
7225 // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
7226 // Work around by temporarily setting element display to inline-block
7227 return jQuery.swap( elem, { "display": "inline-block" },
7228 curCSS, [ elem, "marginRight" ] );
7229 }
7230 }
7231 };
7232 }
7233
7234 // Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084
7235 // getComputedStyle returns percent when specified for top/left/bottom/right
7236 // rather than make the css module depend on the offset module, we just check for it here
7237 if ( !jQuery.support.pixelPosition && jQuery.fn.position ) {
7238 jQuery.each( [ "top", "left" ], function( i, prop ) {
7239 jQuery.cssHooks[ prop ] = {
7240 get: function( elem, computed ) {
7241 if ( computed ) {
7242 computed = curCSS( elem, prop );
7243 // if curCSS returns percentage, fallback to offset
7244 return rnumnonpx.test( computed ) ?
7245 jQuery( elem ).position()[ prop ] + "px" :
7246 computed;
7247 }
7248 }
7249 };
7250 });
7251 }
7252
7253 });
7254
7255 if ( jQuery.expr && jQuery.expr.filters ) {
7256 jQuery.expr.filters.hidden = function( elem ) {
7257 // Support: Opera <= 12.12
7258 // Opera reports offsetWidths and offsetHeights less than zero on some elements
7259 return elem.offsetWidth <= 0 && elem.offsetHeight <= 0 ||
7260 (!jQuery.support.reliableHiddenOffsets && ((elem.style && elem.style.display) || jQuery.css( elem, "display" )) === "none");
7261 };
7262
7263 jQuery.expr.filters.visible = function( elem ) {
7264 return !jQuery.expr.filters.hidden( elem );
7265 };
7266 }
7267
7268 // These hooks are used by animate to expand properties
7269 jQuery.each({
7270 margin: "",
7271 padding: "",
7272 border: "Width"
7273 }, function( prefix, suffix ) {
7274 jQuery.cssHooks[ prefix + suffix ] = {
7275 expand: function( value ) {
7276 var i = 0,
7277 expanded = {},
7278
7279 // assumes a single number if not a string
7280 parts = typeof value === "string" ? value.split(" ") : [ value ];
7281
7282 for ( ; i < 4; i++ ) {
7283 expanded[ prefix + cssExpand[ i ] + suffix ] =
7284 parts[ i ] || parts[ i - 2 ] || parts[ 0 ];
7285 }
7286
7287 return expanded;
7288 }
7289 };
7290
7291 if ( !rmargin.test( prefix ) ) {
7292 jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;
7293 }
7294 });
7295 var r20 = /%20/g,
7296 rbracket = /\[\]$/,
7297 rCRLF = /\r?\n/g,
7298 rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,
7299 rsubmittable = /^(?:input|select|textarea|keygen)/i;
7300
7301 jQuery.fn.extend({
7302 serialize: function() {
7303 return jQuery.param( this.serializeArray() );
7304 },
7305 serializeArray: function() {
7306 return this.map(function(){
7307 // Can add propHook for "elements" to filter or add form elements
7308 var elements = jQuery.prop( this, "elements" );
7309 return elements ? jQuery.makeArray( elements ) : this;
7310 })
7311 .filter(function(){
7312 var type = this.type;
7313 // Use .is(":disabled") so that fieldset[disabled] works
7314 return this.name && !jQuery( this ).is( ":disabled" ) &&
7315 rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&
7316 ( this.checked || !manipulation_rcheckableType.test( type ) );
7317 })
7318 .map(function( i, elem ){
7319 var val = jQuery( this ).val();
7320
7321 return val == null ?
7322 null :
7323 jQuery.isArray( val ) ?
7324 jQuery.map( val, function( val ){
7325 return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
7326 }) :
7327 { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
7328 }).get();
7329 }
7330 });
7331
7332 //Serialize an array of form elements or a set of
7333 //key/values into a query string
7334 jQuery.param = function( a, traditional ) {
7335 var prefix,
7336 s = [],
7337 add = function( key, value ) {
7338 // If value is a function, invoke it and return its value
7339 value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value );
7340 s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value );
7341 };
7342
7343 // Set traditional to true for jQuery <= 1.3.2 behavior.
7344 if ( traditional === undefined ) {
7345 traditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional;
7346 }
7347
7348 // If an array was passed in, assume that it is an array of form elements.
7349 if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
7350 // Serialize the form elements
7351 jQuery.each( a, function() {
7352 add( this.name, this.value );
7353 });
7354
7355 } else {
7356 // If traditional, encode the "old" way (the way 1.3.2 or older
7357 // did it), otherwise encode params recursively.
7358 for ( prefix in a ) {
7359 buildParams( prefix, a[ prefix ], traditional, add );
7360 }
7361 }
7362
7363 // Return the resulting serialization
7364 return s.join( "&" ).replace( r20, "+" );
7365 };
7366
7367 function buildParams( prefix, obj, traditional, add ) {
7368 var name;
7369
7370 if ( jQuery.isArray( obj ) ) {
7371 // Serialize array item.
7372 jQuery.each( obj, function( i, v ) {
7373 if ( traditional || rbracket.test( prefix ) ) {
7374 // Treat each array item as a scalar.
7375 add( prefix, v );
7376
7377 } else {
7378 // Item is non-scalar (array or object), encode its numeric index.
7379 buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add );
7380 }
7381 });
7382
7383 } else if ( !traditional && jQuery.type( obj ) === "object" ) {
7384 // Serialize object item.
7385 for ( name in obj ) {
7386 buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
7387 }
7388
7389 } else {
7390 // Serialize scalar item.
7391 add( prefix, obj );
7392 }
7393 }
7394 jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
7395 "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
7396 "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) {
7397
7398 // Handle event binding
7399 jQuery.fn[ name ] = function( data, fn ) {
7400 return arguments.length > 0 ?
7401 this.on( name, null, data, fn ) :
7402 this.trigger( name );
7403 };
7404 });
7405
7406 jQuery.fn.hover = function( fnOver, fnOut ) {
7407 return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
7408 };
7409 var
7410 // Document location
7411 ajaxLocParts,
7412 ajaxLocation,
7413 ajax_nonce = jQuery.now(),
7414
7415 ajax_rquery = /\?/,
7416 rhash = /#.*$/,
7417 rts = /([?&])_=[^&]*/,
7418 rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL
7419 // #7653, #8125, #8152: local protocol detection
7420 rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,
7421 rnoContent = /^(?:GET|HEAD)$/,
7422 rprotocol = /^\/\//,
7423 rurl = /^([\w.+-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,
7424
7425 // Keep a copy of the old load method
7426 _load = jQuery.fn.load,
7427
7428 /* Prefilters
7429 * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
7430 * 2) These are called:
7431 * - BEFORE asking for a transport
7432 * - AFTER param serialization (s.data is a string if s.processData is true)
7433 * 3) key is the dataType
7434 * 4) the catchall symbol "*" can be used
7435 * 5) execution will start with transport dataType and THEN continue down to "*" if needed
7436 */
7437 prefilters = {},
7438
7439 /* Transports bindings
7440 * 1) key is the dataType
7441 * 2) the catchall symbol "*" can be used
7442 * 3) selection will start with transport dataType and THEN go to "*" if needed
7443 */
7444 transports = {},
7445
7446 // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
7447 allTypes = "*/".concat("*");
7448
7449 // #8138, IE may throw an exception when accessing
7450 // a field from window.location if document.domain has been set
7451 try {
7452 ajaxLocation = location.href;
7453 } catch( e ) {
7454 // Use the href attribute of an A element
7455 // since IE will modify it given document.location
7456 ajaxLocation = document.createElement( "a" );
7457 ajaxLocation.href = "";
7458 ajaxLocation = ajaxLocation.href;
7459 }
7460
7461 // Segment location into parts
7462 ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];
7463
7464 // Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
7465 function addToPrefiltersOrTransports( structure ) {
7466
7467 // dataTypeExpression is optional and defaults to "*"
7468 return function( dataTypeExpression, func ) {
7469
7470 if ( typeof dataTypeExpression !== "string" ) {
7471 func = dataTypeExpression;
7472 dataTypeExpression = "*";
7473 }
7474
7475 var dataType,
7476 i = 0,
7477 dataTypes = dataTypeExpression.toLowerCase().match( core_rnotwhite ) || [];
7478
7479 if ( jQuery.isFunction( func ) ) {
7480 // For each dataType in the dataTypeExpression
7481 while ( (dataType = dataTypes[i++]) ) {
7482 // Prepend if requested
7483 if ( dataType[0] === "+" ) {
7484 dataType = dataType.slice( 1 ) || "*";
7485 (structure[ dataType ] = structure[ dataType ] || []).unshift( func );
7486
7487 // Otherwise append
7488 } else {
7489 (structure[ dataType ] = structure[ dataType ] || []).push( func );
7490 }
7491 }
7492 }
7493 };
7494 }
7495
7496 // Base inspection function for prefilters and transports
7497 function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {
7498
7499 var inspected = {},
7500 seekingTransport = ( structure === transports );
7501
7502 function inspect( dataType ) {
7503 var selected;
7504 inspected[ dataType ] = true;
7505 jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {
7506 var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );
7507 if( typeof dataTypeOrTransport === "string" && !seekingTransport && !inspected[ dataTypeOrTransport ] ) {
7508 options.dataTypes.unshift( dataTypeOrTransport );
7509 inspect( dataTypeOrTransport );
7510 return false;
7511 } else if ( seekingTransport ) {
7512 return !( selected = dataTypeOrTransport );
7513 }
7514 });
7515 return selected;
7516 }
7517
7518 return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" );
7519 }
7520
7521 // A special extend for ajax options
7522 // that takes "flat" options (not to be deep extended)
7523 // Fixes #9887
7524 function ajaxExtend( target, src ) {
7525 var deep, key,
7526 flatOptions = jQuery.ajaxSettings.flatOptions || {};
7527
7528 for ( key in src ) {
7529 if ( src[ key ] !== undefined ) {
7530 ( flatOptions[ key ] ? target : ( deep || (deep = {}) ) )[ key ] = src[ key ];
7531 }
7532 }
7533 if ( deep ) {
7534 jQuery.extend( true, target, deep );
7535 }
7536
7537 return target;
7538 }
7539
7540 jQuery.fn.load = function( url, params, callback ) {
7541 if ( typeof url !== "string" && _load ) {
7542 return _load.apply( this, arguments );
7543 }
7544
7545 var selector, response, type,
7546 self = this,
7547 off = url.indexOf(" ");
7548
7549 if ( off >= 0 ) {
7550 selector = url.slice( off, url.length );
7551 url = url.slice( 0, off );
7552 }
7553
7554 // If it's a function
7555 if ( jQuery.isFunction( params ) ) {
7556
7557 // We assume that it's the callback
7558 callback = params;
7559 params = undefined;
7560
7561 // Otherwise, build a param string
7562 } else if ( params && typeof params === "object" ) {
7563 type = "POST";
7564 }
7565
7566 // If we have elements to modify, make the request
7567 if ( self.length > 0 ) {
7568 jQuery.ajax({
7569 url: url,
7570
7571 // if "type" variable is undefined, then "GET" method will be used
7572 type: type,
7573 dataType: "html",
7574 data: params
7575 }).done(function( responseText ) {
7576
7577 // Save response for use in complete callback
7578 response = arguments;
7579
7580 self.html( selector ?
7581
7582 // If a selector was specified, locate the right elements in a dummy div
7583 // Exclude scripts to avoid IE 'Permission Denied' errors
7584 jQuery("<div>").append( jQuery.parseHTML( responseText ) ).find( selector ) :
7585
7586 // Otherwise use the full result
7587 responseText );
7588
7589 }).complete( callback && function( jqXHR, status ) {
7590 self.each( callback, response || [ jqXHR.responseText, status, jqXHR ] );
7591 });
7592 }
7593
7594 return this;
7595 };
7596
7597 // Attach a bunch of functions for handling common AJAX events
7598 jQuery.each( [ "ajaxStart", "ajaxStop", "ajaxComplete", "ajaxError", "ajaxSuccess", "ajaxSend" ], function( i, type ){
7599 jQuery.fn[ type ] = function( fn ){
7600 return this.on( type, fn );
7601 };
7602 });
7603
7604 jQuery.each( [ "get", "post" ], function( i, method ) {
7605 jQuery[ method ] = function( url, data, callback, type ) {
7606 // shift arguments if data argument was omitted
7607 if ( jQuery.isFunction( data ) ) {
7608 type = type || callback;
7609 callback = data;
7610 data = undefined;
7611 }
7612
7613 return jQuery.ajax({
7614 url: url,
7615 type: method,
7616 dataType: type,
7617 data: data,
7618 success: callback
7619 });
7620 };
7621 });
7622
7623 jQuery.extend({
7624
7625 // Counter for holding the number of active queries
7626 active: 0,
7627
7628 // Last-Modified header cache for next request
7629 lastModified: {},
7630 etag: {},
7631
7632 ajaxSettings: {
7633 url: ajaxLocation,
7634 type: "GET",
7635 isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),
7636 global: true,
7637 processData: true,
7638 async: true,
7639 contentType: "application/x-www-form-urlencoded; charset=UTF-8",
7640 /*
7641 timeout: 0,
7642 data: null,
7643 dataType: null,
7644 username: null,
7645 password: null,
7646 cache: null,
7647 throws: false,
7648 traditional: false,
7649 headers: {},
7650 */
7651
7652 accepts: {
7653 "*": allTypes,
7654 text: "text/plain",
7655 html: "text/html",
7656 xml: "application/xml, text/xml",
7657 json: "application/json, text/javascript"
7658 },
7659
7660 contents: {
7661 xml: /xml/,
7662 html: /html/,
7663 json: /json/
7664 },
7665
7666 responseFields: {
7667 xml: "responseXML",
7668 text: "responseText"
7669 },
7670
7671 // Data converters
7672 // Keys separate source (or catchall "*") and destination types with a single space
7673 converters: {
7674
7675 // Convert anything to text
7676 "* text": window.String,
7677
7678 // Text to html (true = no transformation)
7679 "text html": true,
7680
7681 // Evaluate text as a json expression
7682 "text json": jQuery.parseJSON,
7683
7684 // Parse text as xml
7685 "text xml": jQuery.parseXML
7686 },
7687
7688 // For options that shouldn't be deep extended:
7689 // you can add your own custom options here if
7690 // and when you create one that shouldn't be
7691 // deep extended (see ajaxExtend)
7692 flatOptions: {
7693 url: true,
7694 context: true
7695 }
7696 },
7697
7698 // Creates a full fledged settings object into target
7699 // with both ajaxSettings and settings fields.
7700 // If target is omitted, writes into ajaxSettings.
7701 ajaxSetup: function( target, settings ) {
7702 return settings ?
7703
7704 // Building a settings object
7705 ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) :
7706
7707 // Extending ajaxSettings
7708 ajaxExtend( jQuery.ajaxSettings, target );
7709 },
7710
7711 ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
7712 ajaxTransport: addToPrefiltersOrTransports( transports ),
7713
7714 // Main method
7715 ajax: function( url, options ) {
7716
7717 // If url is an object, simulate pre-1.5 signature
7718 if ( typeof url === "object" ) {
7719 options = url;
7720 url = undefined;
7721 }
7722
7723 // Force options to be an object
7724 options = options || {};
7725
7726 var // Cross-domain detection vars
7727 parts,
7728 // Loop variable
7729 i,
7730 // URL without anti-cache param
7731 cacheURL,
7732 // Response headers as string
7733 responseHeadersString,
7734 // timeout handle
7735 timeoutTimer,
7736
7737 // To know if global events are to be dispatched
7738 fireGlobals,
7739
7740 transport,
7741 // Response headers
7742 responseHeaders,
7743 // Create the final options object
7744 s = jQuery.ajaxSetup( {}, options ),
7745 // Callbacks context
7746 callbackContext = s.context || s,
7747 // Context for global events is callbackContext if it is a DOM node or jQuery collection
7748 globalEventContext = s.context && ( callbackContext.nodeType || callbackContext.jquery ) ?
7749 jQuery( callbackContext ) :
7750 jQuery.event,
7751 // Deferreds
7752 deferred = jQuery.Deferred(),
7753 completeDeferred = jQuery.Callbacks("once memory"),
7754 // Status-dependent callbacks
7755 statusCode = s.statusCode || {},
7756 // Headers (they are sent all at once)
7757 requestHeaders = {},
7758 requestHeadersNames = {},
7759 // The jqXHR state
7760 state = 0,
7761 // Default abort message
7762 strAbort = "canceled",
7763 // Fake xhr
7764 jqXHR = {
7765 readyState: 0,
7766
7767 // Builds headers hashtable if needed
7768 getResponseHeader: function( key ) {
7769 var match;
7770 if ( state === 2 ) {
7771 if ( !responseHeaders ) {
7772 responseHeaders = {};
7773 while ( (match = rheaders.exec( responseHeadersString )) ) {
7774 responseHeaders[ match[1].toLowerCase() ] = match[ 2 ];
7775 }
7776 }
7777 match = responseHeaders[ key.toLowerCase() ];
7778 }
7779 return match == null ? null : match;
7780 },
7781
7782 // Raw string
7783 getAllResponseHeaders: function() {
7784 return state === 2 ? responseHeadersString : null;
7785 },
7786
7787 // Caches the header
7788 setRequestHeader: function( name, value ) {
7789 var lname = name.toLowerCase();
7790 if ( !state ) {
7791 name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;
7792 requestHeaders[ name ] = value;
7793 }
7794 return this;
7795 },
7796
7797 // Overrides response content-type header
7798 overrideMimeType: function( type ) {
7799 if ( !state ) {
7800 s.mimeType = type;
7801 }
7802 return this;
7803 },
7804
7805 // Status-dependent callbacks
7806 statusCode: function( map ) {
7807 var code;
7808 if ( map ) {
7809 if ( state < 2 ) {
7810 for ( code in map ) {
7811 // Lazy-add the new callback in a way that preserves old ones
7812 statusCode[ code ] = [ statusCode[ code ], map[ code ] ];
7813 }
7814 } else {
7815 // Execute the appropriate callbacks
7816 jqXHR.always( map[ jqXHR.status ] );
7817 }
7818 }
7819 return this;
7820 },
7821
7822 // Cancel the request
7823 abort: function( statusText ) {
7824 var finalText = statusText || strAbort;
7825 if ( transport ) {
7826 transport.abort( finalText );
7827 }
7828 done( 0, finalText );
7829 return this;
7830 }
7831 };
7832
7833 // Attach deferreds
7834 deferred.promise( jqXHR ).complete = completeDeferred.add;
7835 jqXHR.success = jqXHR.done;
7836 jqXHR.error = jqXHR.fail;
7837
7838 // Remove hash character (#7531: and string promotion)
7839 // Add protocol if not provided (#5866: IE7 issue with protocol-less urls)
7840 // Handle falsy url in the settings object (#10093: consistency with old signature)
7841 // We also use the url parameter if available
7842 s.url = ( ( url || s.url || ajaxLocation ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" );
7843
7844 // Alias method option to type as per ticket #12004
7845 s.type = options.method || options.type || s.method || s.type;
7846
7847 // Extract dataTypes list
7848 s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().match( core_rnotwhite ) || [""];
7849
7850 // A cross-domain request is in order when we have a protocol:host:port mismatch
7851 if ( s.crossDomain == null ) {
7852 parts = rurl.exec( s.url.toLowerCase() );
7853 s.crossDomain = !!( parts &&
7854 ( parts[ 1 ] !== ajaxLocParts[ 1 ] || parts[ 2 ] !== ajaxLocParts[ 2 ] ||
7855 ( parts[ 3 ] || ( parts[ 1 ] === "http:" ? 80 : 443 ) ) !=
7856 ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? 80 : 443 ) ) )
7857 );
7858 }
7859
7860 // Convert data if not already a string
7861 if ( s.data && s.processData && typeof s.data !== "string" ) {
7862 s.data = jQuery.param( s.data, s.traditional );
7863 }
7864
7865 // Apply prefilters
7866 inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
7867
7868 // If request was aborted inside a prefilter, stop there
7869 if ( state === 2 ) {
7870 return jqXHR;
7871 }
7872
7873 // We can fire global events as of now if asked to
7874 fireGlobals = s.global;
7875
7876 // Watch for a new set of requests
7877 if ( fireGlobals && jQuery.active++ === 0 ) {
7878 jQuery.event.trigger("ajaxStart");
7879 }
7880
7881 // Uppercase the type
7882 s.type = s.type.toUpperCase();
7883
7884 // Determine if request has content
7885 s.hasContent = !rnoContent.test( s.type );
7886
7887 // Save the URL in case we're toying with the If-Modified-Since
7888 // and/or If-None-Match header later on
7889 cacheURL = s.url;
7890
7891 // More options handling for requests with no content
7892 if ( !s.hasContent ) {
7893
7894 // If data is available, append data to url
7895 if ( s.data ) {
7896 cacheURL = ( s.url += ( ajax_rquery.test( cacheURL ) ? "&" : "?" ) + s.data );
7897 // #9682: remove data so that it's not used in an eventual retry
7898 delete s.data;
7899 }
7900
7901 // Add anti-cache in url if needed
7902 if ( s.cache === false ) {
7903 s.url = rts.test( cacheURL ) ?
7904
7905 // If there is already a '_' parameter, set its value
7906 cacheURL.replace( rts, "$1_=" + ajax_nonce++ ) :
7907
7908 // Otherwise add one to the end
7909 cacheURL + ( ajax_rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ajax_nonce++;
7910 }
7911 }
7912
7913 // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
7914 if ( s.ifModified ) {
7915 if ( jQuery.lastModified[ cacheURL ] ) {
7916 jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] );
7917 }
7918 if ( jQuery.etag[ cacheURL ] ) {
7919 jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] );
7920 }
7921 }
7922
7923 // Set the correct header, if data is being sent
7924 if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
7925 jqXHR.setRequestHeader( "Content-Type", s.contentType );
7926 }
7927
7928 // Set the Accepts header for the server, depending on the dataType
7929 jqXHR.setRequestHeader(
7930 "Accept",
7931 s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?
7932 s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
7933 s.accepts[ "*" ]
7934 );
7935
7936 // Check for headers option
7937 for ( i in s.headers ) {
7938 jqXHR.setRequestHeader( i, s.headers[ i ] );
7939 }
7940
7941 // Allow custom headers/mimetypes and early abort
7942 if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {
7943 // Abort if not done already and return
7944 return jqXHR.abort();
7945 }
7946
7947 // aborting is no longer a cancellation
7948 strAbort = "abort";
7949
7950 // Install callbacks on deferreds
7951 for ( i in { success: 1, error: 1, complete: 1 } ) {
7952 jqXHR[ i ]( s[ i ] );
7953 }
7954
7955 // Get transport
7956 transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
7957
7958 // If no transport, we auto-abort
7959 if ( !transport ) {
7960 done( -1, "No Transport" );
7961 } else {
7962 jqXHR.readyState = 1;
7963
7964 // Send global event
7965 if ( fireGlobals ) {
7966 globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
7967 }
7968 // Timeout
7969 if ( s.async && s.timeout > 0 ) {
7970 timeoutTimer = setTimeout(function() {
7971 jqXHR.abort("timeout");
7972 }, s.timeout );
7973 }
7974
7975 try {
7976 state = 1;
7977 transport.send( requestHeaders, done );
7978 } catch ( e ) {
7979 // Propagate exception as error if not done
7980 if ( state < 2 ) {
7981 done( -1, e );
7982 // Simply rethrow otherwise
7983 } else {
7984 throw e;
7985 }
7986 }
7987 }
7988
7989 // Callback for when everything is done
7990 function done( status, nativeStatusText, responses, headers ) {
7991 var isSuccess, success, error, response, modified,
7992 statusText = nativeStatusText;
7993
7994 // Called once
7995 if ( state === 2 ) {
7996 return;
7997 }
7998
7999 // State is "done" now
8000 state = 2;
8001
8002 // Clear timeout if it exists
8003 if ( timeoutTimer ) {
8004 clearTimeout( timeoutTimer );
8005 }
8006
8007 // Dereference transport for early garbage collection
8008 // (no matter how long the jqXHR object will be used)
8009 transport = undefined;
8010
8011 // Cache response headers
8012 responseHeadersString = headers || "";
8013
8014 // Set readyState
8015 jqXHR.readyState = status > 0 ? 4 : 0;
8016
8017 // Get response data
8018 if ( responses ) {
8019 response = ajaxHandleResponses( s, jqXHR, responses );
8020 }
8021
8022 // If successful, handle type chaining
8023 if ( status >= 200 && status < 300 || status === 304 ) {
8024
8025 // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
8026 if ( s.ifModified ) {
8027 modified = jqXHR.getResponseHeader("Last-Modified");
8028 if ( modified ) {
8029 jQuery.lastModified[ cacheURL ] = modified;
8030 }
8031 modified = jqXHR.getResponseHeader("etag");
8032 if ( modified ) {
8033 jQuery.etag[ cacheURL ] = modified;
8034 }
8035 }
8036
8037 // if no content
8038 if ( status === 204 ) {
8039 isSuccess = true;
8040 statusText = "nocontent";
8041
8042 // if not modified
8043 } else if ( status === 304 ) {
8044 isSuccess = true;
8045 statusText = "notmodified";
8046
8047 // If we have data, let's convert it
8048 } else {
8049 isSuccess = ajaxConvert( s, response );
8050 statusText = isSuccess.state;
8051 success = isSuccess.data;
8052 error = isSuccess.error;
8053 isSuccess = !error;
8054 }
8055 } else {
8056 // We extract error from statusText
8057 // then normalize statusText and status for non-aborts
8058 error = statusText;
8059 if ( status || !statusText ) {
8060 statusText = "error";
8061 if ( status < 0 ) {
8062 status = 0;
8063 }
8064 }
8065 }
8066
8067 // Set data for the fake xhr object
8068 jqXHR.status = status;
8069 jqXHR.statusText = ( nativeStatusText || statusText ) + "";
8070
8071 // Success/Error
8072 if ( isSuccess ) {
8073 deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
8074 } else {
8075 deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
8076 }
8077
8078 // Status-dependent callbacks
8079 jqXHR.statusCode( statusCode );
8080 statusCode = undefined;
8081
8082 if ( fireGlobals ) {
8083 globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError",
8084 [ jqXHR, s, isSuccess ? success : error ] );
8085 }
8086
8087 // Complete
8088 completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );
8089
8090 if ( fireGlobals ) {
8091 globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
8092 // Handle the global AJAX counter
8093 if ( !( --jQuery.active ) ) {
8094 jQuery.event.trigger("ajaxStop");
8095 }
8096 }
8097 }
8098
8099 return jqXHR;
8100 },
8101
8102 getScript: function( url, callback ) {
8103 return jQuery.get( url, undefined, callback, "script" );
8104 },
8105
8106 getJSON: function( url, data, callback ) {
8107 return jQuery.get( url, data, callback, "json" );
8108 }
8109 });
8110
8111 /* Handles responses to an ajax request:
8112 * - sets all responseXXX fields accordingly
8113 * - finds the right dataType (mediates between content-type and expected dataType)
8114 * - returns the corresponding response
8115 */
8116 function ajaxHandleResponses( s, jqXHR, responses ) {
8117 var firstDataType, ct, finalDataType, type,
8118 contents = s.contents,
8119 dataTypes = s.dataTypes,
8120 responseFields = s.responseFields;
8121
8122 // Fill responseXXX fields
8123 for ( type in responseFields ) {
8124 if ( type in responses ) {
8125 jqXHR[ responseFields[type] ] = responses[ type ];
8126 }
8127 }
8128
8129 // Remove auto dataType and get content-type in the process
8130 while( dataTypes[ 0 ] === "*" ) {
8131 dataTypes.shift();
8132 if ( ct === undefined ) {
8133 ct = s.mimeType || jqXHR.getResponseHeader("Content-Type");
8134 }
8135 }
8136
8137 // Check if we're dealing with a known content-type
8138 if ( ct ) {
8139 for ( type in contents ) {
8140 if ( contents[ type ] && contents[ type ].test( ct ) ) {
8141 dataTypes.unshift( type );
8142 break;
8143 }
8144 }
8145 }
8146
8147 // Check to see if we have a response for the expected dataType
8148 if ( dataTypes[ 0 ] in responses ) {
8149 finalDataType = dataTypes[ 0 ];
8150 } else {
8151 // Try convertible dataTypes
8152 for ( type in responses ) {
8153 if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) {
8154 finalDataType = type;
8155 break;
8156 }
8157 if ( !firstDataType ) {
8158 firstDataType = type;
8159 }
8160 }
8161 // Or just use first one
8162 finalDataType = finalDataType || firstDataType;
8163 }
8164
8165 // If we found a dataType
8166 // We add the dataType to the list if needed
8167 // and return the corresponding response
8168 if ( finalDataType ) {
8169 if ( finalDataType !== dataTypes[ 0 ] ) {
8170 dataTypes.unshift( finalDataType );
8171 }
8172 return responses[ finalDataType ];
8173 }
8174 }
8175
8176 // Chain conversions given the request and the original response
8177 function ajaxConvert( s, response ) {
8178 var conv2, current, conv, tmp,
8179 converters = {},
8180 i = 0,
8181 // Work with a copy of dataTypes in case we need to modify it for conversion
8182 dataTypes = s.dataTypes.slice(),
8183 prev = dataTypes[ 0 ];
8184
8185 // Apply the dataFilter if provided
8186 if ( s.dataFilter ) {
8187 response = s.dataFilter( response, s.dataType );
8188 }
8189
8190 // Create converters map with lowercased keys
8191 if ( dataTypes[ 1 ] ) {
8192 for ( conv in s.converters ) {
8193 converters[ conv.toLowerCase() ] = s.converters[ conv ];
8194 }
8195 }
8196
8197 // Convert to each sequential dataType, tolerating list modification
8198 for ( ; (current = dataTypes[++i]); ) {
8199
8200 // There's only work to do if current dataType is non-auto
8201 if ( current !== "*" ) {
8202
8203 // Convert response if prev dataType is non-auto and differs from current
8204 if ( prev !== "*" && prev !== current ) {
8205
8206 // Seek a direct converter
8207 conv = converters[ prev + " " + current ] || converters[ "* " + current ];
8208
8209 // If none found, seek a pair
8210 if ( !conv ) {
8211 for ( conv2 in converters ) {
8212
8213 // If conv2 outputs current
8214 tmp = conv2.split(" ");
8215 if ( tmp[ 1 ] === current ) {
8216
8217 // If prev can be converted to accepted input
8218 conv = converters[ prev + " " + tmp[ 0 ] ] ||
8219 converters[ "* " + tmp[ 0 ] ];
8220 if ( conv ) {
8221 // Condense equivalence converters
8222 if ( conv === true ) {
8223 conv = converters[ conv2 ];
8224
8225 // Otherwise, insert the intermediate dataType
8226 } else if ( converters[ conv2 ] !== true ) {
8227 current = tmp[ 0 ];
8228 dataTypes.splice( i--, 0, current );
8229 }
8230
8231 break;
8232 }
8233 }
8234 }
8235 }
8236
8237 // Apply converter (if not an equivalence)
8238 if ( conv !== true ) {
8239
8240 // Unless errors are allowed to bubble, catch and return them
8241 if ( conv && s["throws"] ) {
8242 response = conv( response );
8243 } else {
8244 try {
8245 response = conv( response );
8246 } catch ( e ) {
8247 return { state: "parsererror", error: conv ? e : "No conversion from " + prev + " to " + current };
8248 }
8249 }
8250 }
8251 }
8252
8253 // Update prev for next iteration
8254 prev = current;
8255 }
8256 }
8257
8258 return { state: "success", data: response };
8259 }
8260 // Install script dataType
8261 jQuery.ajaxSetup({
8262 accepts: {
8263 script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
8264 },
8265 contents: {
8266 script: /(?:java|ecma)script/
8267 },
8268 converters: {
8269 "text script": function( text ) {
8270 jQuery.globalEval( text );
8271 return text;
8272 }
8273 }
8274 });
8275
8276 // Handle cache's special case and global
8277 jQuery.ajaxPrefilter( "script", function( s ) {
8278 if ( s.cache === undefined ) {
8279 s.cache = false;
8280 }
8281 if ( s.crossDomain ) {
8282 s.type = "GET";
8283 s.global = false;
8284 }
8285 });
8286
8287 // Bind script tag hack transport
8288 jQuery.ajaxTransport( "script", function(s) {
8289
8290 // This transport only deals with cross domain requests
8291 if ( s.crossDomain ) {
8292
8293 var script,
8294 head = document.head || jQuery("head")[0] || document.documentElement;
8295
8296 return {
8297
8298 send: function( _, callback ) {
8299
8300 script = document.createElement("script");
8301
8302 script.async = true;
8303
8304 if ( s.scriptCharset ) {
8305 script.charset = s.scriptCharset;
8306 }
8307
8308 script.src = s.url;
8309
8310 // Attach handlers for all browsers
8311 script.onload = script.onreadystatechange = function( _, isAbort ) {
8312
8313 if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) {
8314
8315 // Handle memory leak in IE
8316 script.onload = script.onreadystatechange = null;
8317
8318 // Remove the script
8319 if ( script.parentNode ) {
8320 script.parentNode.removeChild( script );
8321 }
8322
8323 // Dereference the script
8324 script = null;
8325
8326 // Callback if not abort
8327 if ( !isAbort ) {
8328 callback( 200, "success" );
8329 }
8330 }
8331 };
8332
8333 // Circumvent IE6 bugs with base elements (#2709 and #4378) by prepending
8334 // Use native DOM manipulation to avoid our domManip AJAX trickery
8335 head.insertBefore( script, head.firstChild );
8336 },
8337
8338 abort: function() {
8339 if ( script ) {
8340 script.onload( undefined, true );
8341 }
8342 }
8343 };
8344 }
8345 });
8346 var oldCallbacks = [],
8347 rjsonp = /(=)\?(?=&|$)|\?\?/;
8348
8349 // Default jsonp settings
8350 jQuery.ajaxSetup({
8351 jsonp: "callback",
8352 jsonpCallback: function() {
8353 var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( ajax_nonce++ ) );
8354 this[ callback ] = true;
8355 return callback;
8356 }
8357 });
8358
8359 // Detect, normalize options and install callbacks for jsonp requests
8360 jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
8361
8362 var callbackName, overwritten, responseContainer,
8363 jsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ?
8364 "url" :
8365 typeof s.data === "string" && !( s.contentType || "" ).indexOf("application/x-www-form-urlencoded") && rjsonp.test( s.data ) && "data"
8366 );
8367
8368 // Handle iff the expected data type is "jsonp" or we have a parameter to set
8369 if ( jsonProp || s.dataTypes[ 0 ] === "jsonp" ) {
8370
8371 // Get callback name, remembering preexisting value associated with it
8372 callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ?
8373 s.jsonpCallback() :
8374 s.jsonpCallback;
8375
8376 // Insert callback into url or form data
8377 if ( jsonProp ) {
8378 s[ jsonProp ] = s[ jsonProp ].replace( rjsonp, "$1" + callbackName );
8379 } else if ( s.jsonp !== false ) {
8380 s.url += ( ajax_rquery.test( s.url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName;
8381 }
8382
8383 // Use data converter to retrieve json after script execution
8384 s.converters["script json"] = function() {
8385 if ( !responseContainer ) {
8386 jQuery.error( callbackName + " was not called" );
8387 }
8388 return responseContainer[ 0 ];
8389 };
8390
8391 // force json dataType
8392 s.dataTypes[ 0 ] = "json";
8393
8394 // Install callback
8395 overwritten = window[ callbackName ];
8396 window[ callbackName ] = function() {
8397 responseContainer = arguments;
8398 };
8399
8400 // Clean-up function (fires after converters)
8401 jqXHR.always(function() {
8402 // Restore preexisting value
8403 window[ callbackName ] = overwritten;
8404
8405 // Save back as free
8406 if ( s[ callbackName ] ) {
8407 // make sure that re-using the options doesn't screw things around
8408 s.jsonpCallback = originalSettings.jsonpCallback;
8409
8410 // save the callback name for future use
8411 oldCallbacks.push( callbackName );
8412 }
8413
8414 // Call if it was a function and we have a response
8415 if ( responseContainer && jQuery.isFunction( overwritten ) ) {
8416 overwritten( responseContainer[ 0 ] );
8417 }
8418
8419 responseContainer = overwritten = undefined;
8420 });
8421
8422 // Delegate to script
8423 return "script";
8424 }
8425 });
8426 var xhrCallbacks, xhrSupported,
8427 xhrId = 0,
8428 // #5280: Internet Explorer will keep connections alive if we don't abort on unload
8429 xhrOnUnloadAbort = window.ActiveXObject && function() {
8430 // Abort all pending requests
8431 var key;
8432 for ( key in xhrCallbacks ) {
8433 xhrCallbacks[ key ]( undefined, true );
8434 }
8435 };
8436
8437 // Functions to create xhrs
8438 function createStandardXHR() {
8439 try {
8440 return new window.XMLHttpRequest();
8441 } catch( e ) {}
8442 }
8443
8444 function createActiveXHR() {
8445 try {
8446 return new window.ActiveXObject("Microsoft.XMLHTTP");
8447 } catch( e ) {}
8448 }
8449
8450 // Create the request object
8451 // (This is still attached to ajaxSettings for backward compatibility)
8452 jQuery.ajaxSettings.xhr = window.ActiveXObject ?
8453 /* Microsoft failed to properly
8454 * implement the XMLHttpRequest in IE7 (can't request local files),
8455 * so we use the ActiveXObject when it is available
8456 * Additionally XMLHttpRequest can be disabled in IE7/IE8 so
8457 * we need a fallback.
8458 */
8459 function() {
8460 return !this.isLocal && createStandardXHR() || createActiveXHR();
8461 } :
8462 // For all other browsers, use the standard XMLHttpRequest object
8463 createStandardXHR;
8464
8465 // Determine support properties
8466 xhrSupported = jQuery.ajaxSettings.xhr();
8467 jQuery.support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported );
8468 xhrSupported = jQuery.support.ajax = !!xhrSupported;
8469
8470 // Create transport if the browser can provide an xhr
8471 if ( xhrSupported ) {
8472
8473 jQuery.ajaxTransport(function( s ) {
8474 // Cross domain only allowed if supported through XMLHttpRequest
8475 if ( !s.crossDomain || jQuery.support.cors ) {
8476
8477 var callback;
8478
8479 return {
8480 send: function( headers, complete ) {
8481
8482 // Get a new xhr
8483 var handle, i,
8484 xhr = s.xhr();
8485
8486 // Open the socket
8487 // Passing null username, generates a login popup on Opera (#2865)
8488 if ( s.username ) {
8489 xhr.open( s.type, s.url, s.async, s.username, s.password );
8490 } else {
8491 xhr.open( s.type, s.url, s.async );
8492 }
8493
8494 // Apply custom fields if provided
8495 if ( s.xhrFields ) {
8496 for ( i in s.xhrFields ) {
8497 xhr[ i ] = s.xhrFields[ i ];
8498 }
8499 }
8500
8501 // Override mime type if needed
8502 if ( s.mimeType && xhr.overrideMimeType ) {
8503 xhr.overrideMimeType( s.mimeType );
8504 }
8505
8506 // X-Requested-With header
8507 // For cross-domain requests, seeing as conditions for a preflight are
8508 // akin to a jigsaw puzzle, we simply never set it to be sure.
8509 // (it can always be set on a per-request basis or even using ajaxSetup)
8510 // For same-domain requests, won't change header if already provided.
8511 if ( !s.crossDomain && !headers["X-Requested-With"] ) {
8512 headers["X-Requested-With"] = "XMLHttpRequest";
8513 }
8514
8515 // Need an extra try/catch for cross domain requests in Firefox 3
8516 try {
8517 for ( i in headers ) {
8518 xhr.setRequestHeader( i, headers[ i ] );
8519 }
8520 } catch( err ) {}
8521
8522 // Do send the request
8523 // This may raise an exception which is actually
8524 // handled in jQuery.ajax (so no try/catch here)
8525 xhr.send( ( s.hasContent && s.data ) || null );
8526
8527 // Listener
8528 callback = function( _, isAbort ) {
8529 var status, responseHeaders, statusText, responses;
8530
8531 // Firefox throws exceptions when accessing properties
8532 // of an xhr when a network error occurred
8533 // http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_(NS_ERROR_NOT_AVAILABLE)
8534 try {
8535
8536 // Was never called and is aborted or complete
8537 if ( callback && ( isAbort || xhr.readyState === 4 ) ) {
8538
8539 // Only called once
8540 callback = undefined;
8541
8542 // Do not keep as active anymore
8543 if ( handle ) {
8544 xhr.onreadystatechange = jQuery.noop;
8545 if ( xhrOnUnloadAbort ) {
8546 delete xhrCallbacks[ handle ];
8547 }
8548 }
8549
8550 // If it's an abort
8551 if ( isAbort ) {
8552 // Abort it manually if needed
8553 if ( xhr.readyState !== 4 ) {
8554 xhr.abort();
8555 }
8556 } else {
8557 responses = {};
8558 status = xhr.status;
8559 responseHeaders = xhr.getAllResponseHeaders();
8560
8561 // When requesting binary data, IE6-9 will throw an exception
8562 // on any attempt to access responseText (#11426)
8563 if ( typeof xhr.responseText === "string" ) {
8564 responses.text = xhr.responseText;
8565 }
8566
8567 // Firefox throws an exception when accessing
8568 // statusText for faulty cross-domain requests
8569 try {
8570 statusText = xhr.statusText;
8571 } catch( e ) {
8572 // We normalize with Webkit giving an empty statusText
8573 statusText = "";
8574 }
8575
8576 // Filter status for non standard behaviors
8577
8578 // If the request is local and we have data: assume a success
8579 // (success with no data won't get notified, that's the best we
8580 // can do given current implementations)
8581 if ( !status && s.isLocal && !s.crossDomain ) {
8582 status = responses.text ? 200 : 404;
8583 // IE - #1450: sometimes returns 1223 when it should be 204
8584 } else if ( status === 1223 ) {
8585 status = 204;
8586 }
8587 }
8588 }
8589 } catch( firefoxAccessException ) {
8590 if ( !isAbort ) {
8591 complete( -1, firefoxAccessException );
8592 }
8593 }
8594
8595 // Call complete if needed
8596 if ( responses ) {
8597 complete( status, statusText, responses, responseHeaders );
8598 }
8599 };
8600
8601 if ( !s.async ) {
8602 // if we're in sync mode we fire the callback
8603 callback();
8604 } else if ( xhr.readyState === 4 ) {
8605 // (IE6 & IE7) if it's in cache and has been
8606 // retrieved directly we need to fire the callback
8607 setTimeout( callback );
8608 } else {
8609 handle = ++xhrId;
8610 if ( xhrOnUnloadAbort ) {
8611 // Create the active xhrs callbacks list if needed
8612 // and attach the unload handler
8613 if ( !xhrCallbacks ) {
8614 xhrCallbacks = {};
8615 jQuery( window ).unload( xhrOnUnloadAbort );
8616 }
8617 // Add to list of active xhrs callbacks
8618 xhrCallbacks[ handle ] = callback;
8619 }
8620 xhr.onreadystatechange = callback;
8621 }
8622 },
8623
8624 abort: function() {
8625 if ( callback ) {
8626 callback( undefined, true );
8627 }
8628 }
8629 };
8630 }
8631 });
8632 }
8633 var fxNow, timerId,
8634 rfxtypes = /^(?:toggle|show|hide)$/,
8635 rfxnum = new RegExp( "^(?:([+-])=|)(" + core_pnum + ")([a-z%]*)$", "i" ),
8636 rrun = /queueHooks$/,
8637 animationPrefilters = [ defaultPrefilter ],
8638 tweeners = {
8639 "*": [function( prop, value ) {
8640 var end, unit,
8641 tween = this.createTween( prop, value ),
8642 parts = rfxnum.exec( value ),
8643 target = tween.cur(),
8644 start = +target || 0,
8645 scale = 1,
8646 maxIterations = 20;
8647
8648 if ( parts ) {
8649 end = +parts[2];
8650 unit = parts[3] || ( jQuery.cssNumber[ prop ] ? "" : "px" );
8651
8652 // We need to compute starting value
8653 if ( unit !== "px" && start ) {
8654 // Iteratively approximate from a nonzero starting point
8655 // Prefer the current property, because this process will be trivial if it uses the same units
8656 // Fallback to end or a simple constant
8657 start = jQuery.css( tween.elem, prop, true ) || end || 1;
8658
8659 do {
8660 // If previous iteration zeroed out, double until we get *something*
8661 // Use a string for doubling factor so we don't accidentally see scale as unchanged below
8662 scale = scale || ".5";
8663
8664 // Adjust and apply
8665 start = start / scale;
8666 jQuery.style( tween.elem, prop, start + unit );
8667
8668 // Update scale, tolerating zero or NaN from tween.cur()
8669 // And breaking the loop if scale is unchanged or perfect, or if we've just had enough
8670 } while ( scale !== (scale = tween.cur() / target) && scale !== 1 && --maxIterations );
8671 }
8672
8673 tween.unit = unit;
8674 tween.start = start;
8675 // If a +=/-= token was provided, we're doing a relative animation
8676 tween.end = parts[1] ? start + ( parts[1] + 1 ) * end : end;
8677 }
8678 return tween;
8679 }]
8680 };
8681
8682 // Animations created synchronously will run synchronously
8683 function createFxNow() {
8684 setTimeout(function() {
8685 fxNow = undefined;
8686 });
8687 return ( fxNow = jQuery.now() );
8688 }
8689
8690 function createTweens( animation, props ) {
8691 jQuery.each( props, function( prop, value ) {
8692 var collection = ( tweeners[ prop ] || [] ).concat( tweeners[ "*" ] ),
8693 index = 0,
8694 length = collection.length;
8695 for ( ; index < length; index++ ) {
8696 if ( collection[ index ].call( animation, prop, value ) ) {
8697
8698 // we're done with this property
8699 return;
8700 }
8701 }
8702 });
8703 }
8704
8705 function Animation( elem, properties, options ) {
8706 var result,
8707 stopped,
8708 index = 0,
8709 length = animationPrefilters.length,
8710 deferred = jQuery.Deferred().always( function() {
8711 // don't match elem in the :animated selector
8712 delete tick.elem;
8713 }),
8714 tick = function() {
8715 if ( stopped ) {
8716 return false;
8717 }
8718 var currentTime = fxNow || createFxNow(),
8719 remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),
8720 // archaic crash bug won't allow us to use 1 - ( 0.5 || 0 ) (#12497)
8721 temp = remaining / animation.duration || 0,
8722 percent = 1 - temp,
8723 index = 0,
8724 length = animation.tweens.length;
8725
8726 for ( ; index < length ; index++ ) {
8727 animation.tweens[ index ].run( percent );
8728 }
8729
8730 deferred.notifyWith( elem, [ animation, percent, remaining ]);
8731
8732 if ( percent < 1 && length ) {
8733 return remaining;
8734 } else {
8735 deferred.resolveWith( elem, [ animation ] );
8736 return false;
8737 }
8738 },
8739 animation = deferred.promise({
8740 elem: elem,
8741 props: jQuery.extend( {}, properties ),
8742 opts: jQuery.extend( true, { specialEasing: {} }, options ),
8743 originalProperties: properties,
8744 originalOptions: options,
8745 startTime: fxNow || createFxNow(),
8746 duration: options.duration,
8747 tweens: [],
8748 createTween: function( prop, end ) {
8749 var tween = jQuery.Tween( elem, animation.opts, prop, end,
8750 animation.opts.specialEasing[ prop ] || animation.opts.easing );
8751 animation.tweens.push( tween );
8752 return tween;
8753 },
8754 stop: function( gotoEnd ) {
8755 var index = 0,
8756 // if we are going to the end, we want to run all the tweens
8757 // otherwise we skip this part
8758 length = gotoEnd ? animation.tweens.length : 0;
8759 if ( stopped ) {
8760 return this;
8761 }
8762 stopped = true;
8763 for ( ; index < length ; index++ ) {
8764 animation.tweens[ index ].run( 1 );
8765 }
8766
8767 // resolve when we played the last frame
8768 // otherwise, reject
8769 if ( gotoEnd ) {
8770 deferred.resolveWith( elem, [ animation, gotoEnd ] );
8771 } else {
8772 deferred.rejectWith( elem, [ animation, gotoEnd ] );
8773 }
8774 return this;
8775 }
8776 }),
8777 props = animation.props;
8778
8779 propFilter( props, animation.opts.specialEasing );
8780
8781 for ( ; index < length ; index++ ) {
8782 result = animationPrefilters[ index ].call( animation, elem, props, animation.opts );
8783 if ( result ) {
8784 return result;
8785 }
8786 }
8787
8788 createTweens( animation, props );
8789
8790 if ( jQuery.isFunction( animation.opts.start ) ) {
8791 animation.opts.start.call( elem, animation );
8792 }
8793
8794 jQuery.fx.timer(
8795 jQuery.extend( tick, {
8796 elem: elem,
8797 anim: animation,
8798 queue: animation.opts.queue
8799 })
8800 );
8801
8802 // attach callbacks from options
8803 return animation.progress( animation.opts.progress )
8804 .done( animation.opts.done, animation.opts.complete )
8805 .fail( animation.opts.fail )
8806 .always( animation.opts.always );
8807 }
8808
8809 function propFilter( props, specialEasing ) {
8810 var value, name, index, easing, hooks;
8811
8812 // camelCase, specialEasing and expand cssHook pass
8813 for ( index in props ) {
8814 name = jQuery.camelCase( index );
8815 easing = specialEasing[ name ];
8816 value = props[ index ];
8817 if ( jQuery.isArray( value ) ) {
8818 easing = value[ 1 ];
8819 value = props[ index ] = value[ 0 ];
8820 }
8821
8822 if ( index !== name ) {
8823 props[ name ] = value;
8824 delete props[ index ];
8825 }
8826
8827 hooks = jQuery.cssHooks[ name ];
8828 if ( hooks && "expand" in hooks ) {
8829 value = hooks.expand( value );
8830 delete props[ name ];
8831
8832 // not quite $.extend, this wont overwrite keys already present.
8833 // also - reusing 'index' from above because we have the correct "name"
8834 for ( index in value ) {
8835 if ( !( index in props ) ) {
8836 props[ index ] = value[ index ];
8837 specialEasing[ index ] = easing;
8838 }
8839 }
8840 } else {
8841 specialEasing[ name ] = easing;
8842 }
8843 }
8844 }
8845
8846 jQuery.Animation = jQuery.extend( Animation, {
8847
8848 tweener: function( props, callback ) {
8849 if ( jQuery.isFunction( props ) ) {
8850 callback = props;
8851 props = [ "*" ];
8852 } else {
8853 props = props.split(" ");
8854 }
8855
8856 var prop,
8857 index = 0,
8858 length = props.length;
8859
8860 for ( ; index < length ; index++ ) {
8861 prop = props[ index ];
8862 tweeners[ prop ] = tweeners[ prop ] || [];
8863 tweeners[ prop ].unshift( callback );
8864 }
8865 },
8866
8867 prefilter: function( callback, prepend ) {
8868 if ( prepend ) {
8869 animationPrefilters.unshift( callback );
8870 } else {
8871 animationPrefilters.push( callback );
8872 }
8873 }
8874 });
8875
8876 function defaultPrefilter( elem, props, opts ) {
8877 /*jshint validthis:true */
8878 var prop, index, length,
8879 value, dataShow, toggle,
8880 tween, hooks, oldfire,
8881 anim = this,
8882 style = elem.style,
8883 orig = {},
8884 handled = [],
8885 hidden = elem.nodeType && isHidden( elem );
8886
8887 // handle queue: false promises
8888 if ( !opts.queue ) {
8889 hooks = jQuery._queueHooks( elem, "fx" );
8890 if ( hooks.unqueued == null ) {
8891 hooks.unqueued = 0;
8892 oldfire = hooks.empty.fire;
8893 hooks.empty.fire = function() {
8894 if ( !hooks.unqueued ) {
8895 oldfire();
8896 }
8897 };
8898 }
8899 hooks.unqueued++;
8900
8901 anim.always(function() {
8902 // doing this makes sure that the complete handler will be called
8903 // before this completes
8904 anim.always(function() {
8905 hooks.unqueued--;
8906 if ( !jQuery.queue( elem, "fx" ).length ) {
8907 hooks.empty.fire();
8908 }
8909 });
8910 });
8911 }
8912
8913 // height/width overflow pass
8914 if ( elem.nodeType === 1 && ( "height" in props || "width" in props ) ) {
8915 // Make sure that nothing sneaks out
8916 // Record all 3 overflow attributes because IE does not
8917 // change the overflow attribute when overflowX and
8918 // overflowY are set to the same value
8919 opts.overflow = [ style.overflow, style.overflowX, style.overflowY ];
8920
8921 // Set display property to inline-block for height/width
8922 // animations on inline elements that are having width/height animated
8923 if ( jQuery.css( elem, "display" ) === "inline" &&
8924 jQuery.css( elem, "float" ) === "none" ) {
8925
8926 // inline-level elements accept inline-block;
8927 // block-level elements need to be inline with layout
8928 if ( !jQuery.support.inlineBlockNeedsLayout || css_defaultDisplay( elem.nodeName ) === "inline" ) {
8929 style.display = "inline-block";
8930
8931 } else {
8932 style.zoom = 1;
8933 }
8934 }
8935 }
8936
8937 if ( opts.overflow ) {
8938 style.overflow = "hidden";
8939 if ( !jQuery.support.shrinkWrapBlocks ) {
8940 anim.always(function() {
8941 style.overflow = opts.overflow[ 0 ];
8942 style.overflowX = opts.overflow[ 1 ];
8943 style.overflowY = opts.overflow[ 2 ];
8944 });
8945 }
8946 }
8947
8948
8949 // show/hide pass
8950 for ( index in props ) {
8951 value = props[ index ];
8952 if ( rfxtypes.exec( value ) ) {
8953 delete props[ index ];
8954 toggle = toggle || value === "toggle";
8955 if ( value === ( hidden ? "hide" : "show" ) ) {
8956 continue;
8957 }
8958 handled.push( index );
8959 }
8960 }
8961
8962 length = handled.length;
8963 if ( length ) {
8964 dataShow = jQuery._data( elem, "fxshow" ) || jQuery._data( elem, "fxshow", {} );
8965 if ( "hidden" in dataShow ) {
8966 hidden = dataShow.hidden;
8967 }
8968
8969 // store state if its toggle - enables .stop().toggle() to "reverse"
8970 if ( toggle ) {
8971 dataShow.hidden = !hidden;
8972 }
8973 if ( hidden ) {
8974 jQuery( elem ).show();
8975 } else {
8976 anim.done(function() {
8977 jQuery( elem ).hide();
8978 });
8979 }
8980 anim.done(function() {
8981 var prop;
8982 jQuery._removeData( elem, "fxshow" );
8983 for ( prop in orig ) {
8984 jQuery.style( elem, prop, orig[ prop ] );
8985 }
8986 });
8987 for ( index = 0 ; index < length ; index++ ) {
8988 prop = handled[ index ];
8989 tween = anim.createTween( prop, hidden ? dataShow[ prop ] : 0 );
8990 orig[ prop ] = dataShow[ prop ] || jQuery.style( elem, prop );
8991
8992 if ( !( prop in dataShow ) ) {
8993 dataShow[ prop ] = tween.start;
8994 if ( hidden ) {
8995 tween.end = tween.start;
8996 tween.start = prop === "width" || prop === "height" ? 1 : 0;
8997 }
8998 }
8999 }
9000 }
9001 }
9002
9003 function Tween( elem, options, prop, end, easing ) {
9004 return new Tween.prototype.init( elem, options, prop, end, easing );
9005 }
9006 jQuery.Tween = Tween;
9007
9008 Tween.prototype = {
9009 constructor: Tween,
9010 init: function( elem, options, prop, end, easing, unit ) {
9011 this.elem = elem;
9012 this.prop = prop;
9013 this.easing = easing || "swing";
9014 this.options = options;
9015 this.start = this.now = this.cur();
9016 this.end = end;
9017 this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" );
9018 },
9019 cur: function() {
9020 var hooks = Tween.propHooks[ this.prop ];
9021
9022 return hooks && hooks.get ?
9023 hooks.get( this ) :
9024 Tween.propHooks._default.get( this );
9025 },
9026 run: function( percent ) {
9027 var eased,
9028 hooks = Tween.propHooks[ this.prop ];
9029
9030 if ( this.options.duration ) {
9031 this.pos = eased = jQuery.easing[ this.easing ](
9032 percent, this.options.duration * percent, 0, 1, this.options.duration
9033 );
9034 } else {
9035 this.pos = eased = percent;
9036 }
9037 this.now = ( this.end - this.start ) * eased + this.start;
9038
9039 if ( this.options.step ) {
9040 this.options.step.call( this.elem, this.now, this );
9041 }
9042
9043 if ( hooks && hooks.set ) {
9044 hooks.set( this );
9045 } else {
9046 Tween.propHooks._default.set( this );
9047 }
9048 return this;
9049 }
9050 };
9051
9052 Tween.prototype.init.prototype = Tween.prototype;
9053
9054 Tween.propHooks = {
9055 _default: {
9056 get: function( tween ) {
9057 var result;
9058
9059 if ( tween.elem[ tween.prop ] != null &&
9060 (!tween.elem.style || tween.elem.style[ tween.prop ] == null) ) {
9061 return tween.elem[ tween.prop ];
9062 }
9063
9064 // passing an empty string as a 3rd parameter to .css will automatically
9065 // attempt a parseFloat and fallback to a string if the parse fails
9066 // so, simple values such as "10px" are parsed to Float.
9067 // complex values such as "rotate(1rad)" are returned as is.
9068 result = jQuery.css( tween.elem, tween.prop, "" );
9069 // Empty strings, null, undefined and "auto" are converted to 0.
9070 return !result || result === "auto" ? 0 : result;
9071 },
9072 set: function( tween ) {
9073 // use step hook for back compat - use cssHook if its there - use .style if its
9074 // available and use plain properties where available
9075 if ( jQuery.fx.step[ tween.prop ] ) {
9076 jQuery.fx.step[ tween.prop ]( tween );
9077 } else if ( tween.elem.style && ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || jQuery.cssHooks[ tween.prop ] ) ) {
9078 jQuery.style( tween.elem, tween.prop, tween.now + tween.unit );
9079 } else {
9080 tween.elem[ tween.prop ] = tween.now;
9081 }
9082 }
9083 }
9084 };
9085
9086 // Remove in 2.0 - this supports IE8's panic based approach
9087 // to setting things on disconnected nodes
9088
9089 Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {
9090 set: function( tween ) {
9091 if ( tween.elem.nodeType && tween.elem.parentNode ) {
9092 tween.elem[ tween.prop ] = tween.now;
9093 }
9094 }
9095 };
9096
9097 jQuery.each([ "toggle", "show", "hide" ], function( i, name ) {
9098 var cssFn = jQuery.fn[ name ];
9099 jQuery.fn[ name ] = function( speed, easing, callback ) {
9100 return speed == null || typeof speed === "boolean" ?
9101 cssFn.apply( this, arguments ) :
9102 this.animate( genFx( name, true ), speed, easing, callback );
9103 };
9104 });
9105
9106 jQuery.fn.extend({
9107 fadeTo: function( speed, to, easing, callback ) {
9108
9109 // show any hidden elements after setting opacity to 0
9110 return this.filter( isHidden ).css( "opacity", 0 ).show()
9111
9112 // animate to the value specified
9113 .end().animate({ opacity: to }, speed, easing, callback );
9114 },
9115 animate: function( prop, speed, easing, callback ) {
9116 var empty = jQuery.isEmptyObject( prop ),
9117 optall = jQuery.speed( speed, easing, callback ),
9118 doAnimation = function() {
9119 // Operate on a copy of prop so per-property easing won't be lost
9120 var anim = Animation( this, jQuery.extend( {}, prop ), optall );
9121 doAnimation.finish = function() {
9122 anim.stop( true );
9123 };
9124 // Empty animations, or finishing resolves immediately
9125 if ( empty || jQuery._data( this, "finish" ) ) {
9126 anim.stop( true );
9127 }
9128 };
9129 doAnimation.finish = doAnimation;
9130
9131 return empty || optall.queue === false ?
9132 this.each( doAnimation ) :
9133 this.queue( optall.queue, doAnimation );
9134 },
9135 stop: function( type, clearQueue, gotoEnd ) {
9136 var stopQueue = function( hooks ) {
9137 var stop = hooks.stop;
9138 delete hooks.stop;
9139 stop( gotoEnd );
9140 };
9141
9142 if ( typeof type !== "string" ) {
9143 gotoEnd = clearQueue;
9144 clearQueue = type;
9145 type = undefined;
9146 }
9147 if ( clearQueue && type !== false ) {
9148 this.queue( type || "fx", [] );
9149 }
9150
9151 return this.each(function() {
9152 var dequeue = true,
9153 index = type != null && type + "queueHooks",
9154 timers = jQuery.timers,
9155 data = jQuery._data( this );
9156
9157 if ( index ) {
9158 if ( data[ index ] && data[ index ].stop ) {
9159 stopQueue( data[ index ] );
9160 }
9161 } else {
9162 for ( index in data ) {
9163 if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {
9164 stopQueue( data[ index ] );
9165 }
9166 }
9167 }
9168
9169 for ( index = timers.length; index--; ) {
9170 if ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) {
9171 timers[ index ].anim.stop( gotoEnd );
9172 dequeue = false;
9173 timers.splice( index, 1 );
9174 }
9175 }
9176
9177 // start the next in the queue if the last step wasn't forced
9178 // timers currently will call their complete callbacks, which will dequeue
9179 // but only if they were gotoEnd
9180 if ( dequeue || !gotoEnd ) {
9181 jQuery.dequeue( this, type );
9182 }
9183 });
9184 },
9185 finish: function( type ) {
9186 if ( type !== false ) {
9187 type = type || "fx";
9188 }
9189 return this.each(function() {
9190 var index,
9191 data = jQuery._data( this ),
9192 queue = data[ type + "queue" ],
9193 hooks = data[ type + "queueHooks" ],
9194 timers = jQuery.timers,
9195 length = queue ? queue.length : 0;
9196
9197 // enable finishing flag on private data
9198 data.finish = true;
9199
9200 // empty the queue first
9201 jQuery.queue( this, type, [] );
9202
9203 if ( hooks && hooks.cur && hooks.cur.finish ) {
9204 hooks.cur.finish.call( this );
9205 }
9206
9207 // look for any active animations, and finish them
9208 for ( index = timers.length; index--; ) {
9209 if ( timers[ index ].elem === this && timers[ index ].queue === type ) {
9210 timers[ index ].anim.stop( true );
9211 timers.splice( index, 1 );
9212 }
9213 }
9214
9215 // look for any animations in the old queue and finish them
9216 for ( index = 0; index < length; index++ ) {
9217 if ( queue[ index ] && queue[ index ].finish ) {
9218 queue[ index ].finish.call( this );
9219 }
9220 }
9221
9222 // turn off finishing flag
9223 delete data.finish;
9224 });
9225 }
9226 });
9227
9228 // Generate parameters to create a standard animation
9229 function genFx( type, includeWidth ) {
9230 var which,
9231 attrs = { height: type },
9232 i = 0;
9233
9234 // if we include width, step value is 1 to do all cssExpand values,
9235 // if we don't include width, step value is 2 to skip over Left and Right
9236 includeWidth = includeWidth? 1 : 0;
9237 for( ; i < 4 ; i += 2 - includeWidth ) {
9238 which = cssExpand[ i ];
9239 attrs[ "margin" + which ] = attrs[ "padding" + which ] = type;
9240 }
9241
9242 if ( includeWidth ) {
9243 attrs.opacity = attrs.width = type;
9244 }
9245
9246 return attrs;
9247 }
9248
9249 // Generate shortcuts for custom animations
9250 jQuery.each({
9251 slideDown: genFx("show"),
9252 slideUp: genFx("hide"),
9253 slideToggle: genFx("toggle"),
9254 fadeIn: { opacity: "show" },
9255 fadeOut: { opacity: "hide" },
9256 fadeToggle: { opacity: "toggle" }
9257 }, function( name, props ) {
9258 jQuery.fn[ name ] = function( speed, easing, callback ) {
9259 return this.animate( props, speed, easing, callback );
9260 };
9261 });
9262
9263 jQuery.speed = function( speed, easing, fn ) {
9264 var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
9265 complete: fn || !fn && easing ||
9266 jQuery.isFunction( speed ) && speed,
9267 duration: speed,
9268 easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing
9269 };
9270
9271 opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
9272 opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;
9273
9274 // normalize opt.queue - true/undefined/null -> "fx"
9275 if ( opt.queue == null || opt.queue === true ) {
9276 opt.queue = "fx";
9277 }
9278
9279 // Queueing
9280 opt.old = opt.complete;
9281
9282 opt.complete = function() {
9283 if ( jQuery.isFunction( opt.old ) ) {
9284 opt.old.call( this );
9285 }
9286
9287 if ( opt.queue ) {
9288 jQuery.dequeue( this, opt.queue );
9289 }
9290 };
9291
9292 return opt;
9293 };
9294
9295 jQuery.easing = {
9296 linear: function( p ) {
9297 return p;
9298 },
9299 swing: function( p ) {
9300 return 0.5 - Math.cos( p*Math.PI ) / 2;
9301 }
9302 };
9303
9304 jQuery.timers = [];
9305 jQuery.fx = Tween.prototype.init;
9306 jQuery.fx.tick = function() {
9307 var timer,
9308 timers = jQuery.timers,
9309 i = 0;
9310
9311 fxNow = jQuery.now();
9312
9313 for ( ; i < timers.length; i++ ) {
9314 timer = timers[ i ];
9315 // Checks the timer has not already been removed
9316 if ( !timer() && timers[ i ] === timer ) {
9317 timers.splice( i--, 1 );
9318 }
9319 }
9320
9321 if ( !timers.length ) {
9322 jQuery.fx.stop();
9323 }
9324 fxNow = undefined;
9325 };
9326
9327 jQuery.fx.timer = function( timer ) {
9328 if ( timer() && jQuery.timers.push( timer ) ) {
9329 jQuery.fx.start();
9330 }
9331 };
9332
9333 jQuery.fx.interval = 13;
9334
9335 jQuery.fx.start = function() {
9336 if ( !timerId ) {
9337 timerId = setInterval( jQuery.fx.tick, jQuery.fx.interval );
9338 }
9339 };
9340
9341 jQuery.fx.stop = function() {
9342 clearInterval( timerId );
9343 timerId = null;
9344 };
9345
9346 jQuery.fx.speeds = {
9347 slow: 600,
9348 fast: 200,
9349 // Default speed
9350 _default: 400
9351 };
9352
9353 // Back Compat <1.8 extension point
9354 jQuery.fx.step = {};
9355
9356 if ( jQuery.expr && jQuery.expr.filters ) {
9357 jQuery.expr.filters.animated = function( elem ) {
9358 return jQuery.grep(jQuery.timers, function( fn ) {
9359 return elem === fn.elem;
9360 }).length;
9361 };
9362 }
9363 jQuery.fn.offset = function( options ) {
9364 if ( arguments.length ) {
9365 return options === undefined ?
9366 this :
9367 this.each(function( i ) {
9368 jQuery.offset.setOffset( this, options, i );
9369 });
9370 }
9371
9372 var docElem, win,
9373 box = { top: 0, left: 0 },
9374 elem = this[ 0 ],
9375 doc = elem && elem.ownerDocument;
9376
9377 if ( !doc ) {
9378 return;
9379 }
9380
9381 docElem = doc.documentElement;
9382
9383 // Make sure it's not a disconnected DOM node
9384 if ( !jQuery.contains( docElem, elem ) ) {
9385 return box;
9386 }
9387
9388 // If we don't have gBCR, just use 0,0 rather than error
9389 // BlackBerry 5, iOS 3 (original iPhone)
9390 if ( typeof elem.getBoundingClientRect !== core_strundefined ) {
9391 box = elem.getBoundingClientRect();
9392 }
9393 win = getWindow( doc );
9394 return {
9395 top: box.top + ( win.pageYOffset || docElem.scrollTop ) - ( docElem.clientTop || 0 ),
9396 left: box.left + ( win.pageXOffset || docElem.scrollLeft ) - ( docElem.clientLeft || 0 )
9397 };
9398 };
9399
9400 jQuery.offset = {
9401
9402 setOffset: function( elem, options, i ) {
9403 var position = jQuery.css( elem, "position" );
9404
9405 // set position first, in-case top/left are set even on static elem
9406 if ( position === "static" ) {
9407 elem.style.position = "relative";
9408 }
9409
9410 var curElem = jQuery( elem ),
9411 curOffset = curElem.offset(),
9412 curCSSTop = jQuery.css( elem, "top" ),
9413 curCSSLeft = jQuery.css( elem, "left" ),
9414 calculatePosition = ( position === "absolute" || position === "fixed" ) && jQuery.inArray("auto", [curCSSTop, curCSSLeft]) > -1,
9415 props = {}, curPosition = {}, curTop, curLeft;
9416
9417 // need to be able to calculate position if either top or left is auto and position is either absolute or fixed
9418 if ( calculatePosition ) {
9419 curPosition = curElem.position();
9420 curTop = curPosition.top;
9421 curLeft = curPosition.left;
9422 } else {
9423 curTop = parseFloat( curCSSTop ) || 0;
9424 curLeft = parseFloat( curCSSLeft ) || 0;
9425 }
9426
9427 if ( jQuery.isFunction( options ) ) {
9428 options = options.call( elem, i, curOffset );
9429 }
9430
9431 if ( options.top != null ) {
9432 props.top = ( options.top - curOffset.top ) + curTop;
9433 }
9434 if ( options.left != null ) {
9435 props.left = ( options.left - curOffset.left ) + curLeft;
9436 }
9437
9438 if ( "using" in options ) {
9439 options.using.call( elem, props );
9440 } else {
9441 curElem.css( props );
9442 }
9443 }
9444 };
9445
9446
9447 jQuery.fn.extend({
9448
9449 position: function() {
9450 if ( !this[ 0 ] ) {
9451 return;
9452 }
9453
9454 var offsetParent, offset,
9455 parentOffset = { top: 0, left: 0 },
9456 elem = this[ 0 ];
9457
9458 // fixed elements are offset from window (parentOffset = {top:0, left: 0}, because it is it's only offset parent
9459 if ( jQuery.css( elem, "position" ) === "fixed" ) {
9460 // we assume that getBoundingClientRect is available when computed position is fixed
9461 offset = elem.getBoundingClientRect();
9462 } else {
9463 // Get *real* offsetParent
9464 offsetParent = this.offsetParent();
9465
9466 // Get correct offsets
9467 offset = this.offset();
9468 if ( !jQuery.nodeName( offsetParent[ 0 ], "html" ) ) {
9469 parentOffset = offsetParent.offset();
9470 }
9471
9472 // Add offsetParent borders
9473 parentOffset.top += jQuery.css( offsetParent[ 0 ], "borderTopWidth", true );
9474 parentOffset.left += jQuery.css( offsetParent[ 0 ], "borderLeftWidth", true );
9475 }
9476
9477 // Subtract parent offsets and element margins
9478 // note: when an element has margin: auto the offsetLeft and marginLeft
9479 // are the same in Safari causing offset.left to incorrectly be 0
9480 return {
9481 top: offset.top - parentOffset.top - jQuery.css( elem, "marginTop", true ),
9482 left: offset.left - parentOffset.left - jQuery.css( elem, "marginLeft", true)
9483 };
9484 },
9485
9486 offsetParent: function() {
9487 return this.map(function() {
9488 var offsetParent = this.offsetParent || document.documentElement;
9489 while ( offsetParent && ( !jQuery.nodeName( offsetParent, "html" ) && jQuery.css( offsetParent, "position") === "static" ) ) {
9490 offsetParent = offsetParent.offsetParent;
9491 }
9492 return offsetParent || document.documentElement;
9493 });
9494 }
9495 });
9496
9497
9498 // Create scrollLeft and scrollTop methods
9499 jQuery.each( {scrollLeft: "pageXOffset", scrollTop: "pageYOffset"}, function( method, prop ) {
9500 var top = /Y/.test( prop );
9501
9502 jQuery.fn[ method ] = function( val ) {
9503 return jQuery.access( this, function( elem, method, val ) {
9504 var win = getWindow( elem );
9505
9506 if ( val === undefined ) {
9507 return win ? (prop in win) ? win[ prop ] :
9508 win.document.documentElement[ method ] :
9509 elem[ method ];
9510 }
9511
9512 if ( win ) {
9513 win.scrollTo(
9514 !top ? val : jQuery( win ).scrollLeft(),
9515 top ? val : jQuery( win ).scrollTop()
9516 );
9517
9518 } else {
9519 elem[ method ] = val;
9520 }
9521 }, method, val, arguments.length, null );
9522 };
9523 });
9524
9525 function getWindow( elem ) {
9526 return jQuery.isWindow( elem ) ?
9527 elem :
9528 elem.nodeType === 9 ?
9529 elem.defaultView || elem.parentWindow :
9530 false;
9531 }
9532 // Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods
9533 jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
9534 jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name }, function( defaultExtra, funcName ) {
9535 // margin is only for outerHeight, outerWidth
9536 jQuery.fn[ funcName ] = function( margin, value ) {
9537 var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ),
9538 extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" );
9539
9540 return jQuery.access( this, function( elem, type, value ) {
9541 var doc;
9542
9543 if ( jQuery.isWindow( elem ) ) {
9544 // As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there
9545 // isn't a whole lot we can do. See pull request at this URL for discussion:
9546 // https://github.com/jquery/jquery/pull/764
9547 return elem.document.documentElement[ "client" + name ];
9548 }
9549
9550 // Get document width or height
9551 if ( elem.nodeType === 9 ) {
9552 doc = elem.documentElement;
9553
9554 // Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height], whichever is greatest
9555 // unfortunately, this causes bug #3838 in IE6/8 only, but there is currently no good, small way to fix it.
9556 return Math.max(
9557 elem.body[ "scroll" + name ], doc[ "scroll" + name ],
9558 elem.body[ "offset" + name ], doc[ "offset" + name ],
9559 doc[ "client" + name ]
9560 );
9561 }
9562
9563 return value === undefined ?
9564 // Get width or height on the element, requesting but not forcing parseFloat
9565 jQuery.css( elem, type, extra ) :
9566
9567 // Set width or height on the element
9568 jQuery.style( elem, type, value, extra );
9569 }, type, chainable ? margin : undefined, chainable, null );
9570 };
9571 });
9572 });
9573 // Limit scope pollution from any deprecated API
9574 // (function() {
9575
9576 // })();
9577 // Expose jQuery to the global object
9578 window.jQuery = window.$ = jQuery;
9579
9580 // Expose jQuery as an AMD module, but only for AMD loaders that
9581 // understand the issues with loading multiple versions of jQuery
9582 // in a page that all might call define(). The loader will indicate
9583 // they have special allowances for multiple jQuery versions by
9584 // specifying define.amd.jQuery = true. Register as a named module,
9585 // since jQuery can be concatenated with other files that may use define,
9586 // but not use a proper concatenation script that understands anonymous
9587 // AMD modules. A named AMD is safest and most robust way to register.
9588 // Lowercase jquery is used because AMD module names are derived from
9589 // file names, and jQuery is normally delivered in a lowercase file name.
9590 // Do this after creating the global so that if an AMD module wants to call
9591 // noConflict to hide this version of jQuery, it will work.
9592 if ( typeof define === "function" && define.amd && define.amd.jQuery ) {
9593 define( "jquery", [], function () { return jQuery; } );
9594 }
9595
9596 })( window );
0 var path = require('path');
1 var fs = require('fs');
2 var visit = require("ast-types").visit;
3 var parse = require("esprima").parse;
4
5 var backbone = fs.readFileSync(
6 path.join(__dirname, "data", "backbone.js"),
7 "utf-8"
8 );
9
10 var ast = parse(backbone);
11
12 var names = [];
13 var start = +new Date;
14
15 visit(ast, {
16 visitNode: function(path) {
17 names.push(path.name);
18 this.traverse(path);
19 }
20 });
21
22 console.log(names.length);
23 console.log(new Date - start, "ms");
0 var assert = require("assert");
1 var types = require("../main");
2 var n = types.namedTypes;
3 var b = types.builders;
4 var path = require("path");
5 var fs = require("fs");
6 var parse = require("esprima").parse;
7 var Path = require("../lib/path");
8 var NodePath = require("../lib/node-path");
9 var PathVisitor = require("../lib/path-visitor");
10 var builtin = types.builtInTypes
11 var isRegExp = builtin.RegExp;
12 var isString = builtin.string;
13 var rawTypes = require("../lib/types");
14
15 var hasOwn = Object.prototype.hasOwnProperty;
16
17 describe("basic type checking", function() {
18 var fooId = b.identifier("foo");
19 var ifFoo = b.ifStatement(fooId, b.blockStatement([
20 b.expressionStatement(b.callExpression(fooId, []))
21 ]));
22
23 it("should exhibit sanity", function() {
24 assert.ok(n.IfStatement.check(ifFoo));
25 assert.ok(n.Statement.check(ifFoo));
26 assert.ok(n.Node.check(ifFoo));
27
28 assert.ok(n.BlockStatement.check(ifFoo.consequent));
29 assert.strictEqual(
30 ifFoo.consequent.body[0].expression.arguments.length,
31 0);
32
33 assert.strictEqual(ifFoo.test, fooId);
34 assert.ok(n.Expression.check(ifFoo.test));
35 assert.ok(n.Identifier.check(ifFoo.test));
36 assert.ok(!n.Statement.check(ifFoo.test));
37 assert.ok(n.ImportDeclaration.check(
38 b.importDeclaration(
39 [b.importDefaultSpecifier(b.identifier("foo"))], b.literal("bar"))
40 )
41 );
42 assert.ok(n.ImportDeclaration.check(
43 b.importDeclaration(
44 [b.importNamespaceSpecifier(b.identifier("foo"))], b.literal("bar"))
45 )
46 );
47 });
48 });
49
50 describe("isSupertypeOf", function() {
51 it("should report correct supertype relationships", function() {
52 var def = types.Type.def;
53
54 assert.ok(def("Node").isSupertypeOf(def("Node")));
55 assert.ok(def("Node").isSupertypeOf(def("Expression")));
56 assert.ok(!def("Expression").isSupertypeOf(def("Node")));
57 assert.ok(!def("Expression").isSupertypeOf(
58 def("DebuggerStatement")));
59
60 // TODO Make this test case more exhaustive.
61 });
62 });
63
64 describe("supertype lookup", function() {
65 it("should resolve the most precise supertypes", function() {
66 var table = require("../lib/types").computeSupertypeLookupTable({
67 Function: true,
68 Declaration: true,
69 ArrowFunctionExpression: true,
70 Expression: true,
71 Identifier: true
72 });
73
74 function check(subtype, expectedSupertype) {
75 assert.strictEqual(table[subtype], expectedSupertype);
76 }
77
78 check("FunctionExpression", "Function");
79 check("FunctionDeclaration", "Function");
80 check("VariableDeclaration", "Declaration");
81 check("Identifier", "Identifier");
82 check("ArrowFunctionExpression", "ArrowFunctionExpression");
83 check("ForInStatement");
84 check("Node");
85 check("ThisExpression", "Expression");
86 check("Property");
87 });
88
89 it("should properly linearize the inheritance hierarchy", function() {
90 assert.deepEqual(
91 types.getSupertypeNames("FunctionExpression"),
92 ["Function", "Expression", "Pattern", "Node", "Printable"]
93 );
94 });
95
96 it("should trigger an AssertionError for unknown types", function() {
97 assert.throws(function() {
98 types.getSupertypeNames("AlienBoomerangDeclaration");
99 });
100 });
101 });
102
103 describe("shallow and deep checks", function() {
104 var index = b.identifier("foo");
105 var decl = b.variableDeclaration("var", [
106 b.variableDeclarator(
107 index,
108 b.literal(42)
109 )
110 ]);
111
112 it("should work when shallow", function() {
113 assert.ok(n.Node.check(decl));
114 assert.ok(n.Statement.check(decl));
115 assert.ok(n.Declaration.check(decl));
116 assert.ok(n.VariableDeclaration.check(decl));
117 });
118
119 it("should work when deep", function() {
120 assert.ok(n.Node.check(decl, true));
121 assert.ok(n.Statement.check(decl, true));
122 assert.ok(n.Declaration.check(decl, true));
123 assert.ok(n.VariableDeclaration.check(decl, true));
124 });
125
126 it("should fail when expected", function() {
127 // Not an Expression.
128 assert.ok(!n.Expression.check(decl));
129
130 // This makes decl cease to conform to n.VariableDeclaration.
131 decl.declarations.push(b.literal("bar"));
132
133 assert.ok(n.Node.check(decl));
134 assert.ok(n.Statement.check(decl));
135 assert.ok(n.Declaration.check(decl));
136 assert.ok(n.VariableDeclaration.check(decl));
137
138 assert.ok(!n.Node.check(decl, true));
139 assert.ok(!n.Statement.check(decl, true));
140 assert.ok(!n.Declaration.check(decl, true));
141
142 // As foretold above.
143 assert.ok(!n.VariableDeclaration.check(decl, true));
144
145 // Still not an Expression.
146 assert.ok(!n.Expression.check(decl));
147 });
148
149 var fs = b.forStatement(
150 decl,
151 b.binaryExpression("<", index, b.literal(48)),
152 b.updateExpression("++", index, true),
153 b.blockStatement([
154 b.expressionStatement(
155 b.callExpression(index, [])
156 )
157 ])
158 );
159
160 it("should disagree according to depth", function() {
161 assert.ok(n.Node.check(fs));
162 assert.ok(n.Statement.check(fs));
163 assert.ok(n.ForStatement.check(fs));
164
165 // Not a true ForStatement because fs.init is not a true
166 // VariableDeclaration.
167 assert.ok(!n.Node.check(fs, true));
168 assert.ok(!n.Statement.check(fs, true));
169 assert.ok(!n.ForStatement.check(fs, true));
170 });
171 });
172
173 function validateProgram(file) {
174 var fullPath = path.join(__dirname, "..", file);
175
176 it("should validate " + file + " with Esprima", function(done) {
177 var parse = require("esprima").parse;
178
179 fs.readFile(fullPath, "utf8", function(err, code) {
180 if (err) throw err;
181
182 n.Program.assert(parse(code), true);
183 n.Program.assert(parse(code, { loc: true }), true);
184
185 done();
186 });
187 });
188
189 it("should validate " + file + " with Babel", function(done) {
190 var parse = require("babel-core").parse;
191
192 fs.readFile(fullPath, "utf8", function(err, code) {
193 if (err) throw err;
194 var ast = parse(code);
195 n.Program.assert(ast, true);
196 done();
197 });
198 });
199 }
200
201 describe("whole-program validation", function() {
202 this.timeout(20000);
203
204 validateProgram("main.js");
205 validateProgram("lib/shared.js");
206 validateProgram("def/core.js");
207 validateProgram("lib/types.js");
208 validateProgram("test/run.js");
209 validateProgram("test/data/backbone.js");
210 validateProgram("test/data/jquery-1.9.1.js");
211 });
212
213 describe("esprima Syntax types", function() {
214 var def = types.Type.def;
215 var typeNames = {};
216
217 function addTypeName(name) {
218 typeNames[name] = name;
219 }
220
221 Object.keys(require("esprima").Syntax).forEach(addTypeName);
222 Object.keys(require("esprima-fb").Syntax).forEach(addTypeName);
223 Object.keys(
224 require("babel-core").types.VISITOR_KEYS
225 ).forEach(addTypeName);
226
227 it("should all be buildable", function() {
228 Object.keys(typeNames).forEach(function(name) {
229 assert.ok(hasOwn.call(n, name), name);
230 assert.strictEqual(def(name).buildable, true, name);
231 });
232 });
233
234 it("builders for subtypes of Expression should have equivalent ExpressionStatement builders", function() {
235 Object.keys(typeNames).forEach(function(name) {
236 if (def(name).buildable &&
237 def("Expression").isSupertypeOf(def(name))) {
238 var statementBuilderName = rawTypes.getStatementBuilderName(name);
239 assert.ok(b[statementBuilderName], name + ":" +statementBuilderName);
240 }
241 });
242
243 // sanity check
244 var expStmt = b.assignmentStatement("=", b.identifier("a"), b.identifier("b"));
245 assert.strictEqual(expStmt.type, "ExpressionStatement");
246 });
247 });
248
249 describe("types.getFieldValue", function() {
250 it("should work for explicit fields", function() {
251 assert.strictEqual(
252 types.getFieldValue({
253 type: "CatchClause"
254 }, "type"),
255 "CatchClause"
256 );
257
258 assert.strictEqual(
259 types.getFieldValue({
260 type: "CatchClause",
261 guard: b.identifier("test")
262 }, "guard").name,
263 "test"
264 );
265 });
266
267 it("should work for implicit/default fields", function() {
268 assert.strictEqual(
269 types.getFieldValue({
270 type: "CatchClause"
271 }, "guard"),
272 null
273 );
274
275 assert.strictEqual(
276 types.getFieldValue({
277 type: "CatchClause"
278 }, "asdf"),
279 void 0
280 );
281
282 assert.deepEqual(
283 types.getFieldValue({
284 type: "TryStatement",
285 }, "handler"),
286 null
287 );
288
289 assert.deepEqual(
290 types.getFieldValue({
291 type: "TryStatement",
292 }, "handlers"),
293 []
294 );
295
296 assert.deepEqual(
297 types.getFieldValue({
298 type: "TryStatement",
299 }, "guardedHandlers"),
300 []
301 );
302 });
303
304 it("should work for explicitly undefined fields", function() {
305 assert.deepEqual(
306 types.getFieldValue({
307 type: "TryStatement",
308 guardedHandlers: void 0
309 }, "guardedHandlers"),
310 []
311 );
312 });
313 });
314
315 describe("types.eachField", function() {
316 var context = {};
317
318 function check(node, names) {
319 var seen = [];
320
321 types.eachField(node, function(name, value) {
322 assert.strictEqual(this, context);
323 if (name === "type")
324 assert.strictEqual(node.type, value);
325 seen.push(name);
326 }, context);
327
328 assert.deepEqual(seen.sort(), names.sort());
329 }
330
331 it("should give correct keys for supertypes", function() {
332 check({ type: "Expression" }, ["type"]);
333 });
334
335 it("should work for non-buildable types", function() {
336 check({ type: "Position" }, [
337 "type", "line", "column"
338 ]);
339
340 check({ type: "SourceLocation" }, [
341 "type", "start", "end", "source"
342 ]);
343 });
344
345 it("should respect hidden fields", function() {
346 check({ type: "TryStatement" }, [
347 // Note that the "handlers" field is now hidden from eachField.
348 "type", "block", "handler", "guardedHandlers", "finalizer"
349 ]);
350 });
351
352 check({ type: "CatchClause" }, [
353 "type", "param", "guard", "body"
354 ]);
355
356 it("should complain about invalid types", function() {
357 assert.throws(function() {
358 check({ type: "asdf" }, ["type"]);
359 }, "did not recognize object of type " + JSON.stringify("asdf"));
360 });
361
362 it("should infer SourceLocation types", function() {
363 check({
364 line: 10,
365 column: 37
366 }, ["line", "column"]);
367 });
368 });
369
370 describe("types.visit", function() {
371 var call = b.expressionStatement(
372 b.callExpression(
373 b.memberExpression(
374 b.identifier("foo"),
375 b.identifier("bar"),
376 false
377 ),
378 [b.literal("baz")]
379 )
380 );
381
382 var ts = b.tryStatement(
383 b.blockStatement([call, call]),
384 b.catchClause(
385 b.identifier("err"),
386 null,
387 b.blockStatement([])
388 )
389 );
390
391 it("should have correct .parent path", function() {
392 var literalCount = 0;
393
394 n.TryStatement.assert(types.visit(ts, {
395 visitLiteral: function(path) {
396 var node = path.node;
397 literalCount += 1;
398 assert.strictEqual(node.value, "baz");
399 assert.strictEqual(path.parent.node, call.expression);
400 assert.strictEqual(path.parent.parent.node, call);
401 assert.strictEqual(path.parent.parent.parent.node, ts.block);
402 assert.strictEqual(path.parent.parent.parent.parent.node, ts);
403 assert.strictEqual(path.parent.parent.parent.parent.parent, null);
404 this.traverse(path);
405 }
406 }), true);
407
408 assert.strictEqual(literalCount, 2);
409 });
410
411 it("should abort subtree traversal when false returned", function() {
412 var ids = {};
413
414 types.visit(ts, {
415 visitMemberExpression: function(path) {
416 return false;
417 },
418
419 visitIdentifier: function(path) {
420 ids[path.node.name] = true;
421 this.traverse(path);
422 }
423 });
424
425 // Make sure all identifers beneath member expressions were skipped.
426 assert.deepEqual(ids, { err: true });
427
428 ids = {};
429
430 types.visit(ts, {
431 visitIdentifier: function(path) {
432 ids[path.node.name] = true;
433 this.traverse(path);
434 }
435 });
436
437 // Now make sure those identifiers (foo and bar) were visited.
438 assert.deepEqual(ids, {
439 err: true,
440 foo: true,
441 bar: true
442 });
443 });
444
445 it("this.abort() should abort entire traversal", function() {
446 var literal = "not visited";
447 var unvisitedTypes = [];
448 var root = types.visit(call, {
449 visitIdentifier: function(path) {
450 if (path.value.name === "foo") {
451 this.abort();
452 }
453 },
454
455 visitLiteral: function(path) {
456 literal = path.value;
457 this.traverse(path);
458 },
459
460 visitNode: function(path) {
461 unvisitedTypes.push(path.value.type);
462 this.traverse(path);
463 }
464 });
465
466 assert.strictEqual(root, call);
467 assert.strictEqual(literal, "not visited");
468 assert.deepEqual(unvisitedTypes, [
469 "ExpressionStatement",
470 "CallExpression",
471 "MemberExpression"
472 ]);
473 });
474
475 it("this.abort() should be cancelable", function() {
476 var literal = "not visited";
477 var unvisitedTypes = [];
478 var root = types.visit(call, {
479 visitIdentifier: function(path) {
480 if (path.value.name === "foo") {
481 this.abort();
482 }
483 },
484
485 visitMemberExpression: function(path) {
486 try {
487 this.traverse(path);
488 } catch (err) {
489 assert.ok(err instanceof this.AbortRequest);
490 err.cancel();
491 }
492 },
493
494 visitLiteral: function(path) {
495 literal = path.value;
496 this.traverse(path);
497 },
498
499 visitNode: function(path) {
500 unvisitedTypes.push(path.value.type);
501 this.traverse(path);
502 }
503 });
504
505 assert.strictEqual(root, call);
506
507 n.Literal.assert(literal);
508 assert.strictEqual(literal.value, "baz");
509 assert.strictEqual(literal, call.expression.arguments[0]);
510
511 assert.deepEqual(unvisitedTypes, [
512 "ExpressionStatement",
513 "CallExpression"
514 // Note that the MemberExpression and the Literal were visited
515 // by their type-specific methods, so they were not visited by
516 // the catch-all visitNode method.
517 ]);
518 });
519
520 it("should visit comments", function() {
521 var ast = parse([
522 "function getArgs(/*arguments*/) {",
523 " // Turn arguments into an array.",
524 " return Array.prototype.slice.call(arguments);",
525 "}"
526 ].join("\n"), {
527 comment: true
528 });
529
530 var blockComments = [];
531 var lineComments = [];
532
533 types.visit(ast, {
534 visitComment: function(path) {
535 this.traverse(path);
536 if (n.Block.check(path.value)) {
537 blockComments.push(path.value);
538 } else if (n.Line.check(path.value)) {
539 lineComments.push(path.value);
540 }
541 }
542 });
543
544 assert.strictEqual(blockComments.length, 1);
545 assert.strictEqual(blockComments[0].value, "arguments");
546
547 assert.strictEqual(lineComments.length, 1);
548 assert.strictEqual(
549 lineComments[0].value,
550 " Turn arguments into an array."
551 );
552
553 blockComments.length = 0;
554 lineComments.length = 0;
555
556 types.visit(ast, {
557 visitBlock: function(path) {
558 blockComments.push(path.value);
559 this.traverse(path);
560 }
561 });
562
563 assert.strictEqual(blockComments.length, 1);
564 assert.strictEqual(blockComments[0].value, "arguments");
565
566 assert.strictEqual(lineComments.length, 0);
567
568 blockComments.length = 0;
569 lineComments.length = 0;
570
571 types.visit(ast, {
572 visitLine: function(path) {
573 lineComments.push(path.value);
574 this.traverse(path);
575 }
576 });
577
578 assert.strictEqual(blockComments.length, 0);
579
580 assert.strictEqual(lineComments.length, 1);
581 assert.strictEqual(
582 lineComments[0].value,
583 " Turn arguments into an array."
584 );
585
586 blockComments.length = 0;
587 lineComments.length = 0;
588
589 types.visit(ast, {
590 visitBlock: function(path) {
591 blockComments.push(path.value);
592 this.traverse(path);
593 },
594
595 visitLine: function(path) {
596 lineComments.push(path.value);
597 this.traverse(path);
598 }
599 });
600
601 assert.strictEqual(blockComments.length, 1);
602 assert.strictEqual(blockComments[0].value, "arguments");
603
604 assert.strictEqual(lineComments.length, 1);
605 assert.strictEqual(
606 lineComments[0].value,
607 " Turn arguments into an array."
608 );
609 });
610 });
611
612 describe("path traversal", function() {
613 var call = b.expressionStatement(
614 b.callExpression(
615 b.memberExpression(
616 b.identifier("foo"),
617 b.identifier("bar"),
618 false
619 ),
620 [b.literal("baz")]
621 )
622 );
623
624 it("should accept root paths as well as AST nodes", function() {
625 var path = new NodePath(call).get("expression", "callee");
626 var idCount = 0;
627
628 // Note that we're passing a path instead of a node as the first
629 // argument to types.traverse.
630 types.visit(path, {
631 visitIdentifier: function(path) {
632 var node = path.node;
633 ++idCount;
634
635 if (node.name === "bar") {
636 n.MemberExpression.assert(path.parent.node);
637 n.CallExpression.assert(path.parent.parent.node);
638 n.ExpressionStatement.assert(path.parent.parent.parent.node);
639 }
640
641 this.traverse(path);
642 }
643 });
644
645 assert.strictEqual(idCount, 2);
646 });
647 });
648
649 describe("replacing the root", function() {
650 var ast = b.expressionStatement(
651 b.unaryExpression("!", b.sequenceExpression([
652 b.identifier("a"),
653 b.identifier("b"),
654 b.identifier("c")
655 ]))
656 );
657
658 it("should be possible", function() {
659 var callExp = types.visit(ast, {
660 visitExpressionStatement: function(path) {
661 path.replace(b.callExpression(b.identifier("f"), [
662 path.node.expression
663 ]));
664
665 this.traverse(path);
666 }
667 });
668
669 n.CallExpression.assert(callExp, true);
670 });
671 });
672
673 describe("NodePath", function() {
674 it("should have the expected type hierarchy", function() {
675 assert.strictEqual(new Path({}).constructor, Path);
676
677 var np = new NodePath(b.identifier("foo"));
678 assert.strictEqual(np.constructor, NodePath);
679 assert.ok(np.get("name") instanceof NodePath);
680 });
681
682 var ast = b.expressionStatement(
683 b.unaryExpression("!", b.sequenceExpression([
684 b.identifier("a"),
685 b.identifier("b"),
686 b.identifier("c")
687 ]))
688 );
689
690 var path = new NodePath(ast);
691
692 it("should have sane values, nodes, parents", function() {
693 var opPath = path.get("expression", "operator");
694 assert.strictEqual(opPath.value, "!");
695 assert.strictEqual(opPath.node, ast.expression);
696 assert.strictEqual(opPath.parent, path);
697 assert.strictEqual(opPath.parent.node, ast);
698 });
699
700 var binaryYield = b.expressionStatement(
701 b.logicalExpression(
702 "&&",
703 b.yieldExpression(b.identifier("a"), false),
704 b.yieldExpression(b.identifier("b"), true)
705 )
706 );
707
708 it("should support .needsParens()", function() {
709 var argPath = path.get("expression", "argument");
710 assert.ok(argPath.needsParens());
711
712 var exprsPath = argPath.get("expressions");
713 assert.ok(!exprsPath.needsParens());
714 assert.strictEqual(exprsPath.get("length").value, 3);
715 assert.ok(!exprsPath.get(1).needsParens());
716
717 var byPath = new NodePath(binaryYield);
718 assert.ok(!byPath.get("expression").needsParens());
719 assert.ok(byPath.get("expression", "left").needsParens());
720 assert.ok(byPath.get("expression", "right").needsParens());
721
722 var sequenceAssignmentAST = b.assignmentExpression(
723 '=',
724 b.identifier('a'),
725 b.sequenceExpression([b.literal(1), b.literal(2)])
726 );
727
728 var sequenceAssignmentPath = new NodePath(sequenceAssignmentAST);
729 assert.ok(sequenceAssignmentPath.get("right").needsParens());
730 });
731
732 it("should support .needsParens(true)", function() {
733 var programPath = new NodePath(parse("(function(){})"));
734 var funExpPath = programPath.get("body", 0, "expression");
735 n.FunctionExpression.assert(funExpPath.value);
736 assert.strictEqual(funExpPath.needsParens(), true);
737 assert.strictEqual(funExpPath.canBeFirstInStatement(), false);
738 assert.strictEqual(funExpPath.firstInStatement(), true);
739 assert.strictEqual(funExpPath.needsParens(true), false);
740
741 programPath = new NodePath(parse("({ foo: 42 })"));
742 var objLitPath = programPath.get("body", 0, "expression");
743 n.ObjectExpression.assert(objLitPath.value);
744 assert.strictEqual(objLitPath.needsParens(), true);
745 assert.strictEqual(objLitPath.canBeFirstInStatement(), false);
746 assert.strictEqual(objLitPath.firstInStatement(), true);
747 assert.strictEqual(objLitPath.needsParens(true), false);
748 });
749
750 it("should prune redundant variable declaration nodes", function() {
751 var programPath = new NodePath(parse("(function(){var y = 1,x = 2;})"));
752 var funBlockStatementPath = programPath.get("body", 0, "expression", "body");
753 var variableDeclaration = funBlockStatementPath.get("body", 0);
754 var yVariableDeclaratorPath = variableDeclaration.get("declarations", 0);
755 var xVariableDeclaratorPath = variableDeclaration.get("declarations", 1);
756
757 n.VariableDeclarator.assert(yVariableDeclaratorPath.node);
758 n.VariableDeclarator.assert(xVariableDeclaratorPath.node);
759
760 var remainingNodePath = yVariableDeclaratorPath.prune();
761
762 assert.strictEqual(remainingNodePath, variableDeclaration);
763
764 remainingNodePath = xVariableDeclaratorPath.prune();
765
766 assert.strictEqual(remainingNodePath, funBlockStatementPath);
767 assert.strictEqual(funBlockStatementPath.get("body", 0).value, undefined);
768 });
769
770 it("should prune redundant expression statement nodes", function() {
771 var programPath = new NodePath(parse("(function(){key = 'value';})"));
772 var funBlockStatementPath = programPath.get("body", 0, "expression", "body");
773 var assignmentExpressionPath = funBlockStatementPath.get("body", 0, "expression");
774
775 n.AssignmentExpression.assert(assignmentExpressionPath.node);
776
777 var remainingNodePath = assignmentExpressionPath.prune();
778
779 assert.strictEqual(remainingNodePath, funBlockStatementPath);
780 assert.strictEqual(funBlockStatementPath.value.body.length, 0);
781 });
782
783 it("should prune redundant if statement node if no consequent and alternate remain after prune", function() {
784 var programPath = new NodePath(parse("if(true){var t = 0;}"));
785 var consequentNodePath = programPath.get("body", 0, "consequent");
786
787 n.BlockStatement.assert(consequentNodePath.node);
788
789 var remainingNodePath = consequentNodePath.prune();
790
791 var testExpressionNodePath = programPath.get("body", 0);
792
793 n.ExpressionStatement.assert(remainingNodePath.node);
794 assert.strictEqual(remainingNodePath, testExpressionNodePath);
795 });
796
797 it("should modify if statement node if consequent is pruned and alternate remains", function() {
798 var programPath = new NodePath(parse("if(x > 10){var t = 0;}else{var f = 2;}"));
799 var consequentNodePath = programPath.get("body", 0, "consequent");
800
801 n.BlockStatement.assert(consequentNodePath.node);
802
803 var remainingNodePath = consequentNodePath.prune();
804
805 var modifiedIfStatementNodePath = programPath.get("body", 0);
806 var negatedTestExpression = modifiedIfStatementNodePath.get("test");
807
808 n.IfStatement.assert(remainingNodePath.node);
809 n.UnaryExpression.assert(negatedTestExpression.node);
810 assert.strictEqual(remainingNodePath, modifiedIfStatementNodePath);
811 assert.strictEqual(negatedTestExpression.node.operator, "!");
812 });
813
814 it("should modify if statement node if consequent is pruned, alternate remains with no double negation", function() {
815 var programPath = new NodePath(parse("if(!condition){var t = 0;}else{var f = 2;}"));
816 var consequentNodePath = programPath.get("body", 0, "consequent");
817
818 n.BlockStatement.assert(consequentNodePath.node);
819
820 var remainingNodePath = consequentNodePath.prune();
821
822 var modifiedIfStatementNodePath = programPath.get("body", 0);
823 var testExpression = modifiedIfStatementNodePath.get("test");
824
825 n.IfStatement.assert(remainingNodePath.node);
826 n.Identifier.assert(testExpression.node);
827 assert.strictEqual(remainingNodePath, modifiedIfStatementNodePath);
828 });
829 });
830
831 describe("path.replace", function() {
832 var ast;
833
834 beforeEach(function() {
835 ast = b.functionDeclaration(
836 b.identifier("fn"),
837 [],
838 b.blockStatement([
839 b.variableDeclaration(
840 "var",
841 [b.variableDeclarator(b.identifier("a"), null)]
842 )
843 ])
844 );
845 });
846
847 it("should support replacement with a single node", function() {
848 types.visit(ast, {
849 visitIdentifier: function(path) {
850 if (path.node.name === "a") {
851 path.replace(b.identifier("b"));
852 }
853 this.traverse(path);
854 }
855 });
856
857 assert.equal(ast.body.body[0].declarations[0].id.name, "b");
858 });
859
860 it("should support replacement in an array with a single node", function() {
861 types.visit(ast, {
862 visitVariableDeclaration: function(path) {
863 path.replace(b.returnStatement(null));
864 this.traverse(path);
865 }
866 });
867
868 assert.equal(ast.body.body.length, 1);
869 assert.ok(n.ReturnStatement.check(ast.body.body[0]));
870 });
871
872 it("should support replacement with nothing", function() {
873 types.visit(ast, {
874 visitVariableDeclaration: function(path) {
875 path.replace();
876 this.traverse(path);
877 }
878 });
879
880 assert.equal(ast.body.body.length, 0);
881 });
882
883 it("should support replacement with itself plus more in an array", function() {
884 types.visit(ast, {
885 visitVariableDeclaration: function(path) {
886 var scopeBody = path.scope.path.get("body", "body");
887
888 // This is contrived such that we just happen to be replacing
889 // the same node we're currently processing, perhaps using a
890 // helper function to create variables at the top of the scope.
891 assert.strictEqual(scopeBody.get(0), path);
892
893 // Prepend `var $$;` inside the block. This should update our
894 // `this` NodePath to correct its array index so that a
895 // subsequent replace will still work.
896 scopeBody.get(0).replace(
897 b.variableDeclaration(
898 "var",
899 [b.variableDeclarator(b.identifier("$$"), null)]
900 ),
901 scopeBody.get(0).value
902 );
903
904 // Now do it again to make sure all the other indexes are
905 // updated, too.
906 scopeBody.get(0).replace(
907 b.variableDeclaration(
908 "var",
909 [b.variableDeclarator(b.identifier("$2"), null)]
910 ),
911 scopeBody.get(0).value
912 );
913
914 assert.strictEqual(scopeBody.get(0), path);
915
916 // Then replace the node, not the one we just added.
917 return b.returnStatement(b.identifier("$3"));
918 }
919 });
920
921 var statements = ast.body.body;
922 assert.deepEqual(
923 statements.map(function(node) { return node.type; }),
924 ['ReturnStatement', 'VariableDeclaration', 'VariableDeclaration']
925 );
926
927 n.ReturnStatement.assert(statements[0]);
928 assert.equal(statements[0].argument.name, "$3");
929
930 n.VariableDeclaration.assert(statements[1]);
931 assert.equal(statements[1].declarations[0].id.name, "$$");
932
933 n.VariableDeclaration.assert(statements[2]);
934 assert.equal(statements[2].declarations[0].id.name, "a");
935 });
936
937 it("should not throw when replacing the same node twice", function() {
938 types.visit(ast, {
939 visitVariableDeclaration: function(path) {
940 path.replace(b.expressionStatement(b.literal(null)));
941 n.ExpressionStatement.assert(path.value);
942 n.Literal.assert(path.value.expression);
943 assert.strictEqual(path.value.expression.value, null);
944
945 path.replace(b.expressionStatement(b.literal("OK")));
946 n.ExpressionStatement.assert(path.value);
947 n.Literal.assert(path.value.expression);
948 assert.strictEqual(path.value.expression.value, "OK");
949
950 if (path.parentPath.get(path.name) !== path) {
951 assert.ok(false, "Should have reused the same path");
952 }
953
954 this.traverse(path);
955 }
956 });
957 });
958 });
959
960 describe("global scope", function() {
961 var scope = [
962 "var foo = 42;",
963 "function bar(baz) {",
964 " return baz + foo;",
965 "}"
966 ];
967
968 var ast = parse(scope.join("\n"));
969
970 it("should be reachable from nested scopes", function() {
971 var globalScope;
972
973 types.visit(ast, {
974 visitProgram: function(path) {
975 assert.strictEqual(path.scope.isGlobal, true);
976 globalScope = path.scope;
977 this.traverse(path);
978 },
979
980 visitFunctionDeclaration: function(path) {
981 var node = path.node;
982 assert.strictEqual(path.scope.isGlobal, false);
983
984 assert.strictEqual(node.id.name, "bar");
985 assert.notStrictEqual(path.scope, globalScope);
986 assert.strictEqual(path.scope.isGlobal, false);
987 assert.strictEqual(path.scope.parent, globalScope);
988
989 assert.strictEqual(path.scope.getGlobalScope(), globalScope);
990
991 this.traverse(path);
992 }
993 });
994 });
995
996 it("should be found by .lookup and .declares", function() {
997 var globalScope;
998
999 types.visit(ast, {
1000 visitProgram: function(path) {
1001 assert.strictEqual(path.scope.isGlobal, true);
1002 globalScope = path.scope;
1003 this.traverse(path);
1004 },
1005
1006 visitFunctionDeclaration: function(path) {
1007 assert.ok(globalScope.declares("foo"));
1008 assert.ok(globalScope.declares("bar"));
1009 assert.strictEqual(path.scope.lookup("foo"), globalScope);
1010 assert.strictEqual(path.scope.lookup("bar"), globalScope);
1011
1012 assert.ok(path.scope.declares("baz"));
1013 assert.strictEqual(path.scope.lookup("baz"), path.scope);
1014
1015 assert.strictEqual(path.scope.lookup("qux"), null);
1016 assert.strictEqual(globalScope.lookup("baz"), null);
1017
1018 this.traverse(path);
1019 }
1020 });
1021 });
1022 });
1023
1024 describe("scope methods", function () {
1025 var scope = [
1026 "var foo = 42;",
1027 "function bar(baz) {",
1028 " return baz + foo;",
1029 "}",
1030 "var nom = function rom(pom) {",
1031 " var zom;",
1032 " return rom(pom);",
1033 "};"
1034 ];
1035
1036 it("getBindings should get local and global scope bindings", function() {
1037 var ast = parse(scope.join("\n"));
1038 var checked = [];
1039
1040 types.visit(ast, {
1041 visitProgram: function(path) {
1042 var bindings = path.scope.getBindings();
1043 assert.deepEqual(["bar", "foo", "nom"], Object.keys(bindings).sort());
1044 assert.equal(1, bindings.foo.length);
1045 assert.equal(1, bindings.bar.length);
1046 checked.push(path.node);
1047 this.traverse(path);
1048 },
1049
1050 visitFunctionDeclaration: function(path) {
1051 var bindings = path.scope.getBindings();
1052 assert.deepEqual(["baz"], Object.keys(bindings));
1053 assert.equal(1, bindings.baz.length);
1054 checked.push(path.node);
1055 this.traverse(path);
1056 },
1057
1058 visitReturnStatement: function(path) {
1059 var node = path.node;
1060 if (n.CallExpression.check(node.argument) &&
1061 node.argument.callee.name === "rom") {
1062 var bindings = path.scope.getBindings();
1063 assert.deepEqual(["pom", "rom", "zom"], Object.keys(bindings).sort());
1064 checked.push(node);
1065 }
1066 this.traverse(path);
1067 }
1068 });
1069
1070 assert.deepEqual(
1071 checked.map(function(node) { return node.type; }),
1072 ['Program', 'FunctionDeclaration', 'ReturnStatement']
1073 );
1074 });
1075
1076 it("getBindings should work for import statements (esprima-fb)", function() {
1077 var ast = require("esprima-fb").parse(
1078 [
1079 "import {x, y as z} from 'xy';",
1080 "import xyDefault from 'xy';",
1081 "import * as xyNamespace from 'xy';"
1082 ].join("\n"),
1083 {sourceType: "module"}
1084 );
1085
1086 var names;
1087
1088 types.visit(ast, {
1089 visitProgram: function(path) {
1090 names = Object.keys(path.scope.getBindings()).sort();
1091 this.traverse(path);
1092 }
1093 });
1094
1095 assert.deepEqual(names, ["x", "xyDefault", "xyNamespace", "z"]);
1096 });
1097
1098 it("getBindings should work for import statements (acorn)", function() {
1099 var ast = require("babel-core").parse([
1100 "import {x, y as z} from 'xy';",
1101 "import xyDefault from 'xy';",
1102 "import * as xyNamespace from 'xy';"
1103 ].join("\n"), {
1104 sourceType: "module",
1105 ecmaVersion: 6
1106 });
1107
1108 var names;
1109
1110 types.visit(ast, {
1111 visitProgram: function(path) {
1112 names = Object.keys(path.scope.getBindings()).sort();
1113 this.traverse(path);
1114 }
1115 });
1116
1117 assert.deepEqual(names, ["x", "xyDefault", "xyNamespace", "z"]);
1118 });
1119
1120 it("should inject temporary into current scope", function() {
1121 var ast = parse(scope.join("\n"));
1122 var bindings;
1123
1124 types.visit(ast, {
1125 visitProgram: function(path) {
1126 path.scope.injectTemporary();
1127 bindings = path.scope.getBindings();
1128 assert.deepEqual(["bar", "foo", "nom", "t$0$0"], Object.keys(bindings).sort());
1129 this.traverse(path);
1130 },
1131
1132 visitFunctionDeclaration: function(path) {
1133 path.scope.injectTemporary(
1134 path.scope.declareTemporary("t$")
1135 )
1136 bindings = path.scope.getBindings();
1137 assert.deepEqual(["baz", "t$1$0"], Object.keys(bindings));
1138 this.traverse(path);
1139 }
1140 });
1141 });
1142
1143 it("declareTemporary should use distinct names in nested scopes", function() {
1144 var ast = parse(scope.join("\n"));
1145 var globalVarDecl;
1146 var barVarDecl;
1147 var romVarDecl;
1148
1149 types.visit(ast, {
1150 visitProgram: function(path) {
1151 path.get("body").unshift(
1152 globalVarDecl = b.variableDeclaration("var", [
1153 b.variableDeclarator(
1154 path.scope.declareTemporary("$"),
1155 b.literal("global")
1156 ),
1157 b.variableDeclarator(
1158 path.scope.declareTemporary("$"),
1159 b.literal("global")
1160 )
1161 ])
1162 );
1163
1164 this.traverse(path);
1165 },
1166
1167 visitFunction: function(path) {
1168 var funcId = path.value.id;
1169
1170 var varDecl = b.variableDeclaration("var", [
1171 b.variableDeclarator(
1172 path.scope.declareTemporary("$"),
1173 b.literal(funcId.name + 1)
1174 ),
1175 b.variableDeclarator(
1176 path.scope.declareTemporary("$"),
1177 b.literal(funcId.name + 2)
1178 )
1179 ]);
1180
1181 path.get("body", "body").unshift(varDecl);
1182
1183 if (funcId.name === "bar") {
1184 barVarDecl = varDecl;
1185 } else if (funcId.name === "rom") {
1186 romVarDecl = varDecl;
1187 }
1188
1189 this.traverse(path);
1190 }
1191 });
1192
1193 assert.strictEqual(globalVarDecl.declarations[0].id.name, "$0$0");
1194 assert.strictEqual(globalVarDecl.declarations[1].id.name, "$0$1");
1195 assert.strictEqual(barVarDecl.declarations[0].id.name, "$1$0");
1196 assert.strictEqual(barVarDecl.declarations[1].id.name, "$1$1");
1197 assert.strictEqual(romVarDecl.declarations[0].id.name, "$1$0");
1198 assert.strictEqual(romVarDecl.declarations[1].id.name, "$1$1");
1199 });
1200 });
1201
1202 describe("catch block scope", function() {
1203 var catchWithVarDecl = [
1204 "function foo(e) {",
1205 " try {",
1206 " bar();",
1207 " } catch (e) {",
1208 " var f = e + 1;",
1209 " return function(g) {",
1210 " return e + g;",
1211 " };",
1212 " }",
1213 " return f;",
1214 "}"
1215 ];
1216
1217 var path = new NodePath(parse(catchWithVarDecl.join("\n")));
1218 var fooPath = path.get("body", 0);
1219 var fooScope = fooPath.scope;
1220 var catchPath = fooPath.get("body", "body", 0, "handler");
1221 var catchScope = catchPath.scope;
1222
1223 it("should not affect outer scope declarations", function() {
1224 n.FunctionDeclaration.assert(fooScope.node);
1225 assert.strictEqual(fooScope.declares("e"), true);
1226 assert.strictEqual(fooScope.declares("f"), true);
1227 assert.strictEqual(fooScope.lookup("e"), fooScope);
1228 });
1229
1230 it("should declare only the guard parameter", function() {
1231 n.CatchClause.assert(catchScope.node);
1232 assert.strictEqual(catchScope.declares("e"), true);
1233 assert.strictEqual(catchScope.declares("f"), false);
1234 assert.strictEqual(catchScope.lookup("e"), catchScope);
1235 assert.strictEqual(catchScope.lookup("f"), fooScope);
1236 });
1237
1238 it("should shadow only the parameter in nested scopes", function() {
1239 var closurePath = catchPath.get("body", "body", 1, "argument");
1240 var closureScope = closurePath.scope;
1241 n.FunctionExpression.assert(closureScope.node);
1242 assert.strictEqual(closureScope.declares("e"), false);
1243 assert.strictEqual(closureScope.declares("f"), false);
1244 assert.strictEqual(closureScope.declares("g"), true);
1245 assert.strictEqual(closureScope.lookup("g"), closureScope);
1246 assert.strictEqual(closureScope.lookup("e"), catchScope);
1247 assert.strictEqual(closureScope.lookup("f"), fooScope);
1248 });
1249 });
1250
1251 describe("array and object pattern scope", function() {
1252
1253 function scopeFromPattern(pattern) {
1254 return new NodePath(
1255 b.program([
1256 b.variableDeclaration('var', [
1257 b.variableDeclarator(pattern, null)
1258 ])
1259 ])
1260 ).scope;
1261 }
1262
1263 // ObjectPattern with Property and SpreadProperty
1264 // ArrayPattern with SpreadElement
1265 describe("esprima", function() {
1266 var objectPattern;
1267 var arrayPattern;
1268
1269 beforeEach(function() {
1270 // {a, b: c, ...d}
1271 objectPattern = b.objectPattern([
1272 b.property('init', b.identifier('a'), b.identifier('a')),
1273 b.property('init', b.identifier('b'), b.identifier('c')),
1274 b.spreadProperty(b.identifier('d')),
1275 ]);
1276
1277 // [foo, bar, ...baz]
1278 arrayPattern = b.arrayPattern([
1279 b.identifier('foo'),
1280 b.identifier('bar'),
1281 b.spreadElement(b.identifier('baz'))
1282 ]);
1283 });
1284
1285 it("should handle object patterns variable declarations", function() {
1286 var scope = scopeFromPattern(objectPattern);
1287
1288 assert.strictEqual(scope.declares("a"), true);
1289 assert.strictEqual(scope.declares("b"), false);
1290 assert.strictEqual(scope.declares("c"), true);
1291 assert.strictEqual(scope.declares("d"), true);
1292 });
1293
1294 it("should handle array patterns in variable declarations", function() {
1295 var scope = scopeFromPattern(arrayPattern);
1296
1297 assert.strictEqual(scope.declares("foo"), true);
1298 assert.strictEqual(scope.declares("bar"), true);
1299 assert.strictEqual(scope.declares("baz"), true);
1300 });
1301
1302 it("should handle nested patterns in variable declarations", function() {
1303 // {a, b: c, ...d, e: [foo, bar, ...baz]}
1304 objectPattern.properties.push(
1305 b.property('init', b.identifier('e'), arrayPattern)
1306 );
1307
1308 var scope = scopeFromPattern(objectPattern);
1309 assert.strictEqual(scope.declares("a"), true);
1310 assert.strictEqual(scope.declares("b"), false);
1311 assert.strictEqual(scope.declares("c"), true);
1312 assert.strictEqual(scope.declares("d"), true);
1313 assert.strictEqual(scope.declares("e"), false);
1314 assert.strictEqual(scope.declares("foo"), true);
1315 assert.strictEqual(scope.declares("bar"), true);
1316 assert.strictEqual(scope.declares("baz"), true);
1317 });
1318 });
1319
1320 // ObjectPattern with PropertyPattern and SpreadPropertyPattern
1321 // ArrayPatterhn with SpreadElementPattern
1322 describe("Mozilla Parser API", function() {
1323 var objectPattern;
1324 var arrayPattern;
1325
1326 beforeEach(function() {
1327 // {a, b: c, ...d}
1328 objectPattern = b.objectPattern([
1329 b.propertyPattern(b.identifier('a'), b.identifier('a')),
1330 b.propertyPattern(b.identifier('b'), b.identifier('c')),
1331 b.spreadPropertyPattern(b.identifier('d')),
1332 ]);
1333
1334 // [foo, bar, ...baz]
1335 arrayPattern = b.arrayPattern([
1336 b.identifier('foo'),
1337 b.identifier('bar'),
1338 b.spreadElementPattern(b.identifier('baz'))
1339 ]);
1340 });
1341
1342 it("should handle object patterns variable declarations", function() {
1343 var scope = scopeFromPattern(objectPattern);
1344
1345 assert.strictEqual(scope.declares("a"), true);
1346 assert.strictEqual(scope.declares("b"), false);
1347 assert.strictEqual(scope.declares("c"), true);
1348 assert.strictEqual(scope.declares("d"), true);
1349 });
1350
1351 it("should handle array patterns in variable declarations", function() {
1352 var scope = scopeFromPattern(arrayPattern);
1353
1354 assert.strictEqual(scope.declares("foo"), true);
1355 assert.strictEqual(scope.declares("bar"), true);
1356 assert.strictEqual(scope.declares("baz"), true);
1357 });
1358
1359 it("should handle nested patterns in variable declarations", function() {
1360 // {a, b: c, ...d, e: [foo, bar, ...baz]}
1361 objectPattern.properties.push(
1362 b.propertyPattern(b.identifier('e'), arrayPattern)
1363 );
1364
1365 var scope = scopeFromPattern(objectPattern);
1366 assert.strictEqual(scope.declares("a"), true);
1367 assert.strictEqual(scope.declares("b"), false);
1368 assert.strictEqual(scope.declares("c"), true);
1369 assert.strictEqual(scope.declares("d"), true);
1370 assert.strictEqual(scope.declares("e"), false);
1371 assert.strictEqual(scope.declares("foo"), true);
1372 assert.strictEqual(scope.declares("bar"), true);
1373 assert.strictEqual(scope.declares("baz"), true);
1374 });
1375 });
1376 });
1377
1378 describe("types.defineMethod", function() {
1379 function at(loc) {
1380 types.namedTypes.SourceLocation.assert(loc);
1381 this.loc = loc;
1382 }
1383
1384 var thisExpr = b.thisExpression();
1385
1386 it("should allow defining an .at method", function() {
1387 assert.strictEqual(types.defineMethod("at", at), void 0);
1388 assert.strictEqual(thisExpr.loc, null);
1389
1390 thisExpr.at(b.sourceLocation(
1391 b.position(1, 0),
1392 b.position(1, 4)
1393 ));
1394
1395 assert.strictEqual(thisExpr.loc.start.line, 1);
1396 assert.strictEqual(thisExpr.loc.start.column, 0);
1397 assert.strictEqual(thisExpr.loc.end.line, 1);
1398 assert.strictEqual(thisExpr.loc.end.column, 4);
1399 });
1400
1401 it("should allow methods to be removed", function() {
1402 // Now try removing the method.
1403 assert.strictEqual(types.defineMethod("at"), at);
1404 assert.strictEqual(thisExpr.at, void 0);
1405 assert.strictEqual("at" in thisExpr, false);
1406 });
1407 });
1408
1409 describe("types.visit", function() {
1410 var objProp;
1411
1412 beforeEach(function() {
1413 objProp = b.memberExpression(
1414 b.identifier("object"),
1415 b.identifier("property"),
1416 false
1417 );
1418 });
1419
1420 it("should be identical to PathVisitor.visit", function() {
1421 assert.strictEqual(types.visit, PathVisitor.visit);
1422 });
1423
1424 it("should work with no visitors", function() {
1425 var foo = b.identifier("foo");
1426 assert.strictEqual(types.visit(foo), foo);
1427 });
1428
1429 it("should allow simple tree modifications", function() {
1430 var bar = types.visit(b.identifier("foo"), {
1431 visitIdentifier: function(path) {
1432 assert.ok(path instanceof NodePath);
1433 path.value.name = "bar";
1434 return false;
1435 }
1436 });
1437
1438 n.Identifier.assert(bar);
1439 assert.strictEqual(bar.name, "bar");
1440 });
1441
1442 it("should complain about missing this.traverse", function() {
1443 try {
1444 types.visit(objProp, {
1445 visitIdentifier: function(path) {
1446 // buh?
1447 }
1448 });
1449
1450 assert.ok(false, "should have thrown an exception");
1451
1452 } catch (err) {
1453 assert.strictEqual(
1454 err.message,
1455 "Must either call this.traverse or return false in visitIdentifier"
1456 );
1457 }
1458 });
1459
1460 it("should support this.traverse", function() {
1461 var idNames = [];
1462
1463 types.visit(objProp, {
1464 visitMemberExpression: function(path) {
1465 this.traverse(path, {
1466 visitIdentifier: function(path) {
1467 idNames.push("*" + path.value.name + "*");
1468 return false;
1469 }
1470 });
1471
1472 path.get("object", "name").replace("asdfasdf");
1473 path.get("property", "name").replace("zxcvzxcv");
1474
1475 this.visit(path.get("property"));
1476 },
1477
1478 visitIdentifier: function(path) {
1479 idNames.push(path.value.name);
1480 return false;
1481 }
1482 });
1483
1484 assert.deepEqual(idNames, ["*object*", "*property*", "zxcvzxcv"]);
1485
1486 idNames.length = 0;
1487
1488 types.visit(objProp, {
1489 visitMemberExpression: function(path) {
1490 path.get("object", "name").replace("asdfasdf");
1491 path.get("property", "name").replace("zxcvzxcv");
1492 this.traverse(path, {
1493 visitIdentifier: function(path) {
1494 idNames.push(path.value.name);
1495 return false;
1496 }
1497 });
1498 }
1499 });
1500
1501 assert.deepEqual(idNames, ["asdfasdf", "zxcvzxcv"]);
1502 });
1503
1504 it("should support this.replace", function() {
1505 var seqExpr = b.sequenceExpression([
1506 b.literal("asdf"),
1507 b.identifier("zxcv"),
1508 b.thisExpression()
1509 ]);
1510
1511 types.visit(seqExpr, {
1512 visitIdentifier: function(path) {
1513 assert.strictEqual(path.value.name, "zxcv");
1514 path.replace(
1515 b.identifier("foo"),
1516 b.identifier("bar")
1517 );
1518 return false;
1519 }
1520 });
1521
1522 assert.strictEqual(seqExpr.expressions.length, 4);
1523
1524 var foo = seqExpr.expressions[1];
1525 n.Identifier.assert(foo);
1526 assert.strictEqual(foo.name, "foo");
1527
1528 var bar = seqExpr.expressions[2];
1529 n.Identifier.assert(bar);
1530 assert.strictEqual(bar.name, "bar");
1531
1532 types.visit(seqExpr, {
1533 visitIdentifier: function(path) {
1534 if (path.value.name === "foo") {
1535 path.replace(path.value, path.value);
1536 }
1537
1538 return false;
1539 }
1540 });
1541
1542 assert.strictEqual(seqExpr.expressions.length, 5);
1543
1544 var foo = seqExpr.expressions[1];
1545 n.Identifier.assert(foo);
1546 assert.strictEqual(foo.name, "foo");
1547
1548 var foo = seqExpr.expressions[2];
1549 n.Identifier.assert(foo);
1550 assert.strictEqual(foo.name, "foo");
1551
1552 var bar = seqExpr.expressions[3];
1553 n.Identifier.assert(bar);
1554 assert.strictEqual(bar.name, "bar");
1555
1556 types.visit(seqExpr, {
1557 visitLiteral: function(path) {
1558 path.replace();
1559 return false;
1560 },
1561
1562 visitIdentifier: function(path) {
1563 if (path.value.name === "bar") {
1564 path.replace();
1565 }
1566
1567 return false;
1568 }
1569 });
1570
1571 assert.strictEqual(seqExpr.expressions.length, 3);
1572
1573 var first = seqExpr.expressions[0];
1574 n.Identifier.assert(first);
1575 assert.strictEqual(first.name, "foo");
1576
1577 var second = seqExpr.expressions[1];
1578 assert.strictEqual(second, first);
1579
1580 var third = seqExpr.expressions[2];
1581 n.ThisExpression.assert(third);
1582 });
1583
1584 it("should reuse old VisitorContext objects", function() {
1585 var objectContext;
1586 var propertyContext;
1587
1588 types.visit(objProp, {
1589 visitIdentifier: function(path) {
1590 assert.strictEqual(this.needToCallTraverse, true);
1591 this.traverse(path);
1592 assert.strictEqual(path.name, path.value.name);
1593 if (path.name === "object") {
1594 objectContext = this;
1595 } else if (path.name === "property") {
1596 propertyContext = this;
1597 }
1598 }
1599 });
1600
1601 assert.ok(objectContext);
1602 assert.ok(propertyContext);
1603 assert.strictEqual(objectContext, propertyContext);
1604 });
1605
1606 it("should dispatch to closest visitSupertype method", function() {
1607 var foo = b.identifier("foo");
1608 var bar = b.identifier("bar");
1609 var callExpr = b.callExpression(
1610 b.memberExpression(
1611 b.functionExpression(
1612 b.identifier("add"),
1613 [foo, bar],
1614 b.blockStatement([
1615 b.returnStatement(
1616 b.binaryExpression("+", foo, bar)
1617 )
1618 ])
1619 ),
1620 b.identifier("bind"),
1621 false
1622 ),
1623 [b.thisExpression()]
1624 );
1625
1626 var nodes = [];
1627 var expressions = [];
1628 var identifiers = [];
1629 var statements = [];
1630 var returnStatements = [];
1631 var functions = [];
1632
1633 function makeVisitorMethod(array) {
1634 return function(path) {
1635 array.push(path.value);
1636 this.traverse(path);
1637 };
1638 }
1639
1640 types.visit(callExpr, {
1641 visitNode: makeVisitorMethod(nodes),
1642 visitExpression: makeVisitorMethod(expressions),
1643 visitIdentifier: makeVisitorMethod(identifiers),
1644 visitStatement: makeVisitorMethod(statements),
1645 visitReturnStatement: makeVisitorMethod(returnStatements),
1646 visitFunction: makeVisitorMethod(functions)
1647 });
1648
1649 function check(array) {
1650 var rest = Array.prototype.slice.call(arguments, 1);
1651 assert.strictEqual(array.length, rest.length);
1652 for (var i = 0; i < rest.length; ++i) {
1653 assert.strictEqual(array[i], rest[i]);
1654 }
1655 }
1656
1657 check(nodes);
1658
1659 check(expressions,
1660 callExpr,
1661 callExpr.callee,
1662 callExpr.callee.object.body.body[0].argument,
1663 callExpr.arguments[0]);
1664
1665 check(identifiers,
1666 callExpr.callee.object.id,
1667 foo,
1668 bar,
1669 foo,
1670 bar,
1671 callExpr.callee.property);
1672
1673 check(statements,
1674 callExpr.callee.object.body);
1675
1676 check(returnStatements,
1677 callExpr.callee.object.body.body[0]);
1678
1679 check(functions,
1680 callExpr.callee.object);
1681 });
1682
1683 it("should replace this.currentPath with returned value", function() {
1684 assert.strictEqual(objProp.computed, false);
1685
1686 types.visit(objProp, {
1687 visitIdentifier: function(path) {
1688 if (path.value.name === "property") {
1689 path.parent.get("computed").replace(true);
1690 return b.callExpression(
1691 b.memberExpression(
1692 b.thisExpression(),
1693 b.identifier("toString"),
1694 false
1695 ),
1696 []
1697 );
1698 }
1699
1700 this.traverse(path);
1701 },
1702
1703 visitThisExpression: function(path) {
1704 return b.identifier("self");
1705 }
1706 });
1707
1708 assert.strictEqual(objProp.computed, true);
1709 n.CallExpression.assert(objProp.property);
1710
1711 var callee = objProp.property.callee;
1712 n.MemberExpression.assert(callee);
1713
1714 n.Identifier.assert(callee.object);
1715 assert.strictEqual(callee.object.name, "self");
1716
1717 n.Identifier.assert(callee.property);
1718 assert.strictEqual(callee.property.name, "toString");
1719
1720 assert.deepEqual(objProp.property.arguments, []);
1721 });
1722 });
1723
1724 describe("path.shift", function() {
1725 it("should work like Array.prototype.shift", function() {
1726 var path = new NodePath({
1727 elements: [0, "foo", true]
1728 });
1729
1730 var first = path.get("elements", 0);
1731 assert.strictEqual(first.name, 0);
1732
1733 var second = path.get("elements", 1);
1734 assert.strictEqual(second.name, 1);
1735
1736 var third = path.get("elements", 2);
1737 assert.strictEqual(third.name, 2);
1738
1739 assert.strictEqual(path.get("elements", "length").value, 3);
1740
1741 assert.strictEqual(path.get("elements").shift(), first.value);
1742 assert.strictEqual(path.get("elements", "length").value, 2);
1743 assert.strictEqual(path.get("elements", 0), second);
1744 assert.strictEqual(path.get("elements", 1), third);
1745 assert.strictEqual(second.name, 0);
1746 assert.strictEqual(third.name, 1);
1747
1748 assert.strictEqual(path.get("elements").shift(), second.value);
1749 assert.strictEqual(path.get("elements", "length").value, 1);
1750 assert.strictEqual(path.get("elements", 0), third);
1751 assert.strictEqual(third.name, 0);
1752
1753 assert.strictEqual(path.get("elements").shift(), third.value);
1754 assert.strictEqual(path.get("elements").shift(), void 0);
1755 assert.strictEqual(path.get("elements", "length").value, 0);
1756 });
1757
1758 it("should throw when path.value not an array", function() {
1759 assert.throws(function() {
1760 new NodePath({ foo: 42 }).get("foo").shift();
1761 });
1762 });
1763 });
1764
1765 describe("path.unshift", function() {
1766 it("should work like Array.prototype.unshift", function() {
1767 var path = new NodePath(b.sequenceExpression([]));
1768 var elems = path.get("expressions");
1769
1770 var one = b.literal(1);
1771 var two = b.literal(2);
1772 var three = b.literal(3);
1773 var four = b.literal(4);
1774 var five = b.literal(5);
1775
1776 assert.strictEqual(elems.get(1).parentPath, elems);
1777 assert.strictEqual(elems.get(1).node, path.value);
1778 assert.strictEqual(elems.get(1).parent, null);
1779
1780 assert.strictEqual(elems.get("length").value, 0);
1781 elems.unshift(three, four, five);
1782 assert.deepEqual(path.value.expressions, [three, four, five]);
1783 var fourPath = elems.get(1);
1784 assert.strictEqual(fourPath.value.value, 4);
1785 elems.unshift(one, two);
1786 assert.deepEqual(elems.value, [one, two, three, four, five]);
1787 elems.unshift();
1788 assert.deepEqual(elems.value, [one, two, three, four, five]);
1789 assert.strictEqual(fourPath.name, 3);
1790 assert.strictEqual(elems.get("length").value, 5);
1791
1792 assert.strictEqual(elems.get(1).parentPath, elems);
1793 assert.strictEqual(elems.get(1).node, two);
1794 assert.strictEqual(elems.get(1).parent, path);
1795 });
1796
1797 it("should throw when path.value not an array", function() {
1798 assert.throws(function() {
1799 new NodePath({ foo: 42 }).get("foo").unshift();
1800 });
1801 });
1802 });
1803
1804 describe("path.push", function() {
1805 it("should work like Array.prototype.push", function() {
1806 var path = new NodePath({ elements: [0] });
1807 var elems = path.get("elements");
1808 assert.strictEqual(elems.get("length").value, 1);
1809 elems.push(1, 2, 3);
1810 assert.deepEqual(path.value.elements, [0, 1, 2, 3]);
1811 var two = elems.get(2);
1812 assert.strictEqual(two.value, 2);
1813 elems.push(4, 5);
1814 assert.deepEqual(elems.value, [0, 1, 2, 3, 4, 5]);
1815 elems.push();
1816 assert.deepEqual(elems.value, [0, 1, 2, 3, 4, 5]);
1817 assert.strictEqual(two.name, 2);
1818 assert.strictEqual(elems.get("length").value, 6);
1819 });
1820
1821 it("should throw when path.value not an array", function() {
1822 assert.throws(function() {
1823 new NodePath({ foo: 42 }).get("foo").push("asdf");
1824 });
1825 });
1826 });
1827
1828 describe("path.pop", function() {
1829 it("should work like Array.prototype.pop", function() {
1830 var path = new NodePath({
1831 elements: [0, "foo", true]
1832 });
1833
1834 var first = path.get("elements", 0);
1835 assert.strictEqual(first.name, 0);
1836
1837 var second = path.get("elements", 1);
1838 assert.strictEqual(second.name, 1);
1839
1840 var third = path.get("elements", 2);
1841 assert.strictEqual(third.name, 2);
1842
1843 assert.strictEqual(path.get("elements", "length").value, 3);
1844
1845 assert.strictEqual(path.get("elements").pop(), third.value);
1846 assert.strictEqual(path.get("elements", "length").value, 2);
1847 assert.strictEqual(path.get("elements", 0), first);
1848 assert.strictEqual(path.get("elements", 1), second);
1849 assert.strictEqual(first.name, 0);
1850 assert.strictEqual(second.name, 1);
1851
1852 assert.strictEqual(path.get("elements").pop(), second.value);
1853 assert.strictEqual(path.get("elements", "length").value, 1);
1854 assert.strictEqual(path.get("elements", 0), first);
1855 assert.strictEqual(first.name, 0);
1856
1857 assert.strictEqual(path.get("elements").pop(), first.value);
1858 assert.strictEqual(path.get("elements").pop(), void 0);
1859 assert.strictEqual(path.get("elements", "length").value, 0);
1860 });
1861
1862 it("should throw when path.value not an array", function() {
1863 assert.throws(function() {
1864 new NodePath({ foo: 42 }).get("foo").pop();
1865 });
1866 });
1867 });
1868
1869 describe("path.insertAt", function() {
1870 it("should insert nodes at the given index", function() {
1871 var path = new NodePath({
1872 elements: [0, "foo", true]
1873 });
1874
1875 var elems = path.get("elements");
1876 elems.insertAt(1, "a", "b");
1877 assert.deepEqual(elems.value, [0, "a", "b", "foo", true]);
1878
1879 elems.insertAt(elems.get("length").value + 1, []);
1880 assert.deepEqual(elems.value, [0, "a", "b", "foo", true,, []]);
1881 assert.strictEqual(elems.get("length").value, 7);
1882
1883 elems.insertAt(elems.get("length").value + 12345);
1884 assert.deepEqual(elems.value, [0, "a", "b", "foo", true,, []]);
1885 assert.strictEqual(elems.get("length").value, 7);
1886
1887 elems.insertAt(-2, -2, -1);
1888 assert.deepEqual(elems.value, [-2, -1, 0, "a", "b", "foo", true,, []]);
1889 assert.strictEqual(elems.get("length").value, 9);
1890 });
1891
1892 it("should throw when path.value not an array", function() {
1893 assert.throws(function() {
1894 new NodePath({ foo: 42 }).get("foo").insertAt(0);
1895 });
1896 });
1897 });
1898
1899 describe("path.insertBefore", function() {
1900 it("should insert nodes before the current path", function() {
1901 var zero = b.literal(0);
1902 var one = b.literal(1);
1903 var two = b.literal(2);
1904 var foo = b.literal("foo");
1905 var truth = b.literal(true);
1906
1907 var path = new NodePath(b.sequenceExpression([zero, foo, truth]));
1908 var fooPath = path.get("expressions", 1);
1909 var truePath = path.get("expressions", 2);
1910 fooPath.insertBefore(one, two);
1911 assert.deepEqual(
1912 fooPath.parent.node.expressions,
1913 [zero, one, two, foo, truth]
1914 );
1915
1916 assert.strictEqual(path.get("expressions", 3), fooPath);
1917 assert.strictEqual(fooPath.value.value, "foo");
1918
1919 assert.strictEqual(path.get("expressions", 4), truePath);
1920 assert.strictEqual(truePath.value.value, true);
1921 });
1922
1923 it("should throw when path.parentPath.value not an array", function() {
1924 assert.throws(function() {
1925 new NodePath({ foo: 42 }).get("foo").insertBefore(0);
1926 });
1927 });
1928 });
1929
1930 describe("path.insertAfter", function() {
1931 it("should insert nodes after the current path", function() {
1932 var zero = b.literal(0);
1933 var one = b.literal(1);
1934 var two = b.literal(2);
1935 var foo = b.literal("foo");
1936 var truth = b.literal(true);
1937
1938 var path = new NodePath(b.sequenceExpression([zero, foo, truth]));
1939 var fooPath = path.get("expressions", 1);
1940 var truePath = path.get("expressions", 2);
1941 fooPath.insertAfter(one, two);
1942 assert.deepEqual(
1943 fooPath.parent.node.expressions,
1944 [zero, foo, one, two, truth]
1945 );
1946
1947 assert.strictEqual(path.get("expressions", 1), fooPath);
1948 assert.strictEqual(fooPath.value.value, "foo");
1949
1950 assert.strictEqual(path.get("expressions", 2).value.value, 1);
1951 assert.strictEqual(path.get("expressions", 3).value.value, 2);
1952
1953 assert.strictEqual(path.get("expressions", 4), truePath);
1954 assert.strictEqual(truePath.value.value, true);
1955
1956 var three = b.literal(3)
1957 truePath.insertAfter(three);
1958 assert.deepEqual(
1959 fooPath.parent.node.expressions,
1960 [zero, foo, one, two, truth, three]
1961 );
1962 });
1963
1964 it("should throw when path.parentPath.value not an array", function() {
1965 assert.throws(function() {
1966 new NodePath({ foo: 42 }).get("foo").insertAfter(0);
1967 });
1968 });
1969 });
1970
1971 describe("types.astNodesAreEquivalent", function() {
1972 it("should work for simple values", function() {
1973 types.astNodesAreEquivalent.assert(1, 2 - 1);
1974 types.astNodesAreEquivalent.assert("1", 1);
1975 types.astNodesAreEquivalent.assert(true, !false);
1976
1977 var d1 = new Date;
1978 var d2 = new Date(+d1);
1979 assert.notStrictEqual(d1, d2);
1980 types.astNodesAreEquivalent.assert(d1, d2);
1981
1982 types.astNodesAreEquivalent.assert(/x/, /x/);
1983 assert.strictEqual(types.astNodesAreEquivalent(/x/g, /x/), false);
1984 });
1985
1986 it("should work for arrays", function() {
1987 types.astNodesAreEquivalent.assert([], [1, 2, 3].slice(10));
1988 types.astNodesAreEquivalent.assert([1, 2, 3], [1].concat(2, [3]));
1989 types.astNodesAreEquivalent.assert([1,, 3], [1,, 3,]);
1990 assert.strictEqual(
1991 types.astNodesAreEquivalent([1,, 3], [1, void 0, 3]),
1992 false
1993 );
1994 });
1995
1996 it("should work for objects", function() {
1997 types.astNodesAreEquivalent.assert({
1998 foo: 42,
1999 bar: "asdf"
2000 }, {
2001 bar: "asdf",
2002 foo: 42
2003 });
2004
2005 assert.strictEqual(types.astNodesAreEquivalent({
2006 foo: 42,
2007 bar: "asdf",
2008 baz: true
2009 }, {
2010 bar: "asdf",
2011 foo: 42
2012 }), false);
2013
2014 assert.strictEqual(types.astNodesAreEquivalent({
2015 foo: 42,
2016 bar: "asdf"
2017 }, {
2018 bar: "asdf",
2019 foo: 42,
2020 baz: true
2021 }), false);
2022 });
2023
2024 it("should work for AST nodes", function() {
2025 function check(src1, src2) {
2026 types.astNodesAreEquivalent.assert(parse(src1), parse(src2));
2027 }
2028
2029 function checkNot(src1, src2) {
2030 var ast1 = parse(src1, { loc: true, range: true });
2031 var ast2 = parse(src2, { loc: true });
2032
2033 assert.throws(function() {
2034 types.astNodesAreEquivalent.assert(ast1, ast2);
2035 });
2036
2037 var problemPath = [];
2038 types.astNodesAreEquivalent(parse(src1), parse(src2), problemPath);
2039 assert.notStrictEqual(problemPath.length, 0);
2040
2041 var a = ast1;
2042 var b = ast2;
2043
2044 problemPath.forEach(function(name) {
2045 assert.strictEqual(name in a, true);
2046 assert.strictEqual(name in b, true);
2047 a = a[name];
2048 b = b[name];
2049 });
2050
2051 assert.notStrictEqual(a, b);
2052 }
2053
2054 check("1\n;", "1;");
2055
2056 check("console.log(this.toString(36));", [
2057 "// leading comment",
2058 "console.log(",
2059 " this.toString(36)",
2060 "/* trailing comment */)"
2061 ].join("\n"));
2062
2063 check("foo()", "foo /*anonymous*/ ()");
2064
2065 check("new (bar(1,2)(3,4)).baz.call(null)",
2066 "new( bar( 1,2) \n (3,4)). baz.call( null)");
2067
2068 check([
2069 "(function(x) {",
2070 " Foo = /asdf/.test(x);",
2071 "}());"
2072 ].join("\n"), [
2073 "(function(x) {",
2074 " Foo = /asdf/.test(x);",
2075 "})();"
2076 ].join("\n\n"));
2077
2078 checkNot([
2079 "(function(x) {",
2080 " Foo = /asdf/.test(x);",
2081 "}());"
2082 ].join("\n"), [
2083 "(function(x) {",
2084 " Foo = /asdf/.test(x);",
2085 "})('~asdf~');"
2086 ].join("\n\n"));
2087
2088 checkNot([
2089 "(function(x) {",
2090 " var Foo = /asdf/.test(x);",
2091 "}());"
2092 ].join("\n"), [
2093 "(function(x) {",
2094 " Foo = /asdf/.test(x);",
2095 "})(/*'~asdf~'*/);"
2096 ].join("\n\n"));
2097 });
2098 });
2099
2100 describe("RegExpLiteral nodes", function() {
2101 it("should have a default-computable .regex field", function() {
2102 var ast = parse('/x*/gmi.test("xxx")');
2103 var regExp = ast.body[0].expression.callee.object;
2104
2105 n.Literal.assert(regExp);
2106 isRegExp.assert(regExp.value);
2107
2108 var regex = types.getFieldValue(regExp, "regex");
2109
2110 assert.deepEqual(regex, {
2111 pattern: "x*",
2112 flags: "img"
2113 });
2114
2115 types.Type.fromObject({
2116 pattern: isString,
2117 flags: isString
2118 }).assert(regex);
2119 });
2120
2121 it("should typecheck with explicit .regex field", function() {
2122 var stringLiteral = b.literal("asdf");
2123 assert.strictEqual(stringLiteral.regex, null);
2124 n.Literal.assert(stringLiteral, true);
2125
2126 var regExpLiteral = b.literal(/a.b/gi);
2127 assert.strictEqual(regExpLiteral.regex.pattern, "a.b");
2128 assert.strictEqual(regExpLiteral.regex.flags, "ig");
2129 n.Literal.assert(regExpLiteral, true);
2130
2131 regExpLiteral.regex.pattern = 1234;
2132 assert.strictEqual(n.Literal.check(regExpLiteral, true), false);
2133 });
2134 });