diff --git a/.changeset/modern-flowers-enjoy.md b/.changeset/modern-flowers-enjoy.md new file mode 100644 index 0000000..025ce8f --- /dev/null +++ b/.changeset/modern-flowers-enjoy.md @@ -0,0 +1,5 @@ +--- +'esrap': minor +--- + +feat: experimental JSX support diff --git a/.changeset/sharp-plants-remain.md b/.changeset/sharp-plants-remain.md new file mode 100644 index 0000000..b3f41a5 --- /dev/null +++ b/.changeset/sharp-plants-remain.md @@ -0,0 +1,5 @@ +--- +'esrap': major +--- + +breaking: add support for custom printers diff --git a/.changeset/thin-lobsters-knock.md b/.changeset/thin-lobsters-knock.md new file mode 100644 index 0000000..aec1704 --- /dev/null +++ b/.changeset/thin-lobsters-knock.md @@ -0,0 +1,5 @@ +--- +'esrap': major +--- + +breaking: `print(...)` only accepts a node, not an array of nodes diff --git a/.github/workflows/preview-release.yml b/.github/workflows/preview-release.yml index b3d4102..69df6e8 100644 --- a/.github/workflows/preview-release.yml +++ b/.github/workflows/preview-release.yml @@ -16,7 +16,6 @@ jobs: node-version: 20 cache: 'pnpm' - - name: Install dependencies - run: pnpm install - + - run: pnpm install + - run: pnpm prepublishOnly - run: pnpm dlx pkg-pr-new publish --no-template diff --git a/README.md b/README.md index 2fdb668..326aff9 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,9 @@ Parse in reverse. AST goes in, code comes out. ```js import { print } from 'esrap'; +import ts from 'esrap/languages/ts'; -const { code, map } = print({ +const ast = { type: 'Program', body: [ { @@ -26,19 +27,105 @@ const { code, map } = print({ } } ] -}); +}; + +const { code, map } = print(ast, ts()); console.log(code); // alert('hello world!'); ``` If the nodes of the input AST have `loc` properties (e.g. the AST was generated with [`acorn`](https://github.com/acornjs/acorn/tree/master/acorn/#interface) with the `locations` option set), sourcemap mappings will be created. +## Built-in languages + +`esrap` ships with two built-in languages — `ts()` and `tsx()` (considered experimental at present!) — which can print ASTs conforming to [`@typescript-eslint/types`](https://www.npmjs.com/package/@typescript-eslint/types) (which extends [ESTree](https://github.com/estree/estree)): + +```js +import ts from 'esrap/languages/ts'; +import tsx from 'esrap/languages/tsx'; // experimental! +``` + +Both languages accept an options object: + +```js +const { code, map } = print( + ast, + ts({ + // how string literals should be quoted — `single` (the default) or `double` + quotes: 'single', + + // an array of `{ type: 'Line' | 'Block', value: string, loc: { start, end } }` objects + comments: [] + }) +); +``` + +You can generate the `comments` array by, for example, using [Acorn's](https://github.com/acornjs/acorn/tree/master/acorn/#interface) `onComment` option. + +## Custom languages + +You can also create your own languages: + +```ts +import { print, type Visitors } from 'esrap'; + +const language: Visitors = { + _(node, context, visit) { + // the `_` visitor handles any node type + context.write('['); + visit(node); + context.write(']'); + }, + List(node, context) { + // node.type === 'List' + for (const child of node.children) { + context.visit(child); + } + }, + Foo(node, context) { + // node.type === 'Foo' + context.write('foo'); + }, + Bar(node, context) { + // node.type === 'Bar' + context.write('bar'); + } +}; + +const ast: MyNodeType = { + type: 'List', + children: [{ type: 'Foo' }, { type: 'Bar' }] +}; + +const { code, map } = print(ast, language); + +code; // `[[foo][bar]]` +``` + +The `context` API has several methods: + +- `context.write(data: string, node?: BaseNode)` — add a string. If `node` is provided and has a standard `loc` property (with `start` and `end` properties each with a `line` and `column`), a sourcemap mapping will be created +- `context.indent()` — increase the indentation level, typically before adding a newline +- `context.newline()` — self-explanatory +- `context.margin()` — causes the next newline to be repeated (consecutive newlines are otherwise merged into one) +- `context.dedent()` — decrease the indentation level (again, typically before adding a newline) +- `context.visit(node: BaseNode)` — calls the visitor corresponding to `node.type` +- `context.location(line: number, column: number)` — insert a sourcemap mapping _without_ calling `context.write(...)` +- `context.measure()` — returns the number of characters contained in `context` +- `context.empty()` — returns true if the context has no content +- `context.new()` — creates a child context +- `context.append(child)` — appends a child context + +In addition, `context.multiline` is `true` if the context has multiline content. (This is useful for knowing, for example, when to insert newlines between nodes.) + +To understand how to wield these methods effectively, read the source code for the built-in languages. + ## Options You can pass the following options: ```js -const { code, map } = print(ast, { +const { code, map } = print(ast, ts(), { // Populate the `sources` field of the resulting sourcemap // (note that the AST is assumed to come from a single file) sourceMapSource: 'input.js', @@ -51,20 +138,10 @@ const { code, map } = print(ast, { sourceMapEncodeMappings: false, // String to use for indentation — defaults to '\t' - indent: ' ', - - // Whether to wrap strings in single or double quotes — defaults to 'single'. - // This only applies to string literals with no `raw` value, which generally - // means the AST node was generated programmatically, rather than parsed - // from an original source - quotes: 'single' + indent: ' ' }); ``` -## TypeScript - -`esrap` can also print TypeScript nodes, assuming they match the ESTree-like [`@typescript-eslint/types`](https://www.npmjs.com/package/@typescript-eslint/types). - ## Why not just use Prettier? Because it's ginormous. diff --git a/package.json b/package.json index 865cbb3..67ae647 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,14 @@ ".": { "types": "./types/index.d.ts", "default": "./src/index.js" + }, + "./languages/ts": { + "types": "./types/index.d.ts", + "default": "./src/languages/ts/index.js" + }, + "./languages/tsx": { + "types": "./types/index.d.ts", + "default": "./src/languages/tsx/index.js" } }, "types": "./types/index.d.ts", @@ -23,8 +31,8 @@ "@sveltejs/acorn-typescript": "^1.0.5", "@typescript-eslint/types": "^8.2.0", "@vitest/ui": "^2.1.1", - "acorn": "^8.11.3", - "dts-buddy": "^0.5.4", + "acorn": "^8.15.0", + "dts-buddy": "^0.6.2", "prettier": "^3.0.3", "typescript": "^5.7.2", "vitest": "^2.1.1", @@ -34,7 +42,7 @@ "changeset:version": "changeset version", "changeset:publish": "changeset publish", "check": "tsc", - "prepublishOnly": "pnpm test && dts-buddy -m esrap:./src/public.d.ts", + "prepublishOnly": "pnpm test && dts-buddy -m esrap:./src/public.d.ts -m esrap/languages/ts:./src/languages/ts/public.d.ts -m esrap/languages/tsx:./src/languages/tsx/public.d.ts", "sandbox": "node test/sandbox/index.js", "test": "vitest --run", "test:ui": "vitest --ui" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c9b6db2..53807dd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -17,7 +17,7 @@ importers: version: 2.27.11 '@sveltejs/acorn-typescript': specifier: ^1.0.5 - version: 1.0.5(acorn@8.12.1) + version: 1.0.5(acorn@8.15.0) '@typescript-eslint/types': specifier: ^8.2.0 version: 8.2.0 @@ -25,11 +25,11 @@ importers: specifier: ^2.1.1 version: 2.1.1(vitest@2.1.1) acorn: - specifier: ^8.11.3 - version: 8.12.1 + specifier: ^8.15.0 + version: 8.15.0 dts-buddy: - specifier: ^0.5.4 - version: 0.5.4(typescript@5.7.2) + specifier: ^0.6.2 + version: 0.6.2(typescript@5.7.2) prettier: specifier: ^3.0.3 version: 3.3.3 @@ -417,8 +417,8 @@ packages: '@vitest/utils@2.1.1': resolution: {integrity: sha512-Y6Q9TsI+qJ2CC0ZKj6VBb+T8UPz593N113nnUykqwANqhgf3QkZeHFlusgKLTqrnVHbj/XDKZcDHol+dxVT+rQ==} - acorn@8.12.1: - resolution: {integrity: sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==} + acorn@8.15.0: + resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} engines: {node: '>=0.4.0'} hasBin: true @@ -493,11 +493,11 @@ packages: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} - dts-buddy@0.5.4: - resolution: {integrity: sha512-a3jJYbMXK98aJvhdV/v+tEKTTEJXXWtMjrl5L8jJL7rnZzGtPA6JNHJZ5//NVRw4JiB5T10Ie5T7h/QsP3aaYw==} + dts-buddy@0.6.2: + resolution: {integrity: sha512-KUmYrRKpVpjmnqM/JY93p1PWezMXodKCiMd5CFvfLtRCRc5i2GZiojrkVQXO2Dd8HeaU1C3sgTKDWxCEK5cyXA==} hasBin: true peerDependencies: - typescript: '>=5.0.4 <5.8' + typescript: '>=5.0.4 <5.9' enquirer@2.4.1: resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} @@ -538,6 +538,14 @@ packages: picomatch: optional: true + fdir@6.4.6: + resolution: {integrity: sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + fflate@0.8.2: resolution: {integrity: sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==} @@ -572,16 +580,10 @@ packages: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} - globalyzer@0.1.0: - resolution: {integrity: sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==} - globby@11.1.0: resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} engines: {node: '>=10'} - globrex@0.1.2: - resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} - graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} @@ -843,15 +845,16 @@ packages: resolution: {integrity: sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==} engines: {node: '>=8'} - tiny-glob@0.2.9: - resolution: {integrity: sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==} - tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} tinyexec@0.3.0: resolution: {integrity: sha512-tVGE0mVJPGb0chKhqmsoosjsS+qUnJVGJpZgsHYQcGoPlG3B51R3PouqTgEGH2Dc9jjFyOqOpix6ZHNMXp1FZg==} + tinyglobby@0.2.14: + resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==} + engines: {node: '>=12.0.0'} + tinyglobby@0.2.6: resolution: {integrity: sha512-NbBoFBpqfcgd1tCiO8Lkfdk+xrA7mlLR9zgvZcZWQQwU63XAfUePyd6wZBaU93Hqw347lHnwFzttAkemHzzz4g==} engines: {node: '>=12.0.0'} @@ -1289,9 +1292,9 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.20.0': optional: true - '@sveltejs/acorn-typescript@1.0.5(acorn@8.12.1)': + '@sveltejs/acorn-typescript@1.0.5(acorn@8.15.0)': dependencies: - acorn: 8.12.1 + acorn: 8.15.0 '@types/estree@1.0.5': {} @@ -1355,7 +1358,7 @@ snapshots: loupe: 3.1.1 tinyrainbow: 1.2.0 - acorn@8.12.1: {} + acorn@8.15.0: {} ansi-colors@4.1.3: {} @@ -1411,16 +1414,15 @@ snapshots: dependencies: path-type: 4.0.0 - dts-buddy@0.5.4(typescript@5.7.2): + dts-buddy@0.6.2(typescript@5.7.2): dependencies: '@jridgewell/source-map': 0.3.6 '@jridgewell/sourcemap-codec': 1.5.0 - globrex: 0.1.2 kleur: 4.1.5 locate-character: 3.0.0 magic-string: 0.30.17 sade: 1.8.1 - tiny-glob: 0.2.9 + tinyglobby: 0.2.14 ts-api-utils: 1.4.3(typescript@5.7.2) typescript: 5.7.2 @@ -1485,6 +1487,10 @@ snapshots: optionalDependencies: picomatch: 4.0.2 + fdir@6.4.6(picomatch@4.0.2): + optionalDependencies: + picomatch: 4.0.2 + fflate@0.8.2: {} fill-range@7.1.1: @@ -1519,8 +1525,6 @@ snapshots: dependencies: is-glob: 4.0.3 - globalyzer@0.1.0: {} - globby@11.1.0: dependencies: array-union: 2.1.0 @@ -1530,8 +1534,6 @@ snapshots: merge2: 1.4.1 slash: 3.0.0 - globrex@0.1.2: {} - graceful-fs@4.2.11: {} human-id@1.0.2: {} @@ -1744,15 +1746,15 @@ snapshots: term-size@2.2.1: {} - tiny-glob@0.2.9: - dependencies: - globalyzer: 0.1.0 - globrex: 0.1.2 - tinybench@2.9.0: {} tinyexec@0.3.0: {} + tinyglobby@0.2.14: + dependencies: + fdir: 6.4.6(picomatch@4.0.2) + picomatch: 4.0.2 + tinyglobby@0.2.6: dependencies: fdir: 6.3.0(picomatch@4.0.2) diff --git a/src/context.js b/src/context.js new file mode 100644 index 0000000..a2d6060 --- /dev/null +++ b/src/context.js @@ -0,0 +1,150 @@ +/** @import { TSESTree } from '@typescript-eslint/types' */ +/** @import { BaseNode, Command, Visitors } from './types' */ + +export const margin = 0; +export const newline = 1; +export const indent = 2; +export const dedent = 3; + +export class Context { + #visitors; + #commands; + + multiline = false; + + /** + * + * @param {Visitors} visitors + * @param {Command[]} commands + */ + constructor(visitors, commands = []) { + this.#visitors = visitors; + this.#commands = commands; + } + + indent() { + this.#commands.push(indent); + } + + dedent() { + this.#commands.push(dedent); + } + + margin() { + this.#commands.push(margin); + } + + newline() { + this.multiline = true; + this.#commands.push(newline); + } + + /** + * @param {Context} context + */ + append(context) { + this.#commands.push(context.#commands); + } + + /** + * + * @param {string} content + * @param {BaseNode} [node] + */ + write(content, node) { + if (node?.loc) { + this.location(node.loc.start.line, node.loc.start.column); + this.#commands.push(content); + this.location(node.loc.end.line, node.loc.end.column); + } else { + this.#commands.push(content); + } + } + + /** + * + * @param {number} line + * @param {number} column + */ + location(line, column) { + this.#commands.push({ type: 'Location', line, column }); + } + + /** + * @param {{ type: string }} node + */ + visit(node) { + const visitor = this.#visitors[node.type]; + + if (!visitor) { + let message = `Not implemented: ${node.type}`; + + if (node.type.includes('TS')) { + message += ` (consider using 'esrap/languages/ts')`; + } + + if (node.type.includes('JSX')) { + message += ` (consider using 'esrap/languages/tsx')`; + } + + throw new Error(message); + } + + if (this.#visitors._) { + // @ts-ignore + this.#visitors._(node, this, (node) => visitor(node, this)); + } else { + // @ts-ignore + visitor(node, this); + } + } + + empty() { + return !this.#commands.some(has_content); + } + + measure() { + return measure(this.#commands); + } + + new() { + return new Context(this.#visitors); + } +} + +/** + * + * @param {Command[]} commands + * @param {number} [from] + * @param {number} [to] + */ +function measure(commands, from = 0, to = commands.length) { + let total = 0; + + for (let i = from; i < to; i += 1) { + const command = commands[i]; + + if (typeof command === 'string') { + total += command.length; + } else if (Array.isArray(command)) { + total += measure(command); + } + } + + return total; +} + +/** + * @param {Command} command + */ +function has_content(command) { + if (Array.isArray(command)) { + return command.some(has_content); + } + + if (typeof command === 'string') { + return command.length > 0; + } + + return false; +} diff --git a/src/handlers.js b/src/handlers.js deleted file mode 100644 index ae7e37b..0000000 --- a/src/handlers.js +++ /dev/null @@ -1,1688 +0,0 @@ -/** @import { TSESTree } from '@typescript-eslint/types' */ -/** @import { Command, Dedent, Handlers, Location, Indent, Newline, NodeWithComments, State, TypeAnnotationNodes } from './types' */ - -/** @type {Newline} */ -const newline = { type: 'Newline' }; - -/** @type {Indent} */ -const indent = { type: 'Indent' }; - -/** @type {Dedent} */ -const dedent = { type: 'Dedent' }; - -/** - * @returns {Command[]} - */ -function create_sequence() { - return []; -} - -/** - * Rough estimate of the combined width of a group of commands - * @param {Command[]} commands - * @param {number} from - * @param {number} to - */ -function measure(commands, from, to = commands.length) { - let total = 0; - for (let i = from; i < to; i += 1) { - const command = commands[i]; - if (typeof command === 'string') { - total += command.length; - } else if (Array.isArray(command)) { - total += - command.length === 0 - ? 2 // assume this is ', ' - : measure(command, 0); - } - } - - return total; -} - -/** - * @param {TSESTree.Node} node - * @param {State} state - */ -export function handle(node, state) { - const node_with_comments = /** @type {NodeWithComments} */ (node); - - const handler = handlers[node.type]; - - if (!handler) { - throw new Error(`Not implemented ${node.type}`); - } - - if (node_with_comments.leadingComments) { - prepend_comments(node_with_comments.leadingComments, state, false); - } - - // @ts-expect-error - handler(node, state); - - if (node_with_comments.trailingComments) { - state.comments.push(node_with_comments.trailingComments[0]); // there is only ever one - } -} - -/** - * @param {number} line - * @param {number} column - * @returns {Location} - */ -function l(line, column) { - return { - type: 'Location', - line, - column - }; -} - -/** - * @param {string} content - * @param {TSESTree.Node} node - * @returns {string | Command[]} - */ -function c(content, node) { - return node.loc - ? [ - l(node.loc.start.line, node.loc.start.column), - content, - l(node.loc.end.line, node.loc.end.column) - ] - : content; -} - -/** - * @param {TSESTree.Comment[]} comments - * @param {State} state - * @param {boolean} newlines - */ -function prepend_comments(comments, state, newlines) { - for (const comment of comments) { - state.commands.push({ type: 'Comment', comment }); - - if (newlines || comment.type === 'Line' || /\n/.test(comment.value)) { - state.commands.push(newline); - } else { - state.commands.push(' '); - } - } -} - -/** - * @param {string} string - * @param {'\'' | '"'} char - */ -function quote(string, char) { - let out = char; - - for (const c of string) { - if (c === '\\') { - out += '\\\\'; - } else if (c === char) { - out += '\\' + c; - } else if (c === '\n') { - out += '\\n'; - } else if (c === '\r') { - out += '\\r'; - } else { - out += c; - } - } - - return out + char; -} - -const OPERATOR_PRECEDENCE = { - '||': 2, - '&&': 3, - '??': 4, - '|': 5, - '^': 6, - '&': 7, - '==': 8, - '!=': 8, - '===': 8, - '!==': 8, - '<': 9, - '>': 9, - '<=': 9, - '>=': 9, - in: 9, - instanceof: 9, - '<<': 10, - '>>': 10, - '>>>': 10, - '+': 11, - '-': 11, - '*': 12, - '%': 12, - '/': 12, - '**': 13 -}; - -/** @type {Record} */ -const EXPRESSIONS_PRECEDENCE = { - JSXFragment: 20, - JSXElement: 20, - ArrayPattern: 20, - ObjectPattern: 20, - ArrayExpression: 20, - TaggedTemplateExpression: 20, - ThisExpression: 20, - Identifier: 20, - TemplateLiteral: 20, - Super: 20, - SequenceExpression: 20, - MemberExpression: 19, - MetaProperty: 19, - CallExpression: 19, - ChainExpression: 19, - ImportExpression: 19, - NewExpression: 19, - Literal: 18, - TSSatisfiesExpression: 18, - TSInstantiationExpression: 18, - TSNonNullExpression: 18, - TSTypeAssertion: 18, - AwaitExpression: 17, - ClassExpression: 17, - FunctionExpression: 17, - ObjectExpression: 17, - TSAsExpression: 16, - UpdateExpression: 16, - UnaryExpression: 15, - BinaryExpression: 14, - LogicalExpression: 13, - ConditionalExpression: 4, - ArrowFunctionExpression: 3, - AssignmentExpression: 3, - YieldExpression: 2, - RestElement: 1 -}; - -/** - * - * @param {TSESTree.Expression | TSESTree.PrivateIdentifier} node - * @param {TSESTree.BinaryExpression | TSESTree.LogicalExpression} parent - * @param {boolean} is_right - * @returns - */ -function needs_parens(node, parent, is_right) { - if (node.type === 'PrivateIdentifier') return false; - - // special case where logical expressions and coalesce expressions cannot be mixed, - // either of them need to be wrapped with parentheses - if ( - node.type === 'LogicalExpression' && - parent.type === 'LogicalExpression' && - ((parent.operator === '??' && node.operator !== '??') || - (parent.operator !== '??' && node.operator === '??')) - ) { - return true; - } - - const precedence = EXPRESSIONS_PRECEDENCE[node.type]; - const parent_precedence = EXPRESSIONS_PRECEDENCE[parent.type]; - - if (precedence !== parent_precedence) { - // Different node types - return ( - (!is_right && precedence === 15 && parent_precedence === 14 && parent.operator === '**') || - precedence < parent_precedence - ); - } - - if (precedence !== 13 && precedence !== 14) { - // Not a `LogicalExpression` or `BinaryExpression` - return false; - } - - if ( - /** @type {TSESTree.BinaryExpression} */ (node).operator === '**' && - parent.operator === '**' - ) { - // Exponentiation operator has right-to-left associativity - return !is_right; - } - - if (is_right) { - // Parenthesis are used if both operators have the same precedence - return ( - OPERATOR_PRECEDENCE[/** @type {TSESTree.BinaryExpression} */ (node).operator] <= - OPERATOR_PRECEDENCE[parent.operator] - ); - } - - return ( - OPERATOR_PRECEDENCE[/** @type {TSESTree.BinaryExpression} */ (node).operator] < - OPERATOR_PRECEDENCE[parent.operator] - ); -} - -/** @param {TSESTree.Node} node */ -function has_call_expression(node) { - while (node) { - if (node.type === 'CallExpression') { - return true; - } else if (node.type === 'MemberExpression') { - node = node.object; - } else { - return false; - } - } -} - -const grouped_expression_types = [ - 'ImportDeclaration', - 'VariableDeclaration', - 'ExportDefaultDeclaration', - 'ExportNamedDeclaration' -]; - -/** - * @param {TSESTree.Node[]} nodes - * @param {State} state - */ -const handle_body = (nodes, state) => { - let last_statement = /** @type {TSESTree.Node} */ ({ - type: 'EmptyStatement' - }); - let first = true; - let needs_margin = false; - - for (const statement of nodes) { - if (statement.type === 'EmptyStatement') continue; - - const margin = create_sequence(); - - if (!first) state.commands.push(margin, newline); - first = false; - - const statement_with_comments = /** @type {NodeWithComments} */ (statement); - const leading_comments = statement_with_comments.leadingComments; - delete statement_with_comments.leadingComments; - - if (leading_comments && leading_comments.length > 0) { - prepend_comments(leading_comments, state, true); - } - - const child_state = { ...state, multiline: false }; - handle(statement, child_state); - - if ( - child_state.multiline || - needs_margin || - ((grouped_expression_types.includes(statement.type) || - grouped_expression_types.includes(last_statement.type)) && - last_statement.type !== statement.type) - ) { - margin.push('\n'); - } - - let add_newline = false; - - while (state.comments.length) { - const comment = /** @type {TSESTree.Comment} */ (state.comments.shift()); - - state.commands.push(add_newline ? newline : ' ', { type: 'Comment', comment }); - add_newline = comment.type === 'Line'; - } - - needs_margin = child_state.multiline; - last_statement = statement; - } -}; - -/** - * @param {TSESTree.VariableDeclaration} node - * @param {State} state - */ -const handle_var_declaration = (node, state) => { - const index = state.commands.length; - - const open = create_sequence(); - const join = create_sequence(); - const child_state = { ...state, multiline: false }; - - state.commands.push(`${node.kind} `, open); - - let first = true; - - for (const d of node.declarations) { - if (!first) state.commands.push(join); - first = false; - - handle(d, child_state); - } - - const multiline = - child_state.multiline || (node.declarations.length > 1 && measure(state.commands, index) > 50); - - if (multiline) { - state.multiline = true; - if (node.declarations.length > 1) open.push(indent); - join.push(',', newline); - if (node.declarations.length > 1) state.commands.push(dedent); - } else { - join.push(', '); - } -}; - -/** - * @template {TSESTree.Node} T - * @param {Array} nodes - * @param {State} state - * @param {boolean} spaces - * @param {(node: T, state: State) => void} fn - */ -function sequence(nodes, state, spaces, fn, separator = ',') { - if (nodes.length === 0) return; - - const index = state.commands.length; - - const open = create_sequence(); - const join = create_sequence(); - const close = create_sequence(); - - state.commands.push(open); - - const child_state = { ...state, multiline: false }; - - let prev; - - for (let i = 0; i < nodes.length; i += 1) { - const node = nodes[i]; - const is_first = i === 0; - const is_last = i === nodes.length - 1; - - if (node) { - if (!is_first && !prev) { - state.commands.push(join); - } - - fn(node, child_state); - - if (!is_last) { - state.commands.push(separator); - } - - if (state.comments.length > 0) { - state.commands.push(' '); - - while (state.comments.length) { - const comment = /** @type {TSESTree.Comment} */ (state.comments.shift()); - state.commands.push({ type: 'Comment', comment }); - if (!is_last) state.commands.push(join); - } - - child_state.multiline = true; - } else { - if (!is_last) state.commands.push(join); - } - } else { - // This is only used for ArrayPattern and ArrayExpression, but - // it makes more sense to have the logic here than there, because - // otherwise we'd duplicate a lot more stuff - state.commands.push(separator); - } - - prev = node; - } - - state.commands.push(close); - - const multiline = child_state.multiline || measure(state.commands, index) > 50; - - if (multiline) { - state.multiline = true; - - open.push(indent, newline); - join.push(newline); - close.push(dedent, newline); - } else { - if (spaces) open.push(' '); - join.push(' '); - if (spaces) close.push(' '); - } -} - -/** - * @param {TypeAnnotationNodes} node - * @param {State} state - */ -function handle_type_annotation(node, state) { - switch (node.type) { - case 'TSNumberKeyword': - state.commands.push('number'); - break; - case 'TSStringKeyword': - state.commands.push('string'); - break; - case 'TSBooleanKeyword': - state.commands.push('boolean'); - break; - case 'TSAnyKeyword': - state.commands.push('any'); - break; - case 'TSVoidKeyword': - state.commands.push('void'); - break; - case 'TSUnknownKeyword': - state.commands.push('unknown'); - break; - case 'TSNeverKeyword': - state.commands.push('never'); - break; - case 'TSSymbolKeyword': - state.commands.push('symbol'); - break; - case 'TSNullKeyword': - state.commands.push('null'); - break; - case 'TSUndefinedKeyword': - state.commands.push('undefined'); - break; - case 'TSArrayType': - handle_type_annotation(node.elementType, state); - state.commands.push('[]'); - break; - case 'TSTypeAnnotation': - state.commands.push(': '); - handle_type_annotation(node.typeAnnotation, state); - break; - case 'TSTypeLiteral': - state.commands.push('{ '); - sequence(node.members, state, false, handle_type_annotation, ';'); - state.commands.push(' }'); - break; - case 'TSPropertySignature': - handle(node.key, state); - if (node.optional) state.commands.push('?'); - if (node.typeAnnotation) handle_type_annotation(node.typeAnnotation, state); - break; - case 'TSTypeReference': - handle(node.typeName, state); - - if (node.typeArguments) { - handle_type_annotation(node.typeArguments, state); - } - break; - case 'TSTypeParameterInstantiation': - case 'TSTypeParameterDeclaration': - state.commands.push('<'); - for (let i = 0; i < node.params.length; i++) { - handle_type_annotation(node.params[i], state); - if (i != node.params.length - 1) state.commands.push(', '); - } - state.commands.push('>'); - break; - case 'TSTypeParameter': - // @ts-expect-error `acorn-typescript` and `@typescript-eslint/types` have slightly different type definitions - state.commands.push(node.name); - - if (node.constraint) { - state.commands.push(' extends '); - handle_type_annotation(node.constraint, state); - } - break; - case 'TSTypeQuery': - state.commands.push('typeof '); - handle(node.exprName, state); - break; - case 'TSEnumMember': - handle(node.id, state); - if (node.initializer) { - state.commands.push(' = '); - handle(node.initializer, state); - } - break; - case 'TSFunctionType': - if (node.typeParameters) handle_type_annotation(node.typeParameters, state); - - // @ts-expect-error `acorn-typescript` and `@typescript-eslint/types` have slightly different type definitions - const parameters = node.parameters; - state.commands.push('('); - sequence(parameters, state, false, handle); - - state.commands.push(') => '); - - // @ts-expect-error `acorn-typescript` and `@typescript-eslint/types` have slightly different type definitions - handle_type_annotation(node.typeAnnotation.typeAnnotation, state); - break; - case 'TSIndexSignature': - const indexParameters = node.parameters; - state.commands.push('['); - sequence(indexParameters, state, false, handle); - state.commands.push(']'); - - // @ts-expect-error `acorn-typescript` and `@typescript-eslint/types` have slightly different type definitions - handle_type_annotation(node.typeAnnotation, state); - break; - case 'TSMethodSignature': - handle(node.key, state); - - // @ts-expect-error `acorn-typescript` and `@typescript-eslint/types` have slightly different type definitions - const parametersSignature = node.parameters; - state.commands.push('('); - sequence(parametersSignature, state, false, handle); - state.commands.push(')'); - - // @ts-expect-error `acorn-typescript` and `@typescript-eslint/types` have slightly different type definitions - handle_type_annotation(node.typeAnnotation, state); - break; - case 'TSExpressionWithTypeArguments': - handle(node.expression, state); - break; - case 'TSTupleType': - state.commands.push('['); - sequence(node.elementTypes, state, false, handle_type_annotation); - state.commands.push(']'); - break; - case 'TSNamedTupleMember': - handle(node.label, state); - state.commands.push(': '); - handle_type_annotation(node.elementType, state); - - break; - case 'TSUnionType': - sequence(node.types, state, false, handle_type_annotation, ' |'); - break; - case 'TSIntersectionType': - sequence(node.types, state, false, handle_type_annotation, ' &'); - break; - case 'TSLiteralType': - handle(node.literal, state); - break; - case 'TSConditionalType': - handle_type_annotation(node.checkType, state); - state.commands.push(' extends '); - handle_type_annotation(node.extendsType, state); - state.commands.push(' ? '); - handle_type_annotation(node.trueType, state); - state.commands.push(' : '); - handle_type_annotation(node.falseType, state); - break; - case 'TSIndexedAccessType': - handle_type_annotation(node.objectType, state); - state.commands.push('['); - handle_type_annotation(node.indexType, state); - state.commands.push(']'); - break; - case 'TSImportType': - state.commands.push('import('); - handle(node.argument, state); - state.commands.push(')'); - - if (node.qualifier) { - state.commands.push('.'); - handle(node.qualifier, state); - } - break; - default: - throw new Error(`Not implemented type annotation ${node.type}`); - } -} - -/** @satisfies {Record undefined>} */ -const shared = { - /** - * @param {TSESTree.ArrayExpression | TSESTree.ArrayPattern} node - * @param {State} state - */ - 'ArrayExpression|ArrayPattern': (node, state) => { - state.commands.push('['); - sequence(/** @type {TSESTree.Node[]} */ (node.elements), state, false, handle); - state.commands.push(']'); - }, - - /** - * @param {TSESTree.BinaryExpression | TSESTree.LogicalExpression} node - * @param {State} state - */ - 'BinaryExpression|LogicalExpression': (node, state) => { - // TODO - // const is_in = node.operator === 'in'; - // if (is_in) { - // // Avoids confusion in `for` loops initializers - // chunks.push(c('(')); - // } - - if (needs_parens(node.left, node, false)) { - state.commands.push('('); - handle(node.left, state); - state.commands.push(')'); - } else { - handle(node.left, state); - } - - state.commands.push(` ${node.operator} `); - - if (needs_parens(node.right, node, true)) { - state.commands.push('('); - handle(node.right, state); - state.commands.push(')'); - } else { - handle(node.right, state); - } - }, - - /** - * @param {TSESTree.BlockStatement | TSESTree.ClassBody} node - * @param {State} state - */ - 'BlockStatement|ClassBody': (node, state) => { - if (node.loc) { - const { line, column } = node.loc.start; - state.commands.push(l(line, column), '{', l(line, column + 1)); - } else { - state.commands.push('{'); - } - - if (node.body.length > 0) { - state.multiline = true; - state.commands.push(indent, newline); - handle_body(node.body, state); - state.commands.push(dedent, newline); - } - - if (node.loc) { - const { line, column } = node.loc.end; - state.commands.push(l(line, column - 1), '}', l(line, column)); - } else { - state.commands.push('}'); - } - }, - - /** - * @param {TSESTree.CallExpression | TSESTree.NewExpression} node - * @param {State} state - */ - 'CallExpression|NewExpression': (node, state) => { - if (node.type === 'NewExpression') { - state.commands.push('new '); - } - - const needs_parens = - EXPRESSIONS_PRECEDENCE[node.callee.type] < EXPRESSIONS_PRECEDENCE.CallExpression || - (node.type === 'NewExpression' && has_call_expression(node.callee)); - - if (needs_parens) { - state.commands.push('('); - handle(node.callee, state); - state.commands.push(')'); - } else { - handle(node.callee, state); - } - - if (/** @type {TSESTree.CallExpression} */ (node).optional) { - state.commands.push('?.'); - } - - if (node.typeArguments) handle_type_annotation(node.typeArguments, state); - - const open = create_sequence(); - const join = create_sequence(); - const close = create_sequence(); - - state.commands.push('(', open); - - // if the final argument is multiline, it doesn't need to force all the - // other arguments to also be multiline - const child_state = { ...state, multiline: false }; - const final_state = { ...state, multiline: false }; - - for (let i = 0; i < node.arguments.length; i += 1) { - if (i > 0) { - if (state.comments.length > 0) { - state.commands.push(', '); - - while (state.comments.length) { - const comment = /** @type {TSESTree.Comment} */ (state.comments.shift()); - - state.commands.push({ type: 'Comment', comment }); - - if (comment.type === 'Line') { - child_state.multiline = true; - state.commands.push(newline); - } else { - state.commands.push(' '); - } - } - } else { - state.commands.push(join); - } - } - - const p = node.arguments[i]; - - handle(p, i === node.arguments.length - 1 ? final_state : child_state); - } - - state.commands.push(close, ')'); - - const multiline = child_state.multiline; - - if (multiline || final_state.multiline) { - state.multiline = true; - } - - if (multiline) { - open.push(indent, newline); - join.push(',', newline); - close.push(dedent, newline); - } else { - join.push(', '); - } - }, - - /** - * @param {TSESTree.ClassDeclaration | TSESTree.ClassExpression} node - * @param {State} state - */ - 'ClassDeclaration|ClassExpression': (node, state) => { - state.commands.push('class '); - - if (node.id) { - handle(node.id, state); - state.commands.push(' '); - } - - if (node.superClass) { - state.commands.push('extends '); - handle(node.superClass, state); - state.commands.push(' '); - } - - if (node.implements) { - state.commands.push('implements '); - sequence(node.implements, state, false, handle_type_annotation); - } - - handle(node.body, state); - }, - - /** - * @param {TSESTree.ForInStatement | TSESTree.ForOfStatement} node - * @param {State} state - */ - 'ForInStatement|ForOfStatement': (node, state) => { - state.commands.push('for '); - if (node.type === 'ForOfStatement' && node.await) state.commands.push('await '); - state.commands.push('('); - - if (node.left.type === 'VariableDeclaration') { - handle_var_declaration(node.left, state); - } else { - handle(node.left, state); - } - - state.commands.push(node.type === 'ForInStatement' ? ` in ` : ` of `); - handle(node.right, state); - state.commands.push(') '); - handle(node.body, state); - }, - - /** - * @param {TSESTree.FunctionDeclaration | TSESTree.FunctionExpression} node - * @param {State} state - */ - 'FunctionDeclaration|FunctionExpression': (node, state) => { - if (node.async) state.commands.push('async '); - state.commands.push(node.generator ? 'function* ' : 'function '); - if (node.id) handle(node.id, state); - - if (node.typeParameters) { - handle_type_annotation(node.typeParameters, state); - } - - state.commands.push('('); - sequence(node.params, state, false, handle); - state.commands.push(')'); - - if (node.returnType) handle_type_annotation(node.returnType, state); - - state.commands.push(' '); - - handle(node.body, state); - }, - - /** - * @param {TSESTree.RestElement | TSESTree.SpreadElement} node - * @param {State} state - */ - 'RestElement|SpreadElement': (node, state) => { - state.commands.push('...'); - handle(node.argument, state); - - // @ts-expect-error `acorn-typescript` and `@typescript-eslint/types` have slightly different type definitions - if (node.typeAnnotation) handle_type_annotation(node.typeAnnotation, state); - } -}; - -/** @type {Handlers} */ -const handlers = { - ArrayExpression: shared['ArrayExpression|ArrayPattern'], - - ArrayPattern: shared['ArrayExpression|ArrayPattern'], - - ArrowFunctionExpression: (node, state) => { - if (node.async) state.commands.push('async '); - - state.commands.push('('); - sequence(node.params, state, false, handle); - state.commands.push(') => '); - - if ( - node.body.type === 'ObjectExpression' || - (node.body.type === 'AssignmentExpression' && node.body.left.type === 'ObjectPattern') || - (node.body.type === 'LogicalExpression' && node.body.left.type === 'ObjectExpression') || - (node.body.type === 'ConditionalExpression' && node.body.test.type === 'ObjectExpression') - ) { - state.commands.push('('); - handle(node.body, state); - state.commands.push(')'); - } else { - handle(node.body, state); - } - }, - - AssignmentExpression(node, state) { - handle(node.left, state); - state.commands.push(` ${node.operator} `); - handle(node.right, state); - }, - - AssignmentPattern(node, state) { - handle(node.left, state); - state.commands.push(' = '); - handle(node.right, state); - }, - - AwaitExpression(node, state) { - if (node.argument) { - const precedence = EXPRESSIONS_PRECEDENCE[node.argument.type]; - - if (precedence && precedence < EXPRESSIONS_PRECEDENCE.AwaitExpression) { - state.commands.push('await ('); - handle(node.argument, state); - state.commands.push(')'); - } else { - state.commands.push('await '); - handle(node.argument, state); - } - } else { - state.commands.push('await'); - } - }, - - BinaryExpression: shared['BinaryExpression|LogicalExpression'], - - BlockStatement: shared['BlockStatement|ClassBody'], - - BreakStatement(node, state) { - if (node.label) { - state.commands.push('break '); - handle(node.label, state); - state.commands.push(';'); - } else { - state.commands.push('break;'); - } - }, - - CallExpression: shared['CallExpression|NewExpression'], - - ChainExpression(node, state) { - handle(node.expression, state); - }, - - ClassBody: shared['BlockStatement|ClassBody'], - - ClassDeclaration: shared['ClassDeclaration|ClassExpression'], - - ClassExpression: shared['ClassDeclaration|ClassExpression'], - - ConditionalExpression(node, state) { - if (EXPRESSIONS_PRECEDENCE[node.test.type] > EXPRESSIONS_PRECEDENCE.ConditionalExpression) { - handle(node.test, state); - } else { - state.commands.push('('); - handle(node.test, state); - state.commands.push(')'); - } - - const if_true = create_sequence(); - const if_false = create_sequence(); - - const child_state = { ...state, multiline: false }; - - state.commands.push(if_true); - handle(node.consequent, child_state); - state.commands.push(if_false); - handle(node.alternate, child_state); - - const multiline = child_state.multiline; - - if (multiline) { - if_true.push(indent, newline, '? '); - if_false.push(newline, ': '); - state.commands.push(dedent); - } else { - if_true.push(' ? '); - if_false.push(' : '); - } - }, - - ContinueStatement(node, state) { - if (node.label) { - state.commands.push('continue '); - handle(node.label, state); - state.commands.push(';'); - } else { - state.commands.push('continue;'); - } - }, - - DebuggerStatement(node, state) { - state.commands.push(c('debugger', node), ';'); - }, - - Decorator(node, state) { - state.commands.push('@'); - handle(node.expression, state); - state.commands.push(newline); - }, - - DoWhileStatement(node, state) { - state.commands.push('do '); - handle(node.body, state); - state.commands.push(' while ('); - handle(node.test, state); - state.commands.push(');'); - }, - - EmptyStatement(node, state) { - state.commands.push(';'); - }, - - ExportAllDeclaration(node, state) { - state.commands.push('export * '); - if (node.exported) { - state.commands.push('as '); - handle(node.exported, state); - } - state.commands.push(' from '); - handle(node.source, state); - state.commands.push(';'); - }, - - ExportDefaultDeclaration(node, state) { - state.commands.push('export default '); - - handle(node.declaration, state); - - if (node.declaration.type !== 'FunctionDeclaration') { - state.commands.push(';'); - } - }, - - ExportNamedDeclaration(node, state) { - state.commands.push('export '); - - if (node.declaration) { - handle(node.declaration, state); - return; - } - - state.commands.push('{'); - sequence(node.specifiers, state, true, (s, state) => { - handle(s.local, state); - - if (s.local.name !== s.exported.name) { - state.commands.push(' as '); - handle(s.exported, state); - } - }); - state.commands.push('}'); - - if (node.source) { - state.commands.push(' from '); - handle(node.source, state); - } - - state.commands.push(';'); - }, - - ExpressionStatement(node, state) { - if ( - node.expression.type === 'ObjectExpression' || - (node.expression.type === 'AssignmentExpression' && - node.expression.left.type === 'ObjectPattern') || - node.expression.type === 'FunctionExpression' - ) { - // is an AssignmentExpression to an ObjectPattern - state.commands.push('('); - handle(node.expression, state); - state.commands.push(');'); - return; - } - - handle(node.expression, state); - state.commands.push(';'); - }, - - ForStatement: (node, state) => { - state.commands.push('for ('); - - if (node.init) { - if (node.init.type === 'VariableDeclaration') { - handle_var_declaration(node.init, state); - } else { - handle(node.init, state); - } - } - - state.commands.push('; '); - if (node.test) handle(node.test, state); - state.commands.push('; '); - if (node.update) handle(node.update, state); - - state.commands.push(') '); - handle(node.body, state); - }, - - ForInStatement: shared['ForInStatement|ForOfStatement'], - - ForOfStatement: shared['ForInStatement|ForOfStatement'], - - FunctionDeclaration: shared['FunctionDeclaration|FunctionExpression'], - - FunctionExpression: shared['FunctionDeclaration|FunctionExpression'], - - Identifier(node, state) { - let name = node.name; - state.commands.push(c(name, node)); - - if (node.typeAnnotation) handle_type_annotation(node.typeAnnotation, state); - }, - - IfStatement(node, state) { - state.commands.push('if ('); - handle(node.test, state); - state.commands.push(') '); - handle(node.consequent, state); - - if (node.alternate) { - state.commands.push(' else '); - handle(node.alternate, state); - } - }, - - ImportDeclaration(node, state) { - if (node.specifiers.length === 0) { - state.commands.push('import '); - handle(node.source, state); - state.commands.push(';'); - return; - } - - /** @type {TSESTree.ImportNamespaceSpecifier | null} */ - let namespace_specifier = null; - - /** @type {TSESTree.ImportDefaultSpecifier | null} */ - let default_specifier = null; - - /** @type {TSESTree.ImportSpecifier[]} */ - const named_specifiers = []; - - for (const s of node.specifiers) { - if (s.type === 'ImportNamespaceSpecifier') { - namespace_specifier = s; - } else if (s.type === 'ImportDefaultSpecifier') { - default_specifier = s; - } else { - named_specifiers.push(s); - } - } - - state.commands.push('import '); - if (node.importKind == 'type') state.commands.push('type '); - - if (default_specifier) { - state.commands.push(c(default_specifier.local.name, default_specifier)); - if (namespace_specifier || named_specifiers.length > 0) state.commands.push(', '); - } - - if (namespace_specifier) { - state.commands.push(c('* as ' + namespace_specifier.local.name, namespace_specifier)); - } - - if (named_specifiers.length > 0) { - state.commands.push('{'); - sequence(named_specifiers, state, true, (s, state) => { - if (s.local.name !== s.imported.name) { - handle(s.imported, state); - state.commands.push(' as '); - } - - if (s.importKind == 'type') state.commands.push('type '); - handle(s.local, state); - }); - state.commands.push('}'); - } - - state.commands.push(' from '); - handle(node.source, state); - if (node.attributes && node.attributes.length > 0) { - state.commands.push(' with { '); - for (let index = 0; index < node.attributes.length; index++) { - const { key, value } = node.attributes[index]; - handle(key, state); - state.commands.push(': '); - handle(value, state); - if (index + 1 !== node.attributes.length) { - state.commands.push(', '); - } - } - state.commands.push(' }'); - } - state.commands.push(';'); - }, - - ImportExpression(node, state) { - state.commands.push('import('); - handle(node.source, state); - //@ts-expect-error for some reason the types haven't been updated - if (node.arguments) { - //@ts-expect-error - for (let index = 0; index < node.arguments.length; index++) { - state.commands.push(', '); - //@ts-expect-error - handle(node.arguments[index], state); - } - } - state.commands.push(')'); - }, - - LabeledStatement(node, state) { - handle(node.label, state); - state.commands.push(': '); - handle(node.body, state); - }, - - Literal(node, state) { - // TODO do we need to handle weird unicode characters somehow? - // str.replace(/\\u(\d{4})/g, (m, n) => String.fromCharCode(+n)) - - const value = - node.raw || - (typeof node.value === 'string' ? quote(node.value, state.quote) : String(node.value)); - - state.commands.push(c(value, node)); - }, - - LogicalExpression: shared['BinaryExpression|LogicalExpression'], - - MemberExpression(node, state) { - if (EXPRESSIONS_PRECEDENCE[node.object.type] < EXPRESSIONS_PRECEDENCE.MemberExpression) { - state.commands.push('('); - handle(node.object, state); - state.commands.push(')'); - } else { - handle(node.object, state); - } - - if (node.computed) { - if (node.optional) { - state.commands.push('?.'); - } - state.commands.push('['); - handle(node.property, state); - state.commands.push(']'); - } else { - state.commands.push(node.optional ? '?.' : '.'); - handle(node.property, state); - } - }, - - MetaProperty(node, state) { - handle(node.meta, state); - state.commands.push('.'); - handle(node.property, state); - }, - - MethodDefinition(node, state) { - if (node.decorators) { - for (const decorator of node.decorators) { - handle(decorator, state); - } - } - - if (node.static) { - state.commands.push('static '); - } - - if (node.kind === 'get' || node.kind === 'set') { - // Getter or setter - state.commands.push(node.kind + ' '); - } - - if (node.value.async) { - state.commands.push('async '); - } - - if (node.value.generator) { - state.commands.push('*'); - } - - if (node.computed) state.commands.push('['); - handle(node.key, state); - if (node.computed) state.commands.push(']'); - - state.commands.push('('); - sequence(node.value.params, state, false, handle); - state.commands.push(')'); - - if (node.value.returnType) handle_type_annotation(node.value.returnType, state); - - state.commands.push(' '); - - if (node.value.body) handle(node.value.body, state); - }, - - NewExpression: shared['CallExpression|NewExpression'], - - ObjectExpression(node, state) { - state.commands.push('{'); - sequence(node.properties, state, true, (p, state) => { - if (p.type === 'Property' && p.value.type === 'FunctionExpression') { - const fn = /** @type {TSESTree.FunctionExpression} */ (p.value); - - if (p.kind === 'get' || p.kind === 'set') { - state.commands.push(p.kind + ' '); - } else { - if (fn.async) state.commands.push('async '); - if (fn.generator) state.commands.push('*'); - } - - if (p.computed) state.commands.push('['); - handle(p.key, state); - if (p.computed) state.commands.push(']'); - - state.commands.push('('); - sequence(fn.params, state, false, handle); - state.commands.push(') '); - - handle(fn.body, state); - } else { - handle(p, state); - } - }); - state.commands.push('}'); - }, - - ObjectPattern(node, state) { - state.commands.push('{'); - sequence(node.properties, state, true, handle); - state.commands.push('}'); - - if (node.typeAnnotation) handle_type_annotation(node.typeAnnotation, state); - }, - - // @ts-expect-error this isn't a real node type, but Acorn produces it - ParenthesizedExpression(node, state) { - return handle(node.expression, state); - }, - - PrivateIdentifier(node, state) { - state.commands.push('#', c(node.name, node)); - }, - - Program(node, state) { - handle_body(node.body, state); - }, - - Property(node, state) { - const value = node.value.type === 'AssignmentPattern' ? node.value.left : node.value; - - const shorthand = - !node.computed && - node.kind === 'init' && - node.key.type === 'Identifier' && - value.type === 'Identifier' && - node.key.name === value.name; - - if (shorthand) { - handle(node.value, state); - return; - } - - if (node.computed) state.commands.push('['); - handle(node.key, state); - state.commands.push(node.computed ? ']: ' : ': '); - handle(node.value, state); - }, - - PropertyDefinition(node, state) { - if (node.decorators) { - for (const decorator of node.decorators) { - handle(decorator, state); - } - } - - if (node.accessibility) { - state.commands.push(node.accessibility, ' '); - } - - if (node.static) { - state.commands.push('static '); - } - - if (node.computed) { - state.commands.push('['); - handle(node.key, state); - state.commands.push(']'); - } else { - handle(node.key, state); - } - - if (node.typeAnnotation) { - state.commands.push(': '); - handle_type_annotation(node.typeAnnotation.typeAnnotation, state); - } - - if (node.value) { - state.commands.push(' = '); - - handle(node.value, state); - } - - state.commands.push(';'); - }, - - RestElement: shared['RestElement|SpreadElement'], - - ReturnStatement(node, state) { - if (node.argument) { - const argumentWithComment = /** @type {NodeWithComments} */ (node.argument); - const contains_comment = - argumentWithComment.leadingComments && - argumentWithComment.leadingComments.some((comment) => comment.type === 'Line'); - - state.commands.push(contains_comment ? 'return (' : 'return '); - handle(node.argument, state); - state.commands.push(contains_comment ? ');' : ';'); - } else { - state.commands.push('return;'); - } - }, - - SequenceExpression(node, state) { - state.commands.push('('); - sequence(node.expressions, state, false, handle); - state.commands.push(')'); - }, - - SpreadElement: shared['RestElement|SpreadElement'], - - StaticBlock(node, state) { - state.commands.push(indent, 'static {', newline); - - handle_body(node.body, state); - - state.commands.push(dedent, newline, '}'); - }, - - Super(node, state) { - state.commands.push(c('super', node)); - }, - - SwitchStatement(node, state) { - state.commands.push('switch ('); - handle(node.discriminant, state); - state.commands.push(') {', indent); - - let first = true; - - for (const block of node.cases) { - if (!first) state.commands.push('\n'); - first = false; - - if (block.test) { - state.commands.push(newline, `case `); - handle(block.test, state); - state.commands.push(':'); - } else { - state.commands.push(newline, `default:`); - } - - state.commands.push(indent); - - for (const statement of block.consequent) { - state.commands.push(newline); - handle(statement, state); - } - - state.commands.push(dedent); - } - - state.commands.push(dedent, newline, `}`); - }, - - TaggedTemplateExpression(node, state) { - handle(node.tag, state); - handle(node.quasi, state); - }, - - TemplateLiteral(node, state) { - state.commands.push('`'); - - const { quasis, expressions } = node; - - for (let i = 0; i < expressions.length; i++) { - const raw = quasis[i].value.raw; - - state.commands.push(raw, '${'); - handle(expressions[i], state); - state.commands.push('}'); - - if (/\n/.test(raw)) state.multiline = true; - } - - const raw = quasis[quasis.length - 1].value.raw; - - state.commands.push(raw, '`'); - if (/\n/.test(raw)) state.multiline = true; - }, - - ThisExpression(node, state) { - state.commands.push(c('this', node)); - }, - - ThrowStatement(node, state) { - state.commands.push('throw '); - if (node.argument) handle(node.argument, state); - state.commands.push(';'); - }, - - TryStatement(node, state) { - state.commands.push('try '); - handle(node.block, state); - - if (node.handler) { - if (node.handler.param) { - state.commands.push(' catch('); - handle(node.handler.param, state); - state.commands.push(') '); - } else { - state.commands.push(' catch '); - } - - handle(node.handler.body, state); - } - - if (node.finalizer) { - state.commands.push(' finally '); - handle(node.finalizer, state); - } - }, - - TSAsExpression(node, state) { - if (node.expression) { - const needs_parens = - EXPRESSIONS_PRECEDENCE[node.expression.type] < EXPRESSIONS_PRECEDENCE.TSAsExpression; - - if (needs_parens) { - state.commands.push('('); - handle(node.expression, state); - state.commands.push(')'); - } else { - handle(node.expression, state); - } - } - state.commands.push(' as '); - handle_type_annotation(node.typeAnnotation, state); - }, - - TSEnumDeclaration(node, state) { - state.commands.push('enum '); - handle(node.id, state); - state.commands.push(' {', indent, newline); - sequence(node.members, state, false, handle_type_annotation); - state.commands.push(dedent, newline, '}', newline); - }, - - TSModuleBlock(node, state) { - state.commands.push(' {', indent, newline); - handle_body(node.body, state); - state.commands.push(dedent, newline, '}'); - }, - - TSModuleDeclaration(node, state) { - if (node.declare) state.commands.push('declare '); - else state.commands.push('namespace '); - - handle(node.id, state); - - if (!node.body) return; - handle(node.body, state); - }, - - TSNonNullExpression(node, state) { - handle(node.expression, state); - state.commands.push('!'); - }, - - TSInterfaceBody(node, state) { - sequence(node.body, state, true, handle_type_annotation, ';'); - }, - - TSInterfaceDeclaration(node, state) { - state.commands.push('interface '); - handle(node.id, state); - if (node.typeParameters) handle_type_annotation(node.typeParameters, state); - if (node.extends) { - state.commands.push(' extends '); - sequence(node.extends, state, false, handle_type_annotation); - } - state.commands.push(' {'); - handle(node.body, state); - state.commands.push('}'); - }, - - TSSatisfiesExpression(node, state) { - if (node.expression) { - const needs_parens = - EXPRESSIONS_PRECEDENCE[node.expression.type] < EXPRESSIONS_PRECEDENCE.TSSatisfiesExpression; - - if (needs_parens) { - state.commands.push('('); - handle(node.expression, state); - state.commands.push(')'); - } else { - handle(node.expression, state); - } - } - state.commands.push(' satisfies '); - handle_type_annotation(node.typeAnnotation, state); - }, - - TSTypeAliasDeclaration(node, state) { - state.commands.push('type '); - handle(node.id, state); - if (node.typeParameters) handle_type_annotation(node.typeParameters, state); - state.commands.push(' = '); - handle_type_annotation(node.typeAnnotation, state); - state.commands.push(';'); - }, - - TSQualifiedName(node, state) { - handle(node.left, state); - state.commands.push('.'); - handle(node.right, state); - }, - - UnaryExpression(node, state) { - state.commands.push(node.operator); - - if (node.operator.length > 1) { - state.commands.push(' '); - } - - if (EXPRESSIONS_PRECEDENCE[node.argument.type] < EXPRESSIONS_PRECEDENCE.UnaryExpression) { - state.commands.push('('); - handle(node.argument, state); - state.commands.push(')'); - } else { - handle(node.argument, state); - } - }, - - UpdateExpression(node, state) { - if (node.prefix) { - state.commands.push(node.operator); - handle(node.argument, state); - } else { - handle(node.argument, state); - state.commands.push(node.operator); - } - }, - - VariableDeclaration(node, state) { - handle_var_declaration(node, state); - state.commands.push(';'); - }, - - VariableDeclarator(node, state) { - handle(node.id, state); - - if (node.init) { - state.commands.push(' = '); - handle(node.init, state); - } - }, - - WhileStatement(node, state) { - state.commands.push('while ('); - handle(node.test, state); - state.commands.push(') '); - handle(node.body, state); - }, - - WithStatement(node, state) { - state.commands.push('with ('); - handle(node.object, state); - state.commands.push(') '); - handle(node.body, state); - }, - - YieldExpression(node, state) { - if (node.argument) { - state.commands.push(node.delegate ? `yield* ` : `yield `); - handle(node.argument, state); - } else { - state.commands.push(node.delegate ? `yield*` : `yield`); - } - } -}; diff --git a/src/index.js b/src/index.js index d5c7546..164d38f 100644 --- a/src/index.js +++ b/src/index.js @@ -1,7 +1,6 @@ -/** @import { TSESTree } from '@typescript-eslint/types' */ -/** @import { Command, PrintOptions, State } from './types' */ -import { handle } from './handlers.js'; +/** @import { BaseNode, Command, Visitors, PrintOptions } from './types' */ import { encode } from '@jridgewell/sourcemap-codec'; +import { Context, dedent, indent, margin, newline } from './context.js'; /** @type {(str: string) => string} str */ let btoa = () => { @@ -10,38 +9,56 @@ let btoa = () => { if (typeof window !== 'undefined' && typeof window.btoa === 'function') { btoa = (str) => window.btoa(unescape(encodeURIComponent(str))); - // @ts-expect-error } else if (typeof Buffer === 'function') { - // @ts-expect-error btoa = (str) => Buffer.from(str, 'utf-8').toString('base64'); } +class SourceMap { + version = 3; + + /** @type {string[]} */ + names = []; + + /** + * @param {[number, number, number, number][][]} mappings + * @param {PrintOptions} opts + */ + constructor(mappings, opts) { + this.sources = [opts.sourceMapSource || null]; + this.sourcesContent = [opts.sourceMapContent || null]; + this.mappings = opts.sourceMapEncodeMappings === false ? mappings : encode(mappings); + } + + /** + * Returns a JSON representation suitable for saving as a `*.map` file + */ + toString() { + return JSON.stringify(this); + } + + /** + * Returns a base64-encoded JSON representation suitable for inlining at the bottom of a file with `//# sourceMappingURL={...}` + */ + toUrl() { + return 'data:application/json;charset=utf-8;base64,' + btoa(this.toString()); + } +} + /** - * @param {{ type: string, [key: string]: any }} node + * @template {BaseNode} [T=BaseNode] + * @param {T} node + * @param {Visitors} visitors * @param {PrintOptions} opts * @returns {{ code: string, map: any }} // TODO */ -export function print(node, opts = {}) { - if (Array.isArray(node)) { - return print( - { - type: 'Program', - body: node, - sourceType: 'module' - }, - opts - ); - } +export function print(node, visitors, opts = {}) { + /** @type {Command[]} */ + const commands = []; - /** @type {State} */ - const state = { - commands: [], - comments: [], - multiline: false, - quote: opts.quotes === 'double' ? '"' : "'" - }; + // @ts-expect-error some nonsense I don't understand + const context = new Context(visitors, commands); - handle(/** @type {TSESTree.Node} */ (node), state); + context.visit(node); /** @typedef {[number, number, number, number]} Segment */ @@ -69,16 +86,14 @@ export function print(node, opts = {}) { } } - let newline = '\n'; - const indent = opts.indent ?? '\t'; + let current_newline = '\n'; + const indent_str = opts.indent ?? '\t'; + + let needs_newline = false; + let needs_margin = false; /** @param {Command} command */ function run(command) { - if (typeof command === 'string') { - append(command); - return; - } - if (Array.isArray(command)) { for (let i = 0; i < command.length; i += 1) { run(command[i]); @@ -86,74 +101,60 @@ export function print(node, opts = {}) { return; } - switch (command.type) { - case 'Location': - current_line.push([ - current_column, - 0, // source index is always zero - command.line - 1, - command.column - ]); - break; - - case 'Newline': - append(newline); - break; - - case 'Indent': - newline += indent; - break; - - case 'Dedent': - newline = newline.slice(0, -indent.length); - break; - - case 'Comment': - if (command.comment.type === 'Line') { - append(`//${command.comment.value}`); - } else { - append(`/*${command.comment.value.replace(/\n/g, newline)}*/`); - } - - break; + if (typeof command === 'number') { + if (command === newline) { + needs_newline = true; + } else if (command === margin) { + needs_margin = true; + } else if (command === indent) { + current_newline += indent_str; + } else if (command === dedent) { + current_newline = current_newline.slice(0, -indent_str.length); + } + + return; + } + + if (needs_newline) { + append(needs_margin ? '\n' + current_newline : current_newline); + } + + needs_margin = needs_newline = false; + + if (typeof command === 'string') { + append(command); + return; + } + + if (command.type === 'Location') { + current_line.push([ + current_column, + 0, // source index is always zero + command.line - 1, + command.column + ]); } } - for (let i = 0; i < state.commands.length; i += 1) { - run(state.commands[i]); + for (let i = 0; i < commands.length; i += 1) { + run(commands[i]); } mappings.push(current_line); - const map = { - version: 3, - /** @type {string[]} */ - names: [], - sources: [opts.sourceMapSource || null], - sourcesContent: [opts.sourceMapContent || null], - mappings: - opts.sourceMapEncodeMappings == undefined || opts.sourceMapEncodeMappings - ? encode(mappings) - : mappings - }; - - Object.defineProperties(map, { - toString: { - enumerable: false, - value: function toString() { - return JSON.stringify(this); - } - }, - toUrl: { - enumerable: false, - value: function toUrl() { - return 'data:application/json;charset=utf-8;base64,' + btoa(this.toString()); - } - } - }); + /** @type {SourceMap} */ + let map; return { code, - map + // create sourcemap lazily in case we don't need it + get map() { + return (map ??= new SourceMap(mappings, opts)); + } }; } + +// it sucks that we have to export the class rather than just +// re-exporting it via public.d.ts, but otherwise TypeScript +// gets confused about private fields because it is really dumb! +export { Context }; diff --git a/src/languages/ts/index.js b/src/languages/ts/index.js new file mode 100644 index 0000000..fb66f70 --- /dev/null +++ b/src/languages/ts/index.js @@ -0,0 +1,1876 @@ +/** @import { TSESTree } from '@typescript-eslint/types' */ +/** @import { Visitors } from '../../types.js' */ +/** @import { TSOptions, Comment } from '../types.js' */ +import { Context } from 'esrap'; + +/** @typedef {TSESTree.Node} Node */ + +/** @type {Record} */ +export const EXPRESSIONS_PRECEDENCE = { + JSXFragment: 20, + JSXElement: 20, + ArrayPattern: 20, + ObjectPattern: 20, + ArrayExpression: 20, + TaggedTemplateExpression: 20, + ThisExpression: 20, + Identifier: 20, + TemplateLiteral: 20, + Super: 20, + SequenceExpression: 20, + MemberExpression: 19, + MetaProperty: 19, + CallExpression: 19, + ChainExpression: 19, + ImportExpression: 19, + NewExpression: 19, + Literal: 18, + TSSatisfiesExpression: 18, + TSInstantiationExpression: 18, + TSNonNullExpression: 18, + TSTypeAssertion: 18, + AwaitExpression: 17, + ClassExpression: 17, + FunctionExpression: 17, + ObjectExpression: 17, + TSAsExpression: 16, + UpdateExpression: 16, + UnaryExpression: 15, + BinaryExpression: 14, + LogicalExpression: 13, + ConditionalExpression: 4, + ArrowFunctionExpression: 3, + AssignmentExpression: 3, + YieldExpression: 2, + RestElement: 1 +}; + +const OPERATOR_PRECEDENCE = { + '||': 2, + '&&': 3, + '??': 4, + '|': 5, + '^': 6, + '&': 7, + '==': 8, + '!=': 8, + '===': 8, + '!==': 8, + '<': 9, + '>': 9, + '<=': 9, + '>=': 9, + in: 9, + instanceof: 9, + '<<': 10, + '>>': 10, + '>>>': 10, + '+': 11, + '-': 11, + '*': 12, + '%': 12, + '/': 12, + '**': 13 +}; + +/** + * @param {Comment} comment + * @param {Context} context + */ +function write_comment(comment, context) { + if (comment.type === 'Line') { + context.write(`//${comment.value}`); + } else { + context.write('/*'); + const lines = comment.value.split('\n'); + + for (let i = 0; i < lines.length; i += 1) { + if (i > 0) context.newline(); + context.write(lines[i]); + } + + context.write('*/'); + } +} + +/** + * @param {TSOptions} [options] + * @returns {Visitors} + */ +export default (options = {}) => { + const quote_char = options.quotes === 'double' ? '"' : "'"; + + const comments = options.comments ?? []; + + let comment_index = 0; + + /** + * Set `comment_index` to be the first comment after `start`. + * Most of the time this is already correct, but if nodes + * have been moved around we may need to search for it + * @param {TSESTree.Node} node + */ + function reset_comment_index(node) { + if (!node.loc) { + comment_index = comments.length; + return; + } + + let previous = comments[comment_index - 1]; + let comment = comments[comment_index]; + + if ( + comment && + comment.loc && + !before(comment.loc.start, node.loc.start) && + (!previous || (previous.loc && before(previous.loc.start, node.loc.start))) + ) { + return; + } + + // TODO use a binary search here, account for synthetic nodes (without `loc`) + comment_index = comments.findIndex( + (comment) => comment.loc && node.loc && !before(comment.loc.start, node.loc.start) + ); + if (comment_index === -1) comment_index = comments.length; + } + + /** + * @param {Context} context + * @param {{ line: number, column: number } | null} prev + * @param {{ line: number, column: number } | null} next + * @returns {boolean} true if final comment is a line comment + */ + function flush_trailing_comments(context, prev, next) { + while (comment_index < comments.length) { + const comment = comments[comment_index]; + + if ( + comment && + prev && + comment.loc.start.line === prev.line && + (next === null || before(comment.loc.end, next)) + ) { + context.write(' '); + write_comment(comment, context); + + comment_index += 1; + + if (comment.type === 'Line') { + return true; + } + } else { + break; + } + } + + return false; + } + + /** + * @param {Context} context + * @param {{ line: number, column: number } | null} from + * @param {{ line: number, column: number }} to + * @param {boolean} pad + */ + function flush_comments_until(context, from, to, pad) { + let first = true; + + while (comment_index < comments.length) { + const comment = comments[comment_index]; + + if (comment && comment.loc && to && before(comment.loc.start, to)) { + if (first && from !== null && comment.loc.start.line > from.line) { + context.margin(); + context.newline(); + } + + first = false; + + write_comment(comment, context); + + if (comment.loc.end.line < to.line) { + context.newline(); + } else if (pad) { + context.write(' '); + } + + comment_index += 1; + } else { + break; + } + } + } + + /** + * @param {Context} context + * @param {TSESTree.Node[]} nodes + * @param {{ line: number, column: number }} until + * @param {boolean} pad + */ + function sequence(context, nodes, until, pad, separator = ',') { + let multiline = false; + let length = -1; + + /** @type {boolean[]} */ + const multiline_nodes = []; + + const children = nodes.map((child, i) => { + const child_context = context.new(); + if (child) child_context.visit(child); + + multiline_nodes[i] = child_context.multiline; + + if (i < nodes.length - 1 || !child) { + child_context.write(separator); + } + + const next = i === nodes.length - 1 ? until : nodes[i + 1]?.loc?.start || null; + if (child && flush_trailing_comments(child_context, child.loc?.end || null, next)) { + multiline = true; + } + + length += child_context.measure() + 1; + multiline ||= child_context.multiline; + + return child_context; + }); + + multiline ||= length > 60; + + if (multiline) { + context.indent(); + context.newline(); + } else if (pad && length > 0) { + context.write(' '); + } + + /** @type {Context | null} */ + let prev = null; + + for (let i = 0; i < nodes.length; i += 1) { + const child = children[i]; + + if (prev !== null) { + if (multiline_nodes[i - 1] || multiline_nodes[i]) { + context.margin(); + } + + if (nodes[i]) { + if (multiline) { + context.newline(); + } else { + context.write(' '); + } + } + } + + context.append(child); + + prev = child; + } + + flush_comments_until(context, nodes[nodes.length - 1]?.loc?.end ?? null, until, false); + + if (multiline) { + context.dedent(); + context.newline(); + } else if (pad && length > 0) { + context.write(' '); + } + } + + /** + * Push a sequence of nodes onto separate lines, separating them with + * an extra newline where appropriate + * @param {Context} context + * @param {TSESTree.Node & { body: TSESTree.Node[] }} node + */ + function body(context, node) { + reset_comment_index(node); + + /** @type {string | null} */ + let prev_type = null; + let prev_multiline = false; + + for (const child of node.body) { + if (child.type === 'EmptyStatement') continue; + + const child_context = context.new(); + child_context.visit(child); + + if (prev_type !== null) { + if (child_context.multiline || prev_multiline || child.type !== prev_type) { + context.margin(); + } + + context.newline(); + } + + context.append(child_context); + + prev_type = child.type; + prev_multiline = child_context.multiline; + } + + if (node.loc) { + context.newline(); + flush_comments_until( + context, + node.body[node.body.length - 1]?.loc?.end ?? null, + node.loc.end, + false + ); + } + } + + const shared = { + /** + * @param {TSESTree.ArrayExpression | TSESTree.ArrayPattern} node + * @param {Context} context + */ + 'ArrayExpression|ArrayPattern': (node, context) => { + context.write('['); + sequence( + context, + /** @type {TSESTree.Node[]} */ (node.elements), + node.loc?.end ?? null, + false + ); + context.write(']'); + }, + + /** + * @param {TSESTree.BinaryExpression | TSESTree.LogicalExpression} node + * @param {Context} context + */ + 'BinaryExpression|LogicalExpression': (node, context) => { + // TODO + // const is_in = node.operator === 'in'; + // if (is_in) { + // // Avoids confusion in `for` loops initializers + // chunks.write('('); + // } + if (needs_parens(node.left, node, false)) { + context.write('('); + context.visit(node.left); + context.write(')'); + } else { + context.visit(node.left); + } + + context.write(` ${node.operator} `); + + if (needs_parens(node.right, node, true)) { + context.write('('); + context.visit(node.right); + context.write(')'); + } else { + context.visit(node.right); + } + }, + + /** + * @param {TSESTree.BlockStatement | TSESTree.ClassBody} node + * @param {Context} context + */ + 'BlockStatement|ClassBody': (node, context) => { + if (node.loc) { + const { line, column } = node.loc.start; + context.location(line, column); + context.write('{'); + context.location(line, column + 1); + } else { + context.write('{'); + } + + const child_context = context.new(); + body(child_context, node); + + if (!child_context.empty()) { + context.indent(); + context.newline(); + context.append(child_context); + context.dedent(); + context.newline(); + } + + if (node.loc) { + const { line, column } = node.loc.end; + + context.location(line, column - 1); + context.write('}'); + context.location(line, column); + } else { + context.write('}'); + } + }, + + /** + * @param {TSESTree.CallExpression | TSESTree.NewExpression} node + * @param {Context} context + */ + 'CallExpression|NewExpression': (node, context) => { + if (node.type === 'NewExpression') { + context.write('new '); + } + + const needs_parens = + EXPRESSIONS_PRECEDENCE[node.callee.type] < EXPRESSIONS_PRECEDENCE.CallExpression || + (node.type === 'NewExpression' && has_call_expression(node.callee)); + + if (needs_parens) { + context.write('('); + context.visit(node.callee); + context.write(')'); + } else { + context.visit(node.callee); + } + + if (/** @type {TSESTree.CallExpression} */ (node).optional) { + context.write('?.'); + } + + if (node.typeArguments) context.visit(node.typeArguments); + + const open = context.new(); + const join = context.new(); + + context.write('('); + context.append(open); + + // if the final argument is multiline, it doesn't need to force all the + // other arguments to also be multiline + const child_context = context.new(); + const final_context = context.new(); + + context.append(child_context); + context.append(final_context); + + for (let i = 0; i < node.arguments.length; i += 1) { + const is_last = i === node.arguments.length - 1; + const context = is_last ? final_context : child_context; + const arg = node.arguments[i]; + + // special case — if final argument has a comment above it, + // we make the whole sequence multiline + if ( + is_last && + arg.loc && + comments[comment_index] && + comments[comment_index].loc && + comments[comment_index].loc.start.line < arg.loc.start.line + ) { + child_context.multiline = true; + } + + context.visit(arg); + + if (!is_last) context.write(','); + + const next = is_last + ? (node.loc?.end ?? null) + : (node.arguments[i + 1]?.loc?.start ?? null); + + if (flush_trailing_comments(context, arg.loc?.end ?? null, next)) { + child_context.multiline = true; + } + + if (!is_last) context.append(join); + } + + context.multiline ||= child_context.multiline || final_context.multiline; + + if (child_context.multiline) { + open.indent(); + open.newline(); + join.newline(); + context.dedent(); + context.newline(); + } else { + join.write(' '); + } + + context.write(')'); + }, + + /** + * @param {TSESTree.ClassDeclaration | TSESTree.ClassExpression} node + * @param {Context} context + */ + 'ClassDeclaration|ClassExpression': (node, context) => { + if (node.declare) { + context.write('declare '); + } + + context.write('class '); + + if (node.id) { + context.visit(node.id); + context.write(' '); + } + + if (node.superClass) { + context.write('extends '); + context.visit(node.superClass); + context.write(' '); + } + + if (node.implements) { + context.write('implements '); + sequence(context, node.implements, node.body.loc?.start ?? null, false); + } + + context.visit(node.body); + }, + + /** + * @param {TSESTree.ForInStatement | TSESTree.ForOfStatement} node + * @param {Context} context + */ + 'ForInStatement|ForOfStatement': (node, context) => { + context.write('for '); + if (node.type === 'ForOfStatement' && node.await) context.write('await '); + context.write('('); + + if (node.left.type === 'VariableDeclaration') { + handle_var_declaration(node.left, context); + } else { + context.visit(node.left); + } + + context.write(node.type === 'ForInStatement' ? ' in ' : ' of '); + context.visit(node.right); + context.write(') '); + context.visit(node.body); + }, + + /** + * @param {TSESTree.FunctionDeclaration | TSESTree.FunctionExpression} node + * @param {Context} context + */ + 'FunctionDeclaration|FunctionExpression': (node, context) => { + if (node.async) context.write('async '); + context.write(node.generator ? 'function* ' : 'function '); + if (node.id) context.visit(node.id); + + if (node.typeParameters) { + context.visit(node.typeParameters); + } + + context.write('('); + sequence(context, node.params, (node.returnType ?? node.body).loc?.start ?? null, false); + context.write(')'); + + if (node.returnType) context.visit(node.returnType); + + context.write(' '); + + context.visit(node.body); + }, + + /** + * @param {TSESTree.RestElement | TSESTree.SpreadElement} node + * @param {Context} context + */ + 'RestElement|SpreadElement': (node, context) => { + context.write('...'); + context.visit(node.argument); + + // @ts-expect-error `acorn-typescript` and `@typescript-eslint/types` have slightly different type definitions + if (node.typeAnnotation) context.visit(node.typeAnnotation); + } + }; + + return { + _(node, context, visit) { + const is_statement = /(Statement|Declaration)$/.test(node.type); + + if (node.loc) { + flush_comments_until(context, null, node.loc.start, true); + } + + visit(node); + + if (is_statement && node.loc) { + flush_trailing_comments(context, node.loc.end, null); + } + }, + + ArrayExpression: shared['ArrayExpression|ArrayPattern'], + + ArrayPattern: shared['ArrayExpression|ArrayPattern'], + + ArrowFunctionExpression: (node, context) => { + if (node.async) context.write('async '); + + context.write('('); + sequence(context, node.params, node.body.loc?.start ?? null, false); + context.write(') => '); + + if ( + node.body.type === 'ObjectExpression' || + (node.body.type === 'AssignmentExpression' && node.body.left.type === 'ObjectPattern') || + (node.body.type === 'LogicalExpression' && node.body.left.type === 'ObjectExpression') || + (node.body.type === 'ConditionalExpression' && node.body.test.type === 'ObjectExpression') + ) { + context.write('('); + context.visit(node.body); + context.write(')'); + } else { + context.visit(node.body); + } + }, + + AssignmentExpression(node, context) { + context.visit(node.left); + context.write(` ${node.operator} `); + context.visit(node.right); + }, + + AssignmentPattern(node, context) { + context.visit(node.left); + context.write(' = '); + context.visit(node.right); + }, + + AwaitExpression(node, context) { + if (node.argument) { + const precedence = EXPRESSIONS_PRECEDENCE[node.argument.type]; + + if (precedence && precedence < EXPRESSIONS_PRECEDENCE.AwaitExpression) { + context.write('await ('); + context.visit(node.argument); + context.write(')'); + } else { + context.write('await '); + context.visit(node.argument); + } + } else { + context.write('await'); + } + }, + + BinaryExpression: shared['BinaryExpression|LogicalExpression'], + + BlockStatement: shared['BlockStatement|ClassBody'], + + BreakStatement(node, context) { + if (node.label) { + context.write('break '); + context.visit(node.label); + context.write(';'); + } else { + context.write('break;'); + } + }, + + CallExpression: shared['CallExpression|NewExpression'], + + ChainExpression(node, context) { + context.visit(node.expression); + }, + + ClassBody: shared['BlockStatement|ClassBody'], + + ClassDeclaration: shared['ClassDeclaration|ClassExpression'], + + ClassExpression: shared['ClassDeclaration|ClassExpression'], + + ConditionalExpression(node, context) { + if (EXPRESSIONS_PRECEDENCE[node.test.type] > EXPRESSIONS_PRECEDENCE.ConditionalExpression) { + context.visit(node.test); + } else { + context.write('('); + context.visit(node.test); + context.write(')'); + } + + const consequent = context.new(); + const alternate = context.new(); + + // TODO flush comments here, rather than in visitors + + consequent.visit(node.consequent); + alternate.visit(node.alternate); + + if ( + consequent.multiline || + alternate.multiline || + consequent.measure() + alternate.measure() > 50 + ) { + context.indent(); + context.newline(); + context.write('? '); + context.append(consequent); + context.newline(); + context.write(': '); + context.append(alternate); + context.dedent(); + } else { + context.write(' ? '); + context.append(consequent); + context.write(' : '); + context.append(alternate); + } + }, + + ContinueStatement(node, context) { + if (node.label) { + context.write('continue '); + context.visit(node.label); + context.write(';'); + } else { + context.write('continue;'); + } + }, + + DebuggerStatement(node, context) { + context.write('debugger', node); + context.write(';'); + }, + + Decorator(node, context) { + context.write('@'); + context.visit(node.expression); + context.newline(); + }, + + DoWhileStatement(node, context) { + context.write('do '); + context.visit(node.body); + context.write(' while ('); + context.visit(node.test); + context.write(');'); + }, + + EmptyStatement(node, context) { + context.write(';'); + }, + + ExportAllDeclaration(node, context) { + context.write(node.exportKind === 'type' ? 'export type * ' : 'export * '); + + if (node.exported) { + context.write('as '); + context.visit(node.exported); + } + + context.write(' from '); + context.visit(node.source); + context.write(';'); + }, + + ExportDefaultDeclaration(node, context) { + context.write('export default '); + + context.visit(node.declaration); + + if (node.declaration.type !== 'FunctionDeclaration') { + context.write(';'); + } + }, + + ExportNamedDeclaration(node, context) { + context.write('export '); + + if (node.declaration) { + context.visit(node.declaration); + return; + } + + if (node.exportKind === 'type') { + context.write('type '); + } + + context.write('{'); + sequence(context, node.specifiers, node.source?.loc?.start ?? node.loc?.end ?? null, true); + context.write('}'); + + if (node.source) { + context.write(' from '); + context.visit(node.source); + } + + context.write(';'); + }, + + ExportSpecifier(node, context) { + if (node.exportKind === 'type') { + context.write('type '); + } + + context.visit(node.local); + + if (node.local.name !== node.exported.name) { + context.write(' as '); + context.visit(node.exported); + } + }, + + ExpressionStatement(node, context) { + if ( + node.expression.type === 'ObjectExpression' || + (node.expression.type === 'AssignmentExpression' && + node.expression.left.type === 'ObjectPattern') || + node.expression.type === 'FunctionExpression' + ) { + // is an AssignmentExpression to an ObjectPattern + context.write('('); + context.visit(node.expression); + context.write(');'); + return; + } + + context.visit(node.expression); + context.write(';'); + }, + + ForStatement: (node, context) => { + context.write('for ('); + + if (node.init) { + if (node.init.type === 'VariableDeclaration') { + handle_var_declaration(node.init, context); + } else { + context.visit(node.init); + } + } + + context.write('; '); + if (node.test) context.visit(node.test); + context.write('; '); + if (node.update) context.visit(node.update); + + context.write(') '); + context.visit(node.body); + }, + + ForInStatement: shared['ForInStatement|ForOfStatement'], + + ForOfStatement: shared['ForInStatement|ForOfStatement'], + + FunctionDeclaration: shared['FunctionDeclaration|FunctionExpression'], + + FunctionExpression: shared['FunctionDeclaration|FunctionExpression'], + + Identifier(node, context) { + let name = node.name; + context.write(name, node); + + if (node.typeAnnotation) context.visit(node.typeAnnotation); + }, + + IfStatement(node, context) { + context.write('if ('); + context.visit(node.test); + context.write(') '); + context.visit(node.consequent); + + if (node.alternate) { + context.write(' else '); + context.visit(node.alternate); + } + }, + + ImportDeclaration(node, context) { + if (node.specifiers.length === 0) { + context.write('import '); + context.visit(node.source); + context.write(';'); + return; + } + + /** @type {TSESTree.ImportNamespaceSpecifier | null} */ + let namespace_specifier = null; + + /** @type {TSESTree.ImportDefaultSpecifier | null} */ + let default_specifier = null; + + /** @type {TSESTree.ImportSpecifier[]} */ + const named_specifiers = []; + + for (const s of node.specifiers) { + if (s.type === 'ImportNamespaceSpecifier') { + namespace_specifier = s; + } else if (s.type === 'ImportDefaultSpecifier') { + default_specifier = s; + } else { + named_specifiers.push(s); + } + } + + context.write('import '); + if (node.importKind == 'type') context.write('type '); + + if (default_specifier) { + context.write(default_specifier.local.name, default_specifier); + if (namespace_specifier || named_specifiers.length > 0) context.write(', '); + } + + if (namespace_specifier) { + context.write('* as ' + namespace_specifier.local.name, namespace_specifier); + } + + if (named_specifiers.length > 0) { + context.write('{'); + sequence(context, named_specifiers, node.source.loc?.start ?? null, true); + context.write('}'); + } + + context.write(' from '); + context.visit(node.source); + if (node.attributes && node.attributes.length > 0) { + context.write(' with { '); + for (let index = 0; index < node.attributes.length; index++) { + const { key, value } = node.attributes[index]; + context.visit(key); + context.write(': '); + context.visit(value); + if (index + 1 !== node.attributes.length) { + context.write(', '); + } + } + context.write(' }'); + } + context.write(';'); + }, + + ImportExpression(node, context) { + context.write('import('); + context.visit(node.source); + //@ts-expect-error for some reason the types haven't been updated + if (node.arguments) { + //@ts-expect-error + for (let index = 0; index < node.arguments.length; index++) { + context.write(', '); + //@ts-expect-error + context.visit(node.arguments[index]); + } + } + context.write(')'); + }, + + ImportSpecifier(node, context) { + if (node.local.name !== node.imported.name) { + context.visit(node.imported); + context.write(' as '); + } + + if (node.importKind == 'type') context.write('type '); + context.visit(node.local); + }, + + LabeledStatement(node, context) { + context.visit(node.label); + context.write(': '); + context.visit(node.body); + }, + + Literal(node, context) { + // TODO do we need to handle weird unicode characters somehow? + // str.replace(/\\u(\d{4})/g, (m, n) => String.fromCharCode(+n)) + + const value = + node.raw || + (typeof node.value === 'string' ? quote(node.value, quote_char) : String(node.value)); + + context.write(value, node); + }, + + LogicalExpression: shared['BinaryExpression|LogicalExpression'], + + MemberExpression(node, context) { + if (EXPRESSIONS_PRECEDENCE[node.object.type] < EXPRESSIONS_PRECEDENCE.MemberExpression) { + context.write('('); + context.visit(node.object); + context.write(')'); + } else { + context.visit(node.object); + } + + if (node.computed) { + if (node.optional) { + context.write('?.'); + } + context.write('['); + context.visit(node.property); + context.write(']'); + } else { + context.write(node.optional ? '?.' : '.'); + context.visit(node.property); + } + }, + + MetaProperty(node, context) { + context.visit(node.meta); + context.write('.'); + context.visit(node.property); + }, + + MethodDefinition(node, context) { + if (node.decorators) { + for (const decorator of node.decorators) { + context.visit(decorator); + } + } + + if (node.static) { + context.write('static '); + } + + if (node.kind === 'get' || node.kind === 'set') { + // Getter or setter + context.write(node.kind + ' '); + } + + if (node.value.async) { + context.write('async '); + } + + if (node.value.generator) { + context.write('*'); + } + + if (node.computed) context.write('['); + context.visit(node.key); + if (node.computed) context.write(']'); + + context.write('('); + sequence( + context, + node.value.params, + (node.value.returnType ?? node.value.body)?.loc?.start ?? node.loc?.end ?? null, + false + ); + context.write(')'); + + if (node.value.returnType) context.visit(node.value.returnType); + + context.write(' '); + + if (node.value.body) context.visit(node.value.body); + }, + + NewExpression: shared['CallExpression|NewExpression'], + + ObjectExpression(node, context) { + context.write('{'); + sequence(context, node.properties, node.loc?.end ?? null, true); + context.write('}'); + }, + + ObjectPattern(node, context) { + context.write('{'); + sequence(context, node.properties, node.loc?.end ?? null, true); + context.write('}'); + + if (node.typeAnnotation) context.visit(node.typeAnnotation); + }, + + // @ts-expect-error this isn't a real node type, but Acorn produces it + ParenthesizedExpression(node, context) { + return context.visit(node.expression); + }, + + PrivateIdentifier(node, context) { + context.write('#'); + context.write(node.name, node); + }, + + Program(node, context) { + body(context, node); + }, + + Property(node, context) { + const value = node.value.type === 'AssignmentPattern' ? node.value.left : node.value; + + const shorthand = + !node.computed && + node.kind === 'init' && + node.key.type === 'Identifier' && + value.type === 'Identifier' && + node.key.name === value.name; + + if (shorthand) { + context.visit(node.value); + return; + } + + // shorthand methods + if (node.value.type === 'FunctionExpression') { + if (node.kind !== 'init') context.write(node.kind + ' '); + if (node.value.async) context.write('async '); + if (node.value.generator) context.write('*'); + if (node.computed) context.write('['); + context.visit(node.key); + if (node.computed) context.write(']'); + context.write('('); + sequence( + context, + node.value.params, + (node.value.returnType ?? node.value.body).loc?.start ?? null, + false + ); + context.write(')'); + + if (node.value.returnType) context.visit(node.value.returnType); + + context.write(' '); + context.visit(node.value.body); + } else { + if (node.computed) context.write('['); + if (node.kind === 'get' || node.kind === 'set') context.write(node.kind + ' '); + context.visit(node.key); + context.write(node.computed ? ']: ' : ': '); + context.visit(node.value); + } + }, + + PropertyDefinition(node, context) { + if (node.decorators) { + for (const decorator of node.decorators) { + context.visit(decorator); + } + } + + if (node.accessibility) { + context.write(node.accessibility + ' '); + } + + if (node.static) { + context.write('static '); + } + + if (node.computed) { + context.write('['); + context.visit(node.key); + context.write(']'); + } else { + context.visit(node.key); + } + + if (node.typeAnnotation) { + context.write(': '); + context.visit(node.typeAnnotation.typeAnnotation); + } + + if (node.value) { + context.write(' = '); + context.visit(node.value); + } + + context.write(';'); + + flush_trailing_comments( + context, + (node.value ?? node.typeAnnotation ?? node.key).loc?.end ?? null, + null + ); + }, + + RestElement: shared['RestElement|SpreadElement'], + + ReturnStatement(node, context) { + if (node.argument) { + const contains_comment = + comments[comment_index] && + comments[comment_index].loc && + node.argument.loc && + before(comments[comment_index].loc.start, node.argument.loc.start); + + context.write(contains_comment ? 'return (' : 'return '); + context.visit(node.argument); + context.write(contains_comment ? ');' : ';'); + } else { + context.write('return;'); + } + }, + + SequenceExpression(node, context) { + context.write('('); + sequence(context, node.expressions, node.loc?.end ?? null, false); + context.write(')'); + }, + + SpreadElement: shared['RestElement|SpreadElement'], + + StaticBlock(node, context) { + context.write('static {'); + context.indent(); + context.newline(); + + body(context, node); + + context.dedent(); + context.newline(); + context.write('}'); + }, + + Super(node, context) { + context.write('super', node); + }, + + SwitchStatement(node, context) { + context.write('switch ('); + context.visit(node.discriminant); + context.write(') {'); + context.indent(); + + let first = true; + + for (const block of node.cases) { + if (!first) { + context.margin(); + } + + first = false; + + if (block.test) { + context.newline(); + context.write('case '); + context.visit(block.test); + context.write(':'); + } else { + context.newline(); + context.write('default:'); + } + + context.indent(); + + for (const statement of block.consequent) { + context.newline(); + context.visit(statement); + } + + context.dedent(); + } + + context.dedent(); + context.newline(); + context.write('}'); + }, + + TaggedTemplateExpression(node, context) { + context.visit(node.tag); + context.visit(node.quasi); + }, + + TemplateLiteral(node, context) { + context.write('`'); + + const { quasis, expressions } = node; + + for (let i = 0; i < expressions.length; i++) { + const raw = quasis[i].value.raw; + + context.write(raw + '${'); + context.visit(expressions[i]); + context.write('}'); + + if (/\n/.test(raw)) context.multiline = true; + } + + const raw = quasis[quasis.length - 1].value.raw; + + context.write(raw + '`'); + if (/\n/.test(raw)) context.multiline = true; + }, + + ThisExpression(node, context) { + context.write('this', node); + }, + + ThrowStatement(node, context) { + context.write('throw '); + if (node.argument) context.visit(node.argument); + context.write(';'); + }, + + TryStatement(node, context) { + context.write('try '); + context.visit(node.block); + + if (node.handler) { + if (node.handler.param) { + context.write(' catch('); + context.visit(node.handler.param); + context.write(') '); + } else { + context.write(' catch '); + } + + context.visit(node.handler.body); + } + + if (node.finalizer) { + context.write(' finally '); + context.visit(node.finalizer); + } + }, + + UnaryExpression(node, context) { + context.write(node.operator); + + if (node.operator.length > 1) { + context.write(' '); + } + + if (EXPRESSIONS_PRECEDENCE[node.argument.type] < EXPRESSIONS_PRECEDENCE.UnaryExpression) { + context.write('('); + context.visit(node.argument); + context.write(')'); + } else { + context.visit(node.argument); + } + }, + + UpdateExpression(node, context) { + if (node.prefix) { + context.write(node.operator); + context.visit(node.argument); + } else { + context.visit(node.argument); + context.write(node.operator); + } + }, + + VariableDeclaration(node, context) { + handle_var_declaration(node, context); + context.write(';'); + }, + + VariableDeclarator(node, context) { + context.visit(node.id); + + if (node.init) { + context.write(' = '); + context.visit(node.init); + } + }, + + WhileStatement(node, context) { + context.write('while ('); + context.visit(node.test); + context.write(') '); + context.visit(node.body); + }, + + WithStatement(node, context) { + context.write('with ('); + context.visit(node.object); + context.write(') '); + context.visit(node.body); + }, + + YieldExpression(node, context) { + if (node.argument) { + context.write(node.delegate ? `yield* ` : `yield `); + context.visit(node.argument); + } else { + context.write(node.delegate ? `yield*` : `yield`); + } + }, + + TSDeclareFunction(node, context) { + context.write('declare '); + + if (node.async) { + context.write('async '); + } + + context.write('function'); + + if (node.generator) { + context.write('*'); + } + + if (node.id) { + context.write(' '); + context.visit(node.id); + } + + if (node.typeParameters) { + context.visit(node.typeParameters); + } + + context.write('('); + sequence(context, node.params, node.returnType?.loc?.start ?? node.loc?.end ?? null, false); + context.write(')'); + + if (node.returnType) { + context.visit(node.returnType); + } + + context.write(';'); + }, + + TSNumberKeyword(node, context) { + context.write('number', node); + }, + + TSStringKeyword(node, context) { + context.write('string', node); + }, + + TSBooleanKeyword(node, context) { + context.write('boolean', node); + }, + + TSAnyKeyword(node, context) { + context.write('any', node); + }, + + TSVoidKeyword(node, context) { + context.write('void', node); + }, + + TSUnknownKeyword(node, context) { + context.write('unknown', node); + }, + + TSNeverKeyword(node, context) { + context.write('never', node); + }, + + TSSymbolKeyword(node, context) { + context.write('symbol', node); + }, + + TSNullKeyword(node, context) { + context.write('null', node); + }, + + TSUndefinedKeyword(node, context) { + context.write('undefined', node); + }, + + TSArrayType(node, context) { + context.visit(node.elementType); + context.write('[]'); + }, + + TSTypeAnnotation(node, context) { + context.write(': '); + context.visit(node.typeAnnotation); + }, + + TSTypeLiteral(node, context) { + context.write('{ '); + sequence(context, node.members, node.loc?.end ?? null, false, ';'); + context.write(' }'); + }, + + TSPropertySignature(node, context) { + context.visit(node.key); + if (node.optional) context.write('?'); + if (node.typeAnnotation) context.visit(node.typeAnnotation); + }, + + TSTypeReference(node, context) { + context.visit(node.typeName); + + if (node.typeArguments) { + context.visit(node.typeArguments); + } + }, + + //@ts-expect-error I don't know why, but this is relied upon in the tests, but doesn't exist in the TSESTree types + TSExpressionWithTypeArguments(node, context) { + context.visit(node.expression); + }, + + TSTypeParameterInstantiation(node, context) { + context.write('<'); + for (let i = 0; i < node.params.length; i++) { + context.visit(node.params[i]); + if (i != node.params.length - 1) context.write(', '); + } + context.write('>'); + }, + + TSTypeParameterDeclaration(node, context) { + context.write('<'); + for (let i = 0; i < node.params.length; i++) { + context.visit(node.params[i]); + if (i != node.params.length - 1) context.write(', '); + } + context.write('>'); + }, + + TSTypeParameter(node, context) { + // @ts-expect-error type mismatch TSESTree and acorn-typescript? + context.write(node.name, node); + + if (node.constraint) { + context.write(' extends '); + context.visit(node.constraint); + } + }, + + TSTypeQuery(node, context) { + context.write('typeof '); + context.visit(node.exprName); + }, + + TSEnumMember(node, context) { + context.visit(node.id); + if (node.initializer) { + context.write(' = '); + context.visit(node.initializer); + } + }, + + TSFunctionType(node, context) { + if (node.typeParameters) context.visit(node.typeParameters); + + context.write('('); + + sequence( + context, + // @ts-expect-error `acorn-typescript` and `@typescript-eslint/types` have slightly different type definitions + node.parameters, + // @ts-expect-error `acorn-typescript` and `@typescript-eslint/types` have slightly different type definitions + node.typeAnnotation.typeAnnotation.loc?.start ?? null, + false + ); + + context.write(') => '); + + // @ts-expect-error `acorn-typescript` and `@typescript-eslint/types` have slightly different type definitions + context.visit(node.typeAnnotation.typeAnnotation); + }, + + TSIndexSignature(node, context) { + context.write('['); + + // @ts-expect-error `acorn-typescript` and `@typescript-eslint/types` have slightly different type definitions + sequence(context, node.parameters, node.typeAnnotation?.loc?.start ?? null, false); + context.write(']'); + + // @ts-expect-error `acorn-typescript` and `@typescript-eslint/types` have slightly different type definitions + context.visit(node.typeAnnotation); + }, + + TSMethodSignature(node, context) { + context.visit(node.key); + + context.write('('); + + // @ts-expect-error `acorn-typescript` and `@typescript-eslint/types` have slightly different type definitions + sequence(context, node.parameters, node.typeAnnotation.loc?.start ?? null, false); + context.write(')'); + + // @ts-expect-error `acorn-typescript` and `@typescript-eslint/types` have slightly different type definitions + context.visit(node.typeAnnotation); + }, + + TSTupleType(node, context) { + context.write('['); + sequence(context, node.elementTypes, node.loc?.end ?? null, false); + context.write(']'); + }, + + TSNamedTupleMember(node, context) { + context.visit(node.label); + context.write(': '); + context.visit(node.elementType); + }, + + TSUnionType(node, context) { + sequence(context, node.types, node.loc?.end ?? null, false, ' |'); + }, + + TSIntersectionType(node, context) { + sequence(context, node.types, node.loc?.end ?? null, false, ' &'); + }, + + TSLiteralType(node, context) { + context.visit(node.literal); + }, + + TSConditionalType(node, context) { + context.visit(node.checkType); + context.write(' extends '); + context.visit(node.extendsType); + context.write(' ? '); + context.visit(node.trueType); + context.write(' : '); + context.visit(node.falseType); + }, + + TSIndexedAccessType(node, context) { + context.visit(node.objectType); + context.write('['); + context.visit(node.indexType); + context.write(']'); + }, + + TSImportType(node, context) { + context.write('import('); + context.visit(node.argument); + context.write(')'); + + if (node.qualifier) { + context.write('.'); + context.visit(node.qualifier); + } + }, + + TSAsExpression(node, context) { + if (node.expression) { + const needs_parens = + EXPRESSIONS_PRECEDENCE[node.expression.type] < EXPRESSIONS_PRECEDENCE.TSAsExpression; + + if (needs_parens) { + context.write('('); + context.visit(node.expression); + context.write(')'); + } else { + context.visit(node.expression); + } + } + context.write(' as '); + context.visit(node.typeAnnotation); + }, + + TSEnumDeclaration(node, context) { + context.write('enum '); + context.visit(node.id); + context.write(' {'); + context.indent(); + context.newline(); + sequence(context, node.members, node.loc?.end ?? null, false); + context.dedent(); + context.newline(); + context.write('}'); + }, + + TSModuleBlock(node, context) { + context.write(' {'); + context.indent(); + context.newline(); + body(context, node); + context.dedent(); + context.newline(); + context.write('}'); + }, + + TSModuleDeclaration(node, context) { + if (node.declare) context.write('declare '); + else context.write('namespace '); + + context.visit(node.id); + + if (!node.body) return; + context.visit(node.body); + }, + + TSNonNullExpression(node, context) { + context.visit(node.expression); + context.write('!'); + }, + + TSInterfaceBody(node, context) { + sequence(context, node.body, node.loc?.end ?? null, true, ';'); + }, + + TSInterfaceDeclaration(node, context) { + context.write('interface '); + context.visit(node.id); + if (node.typeParameters) context.visit(node.typeParameters); + if (node.extends) { + context.write(' extends '); + sequence(context, node.extends, node.body.loc?.start ?? null, false); + } + context.write(' {'); + context.visit(node.body); + context.write('}'); + }, + + TSSatisfiesExpression(node, context) { + if (node.expression) { + const needs_parens = + EXPRESSIONS_PRECEDENCE[node.expression.type] < + EXPRESSIONS_PRECEDENCE.TSSatisfiesExpression; + + if (needs_parens) { + context.write('('); + context.visit(node.expression); + context.write(')'); + } else { + context.visit(node.expression); + } + } + context.write(' satisfies '); + context.visit(node.typeAnnotation); + }, + + TSTypeAliasDeclaration(node, context) { + context.write('type '); + context.visit(node.id); + if (node.typeParameters) context.visit(node.typeParameters); + context.write(' = '); + context.visit(node.typeAnnotation); + context.write(';'); + }, + + TSQualifiedName(node, context) { + context.visit(node.left); + context.write('.'); + context.visit(node.right); + } + }; +}; + +/** @satisfies {Visitors} */ + +/** + * + * @param {TSESTree.Expression | TSESTree.PrivateIdentifier} node + * @param {TSESTree.BinaryExpression | TSESTree.LogicalExpression} parent + * @param {boolean} is_right + * @returns + */ +function needs_parens(node, parent, is_right) { + if (node.type === 'PrivateIdentifier') return false; + + // special case where logical expressions and coalesce expressions cannot be mixed, + // either of them need to be wrapped with parentheses + if ( + node.type === 'LogicalExpression' && + parent.type === 'LogicalExpression' && + ((parent.operator === '??' && node.operator !== '??') || + (parent.operator !== '??' && node.operator === '??')) + ) { + return true; + } + + const precedence = EXPRESSIONS_PRECEDENCE[node.type]; + const parent_precedence = EXPRESSIONS_PRECEDENCE[parent.type]; + + if (precedence !== parent_precedence) { + // Different node types + return ( + (!is_right && precedence === 15 && parent_precedence === 14 && parent.operator === '**') || + precedence < parent_precedence + ); + } + + if (precedence !== 13 && precedence !== 14) { + // Not a `LogicalExpression` or `BinaryExpression` + return false; + } + + if ( + /** @type {TSESTree.BinaryExpression} */ (node).operator === '**' && + parent.operator === '**' + ) { + // Exponentiation operator has right-to-left associativity + return !is_right; + } + + if (is_right) { + // Parenthesis are used if both operators have the same precedence + return ( + OPERATOR_PRECEDENCE[/** @type {TSESTree.BinaryExpression} */ (node).operator] <= + OPERATOR_PRECEDENCE[parent.operator] + ); + } + + return ( + OPERATOR_PRECEDENCE[/** @type {TSESTree.BinaryExpression} */ (node).operator] < + OPERATOR_PRECEDENCE[parent.operator] + ); +} + +/** @param {TSESTree.Node} node */ +function has_call_expression(node) { + while (node) { + if (node.type === 'CallExpression') { + return true; + } else if (node.type === 'MemberExpression') { + node = node.object; + } else { + return false; + } + } +} + +/** + * @param {TSESTree.VariableDeclaration} node + * @param {Context} context + */ +function handle_var_declaration(node, context) { + const open = context.new(); + const join = context.new(); + const child_context = context.new(); + + context.append(child_context); + + if (node.declare) { + child_context.write('declare '); + } + + child_context.write(`${node.kind} `); + child_context.append(open); + + let first = true; + + for (const d of node.declarations) { + if (!first) child_context.append(join); + first = false; + + child_context.visit(d); + } + + const length = child_context.measure() + 2 * (node.declarations.length - 1); + + const multiline = child_context.multiline || (node.declarations.length > 1 && length > 50); + + if (multiline) { + context.multiline = true; + + if (node.declarations.length > 1) open.indent(); + join.write(','); + join.newline(); + if (node.declarations.length > 1) context.dedent(); + } else { + join.write(', '); + } +} + +/** + * @param {string} string + * @param {string} char + */ +function quote(string, char) { + let out = char; + + for (const c of string) { + if (c === '\\') { + out += '\\\\'; + } else if (c === char) { + out += '\\' + c; + } else if (c === '\n') { + out += '\\n'; + } else if (c === '\r') { + out += '\\r'; + } else { + out += c; + } + } + + return out + char; +} + +/** + * + * @param {{ line: number, column: number }} a + * @param {{ line: number, column: number }} b + */ +function before(a, b) { + if (a.line < b.line) return true; + if (a.line > b.line) return false; + return a.column < b.column; +} diff --git a/src/languages/ts/public.d.ts b/src/languages/ts/public.d.ts new file mode 100644 index 0000000..06fa86b --- /dev/null +++ b/src/languages/ts/public.d.ts @@ -0,0 +1,2 @@ +export * from './index'; +export { Comment } from '../types'; diff --git a/src/languages/tsx/index.js b/src/languages/tsx/index.js new file mode 100644 index 0000000..b6b4ec1 --- /dev/null +++ b/src/languages/tsx/index.js @@ -0,0 +1,139 @@ +/** @import { TSESTree } from '@typescript-eslint/types' */ +/** @import { Visitors } from '../../types.js' */ +/** @import { TSOptions } from '../types.js' */ +import ts from '../ts/index.js'; + +/** @typedef {TSESTree.Node} Node */ + +/** + * @param {TSOptions} [options] + * @returns {Visitors} + */ +export default (options) => ({ + ...ts(options), + + JSXElement(node, context) { + context.visit(node.openingElement); + + if (node.children.length > 0) { + context.indent(); + } + + for (const child of node.children) { + context.visit(child); + } + + if (node.children.length > 0) { + context.dedent(); + } + + if (node.closingElement) { + context.visit(node.closingElement); + } + }, + + JSXOpeningElement(node, context) { + context.write('<'); + + context.visit(node.name); + + for (const attribute of node.attributes) { + context.write(' '); + context.visit(attribute); + } + + if (node.selfClosing) { + context.write(' /'); + } + + context.write('>'); + }, + + JSXClosingElement(node, context) { + context.write(''); + }, + + JSXNamespacedName(node, context) { + context.visit(node.namespace); + context.write(':'); + context.visit(node.name); + }, + + JSXIdentifier(node, context) { + context.write(node.name, node); + }, + + JSXMemberExpression(node, context) { + context.visit(node.object); + context.write('.'); + context.visit(node.property); + }, + + JSXText(node, context) { + context.write(node.value, node); + }, + + JSXAttribute(node, context) { + context.visit(node.name); + if (node.value) { + context.write('='); + context.visit(node.value); + } + }, + + JSXEmptyExpression(node, context) {}, + + JSXFragment(node, context) { + context.visit(node.openingFragment); + + if (node.children.length > 0) { + context.indent(); + } + + for (const child of node.children) { + context.visit(child); + } + + if (node.children.length > 0) { + context.dedent(); + } + + context.visit(node.closingFragment); + }, + + JSXOpeningFragment(node, context) { + context.write('<>'); + }, + + JSXClosingFragment(node, context) { + context.write(''); + }, + + JSXExpressionContainer(node, context) { + context.write('{'); + + context.visit(node.expression); + + context.write('}'); + }, + + JSXSpreadChild(node, context) { + context.write('{...'); + + context.visit(node.expression); + + context.write('}'); + }, + + JSXSpreadAttribute(node, context) { + context.write('{...'); + + context.visit(node.argument); + + context.write('}'); + } +}); diff --git a/src/languages/tsx/public.d.ts b/src/languages/tsx/public.d.ts new file mode 100644 index 0000000..06fa86b --- /dev/null +++ b/src/languages/tsx/public.d.ts @@ -0,0 +1,2 @@ +export * from './index'; +export { Comment } from '../types'; diff --git a/src/languages/types.d.ts b/src/languages/types.d.ts new file mode 100644 index 0000000..1229d88 --- /dev/null +++ b/src/languages/types.d.ts @@ -0,0 +1,22 @@ +export type TSOptions = { + quotes?: 'double' | 'single'; + comments?: Comment[]; +}; + +interface Position { + line: number; + column: number; +} + +// this exists in TSESTree but because of the inanity around enums +// it's easier to do this ourselves +export interface Comment { + type: 'Line' | 'Block'; + value: string; + start?: number; + end?: number; + loc: { + start: Position; + end: Position; + }; +} diff --git a/src/public.d.ts b/src/public.d.ts index 2b85b93..5fababa 100644 --- a/src/public.d.ts +++ b/src/public.d.ts @@ -1,2 +1,2 @@ -export { PrintOptions } from './types'; +export { PrintOptions, Visitors } from './types'; export * from './index'; diff --git a/src/types.d.ts b/src/types.d.ts index 07ac263..5763af7 100644 --- a/src/types.d.ts +++ b/src/types.d.ts @@ -1,11 +1,28 @@ import { TSESTree } from '@typescript-eslint/types'; +import { Context } from 'esrap'; + +export type BaseNode = { + type: string; + loc?: null | { + start: { line: number; column: number }; + end: { line: number; column: number }; + }; +}; -type Handler = (node: T, state: State) => undefined; +type NodeOf = X extends { type: T } ? X : never; -export type Handlers = { - [T in TSESTree.Node['type']]: Handler>; +type SpecialisedVisitors = { + [K in T['type']]?: Visitor>; }; +export type Visitor = (node: T, context: Context) => void; + +export type Visitors = T['type'] extends '_' + ? never + : SpecialisedVisitors & { _?: (node: T, context: Context, visit: (node: T) => void) => void }; + +export { Context }; + export type TypeAnnotationNodes = | TSESTree.TypeNode | TSESTree.TypeElement @@ -24,54 +41,22 @@ type TSExpressionWithTypeArguments = { expression: any; }; -// `@typescript-eslint/types` differs from the official `estree` spec by handling -// comments differently. This is a node which we can use to ensure type saftey. -export type NodeWithComments = { - leadingComments?: TSESTree.Comment[] | undefined; - trailingComments?: TSESTree.Comment[] | undefined; -} & TSESTree.Node; - -export interface State { - commands: Command[]; - comments: TSESTree.Comment[]; - multiline: boolean; - quote: "'" | '"'; -} - export interface Location { type: 'Location'; line: number; column: number; } -export interface Newline { - type: 'Newline'; -} - -export interface Indent { - type: 'Indent'; -} - -export interface Dedent { - type: 'Dedent'; -} - export interface IndentChange { type: 'IndentChange'; offset: number; } -export interface CommentChunk { - type: 'Comment'; - comment: TSESTree.Comment; -} - -export type Command = string | Location | Newline | Indent | Dedent | CommentChunk | Command[]; +export type Command = string | number | Location | Command[]; export interface PrintOptions { sourceMapSource?: string; sourceMapContent?: string; sourceMapEncodeMappings?: boolean; // default true indent?: string; // default tab - quotes?: 'single' | 'double'; // default single } diff --git a/test/common.js b/test/common.js index e29c421..e8a5d27 100644 --- a/test/common.js +++ b/test/common.js @@ -2,24 +2,25 @@ import * as acorn from 'acorn'; import { tsPlugin } from '@sveltejs/acorn-typescript'; -import { walk } from 'zimmerframe'; /** @import { TSESTree } from '@typescript-eslint/types' */ -/** @import { NodeWithComments } from '../src/types' */ -// @ts-expect-error -export const acornTs = acorn.Parser.extend(tsPlugin({ allowSatisfies: true })); +export const acornTs = acorn.Parser.extend(tsPlugin()); +export const acornTsx = acorn.Parser.extend(tsPlugin({ jsx: true })); -/** @param {string} input */ -export function load(input) { +/** @param {string} input + * @param {{ jsx?: boolean }} opts + */ +export function load(input, opts = {}) { + const jsx = opts.jsx ?? false; /** @type {any[]} */ const comments = []; - const ast = acornTs.parse(input, { + const ast = (jsx ? acornTsx : acornTs).parse(input, { ecmaVersion: 'latest', sourceType: 'module', locations: true, - onComment: (block, value, start, end) => { + onComment: (block, value, start, end, startLoc, endLoc) => { if (block && /\n/.test(value)) { let a = start; while (a > 0 && input[a - 1] !== '\n') a -= 1; @@ -31,31 +32,18 @@ export function load(input) { value = value.replace(new RegExp(`^${indentation}`, 'gm'), ''); } - comments.push({ type: block ? 'Block' : 'Line', value, start, end }); + comments.push({ + type: block ? 'Block' : 'Line', + value, + start, + end, + loc: { start: startLoc, end: endLoc } + }); } }); - walk(ast, null, { - _(node, { next }) { - let comment; - const commentNode = /** @type {NodeWithComments} */ (/** @type {any} */ (node)); - - while (comments[0] && comments[0].start < node.start) { - comment = comments.shift(); - (commentNode.leadingComments ??= []).push(comment); - } - - next(); - - if (comments[0]) { - const slice = input.slice(node.end, comments[0].start); - - if (/^[,) \t]*$/.test(slice)) { - commentNode.trailingComments = [comments.shift()]; - } - } - } - }); - - return /** @type {TSESTree.Program} */ (/** @type {any} */ (ast)); + return { + ast: /** @type {TSESTree.Program} */ (/** @type {any} */ (ast)), + comments + }; } diff --git a/test/esrap.test.js b/test/esrap.test.js index 0096d1b..939e55c 100644 --- a/test/esrap.test.js +++ b/test/esrap.test.js @@ -5,7 +5,8 @@ import fs from 'node:fs'; import { expect, test } from 'vitest'; import { walk } from 'zimmerframe'; import { print } from '../src/index.js'; -import { acornTs, load } from './common.js'; +import { acornTs, acornTsx, load } from './common.js'; +import tsx from '../src/languages/tsx/index.js'; /** @param {TSESTree.Node} ast */ function clean(ast) { @@ -17,10 +18,6 @@ function clean(ast) { delete node.start; // @ts-expect-error delete node.end; - // @ts-expect-error - delete node.leadingComments; - // @ts-expect-error - delete node.trailingComments; context.next(); }, Program(node, context) { @@ -45,6 +42,13 @@ function clean(ast) { } context.next(); + }, + JSXText(node) { + return { + ...node, + raw: node.raw.replaceAll('\r', ''), + value: node.value.replaceAll('\r', '') + }; } }); @@ -53,8 +57,11 @@ function clean(ast) { for (const dir of fs.readdirSync(`${__dirname}/samples`)) { if (dir[0] === '.') continue; - const tsMode = dir.startsWith('ts-'); - const fileExtension = tsMode ? 'ts' : 'js'; + const tsMode = dir.startsWith('ts-') || dir.startsWith('tsx-'); + const jsxMode = dir.startsWith('jsx-') || dir.startsWith('tsx-'); + const fileExtension = (tsMode ? 'ts' : 'js') + (jsxMode ? 'x' : ''); + + // if (dir.includes('large-file')) continue; test(dir, async () => { let input_js = ''; @@ -69,22 +76,26 @@ for (const dir of fs.readdirSync(`${__dirname}/samples`)) { /** @type {TSESTree.Program} */ let ast; + /** @type {TSESTree.Comment[]} */ + let comments; + /** @type {PrintOptions} */ let opts; if (input_json.length > 0) { ast = JSON.parse(input_json); + comments = []; opts = {}; } else { - const content = input_js; - ast = load(content); + ({ ast, comments } = load(input_js, { jsx: true })); + opts = { sourceMapSource: 'input.js', - sourceMapContent: content + sourceMapContent: input_js }; } - const { code, map } = print(ast, opts); + const { code, map } = print(ast, tsx({ comments }), opts); fs.writeFileSync(`${__dirname}/samples/${dir}/_actual.${fileExtension}`, code); fs.writeFileSync( @@ -92,7 +103,7 @@ for (const dir of fs.readdirSync(`${__dirname}/samples`)) { JSON.stringify(map, null, '\t') ); - const parsed = acornTs.parse(code, { + const parsed = (jsxMode ? acornTsx : acornTs).parse(code, { ecmaVersion: 'latest', sourceType: input_json.length > 0 ? 'script' : 'module', locations: true diff --git a/test/indent.test.js b/test/indent.test.js index 43e7112..9b86e24 100644 --- a/test/indent.test.js +++ b/test/indent.test.js @@ -4,12 +4,13 @@ import { test } from 'vitest'; import { load } from './common'; import { print } from '../src'; import { expect } from 'vitest'; +import ts from '../src/languages/ts/index.js'; const test_code = "const foo = () => { const bar = 'baz' }"; test('default indent type is tab', () => { - const ast = load(test_code); - const code = print(ast).code; + const { ast } = load(test_code); + const code = print(ast, ts()).code; expect(code).toMatchInlineSnapshot(` "const foo = () => { @@ -19,8 +20,8 @@ test('default indent type is tab', () => { }); test('two space indent', () => { - const ast = load(test_code); - const code = print(ast, { indent: ' ' }).code; + const { ast } = load(test_code); + const code = print(ast, ts(), { indent: ' ' }).code; expect(code).toMatchInlineSnapshot(` "const foo = () => { @@ -30,8 +31,8 @@ test('two space indent', () => { }); test('four space indent', () => { - const ast = load(test_code); - const code = print(ast, { indent: ' ' }).code; + const { ast } = load(test_code); + const code = print(ast, ts(), { indent: ' ' }).code; expect(code).toMatchInlineSnapshot(` "const foo = () => { diff --git a/test/pluggability.test.js b/test/pluggability.test.js new file mode 100644 index 0000000..12229c4 --- /dev/null +++ b/test/pluggability.test.js @@ -0,0 +1,25 @@ +import { expect, test } from 'vitest'; +import { print } from '../src'; + +/** @import { Visitors } from '../types' */ +test('custom printers work', () => { + const { code } = print( + { + type: 'CustomType', + value: 'testing 123' + }, + { + CustomType(node, context) { + if (typeof node.value === 'string') { + context.write(`:) - `); + + context.write(node.value); + + context.write(` - (:`); + } + } + } + ); + + expect(code).toEqual(':) - testing 123 - (:'); +}); diff --git a/test/quotes.test.js b/test/quotes.test.js index e5e207b..1157a9a 100644 --- a/test/quotes.test.js +++ b/test/quotes.test.js @@ -5,6 +5,7 @@ import { print } from '../src/index.js'; import { expect } from 'vitest'; import { load } from './common.js'; import { walk } from 'zimmerframe'; +import ts from '../src/languages/ts/index.js'; /** @import { TSESTree } from '@typescript-eslint/types' */ @@ -27,97 +28,97 @@ function clean(ast) { const test_code = "const foo = 'bar'"; test('default quote type is single', () => { - const ast = load(test_code); + const { ast } = load(test_code); clean(ast); - const code = print(ast).code; + const code = print(ast, ts()).code; expect(code).toMatchInlineSnapshot(`"const foo = 'bar';"`); }); test('single quotes used when single quote type provided', () => { - const ast = load(test_code); + const { ast } = load(test_code); clean(ast); - const code = print(ast, { quotes: 'single' }).code; + const code = print(ast, ts({ quotes: 'single' })).code; expect(code).toMatchInlineSnapshot(`"const foo = 'bar';"`); }); test('double quotes used when double quote type provided', () => { - const ast = load(test_code); + const { ast } = load(test_code); clean(ast); - const code = print(ast, { quotes: 'double' }).code; + const code = print(ast, ts({ quotes: 'double' })).code; expect(code).toMatchInlineSnapshot(`"const foo = "bar";"`); }); test('escape single quotes if present in string literal', () => { - const ast = load('const foo = "b\'ar"'); + const { ast } = load('const foo = "b\'ar"'); clean(ast); - const code = print(ast, { quotes: 'single' }).code; + const code = print(ast, ts({ quotes: 'single' })).code; expect(code).toMatchInlineSnapshot(`"const foo = 'b\\'ar';"`); }); test('escape double quotes if present in string literal', () => { - const ast = load("const foo = 'b\"ar'"); + const { ast } = load("const foo = 'b\"ar'"); clean(ast); - const code = print(ast, { quotes: 'double' }).code; + const code = print(ast, ts({ quotes: 'double' })).code; expect(code).toMatchInlineSnapshot(`"const foo = "b\\"ar";"`); }); test('escapes new lines', () => { - const ast = load('const str = "a\\nb"'); + const { ast } = load('const str = "a\\nb"'); clean(ast); - const code = print(ast).code; + const code = print(ast, ts()).code; expect(code).toMatchInlineSnapshot(`"const str = 'a\\nb';"`); }); test('escapes escape characters', () => { - const ast = load('const str = "a\\\\nb"'); + const { ast } = load('const str = "a\\\\nb"'); clean(ast); - const code = print(ast).code; + const code = print(ast, ts()).code; expect(code).toMatchInlineSnapshot(`"const str = 'a\\\\nb';"`); }); test('escapes escape characters#2', () => { - const ast = load('const str = "a\\\\\\nb"'); + const { ast } = load('const str = "a\\\\\\nb"'); clean(ast); - const code = print(ast).code; + const code = print(ast, ts()).code; expect(code).toMatchInlineSnapshot(`"const str = 'a\\\\\\nb';"`); }); test('escapes double escaped backslashes', () => { - const ast = load("var text = $.text('\\\\\\\\');"); + const { ast } = load("var text = $.text('\\\\\\\\');"); clean(ast); - const code = print(ast).code; + const code = print(ast, ts()).code; expect(code).toMatchInlineSnapshot(`"var text = $.text('\\\\\\\\');"`); }); test('does not escape already-escaped single quotes', () => { - const ast = load(`const str = 'a\\'b'`); + const { ast } = load(`const str = 'a\\'b'`); clean(ast); - const code = print(ast).code; + const code = print(ast, ts()).code; expect(code).toMatchInlineSnapshot(`"const str = 'a\\'b';"`); }); test('does not escape already-escaped double quotes', () => { - const ast = load('const str = "a\\"b"'); + const { ast } = load('const str = "a\\"b"'); clean(ast); - const code = print(ast).code; + const code = print(ast, ts()).code; expect(code).toMatchInlineSnapshot(`"const str = 'a"b';"`); }); test('correctly handle \\n\\r', () => { - const ast = load('const str = "a\\n\\rb"'); + const { ast } = load('const str = "a\\n\\rb"'); clean(ast); - const code = print(ast).code; + const code = print(ast, ts()).code; expect(code).toMatchInlineSnapshot(`"const str = 'a\\n\\rb';"`); }); diff --git a/test/samples/class-property/expected.js b/test/samples/class-property/expected.js index 59cc686..5cac970 100644 --- a/test/samples/class-property/expected.js +++ b/test/samples/class-property/expected.js @@ -1,5 +1,5 @@ class Foo { - hi; - static foo = 1; - [KEY] = 2; -} \ No newline at end of file + hi; // a + static foo = 1; // b + [KEY] = 2; // c +} diff --git a/test/samples/class-property/expected.js.map b/test/samples/class-property/expected.js.map index 9d2f9cb..9eb7083 100644 --- a/test/samples/class-property/expected.js.map +++ b/test/samples/class-property/expected.js.map @@ -5,7 +5,7 @@ "input.js" ], "sourcesContent": [ - "class Foo {\n\thi;\n\tstatic foo = 1;\n\t[KEY] = 2;\n}" + "class Foo {\n\thi; // a\n\tstatic foo = 1; // b\n\t[KEY] = 2; // c\n}\n" ], "mappings": "MAAM,GAAG,CAAC,CAAC;CACV,EAAE;QACK,GAAG,GAAG,CAAC;EACb,GAAG,IAAI,CAAC;AACV,CAAC" } \ No newline at end of file diff --git a/test/samples/class-property/input.js b/test/samples/class-property/input.js index 59cc686..5cac970 100644 --- a/test/samples/class-property/input.js +++ b/test/samples/class-property/input.js @@ -1,5 +1,5 @@ class Foo { - hi; - static foo = 1; - [KEY] = 2; -} \ No newline at end of file + hi; // a + static foo = 1; // b + [KEY] = 2; // c +} diff --git a/test/samples/comment-before-import/expected.js b/test/samples/comment-before-import/expected.js new file mode 100644 index 0000000..fdd8235 --- /dev/null +++ b/test/samples/comment-before-import/expected.js @@ -0,0 +1,2 @@ +/* hello */ +import 'potato'; diff --git a/test/samples/comment-before-import/expected.js.map b/test/samples/comment-before-import/expected.js.map new file mode 100644 index 0000000..92e0124 --- /dev/null +++ b/test/samples/comment-before-import/expected.js.map @@ -0,0 +1,11 @@ +{ + "version": 3, + "names": [], + "sources": [ + "input.js" + ], + "sourcesContent": [ + "/* hello */\nimport 'potato';\n" + ], + "mappings": ";OACO,QAAQ" +} \ No newline at end of file diff --git a/test/samples/comment-before-import/input.js b/test/samples/comment-before-import/input.js new file mode 100644 index 0000000..fdd8235 --- /dev/null +++ b/test/samples/comment-before-import/input.js @@ -0,0 +1,2 @@ +/* hello */ +import 'potato'; diff --git a/test/samples/comment-block/expected.js b/test/samples/comment-block/expected.js index 27bac73..8f198e2 100644 --- a/test/samples/comment-block/expected.js +++ b/test/samples/comment-block/expected.js @@ -1,9 +1,7 @@ /* comment before a node * second line */ console.log(1); + console.log(2); /* comment on same line as node */ -const obj = { - foo: 1, /* comment in middle of object */ - bar: 2 -}; \ No newline at end of file +const obj = { foo: 1, /* comment in middle of object */ bar: 2 }; \ No newline at end of file diff --git a/test/samples/comment-block/expected.js.map b/test/samples/comment-block/expected.js.map index 56e2a99..d38ea3f 100644 --- a/test/samples/comment-block/expected.js.map +++ b/test/samples/comment-block/expected.js.map @@ -5,7 +5,7 @@ "input.js" ], "sourcesContent": [ - "/* comment before a node\n * second line */\nconsole.log(1);\n\nconsole.log(2); /* comment on same line as node */\n\nconst obj = {\n\tfoo: 1, /* comment in middle of object */\n\tbar: 2\n};" + "/* comment before a node\n * second line */\nconsole.log(1);\n\nconsole.log(2); /* comment on same line as node */\n\nconst obj = {\n\tfoo: 1, /* comment in middle of object */\n\tbar: 2\n};\n" ], - "mappings": ";;AAEA,OAAO,CAAC,GAAG,CAAC,CAAC;AAEb,OAAO,CAAC,GAAG,CAAC,CAAC;;MAEP,GAAG;CACR,GAAG,EAAE,CAAC;CACN,GAAG,EAAE,CAAC;" -} + "mappings": ";;AAEA,OAAO,CAAC,GAAG,CAAC,CAAC;;AAEb,OAAO,CAAC,GAAG,CAAC,CAAC;;MAEP,GAAG,KACR,GAAG,EAAE,CAAC,oCACN,GAAG,EAAE,CAAC" +} \ No newline at end of file diff --git a/test/samples/comment-block/input.js b/test/samples/comment-block/input.js index aa5270f..9f0e76c 100644 --- a/test/samples/comment-block/input.js +++ b/test/samples/comment-block/input.js @@ -7,4 +7,4 @@ console.log(2); /* comment on same line as node */ const obj = { foo: 1, /* comment in middle of object */ bar: 2 -}; \ No newline at end of file +}; diff --git a/test/samples/comment-inline/expected.js b/test/samples/comment-inline/expected.js index ed438c7..7d3db61 100644 --- a/test/samples/comment-inline/expected.js +++ b/test/samples/comment-inline/expected.js @@ -1,13 +1,14 @@ // comment before a node // second line console.log(1); + console.log(2); // comment on same line as node const obj = { foo: 1, // comment in middle of object - bar: 2 + bar: 2 // comment in middle of object }; function bar() { - return /*result*/ foo; -} + return (/*result*/ foo); +} \ No newline at end of file diff --git a/test/samples/comment-inline/expected.js.map b/test/samples/comment-inline/expected.js.map index 7ce0c3c..090f1f8 100644 --- a/test/samples/comment-inline/expected.js.map +++ b/test/samples/comment-inline/expected.js.map @@ -5,7 +5,7 @@ "input.js" ], "sourcesContent": [ - "// comment before a node\n// second line\nconsole.log(1);\nconsole.log(2); // comment on same line as node\n\nconst obj = {\n\tfoo: 1, // comment in middle of object\n\tbar: 2\n};\n\nfunction bar() {\n\treturn /*result*/ foo;\n}\n" + "// comment before a node\n// second line\nconsole.log(1);\nconsole.log(2); // comment on same line as node\n\nconst obj = {\n\tfoo: 1, // comment in middle of object\n\tbar: 2 // comment in middle of object\n};\n\nfunction bar() {\n\treturn /*result*/ foo;\n}\n" ], - "mappings": ";;AAEA,OAAO,CAAC,GAAG,CAAC,CAAC;AACb,OAAO,CAAC,GAAG,CAAC,CAAC;;MAEP,GAAG;CACR,GAAG,EAAE,CAAC;CACN,GAAG,EAAE,CAAC;;;SAGE,GAAG,GAAG,CAAC;mBACG,GAAG;AACtB,CAAC" + "mappings": ";;AAEA,OAAO,CAAC,GAAG,CAAC,CAAC;;AACb,OAAO,CAAC,GAAG,CAAC,CAAC;;MAEP,GAAG;CACR,GAAG,EAAE,CAAC;CACN,GAAG,EAAE,CAAC;;;SAGE,GAAG,GAAG,CAAC;oBACG,GAAG;AACtB,CAAC" } \ No newline at end of file diff --git a/test/samples/comment-inline/input.js b/test/samples/comment-inline/input.js index ed438c7..8f9ca9d 100644 --- a/test/samples/comment-inline/input.js +++ b/test/samples/comment-inline/input.js @@ -5,7 +5,7 @@ console.log(2); // comment on same line as node const obj = { foo: 1, // comment in middle of object - bar: 2 + bar: 2 // comment in middle of object }; function bar() { diff --git a/test/samples/comment-mixed-trailing/expected.js b/test/samples/comment-mixed-trailing/expected.js index 9587fb6..08aac9d 100644 --- a/test/samples/comment-mixed-trailing/expected.js +++ b/test/samples/comment-mixed-trailing/expected.js @@ -1,4 +1,6 @@ -function foo() {} // hey1 -/* -hey2 -*/ \ No newline at end of file +function foo() { + // hey1 + /* + hey2 + */ +} \ No newline at end of file diff --git a/test/samples/comment-mixed-trailing/expected.js.map b/test/samples/comment-mixed-trailing/expected.js.map index 0570a45..507d578 100644 --- a/test/samples/comment-mixed-trailing/expected.js.map +++ b/test/samples/comment-mixed-trailing/expected.js.map @@ -7,5 +7,5 @@ "sourcesContent": [ "function foo() {\n\t// hey1\n\t/*\n\they2\n\t*/\n}\n" ], - "mappings": "SAAS,GAAG,GAAG,CAAC,AAKhB,CAAC;;;" + "mappings": "SAAS,GAAG,GAAG,CAAC;;;;;AAKhB,CAAC" } \ No newline at end of file diff --git a/test/samples/comment-within-parentheses/expected.js b/test/samples/comment-within-parentheses/expected.js index ec9f9aa..8acd362 100644 --- a/test/samples/comment-within-parentheses/expected.js +++ b/test/samples/comment-within-parentheses/expected.js @@ -4,5 +4,6 @@ function foo() { } function bar() { - return /* hey */ abc; -} + return (/* hey */ + abc); +} \ No newline at end of file diff --git a/test/samples/comment-within-parentheses/expected.js.map b/test/samples/comment-within-parentheses/expected.js.map index 9c1631f..28bf4a7 100644 --- a/test/samples/comment-within-parentheses/expected.js.map +++ b/test/samples/comment-within-parentheses/expected.js.map @@ -7,5 +7,5 @@ "sourcesContent": [ "function foo() {\n\treturn (// hey\n\tabc);\n}\n\nfunction bar() {\n\treturn (/* hey */\n\tabc);\n}" ], - "mappings": "SAAS,GAAG,GAAG,CAAC;;CAEf,GAAG;AACJ,CAAC;;SAEQ,GAAG,GAAG,CAAC;kBAEf,GAAG;AACJ,CAAC" + "mappings": "SAAS,GAAG,GAAG,CAAC;;CAEf,GAAG;AACJ,CAAC;;SAEQ,GAAG,GAAG,CAAC;;CAEf,GAAG;AACJ,CAAC" } \ No newline at end of file diff --git a/test/samples/computed-getter/expected.js b/test/samples/computed-getter/expected.js new file mode 100644 index 0000000..a058bbd --- /dev/null +++ b/test/samples/computed-getter/expected.js @@ -0,0 +1,5 @@ +obj = { + get [foo]() { + return bar; + } +}; \ No newline at end of file diff --git a/test/samples/computed-getter/expected.js.map b/test/samples/computed-getter/expected.js.map new file mode 100644 index 0000000..afac079 --- /dev/null +++ b/test/samples/computed-getter/expected.js.map @@ -0,0 +1,11 @@ +{ + "version": 3, + "names": [], + "sources": [ + "input.js" + ], + "sourcesContent": [ + "obj = {\n\tget [foo]() {\n\t\treturn bar;\n\t}\n}\n" + ], + "mappings": "AAAA,GAAG;MACG,GAAG,IAAI,CAAC;SACL,GAAG;CACX,CAAC;" +} \ No newline at end of file diff --git a/test/samples/computed-getter/input.js b/test/samples/computed-getter/input.js new file mode 100644 index 0000000..65adba1 --- /dev/null +++ b/test/samples/computed-getter/input.js @@ -0,0 +1,5 @@ +obj = { + get [foo]() { + return bar; + } +} diff --git a/test/samples/empty-block/expected.js b/test/samples/empty-block/expected.js index 9f22386..bf9e951 100644 --- a/test/samples/empty-block/expected.js +++ b/test/samples/empty-block/expected.js @@ -1,2 +1,3 @@ if (false) {} -function x() {} + +function x() {} \ No newline at end of file diff --git a/test/samples/empty-block/expected.js.map b/test/samples/empty-block/expected.js.map index 66fbe7f..191f48d 100644 --- a/test/samples/empty-block/expected.js.map +++ b/test/samples/empty-block/expected.js.map @@ -7,5 +7,5 @@ "sourcesContent": [ "if (false) {\n\n}\n\nfunction x() {\n\n}\n" ], - "mappings": "IAAI,KAAK,EAAE,CAAC,AAEZ,CAAC;SAEQ,CAAC,GAAG,CAAC,AAEd,CAAC" + "mappings": "IAAI,KAAK,EAAE,CAAC,AAEZ,CAAC;;SAEQ,CAAC,GAAG,CAAC,AAEd,CAAC" } \ No newline at end of file diff --git a/test/samples/empty-body/expected.js b/test/samples/empty-body/expected.js index 4071743..983ab83 100644 --- a/test/samples/empty-body/expected.js +++ b/test/samples/empty-body/expected.js @@ -1,6 +1,9 @@ while (a) ; + do ; while (a); + for (; ; ) ; + if (a) ; if (a) ; else ; if (a) ; else if (b) ; else ; \ No newline at end of file diff --git a/test/samples/empty-body/expected.js.map b/test/samples/empty-body/expected.js.map index fabd387..097f5cd 100644 --- a/test/samples/empty-body/expected.js.map +++ b/test/samples/empty-body/expected.js.map @@ -7,5 +7,5 @@ "sourcesContent": [ "while (a) ;\ndo ; while (a);\nfor (; ; ) ;\nif (a) ;\nif (a) ; else ;\nif (a) ; else if (b) ; else ;" ], - "mappings": "OAAO,CAAC;YACI,CAAC;;IAET,CAAC;IACD,CAAC;IACD,CAAC,aAAa,CAAC" + "mappings": "OAAO,CAAC;;YACI,CAAC;;;;IAET,CAAC;IACD,CAAC;IACD,CAAC,aAAa,CAAC" } \ No newline at end of file diff --git a/test/samples/jsdoc-indentation/expected.js b/test/samples/jsdoc-indentation/expected.js new file mode 100644 index 0000000..e943664 --- /dev/null +++ b/test/samples/jsdoc-indentation/expected.js @@ -0,0 +1,9 @@ +class Foo { + /** + * @param {number} a + * @param {number} b + */ + add(a, b) { + return a + b; + } +} \ No newline at end of file diff --git a/test/samples/jsdoc-indentation/expected.js.map b/test/samples/jsdoc-indentation/expected.js.map new file mode 100644 index 0000000..94bcfe9 --- /dev/null +++ b/test/samples/jsdoc-indentation/expected.js.map @@ -0,0 +1,11 @@ +{ + "version": 3, + "names": [], + "sources": [ + "input.js" + ], + "sourcesContent": [ + "class Foo {\n\t/**\n\t * @param {number} a\n\t * @param {number} b\n\t */\n\tadd(a, b) {\n\t\treturn a + b;\n\t}\n}\n" + ], + "mappings": "MAAM,GAAG,CAAC,CAAC;;;;;CAKV,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;SACH,CAAC,GAAG,CAAC;CACb,CAAC;AACF,CAAC" +} \ No newline at end of file diff --git a/test/samples/jsdoc-indentation/input.js b/test/samples/jsdoc-indentation/input.js new file mode 100644 index 0000000..527f30c --- /dev/null +++ b/test/samples/jsdoc-indentation/input.js @@ -0,0 +1,9 @@ +class Foo { + /** + * @param {number} a + * @param {number} b + */ + add(a, b) { + return a + b; + } +} diff --git a/test/samples/jsx-basic/expected.jsx b/test/samples/jsx-basic/expected.jsx new file mode 100644 index 0000000..8830fe7 --- /dev/null +++ b/test/samples/jsx-basic/expected.jsx @@ -0,0 +1,6 @@ +console.log(<> +
+ {"An + Time since last cat incident: {"5 days"} +
+); diff --git a/test/samples/jsx-basic/expected.jsx.map b/test/samples/jsx-basic/expected.jsx.map new file mode 100644 index 0000000..06a812c --- /dev/null +++ b/test/samples/jsx-basic/expected.jsx.map @@ -0,0 +1,11 @@ +{ + "version": 3, + "names": [], + "sources": [ + "input.js" + ], + "sourcesContent": [ + "console.log(<>\n
\n {\"An\n Time since last cat incident: {\"5 days\"}\n
\n)" + ], + "mappings": "AAAA,OAAO,CAAC,GAAG,GAAG;IACV,CAAC,GAAG,CAAC;QACD,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,0BAA0B,IAAI;sCACxB,CAAC,QAAQ,CAAC;IAC5C,EAAE,GAAG,CAAC;AACV" +} \ No newline at end of file diff --git a/test/samples/jsx-basic/input.jsx b/test/samples/jsx-basic/input.jsx new file mode 100644 index 0000000..6ad284a --- /dev/null +++ b/test/samples/jsx-basic/input.jsx @@ -0,0 +1,6 @@ +console.log(<> +
+ {"An + Time since last cat incident: {"5 days"} +
+) \ No newline at end of file diff --git a/test/samples/large-file/expected.js b/test/samples/large-file/expected.js index 483086f..8934aa8 100644 --- a/test/samples/large-file/expected.js +++ b/test/samples/large-file/expected.js @@ -31,9672 +31,10239 @@ } else { factory(global); } -})( - typeof window !== "undefined" ? window : this, // Pass this if window is not defined yet - function (window, noGlobal) { - // Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1 - // throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode - // arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common - // enough that all such attempts are guarded in a try block. - "use strict"; - - var arr = []; - var getProto = Object.getPrototypeOf; - var slice = arr.slice; - var flat = arr.flat - ? function (array) { - return arr.flat.call(array); - } - : function (array) { - return arr.concat.apply([], array); - }; - var push = arr.push; - var indexOf = arr.indexOf; - var class2type = {}; - var toString = class2type.toString; - var hasOwn = class2type.hasOwnProperty; - var fnToString = hasOwn.toString; - var ObjectFunctionString = fnToString.call(Object); - var support = {}; - - var isFunction = function isFunction(obj) { - // Support: Chrome <=57, Firefox <=52 - // In some browsers, typeof returns "function" for HTML elements - // (i.e., `typeof document.createElement( "object" ) === "function"`). - // We don't want to classify *any* DOM node as a function. - // Support: QtWeb <=3.8.5, WebKit <=534.34, wkhtmltopdf tool <=0.12.5 - // Plus for old WebKit, typeof returns "function" for HTML collections - // (e.g., `typeof document.getElementsByTagName("div") === "function"`). (gh-4756) - return typeof obj === "function" && typeof obj.nodeType !== "number" && typeof obj.item !== "function"; - }; - var isWindow = function isWindow(obj) { - return obj != null && obj === obj.window; + // Pass this if window is not defined yet +})(typeof window !== "undefined" ? window : this, function (window, noGlobal) { + // Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1 + // throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode + // arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common + // enough that all such attempts are guarded in a try block. + "use strict"; + + var arr = []; + var getProto = Object.getPrototypeOf; + var slice = arr.slice; + + var flat = arr.flat + ? function (array) { + return arr.flat.call(array); + } + : function (array) { + return arr.concat.apply([], array); }; - var document = window.document; + var push = arr.push; + var indexOf = arr.indexOf; + var class2type = {}; + var toString = class2type.toString; + var hasOwn = class2type.hasOwnProperty; + var fnToString = hasOwn.toString; + var ObjectFunctionString = fnToString.call(Object); + var support = {}; + + var isFunction = function isFunction(obj) { + // Support: Chrome <=57, Firefox <=52 + // In some browsers, typeof returns "function" for HTML elements + // (i.e., `typeof document.createElement( "object" ) === "function"`). + // We don't want to classify *any* DOM node as a function. + // Support: QtWeb <=3.8.5, WebKit <=534.34, wkhtmltopdf tool <=0.12.5 + // Plus for old WebKit, typeof returns "function" for HTML collections + // (e.g., `typeof document.getElementsByTagName("div") === "function"`). (gh-4756) + return typeof obj === "function" && typeof obj.nodeType !== "number" && typeof obj.item !== "function"; + }; + + var isWindow = function isWindow(obj) { + return obj != null && obj === obj.window; + }; + + var document = window.document; + var preservedScriptAttributes = { type: true, src: true, nonce: true, noModule: true }; + + function DOMEval(code, node, doc) { + doc = doc || document; + + var i, val, script = doc.createElement("script"); + + script.text = code; + + if (node) { + for (i in preservedScriptAttributes) { + // Support: Firefox 64+, Edge 18+ + // Some browsers don't support the "nonce" property on scripts. + // On the other hand, just using `getAttribute` is not enough as + // the `nonce` attribute is reset to an empty string whenever it + // becomes browsing-context connected. + // See https://github.com/whatwg/html/issues/2369 + // See https://html.spec.whatwg.org/#nonce-attributes + // The `node.getAttribute` check was added for the sake of + // `jQuery.globalEval` so that it can fake a nonce-containing node + // via an object. + val = node[i] || node.getAttribute && node.getAttribute(i); + + if (val) { + script.setAttribute(i, val); + } + } + } + + doc.head.appendChild(script).parentNode.removeChild(script); + } + + function toType(obj) { + if (obj == null) { + return obj + ""; + } + + // Support: Android <=2.3 only (functionish RegExp) + return typeof obj === "object" || typeof obj === "function" + ? class2type[toString.call(obj)] || "object" + : typeof obj; + } - var preservedScriptAttributes = { - type: true, - src: true, - nonce: true, - noModule: true + /* global Symbol */ + // Defining this global in .eslintrc.json would create a danger of using the global + // unguarded in another place, it seems safer to define global only for this module + var version = "3.7.1", + rhtmlSuffix = /HTML$/i, + // Define a local copy of jQuery + jQuery = function (selector, context) { + // The jQuery object is actually just the init constructor 'enhanced' + // Need init if jQuery is called (just allow error to be thrown if not included) + return new jQuery.fn.init(selector, context); }; - function DOMEval(code, node, doc) { - doc = doc || document; + jQuery.fn = jQuery.prototype = { + // The current version of jQuery being used + jquery: version, - var i, - val, - script = doc.createElement("script"); + constructor: jQuery, - script.text = code; + // The default length of a jQuery object is 0 + length: 0, - if (node) { - for (i in preservedScriptAttributes) { - // Support: Firefox 64+, Edge 18+ - // Some browsers don't support the "nonce" property on scripts. - // On the other hand, just using `getAttribute` is not enough as - // the `nonce` attribute is reset to an empty string whenever it - // becomes browsing-context connected. - // See https://github.com/whatwg/html/issues/2369 - // See https://html.spec.whatwg.org/#nonce-attributes - // The `node.getAttribute` check was added for the sake of - // `jQuery.globalEval` so that it can fake a nonce-containing node - // via an object. - val = node[i] || node.getAttribute && node.getAttribute(i); + toArray() { + return slice.call(this); + }, - if (val) { - script.setAttribute(i, val); - } - } + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get(num) { + // Return all the elements in a clean array + if (num == null) { + return slice.call(this); } - doc.head.appendChild(script).parentNode.removeChild(script); - } + // Return just the one element from the set + return num < 0 ? this[num + this.length] : this[num]; + }, - function toType(obj) { - if (obj == null) { - return obj + ""; - } + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack(elems) { + // Build a new jQuery matched element set + var ret = jQuery.merge(this.constructor(), elems); - // Support: Android <=2.3 only (functionish RegExp) - return typeof obj === "object" || typeof obj === "function" ? class2type[toString.call(obj)] || "object" : typeof obj; - } + // Add the old object onto the stack (as a reference) + ret.prevObject = this; - /* global Symbol */ - // Defining this global in .eslintrc.json would create a danger of using the global - // unguarded in another place, it seems safer to define global only for this module - var version = "3.7.1", - rhtmlSuffix = /HTML$/i, - // Define a local copy of jQuery - jQuery = function (selector, context) { - // The jQuery object is actually just the init constructor 'enhanced' - // Need init if jQuery is called (just allow error to be thrown if not included) - return new jQuery.fn.init(selector, context); - }; + // Return the newly-formed element set + return ret; + }, - jQuery.fn = jQuery.prototype = { - // The current version of jQuery being used - jquery: version, - constructor: jQuery, - // The default length of a jQuery object is 0 - length: 0, - toArray() { - return slice.call(this); - }, - get(num) { - // Return all the elements in a clean array - if (num == null) { - return slice.call(this); - } + // Execute a callback for every element in the matched set. + each(callback) { + return jQuery.each(this, callback); + }, - // Return just the one element from the set - return num < 0 ? this[num + this.length] : this[num]; - }, - pushStack(elems) { - // Build a new jQuery matched element set - var ret = jQuery.merge(this.constructor(), elems); + map(callback) { + return this.pushStack(jQuery.map(this, function (elem, i) { + return callback.call(elem, i, elem); + })); + }, - // Add the old object onto the stack (as a reference) - ret.prevObject = this; - // Return the newly-formed element set - return ret; - }, - each(callback) { - return jQuery.each(this, callback); - }, - map(callback) { - return this.pushStack(jQuery.map(this, function (elem, i) { - return callback.call(elem, i, elem); - })); - }, - slice() { - return this.pushStack(slice.apply(this, arguments)); - }, - first() { - return this.eq(0); - }, - last() { - return this.eq(-1); - }, - even() { - return this.pushStack(jQuery.grep(this, function (_elem, i) { - return (i + 1) % 2; - })); - }, - odd() { - return this.pushStack(jQuery.grep(this, function (_elem, i) { - return i % 2; - })); - }, - eq(i) { - var len = this.length, - j = +i + (i < 0 ? len : 0); + slice() { + return this.pushStack(slice.apply(this, arguments)); + }, - return this.pushStack(j >= 0 && j < len ? [this[j]] : []); - }, - end() { - return this.prevObject || this.constructor(); - }, - // For internal use only. - // Behaves like an Array's method, not like a jQuery method. - push, - sort: arr.sort, - splice: arr.splice - }; + first() { + return this.eq(0); + }, - jQuery.extend = jQuery.fn.extend = function () { - var options, - name, - src, - copy, - copyIsArray, - clone, - target = arguments[0] || {}, - i = 1, - length = arguments.length, - deep = false; + last() { + return this.eq(-1); + }, - // Handle a deep copy situation - if (typeof target === "boolean") { - deep = target; - // Skip the boolean and the target - target = arguments[i] || {}; - i++; - } + even() { + return this.pushStack(jQuery.grep(this, function (_elem, i) { + return (i + 1) % 2; + })); + }, - // Handle case when target is a string or something (possible in deep copy) - if (typeof target !== "object" && !isFunction(target)) { - target = {}; - } + odd() { + return this.pushStack(jQuery.grep(this, function (_elem, i) { + return i % 2; + })); + }, + + eq(i) { + var len = this.length, j = +i + (i < 0 ? len : 0); + + return this.pushStack(j >= 0 && j < len ? [this[j]] : []); + }, + + end() { + return this.prevObject || this.constructor(); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push, + + sort: arr.sort, + splice: arr.splice + }; + + jQuery.extend = jQuery.fn.extend = function () { + var options, + name, + src, + copy, + copyIsArray, + clone, + target = arguments[0] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if (typeof target === "boolean") { + deep = target; + + // Skip the boolean and the target + target = arguments[i] || {}; + + i++; + } - // Extend jQuery itself if only one argument is passed - if (i === length) { - target = this; - i--; - } + // Handle case when target is a string or something (possible in deep copy) + if (typeof target !== "object" && !isFunction(target)) { + target = {}; + } - for (; i < length; i++) { - // Only deal with non-null/undefined values - if ((options = arguments[i]) != null) { - // Extend the base object - for (name in options) { - copy = options[name]; - - // Prevent Object.prototype pollution - // Prevent never-ending loop - if (name === "__proto__" || target === copy) { - continue; - } + // Extend jQuery itself if only one argument is passed + if (i === length) { + target = this; + i--; + } - // Recurse if we're merging plain objects or arrays - if (deep && copy && (jQuery.isPlainObject(copy) || (copyIsArray = Array.isArray(copy)))) { - src = target[name]; + for (; i < length; i++) { + // Only deal with non-null/undefined values + if ((options = arguments[i]) != null) { + // Extend the base object + for (name in options) { + copy = options[name]; - // Ensure proper type for the source value - if (copyIsArray && !Array.isArray(src)) { - clone = []; - } else if (!copyIsArray && !jQuery.isPlainObject(src)) { - clone = {}; - } else { - clone = src; - } + // Prevent Object.prototype pollution + // Prevent never-ending loop + if (name === "__proto__" || target === copy) { + continue; + } - copyIsArray = false; - // Never move original objects, clone them - target[name] = jQuery.extend(deep, clone, copy); - } else if (copy !== undefined) { - target[name] = copy; // Don't bring in undefined values + // Recurse if we're merging plain objects or arrays + if (deep && copy && (jQuery.isPlainObject(copy) || (copyIsArray = Array.isArray(copy)))) { + src = target[name]; + + // Ensure proper type for the source value + if (copyIsArray && !Array.isArray(src)) { + clone = []; + } else if (!copyIsArray && !jQuery.isPlainObject(src)) { + clone = {}; + } else { + clone = src; } + + copyIsArray = false; + + // Never move original objects, clone them + target[name] = jQuery.extend(deep, clone, copy); + + // Don't bring in undefined values + } else if (copy !== undefined) { + target[name] = copy; } } } + } - // Return the modified object - return target; - }; + // Return the modified object + return target; + }; - jQuery.extend({ - // Unique for each copy of jQuery on the page - expando: "jQuery" + (version + Math.random()).replace(/\D/g, ""), - // Assume jQuery is ready without the ready module - isReady: true, - error(msg) { - throw new Error(msg); - }, - noop() {}, - isPlainObject(obj) { - var proto, Ctor; + jQuery.extend({ + // Unique for each copy of jQuery on the page + expando: "jQuery" + (version + Math.random()).replace(/\D/g, ""), - // Detect obvious negatives - // Use toString instead of jQuery.type to catch host objects - if (!obj || toString.call(obj) !== "[object Object]") { - return false; - } + // Assume jQuery is ready without the ready module + isReady: true, - proto = getProto(obj); + error(msg) { + throw new Error(msg); + }, - // Objects with no prototype (e.g., `Object.create( null )`) are plain - if (!proto) { - return true; - } + noop() {}, - // Objects with prototype are plain iff they were constructed by a global Object function - Ctor = hasOwn.call(proto, "constructor") && proto.constructor; - return typeof Ctor === "function" && fnToString.call(Ctor) === ObjectFunctionString; - }, - isEmptyObject(obj) { - var name; + isPlainObject(obj) { + var proto, Ctor; - for (name in obj) { - return false; - } + // Detect obvious negatives + // Use toString instead of jQuery.type to catch host objects + if (!obj || toString.call(obj) !== "[object Object]") { + return false; + } + + proto = getProto(obj); + // Objects with no prototype (e.g., `Object.create( null )`) are plain + if (!proto) { return true; - }, - globalEval(code, options, doc) { - DOMEval(code, { nonce: options && options.nonce }, doc); - }, - each(obj, callback) { - var length, i = 0; + } - if (isArrayLike(obj)) { - length = obj.length; + // Objects with prototype are plain iff they were constructed by a global Object function + Ctor = hasOwn.call(proto, "constructor") && proto.constructor; - for (; i < length; i++) { - if (callback.call(obj[i], i, obj[i]) === false) { - break; - } + return typeof Ctor === "function" && fnToString.call(Ctor) === ObjectFunctionString; + }, + + isEmptyObject(obj) { + var name; + + for (name in obj) { + return false; + } + + return true; + }, + + // Evaluates a script in a provided context; falls back to the global one + // if not specified. + globalEval(code, options, doc) { + DOMEval(code, { nonce: options && options.nonce }, doc); + }, + + each(obj, callback) { + var length, i = 0; + + if (isArrayLike(obj)) { + length = obj.length; + + for (; i < length; i++) { + if (callback.call(obj[i], i, obj[i]) === false) { + break; } - } else { - for (i in obj) { - if (callback.call(obj[i], i, obj[i]) === false) { - break; - } + } + } else { + for (i in obj) { + if (callback.call(obj[i], i, obj[i]) === false) { + break; } } + } - return obj; - }, - text(elem) { - var node, - ret = "", - i = 0, - nodeType = elem.nodeType; + return obj; + }, - if (!nodeType) { - // If no nodeType, this is expected to be an array - while (node = elem[i++]) { - // Do not traverse comment nodes - ret += jQuery.text(node); - } - } + // Retrieve the text value of an array of DOM nodes + text(elem) { + var node, + ret = "", + i = 0, + nodeType = elem.nodeType; - if (nodeType === 1 || nodeType === 11) { - return elem.textContent; + if (!nodeType) { + // If no nodeType, this is expected to be an array + while (node = elem[i++]) { + // Do not traverse comment nodes + ret += jQuery.text(node); } + } - if (nodeType === 9) { - return elem.documentElement.textContent; - } + if (nodeType === 1 || nodeType === 11) { + return elem.textContent; + } - if (nodeType === 3 || nodeType === 4) { - return elem.nodeValue; - } + if (nodeType === 9) { + return elem.documentElement.textContent; + } - // Do not include comment or processing instruction nodes - return ret; - }, - makeArray(arr, results) { - var ret = results || []; + if (nodeType === 3 || nodeType === 4) { + return elem.nodeValue; + } - if (arr != null) { - if (isArrayLike(Object(arr))) { - jQuery.merge(ret, typeof arr === "string" ? [arr] : arr); - } else { - push.call(ret, arr); - } + // Do not include comment or processing instruction nodes + return ret; + }, + + // results is for internal usage only + makeArray(arr, results) { + var ret = results || []; + + if (arr != null) { + if (isArrayLike(Object(arr))) { + jQuery.merge(ret, typeof arr === "string" ? [arr] : arr); + } else { + push.call(ret, arr); } + } - return ret; - }, - inArray(elem, arr, i) { - return arr == null ? -1 : indexOf.call(arr, elem, i); - }, - isXMLDoc(elem) { - var namespace = elem && elem.namespaceURI, - docElem = elem && (elem.ownerDocument || elem).documentElement; + return ret; + }, - // Assume HTML when documentElement doesn't yet exist, such as inside - // document fragments. - return !rhtmlSuffix.test(namespace || docElem && docElem.nodeName || "HTML"); - }, - merge(first, second) { - var len = +second.length, - j = 0, - i = first.length; + inArray(elem, arr, i) { + return arr == null ? -1 : indexOf.call(arr, elem, i); + }, - for (; j < len; j++) { - first[i++] = second[j]; - } + isXMLDoc(elem) { + var namespace = elem && elem.namespaceURI, + docElem = elem && (elem.ownerDocument || elem).documentElement; - first.length = i; - return first; - }, - grep(elems, callback, invert) { - var callbackInverse, - matches = [], - i = 0, - length = elems.length, - callbackExpect = !invert; - - // Go through the array, only saving the items - // that pass the validator function - for (; i < length; i++) { - callbackInverse = !callback(elems[i], i); + // Assume HTML when documentElement doesn't yet exist, such as inside + // document fragments. + return !rhtmlSuffix.test(namespace || docElem && docElem.nodeName || "HTML"); + }, - if (callbackInverse !== callbackExpect) { - matches.push(elems[i]); - } + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + merge(first, second) { + var len = +second.length, j = 0, i = first.length; + + for (; j < len; j++) { + first[i++] = second[j]; + } + + first.length = i; + + return first; + }, + + grep(elems, callback, invert) { + var callbackInverse, + matches = [], + i = 0, + length = elems.length, + callbackExpect = !invert; + + // Go through the array, only saving the items + // that pass the validator function + for (; i < length; i++) { + callbackInverse = !callback(elems[i], i); + + if (callbackInverse !== callbackExpect) { + matches.push(elems[i]); } + } - return matches; - }, - map(elems, callback, arg) { - var length, value, i = 0, ret = []; + return matches; + }, - // Go through the array, translating each of the items to their new values - if (isArrayLike(elems)) { - length = elems.length; + // arg is for internal usage only + map(elems, callback, arg) { + var length, value, i = 0, ret = []; - for (; i < length; i++) { - value = callback(elems[i], i, arg); + // Go through the array, translating each of the items to their new values + if (isArrayLike(elems)) { + length = elems.length; - if (value != null) { - ret.push(value); - } + for (; i < length; i++) { + value = callback(elems[i], i, arg); + + if (value != null) { + ret.push(value); } - } else { - for (i in elems) { - value = callback( - elems[i], // Go through every key on the object, - i, - arg - ); + } - if (value != null) { - ret.push(value); - } + // Go through every key on the object, + } else { + for (i in elems) { + value = callback(elems[i], i, arg); + + if (value != null) { + ret.push(value); } } + } - // Flatten any nested arrays - return flat(ret); - }, - // A global GUID counter for objects - guid: 1, - // jQuery.support is not used in Core but other projects attach their - // properties to it so it needs to exist. - support - }); + // Flatten any nested arrays + return flat(ret); + }, - if (typeof Symbol === "function") { - jQuery.fn[Symbol.iterator] = arr[Symbol.iterator]; - } + // A global GUID counter for objects + guid: 1, - // Populate the class2type map - jQuery.each(("Boolean Number String Function Array Date RegExp Object Error Symbol").split(" "), function (_i, name) { - class2type["[object " + name + "]"] = name.toLowerCase(); - }); + // jQuery.support is not used in Core but other projects attach their + // properties to it so it needs to exist. + support + }); + + if (typeof Symbol === "function") { + jQuery.fn[Symbol.iterator] = arr[Symbol.iterator]; + } - function isArrayLike(obj) { - // Support: real iOS 8.2 only (not reproducible in simulator) - // `in` check used to prevent JIT error (gh-2145) - // hasOwn isn't used here due to false negatives - // regarding Nodelist length in IE - var length = !!obj && "length" in obj && obj.length, - type = toType(obj); + // Populate the class2type map + jQuery.each(("Boolean Number String Function Array Date RegExp Object Error Symbol").split(" "), function (_i, name) { + class2type["[object " + name + "]"] = name.toLowerCase(); + }); - if (isFunction(obj) || isWindow(obj)) { - return false; - } + function isArrayLike(obj) { + // Support: real iOS 8.2 only (not reproducible in simulator) + // `in` check used to prevent JIT error (gh-2145) + // hasOwn isn't used here due to false negatives + // regarding Nodelist length in IE + var length = !!obj && "length" in obj && obj.length, + type = toType(obj); - return type === "array" || length === 0 || typeof length === "number" && length > 0 && length - 1 in obj; + if (isFunction(obj) || isWindow(obj)) { + return false; } - function nodeName(elem, name) { - return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); - } + return type === "array" || length === 0 || typeof length === "number" && length > 0 && length - 1 in obj; + } - var pop = arr.pop; - var sort = arr.sort; - var splice = arr.splice; - var whitespace = "[\\x20\\t\\r\\n\\f]"; - var rtrimCSS = new RegExp("^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g"); + function nodeName(elem, name) { + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + } - // Note: an element does not contain itself - jQuery.contains = function (a, b) { - var bup = b && b.parentNode; + var pop = arr.pop; + var sort = arr.sort; + var splice = arr.splice; + var whitespace = "[\\x20\\t\\r\\n\\f]"; + var rtrimCSS = new RegExp("^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g"); - return a === bup || !!(bup && bup.nodeType === 1 && (// Support: IE 9 - 11+ - // IE doesn't have `contains` on SVG. - a.contains ? a.contains(bup) : a.compareDocumentPosition && a.compareDocumentPosition(bup) & 16)); - }; + // Note: an element does not contain itself + jQuery.contains = function (a, b) { + var bup = b && b.parentNode; - // CSS string/identifier serialization - // https://drafts.csswg.org/cssom/#common-serializing-idioms - var rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\x80-\uFFFF\w-]/g; + return a === bup || !!(bup && bup.nodeType === 1 && (// Support: IE 9 - 11+ + // IE doesn't have `contains` on SVG. + a.contains + ? a.contains(bup) + : a.compareDocumentPosition && a.compareDocumentPosition(bup) & 16)); + }; - function fcssescape(ch, asCodePoint) { - if (asCodePoint) { - // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER - if (ch === "\0") { - return "\uFFFD"; - } + // CSS string/identifier serialization + // https://drafts.csswg.org/cssom/#common-serializing-idioms + var rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\x80-\uFFFF\w-]/g; - // Control characters and (dependent upon position) numbers get escaped as code points - return ch.slice(0, -1) + "\\" + ch.charCodeAt(ch.length - 1).toString(16) + " "; + function fcssescape(ch, asCodePoint) { + if (asCodePoint) { + // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER + if (ch === "\0") { + return "\uFFFD"; } - // Other potentially-special ASCII characters get backslash-escaped - return "\\" + ch; + // Control characters and (dependent upon position) numbers get escaped as code points + return ch.slice(0, -1) + "\\" + ch.charCodeAt(ch.length - 1).toString(16) + " "; } - jQuery.escapeSelector = function (sel) { - return (sel + "").replace(rcssescape, fcssescape); - }; - - var preferredDoc = document, pushNative = push; + // Other potentially-special ASCII characters get backslash-escaped + return "\\" + ch; + } - (function () { - var i, - Expr, - outermostContext, - sortInput, - hasDuplicate, - push = pushNative, - // Local document vars - document, - documentElement, - documentIsHTML, - rbuggyQSA, - matches, - // Instance-specific data - expando = jQuery.expando, - dirruns = 0, - done = 0, - classCache = createCache(), - tokenCache = createCache(), - compilerCache = createCache(), - nonnativeSelectorCache = createCache(), - sortOrder = function (a, b) { - if (a === b) { - hasDuplicate = true; - } + jQuery.escapeSelector = function (sel) { + return (sel + "").replace(rcssescape, fcssescape); + }; + + var preferredDoc = document, pushNative = push; + + (function () { + var i, + Expr, + outermostContext, + sortInput, + hasDuplicate, + push = pushNative, + // Local document vars + document, + documentElement, + documentIsHTML, + rbuggyQSA, + matches, + // Instance-specific data + expando = jQuery.expando, + dirruns = 0, + done = 0, + classCache = createCache(), + tokenCache = createCache(), + compilerCache = createCache(), + nonnativeSelectorCache = createCache(), + sortOrder = function (a, b) { + if (a === b) { + hasDuplicate = true; + } - return 0; - }, - booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|" + "loop|multiple|open|readonly|required|scoped", - // Regular expressions - // https://www.w3.org/TR/css-syntax-3/#ident-token-diagram - identifier = "(?:\\\\[\\da-fA-F]{1,6}" + whitespace + "?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+", - // Attribute selectors: https://www.w3.org/TR/selectors/#attribute-selectors - attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + // Operator (capture 2) - "*([*^$|!~]?=)" + whitespace + // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]" - "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace + "*\\]", - pseudos = ":(" + identifier + ")(?:\\((" + // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: - // 1. quoted (capture 3; capture 4 or capture 5) - "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + // 2. simple (capture 6) - "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + // 3. anything else (capture 2) - ".*" + ")\\)|)", - // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter - rwhitespace = new RegExp(whitespace + "+", "g"), - rcomma = new RegExp("^" + whitespace + "*," + whitespace + "*"), - rleadingCombinator = new RegExp("^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*"), - rdescend = new RegExp(whitespace + "|>"), - rpseudo = new RegExp(pseudos), - ridentifier = new RegExp("^" + identifier + "$"), - matchExpr = { - ID: new RegExp("^#(" + identifier + ")"), - CLASS: new RegExp("^\\.(" + identifier + ")"), - TAG: new RegExp("^(" + identifier + "|[*])"), - ATTR: new RegExp("^" + attributes), - PSEUDO: new RegExp("^" + pseudos), - CHILD: new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + "*(\\d+)|))" + whitespace + "*\\)|)", "i"), - bool: new RegExp("^(?:" + booleans + ")$", "i"), - // For use in libraries implementing .is() - // We use this for POS matching in `select` - needsContext: new RegExp("^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i") - }, - rinputs = /^(?:input|select|textarea|button)$/i, - rheader = /^h\d$/i, - // Easily-parseable/retrievable ID or TAG or CLASS selectors - rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, - rsibling = /[+~]/, - // CSS escapes - // https://www.w3.org/TR/CSS21/syndata.html#escaped-characters - runescape = new RegExp("\\\\[\\da-fA-F]{1,6}" + whitespace + "?|\\\\([^\\r\\n\\f])", "g"), - funescape = function (escape, nonHex) { - var high = "0x" + escape.slice(1) - 0x10000; - - if (nonHex) { - // Strip the backslash prefix from a non-hex escape sequence - return nonHex; - } - - // Replace a hexadecimal escape sequence with the encoded Unicode code point - // Support: IE <=11+ - // For values outside the Basic Multilingual Plane (BMP), manually construct a - // surrogate pair - return high < 0 ? String.fromCharCode(high + 0x10000) : String.fromCharCode(high >> 10 | 0xD800, high & 0x3FF | 0xDC00); + return 0; + }, + booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|" + "loop|multiple|open|readonly|required|scoped", + // Regular expressions + // https://www.w3.org/TR/css-syntax-3/#ident-token-diagram + identifier = "(?:\\\\[\\da-fA-F]{1,6}" + whitespace + "?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+", + // Attribute selectors: https://www.w3.org/TR/selectors/#attribute-selectors + attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + // Operator (capture 2) + "*([*^$|!~]?=)" + whitespace + // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]" + "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace + "*\\]", + pseudos = ":(" + identifier + ")(?:\\((" + // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: + // 1. quoted (capture 3; capture 4 or capture 5) + "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + // 2. simple (capture 6) + "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + // 3. anything else (capture 2) + ".*" + ")\\)|)", + // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter + rwhitespace = new RegExp(whitespace + "+", "g"), + rcomma = new RegExp("^" + whitespace + "*," + whitespace + "*"), + rleadingCombinator = new RegExp("^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*"), + rdescend = new RegExp(whitespace + "|>"), + rpseudo = new RegExp(pseudos), + ridentifier = new RegExp("^" + identifier + "$"), + matchExpr = { + ID: new RegExp("^#(" + identifier + ")"), + CLASS: new RegExp("^\\.(" + identifier + ")"), + TAG: new RegExp("^(" + identifier + "|[*])"), + ATTR: new RegExp("^" + attributes), + PSEUDO: new RegExp("^" + pseudos), + CHILD: new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + "*(\\d+)|))" + whitespace + "*\\)|)", "i"), + bool: new RegExp("^(?:" + booleans + ")$", "i"), + + // For use in libraries implementing .is() + // We use this for POS matching in `select` + needsContext: new RegExp("^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i") + }, + rinputs = /^(?:input|select|textarea|button)$/i, + rheader = /^h\d$/i, + // Easily-parseable/retrievable ID or TAG or CLASS selectors + rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, + rsibling = /[+~]/, + // CSS escapes + // https://www.w3.org/TR/CSS21/syndata.html#escaped-characters + runescape = new RegExp("\\\\[\\da-fA-F]{1,6}" + whitespace + "?|\\\\([^\\r\\n\\f])", "g"), + funescape = function (escape, nonHex) { + var high = "0x" + escape.slice(1) - 0x10000; + + if (nonHex) { + // Strip the backslash prefix from a non-hex escape sequence + return nonHex; + } + + // Replace a hexadecimal escape sequence with the encoded Unicode code point + // Support: IE <=11+ + // For values outside the Basic Multilingual Plane (BMP), manually construct a + // surrogate pair + return high < 0 + ? String.fromCharCode(high + 0x10000) + : String.fromCharCode(high >> 10 | 0xD800, high & 0x3FF | 0xDC00); + }, + // Used for iframes; see `setDocument`. + // Support: IE 9 - 11+, Edge 12 - 18+ + // Removing the function wrapper causes a "Permission Denied" + // error in IE/Edge. + unloadHandler = function () { + setDocument(); + }, + inDisabledFieldset = addCombinator( + function (elem) { + return elem.disabled === true && nodeName(elem, "fieldset"); }, - // Used for iframes; see `setDocument`. - // Support: IE 9 - 11+, Edge 12 - 18+ - // Removing the function wrapper causes a "Permission Denied" - // error in IE/Edge. - unloadHandler = function () { - setDocument(); + { dir: "parentNode", next: "legend" } + ); + + // Support: IE <=9 only + // Accessing document.activeElement can throw unexpectedly + // https://bugs.jquery.com/ticket/13393 + function safeActiveElement() { + try { + return document.activeElement; + } catch(err) {} + } + + // Optimize for push.apply( _, NodeList ) + try { + push.apply(arr = slice.call(preferredDoc.childNodes), preferredDoc.childNodes); + + // Support: Android <=4.0 + // Detect silently failing push.apply + // eslint-disable-next-line no-unused-expressions + arr[preferredDoc.childNodes.length].nodeType; + } catch(e) { + push = { + apply(target, els) { + pushNative.apply(target, slice.call(els)); }, - inDisabledFieldset = addCombinator( - function (elem) { - return elem.disabled === true && nodeName(elem, "fieldset"); - }, - { dir: "parentNode", next: "legend" } - ); - // Support: IE <=9 only - // Accessing document.activeElement can throw unexpectedly - // https://bugs.jquery.com/ticket/13393 - function safeActiveElement() { - try { - return document.activeElement; - } catch(err) {} - } + call(target) { + pushNative.apply(target, slice.call(arguments, 1)); + } + }; + } - // Optimize for push.apply( _, NodeList ) - try { - push.apply(arr = slice.call(preferredDoc.childNodes), preferredDoc.childNodes); - // Support: Android <=4.0 - // Detect silently failing push.apply - // eslint-disable-next-line no-unused-expressions - arr[preferredDoc.childNodes.length].nodeType; - } catch(e) { - push = { - apply(target, els) { - pushNative.apply(target, slice.call(els)); - }, - call(target) { - pushNative.apply(target, slice.call(arguments, 1)); - } - }; + function find(selector, context, results, seed) { + var m, + i, + elem, + nid, + match, + groups, + newSelector, + newContext = context && context.ownerDocument, + // nodeType defaults to 9, since context defaults to document + nodeType = context ? context.nodeType : 9; + + results = results || []; + + // Return early from calls with invalid selector or context + if (typeof selector !== "string" || !selector || nodeType !== 1 && nodeType !== 9 && nodeType !== 11) { + return results; } - function find(selector, context, results, seed) { - var m, - i, - elem, - nid, - match, - groups, - newSelector, - newContext = context && context.ownerDocument, - // nodeType defaults to 9, since context defaults to document - nodeType = context ? context.nodeType : 9; - - results = results || []; - - // Return early from calls with invalid selector or context - if (typeof selector !== "string" || !selector || nodeType !== 1 && nodeType !== 9 && nodeType !== 11) { - return results; - } - - // Try to shortcut find operations (as opposed to filters) in HTML documents - if (!seed) { - setDocument(context); - context = context || document; - - if (documentIsHTML) { - // If the selector is sufficiently simple, try using a "get*By*" DOM method - // (excepting DocumentFragment context, where the methods don't exist) - if (nodeType !== 11 && (match = rquickExpr.exec(selector))) { - // ID selector - if (m = match[1]) { - // Document context - if (nodeType === 9) { - if (elem = context.getElementById(m)) { - // Support: IE 9 only - // getElementById can match elements by name instead of ID - if (elem.id === m) { - push.call(results, elem); - return results; - } - } else { - return results; - } - } else { + // Try to shortcut find operations (as opposed to filters) in HTML documents + if (!seed) { + setDocument(context); + context = context || document; + + if (documentIsHTML) { + // If the selector is sufficiently simple, try using a "get*By*" DOM method + // (excepting DocumentFragment context, where the methods don't exist) + if (nodeType !== 11 && (match = rquickExpr.exec(selector))) { + // ID selector + if (m = match[1]) { + // Document context + if (nodeType === 9) { + if (elem = context.getElementById(m)) { // Support: IE 9 only // getElementById can match elements by name instead of ID - if (newContext && (elem = newContext.getElementById(m)) && find.contains( - context, // Element context - elem - ) && elem.id === m) { + if (elem.id === m) { push.call(results, elem); + return results; } + } else { + return results; } - } else if (match[2]) { - push.apply( - results, // Type selector - context.getElementsByTagName(selector) - ); - return results; - } else if ((m = match[3]) && context.getElementsByClassName) { - push.apply( - results, // Class selector - context.getElementsByClassName(m) - ); + // Element context + } else { + // Support: IE 9 only + // getElementById can match elements by name instead of ID + if (newContext && (elem = newContext.getElementById(m)) && find.contains(context, elem) && elem.id === m) { + push.call(results, elem); - return results; + return results; + } } + + // Type selector + } else if (match[2]) { + push.apply(results, context.getElementsByTagName(selector)); + + return results; + + // Class selector + } else if ((m = match[3]) && context.getElementsByClassName) { + push.apply(results, context.getElementsByClassName(m)); + + return results; } + } - // Take advantage of querySelectorAll - if (!nonnativeSelectorCache[selector + " "] && (!rbuggyQSA || !rbuggyQSA.test(selector))) { - newSelector = selector; - newContext = context; - - // qSA considers elements outside a scoping root when evaluating child or - // descendant combinators, which is not what we want. - // In such cases, we work around the behavior by prefixing every selector in the - // list with an ID selector referencing the scope context. - // The technique has to be used as well when a leading combinator is used - // as such selectors are not recognized by querySelectorAll. - // Thanks to Andrew Dupont for this technique. - if (nodeType === 1 && (rdescend.test(selector) || rleadingCombinator.test(selector))) { - // Expand context for sibling selectors - newContext = rsibling.test(selector) && testContext(context.parentNode) || context; - - // We can use :scope instead of the ID hack if the browser - // supports it & if we're not changing the context. - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when - // strict-comparing two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - if (newContext != context || !support.scope) { - // Capture the context ID, setting it first if necessary - if (nid = context.getAttribute("id")) { - nid = jQuery.escapeSelector(nid); - } else { - context.setAttribute("id", nid = expando); - } - } + // Take advantage of querySelectorAll + if (!nonnativeSelectorCache[selector + " "] && (!rbuggyQSA || !rbuggyQSA.test(selector))) { + newSelector = selector; + newContext = context; - // Prefix every selector in the list - groups = tokenize(selector); - i = groups.length; + // qSA considers elements outside a scoping root when evaluating child or + // descendant combinators, which is not what we want. + // In such cases, we work around the behavior by prefixing every selector in the + // list with an ID selector referencing the scope context. + // The technique has to be used as well when a leading combinator is used + // as such selectors are not recognized by querySelectorAll. + // Thanks to Andrew Dupont for this technique. + if (nodeType === 1 && (rdescend.test(selector) || rleadingCombinator.test(selector))) { + // Expand context for sibling selectors + newContext = rsibling.test(selector) && testContext(context.parentNode) || context; - while (i--) { - groups[i] = (nid ? "#" + nid : ":scope") + " " + toSelector(groups[i]); + // We can use :scope instead of the ID hack if the browser + // supports it & if we're not changing the context. + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when + // strict-comparing two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if (newContext != context || !support.scope) { + // Capture the context ID, setting it first if necessary + if (nid = context.getAttribute("id")) { + nid = jQuery.escapeSelector(nid); + } else { + context.setAttribute("id", nid = expando); } + } + + // Prefix every selector in the list + groups = tokenize(selector); - newSelector = groups.join(","); + i = groups.length; + + while (i--) { + groups[i] = (nid ? "#" + nid : ":scope") + " " + toSelector(groups[i]); } - try { - push.apply(results, newContext.querySelectorAll(newSelector)); - return results; - } catch(qsaError) { - nonnativeSelectorCache(selector, true); - } finally { - if (nid === expando) { - context.removeAttribute("id"); - } + newSelector = groups.join(","); + } + + try { + push.apply(results, newContext.querySelectorAll(newSelector)); + + return results; + } catch(qsaError) { + nonnativeSelectorCache(selector, true); + } finally { + if (nid === expando) { + context.removeAttribute("id"); } } } } - - // All others - return select(selector.replace(rtrimCSS, "$1"), context, results, seed); } - /** - * Create key-value caches of limited size - * @returns {function(string, object)} Returns the Object data after storing it on itself with - * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) - * deleting the oldest entry - */ - function createCache() { - var keys = []; + // All others + return select(selector.replace(rtrimCSS, "$1"), context, results, seed); + } - function cache(key, value) { - // Use (key + " ") to avoid collision with native prototype properties - // (see https://github.com/jquery/sizzle/issues/157) - if (keys.push(key + " ") > Expr.cacheLength) { - // Only keep the most recent entries - delete cache[keys.shift()]; - } + /** + * Create key-value caches of limited size + * @returns {function(string, object)} Returns the Object data after storing it on itself with + * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) + * deleting the oldest entry + */ + function createCache() { + var keys = []; - return cache[key + " "] = value; + function cache(key, value) { + // Use (key + " ") to avoid collision with native prototype properties + // (see https://github.com/jquery/sizzle/issues/157) + if (keys.push(key + " ") > Expr.cacheLength) { + // Only keep the most recent entries + delete cache[keys.shift()]; } - return cache; - } - - /** - * Mark a function for special use by jQuery selector module - * @param {Function} fn The function to mark - */ - function markFunction(fn) { - fn[expando] = true; - return fn; + return cache[key + " "] = value; } - /** - * Support testing using an element - * @param {Function} fn Passed the created element and returns a boolean result - */ - function assert(fn) { - var el = document.createElement("fieldset"); + return cache; + } - try { - return !!fn(el); - } catch(e) { - return false; - } finally { - // Remove from its parent by default - if (el.parentNode) { - el.parentNode.removeChild(el); - } + /** + * Mark a function for special use by jQuery selector module + * @param {Function} fn The function to mark + */ + function markFunction(fn) { + fn[expando] = true; + + return fn; + } - // release memory in IE - el = null; + /** + * Support testing using an element + * @param {Function} fn Passed the created element and returns a boolean result + */ + function assert(fn) { + var el = document.createElement("fieldset"); + + try { + return !!fn(el); + } catch(e) { + return false; + } finally { + // Remove from its parent by default + if (el.parentNode) { + el.parentNode.removeChild(el); } - } - /** - * Returns a function to use in pseudos for input types - * @param {String} type - */ - function createInputPseudo(type) { - return function (elem) { - return nodeName(elem, "input") && elem.type === type; - }; + // release memory in IE + el = null; } + } - /** - * Returns a function to use in pseudos for buttons - * @param {String} type - */ - function createButtonPseudo(type) { - return function (elem) { - return (nodeName(elem, "input") || nodeName(elem, "button")) && elem.type === type; - }; - } + /** + * Returns a function to use in pseudos for input types + * @param {String} type + */ + function createInputPseudo(type) { + return function (elem) { + return nodeName(elem, "input") && elem.type === type; + }; + } - /** - * Returns a function to use in pseudos for :enabled/:disabled - * @param {Boolean} disabled true for :disabled; false for :enabled - */ - function createDisabledPseudo(disabled) { - // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable - return function (elem) { - // Only certain elements can match :enabled or :disabled - // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled - // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled - if ("form" in elem) { - // Check for inherited disabledness on relevant non-disabled elements: - // * listed form-associated elements in a disabled fieldset - // https://html.spec.whatwg.org/multipage/forms.html#category-listed - // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled - // * option elements in a disabled optgroup - // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled - // All such elements have a "form" property. - if (elem.parentNode && elem.disabled === false) { - // Option elements defer to a parent optgroup if present - if ("label" in elem) { - if ("label" in elem.parentNode) { - return elem.parentNode.disabled === disabled; - } else { - return elem.disabled === disabled; - } - } + /** + * Returns a function to use in pseudos for buttons + * @param {String} type + */ + function createButtonPseudo(type) { + return function (elem) { + return (nodeName(elem, "input") || nodeName(elem, "button")) && elem.type === type; + }; + } - // Support: IE 6 - 11+ - // Use the isDisabled shortcut property to check for disabled fieldset ancestors - return elem.isDisabled === disabled || // Where there is no isDisabled, check manually - elem.isDisabled !== !disabled && inDisabledFieldset(elem) === disabled; + /** + * Returns a function to use in pseudos for :enabled/:disabled + * @param {Boolean} disabled true for :disabled; false for :enabled + */ + function createDisabledPseudo(disabled) { + // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable + return function (elem) { + // Only certain elements can match :enabled or :disabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled + if ("form" in elem) { + // Check for inherited disabledness on relevant non-disabled elements: + // * listed form-associated elements in a disabled fieldset + // https://html.spec.whatwg.org/multipage/forms.html#category-listed + // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled + // * option elements in a disabled optgroup + // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled + // All such elements have a "form" property. + if (elem.parentNode && elem.disabled === false) { + // Option elements defer to a parent optgroup if present + if ("label" in elem) { + if ("label" in elem.parentNode) { + return elem.parentNode.disabled === disabled; + } else { + return elem.disabled === disabled; + } } - return elem.disabled === disabled; - } else // Some victims get caught in our net (label, legend, menu, track), but it shouldn't - // even exist on them, let alone have a boolean value. - if ("label" in elem) { - return elem.disabled === disabled; // Try to winnow out elements that can't be disabled before trusting the disabled property. + // Support: IE 6 - 11+ + // Use the isDisabled shortcut property to check for disabled fieldset ancestors + return elem.isDisabled === disabled || // Where there is no isDisabled, check manually + elem.isDisabled !== !disabled && inDisabledFieldset(elem) === disabled; } - // Remaining elements are neither :enabled nor :disabled - return false; - }; - } + return elem.disabled === disabled; + + // Try to winnow out elements that can't be disabled before trusting the disabled property. + // Some victims get caught in our net (label, legend, menu, track), but it shouldn't + // even exist on them, let alone have a boolean value. + } else if ("label" in elem) { + return elem.disabled === disabled; + } - /** - * Returns a function to use in pseudos for positionals - * @param {Function} fn - */ - function createPositionalPseudo(fn) { - return markFunction(function (argument) { - argument = +argument; + // Remaining elements are neither :enabled nor :disabled + return false; + }; + } - return markFunction(function (seed, matches) { - var j, - matchIndexes = fn([], seed.length, argument), - i = matchIndexes.length; + /** + * Returns a function to use in pseudos for positionals + * @param {Function} fn + */ + function createPositionalPseudo(fn) { + return markFunction(function (argument) { + argument = +argument; - // Match elements found at the specified indexes - while (i--) { - if (seed[j = matchIndexes[i]]) { - seed[j] = !(matches[j] = seed[j]); - } + return markFunction(function (seed, matches) { + var j, + matchIndexes = fn([], seed.length, argument), + i = matchIndexes.length; + + // Match elements found at the specified indexes + while (i--) { + if (seed[j = matchIndexes[i]]) { + seed[j] = !(matches[j] = seed[j]); } - }); + } }); - } + }); + } + + /** + * Checks a node for validity as a jQuery selector context + * @param {Element|Object=} context + * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value + */ + function testContext(context) { + return context && typeof context.getElementsByTagName !== "undefined" && context; + } - /** - * Checks a node for validity as a jQuery selector context - * @param {Element|Object=} context - * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value - */ - function testContext(context) { - return context && typeof context.getElementsByTagName !== "undefined" && context; + /** + * Sets document-related variables once based on the current document + * @param {Element|Object} [node] An element or document object to use to set the document + * @returns {Object} Returns the current document + */ + function setDocument(node) { + var subWindow, + doc = node ? node.ownerDocument || node : preferredDoc; + + // Return early if doc is invalid or already selected + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if (doc == document || doc.nodeType !== 9 || !doc.documentElement) { + return document; } - /** - * Sets document-related variables once based on the current document - * @param {Element|Object} [node] An element or document object to use to set the document - * @returns {Object} Returns the current document - */ - function setDocument(node) { - var subWindow, - doc = node ? node.ownerDocument || node : preferredDoc; + // Update global variables + document = doc; - // Return early if doc is invalid or already selected - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - if (doc == document || doc.nodeType !== 9 || !doc.documentElement) { - return document; - } + documentElement = document.documentElement; + documentIsHTML = !jQuery.isXMLDoc(document); - // Update global variables - document = doc; - documentElement = document.documentElement; - documentIsHTML = !jQuery.isXMLDoc(document); - // Support: iOS 7 only, IE 9 - 11+ - // Older browsers didn't support unprefixed `matches`. - matches = documentElement.matches || documentElement.webkitMatchesSelector || documentElement.msMatchesSelector; + // Support: iOS 7 only, IE 9 - 11+ + // Older browsers didn't support unprefixed `matches`. + matches = documentElement.matches || documentElement.webkitMatchesSelector || documentElement.msMatchesSelector; + // Support: IE 9 - 11+, Edge 12 - 18+ + // Accessing iframe documents after unload throws "permission denied" errors + // (see trac-13936). + // Limit the fix to IE & Edge Legacy; despite Edge 15+ implementing `matches`, + // all IE 9+ and Edge Legacy versions implement `msMatchesSelector` as well. + if (documentElement.msMatchesSelector && // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + preferredDoc != document && (subWindow = document.defaultView) && subWindow.top !== subWindow) { // Support: IE 9 - 11+, Edge 12 - 18+ - // Accessing iframe documents after unload throws "permission denied" errors - // (see trac-13936). - // Limit the fix to IE & Edge Legacy; despite Edge 15+ implementing `matches`, - // all IE 9+ and Edge Legacy versions implement `msMatchesSelector` as well. - if (documentElement.msMatchesSelector && // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - preferredDoc != document && (subWindow = document.defaultView) && subWindow.top !== subWindow) { - // Support: IE 9 - 11+, Edge 12 - 18+ - subWindow.addEventListener("unload", unloadHandler); - } - - // Support: IE <10 - // Check if getElementById returns elements by name - // The broken getElementById methods don't pick up programmatically-set names, - // so use a roundabout getElementsByName test - support.getById = assert(function (el) { - documentElement.appendChild(el).id = jQuery.expando; - return !document.getElementsByName || !document.getElementsByName(jQuery.expando).length; - }); + subWindow.addEventListener("unload", unloadHandler); + } - // Support: IE 9 only - // Check to see if it's possible to do matchesSelector - // on a disconnected node. - support.disconnectedMatch = assert(function (el) { - return matches.call(el, "*"); - }); + // Support: IE <10 + // Check if getElementById returns elements by name + // The broken getElementById methods don't pick up programmatically-set names, + // so use a roundabout getElementsByName test + support.getById = assert(function (el) { + documentElement.appendChild(el).id = jQuery.expando; - // Support: IE 9 - 11+, Edge 12 - 18+ - // IE/Edge don't support the :scope pseudo-class. - support.scope = assert(function () { - return document.querySelectorAll(":scope"); - }); + return !document.getElementsByName || !document.getElementsByName(jQuery.expando).length; + }); - // Support: Chrome 105 - 111 only, Safari 15.4 - 16.3 only - // Make sure the `:has()` argument is parsed unforgivingly. - // We include `*` in the test to detect buggy implementations that are - // _selectively_ forgiving (specifically when the list includes at least - // one valid selector). - // Note that we treat complete lack of support for `:has()` as if it were - // spec-compliant support, which is fine because use of `:has()` in such - // environments will fail in the qSA path and fall back to jQuery traversal - // anyway. - support.cssHas = assert(function () { - try { - document.querySelector(":has(*,:jqfake)"); - return false; - } catch(e) { - return true; - } - }); + // Support: IE 9 only + // Check to see if it's possible to do matchesSelector + // on a disconnected node. + support.disconnectedMatch = assert(function (el) { + return matches.call(el, "*"); + }); + + // Support: IE 9 - 11+, Edge 12 - 18+ + // IE/Edge don't support the :scope pseudo-class. + support.scope = assert(function () { + return document.querySelectorAll(":scope"); + }); - // ID filter and find - if (support.getById) { - Expr.filter.ID = function (id) { - var attrId = id.replace(runescape, funescape); + // Support: Chrome 105 - 111 only, Safari 15.4 - 16.3 only + // Make sure the `:has()` argument is parsed unforgivingly. + // We include `*` in the test to detect buggy implementations that are + // _selectively_ forgiving (specifically when the list includes at least + // one valid selector). + // Note that we treat complete lack of support for `:has()` as if it were + // spec-compliant support, which is fine because use of `:has()` in such + // environments will fail in the qSA path and fall back to jQuery traversal + // anyway. + support.cssHas = assert(function () { + try { + document.querySelector(":has(*,:jqfake)"); - return function (elem) { - return elem.getAttribute("id") === attrId; - }; - }; + return false; + } catch(e) { + return true; + } + }); - Expr.find.ID = function (id, context) { - if (typeof context.getElementById !== "undefined" && documentIsHTML) { - var elem = context.getElementById(id); + // ID filter and find + if (support.getById) { + Expr.filter.ID = function (id) { + var attrId = id.replace(runescape, funescape); - return elem ? [elem] : []; - } + return function (elem) { + return elem.getAttribute("id") === attrId; }; - } else { - Expr.filter.ID = function (id) { - var attrId = id.replace(runescape, funescape); + }; - return function (elem) { - var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id"); + Expr.find.ID = function (id, context) { + if (typeof context.getElementById !== "undefined" && documentIsHTML) { + var elem = context.getElementById(id); - return node && node.value === attrId; - }; + return elem ? [elem] : []; + } + }; + } else { + Expr.filter.ID = function (id) { + var attrId = id.replace(runescape, funescape); + + return function (elem) { + var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id"); + + return node && node.value === attrId; }; + }; - // Support: IE 6 - 7 only - // getElementById is not reliable as a find shortcut - Expr.find.ID = function (id, context) { - if (typeof context.getElementById !== "undefined" && documentIsHTML) { - var node, - i, - elems, - elem = context.getElementById(id); - - if (elem) { - // Verify the id attribute - node = elem.getAttributeNode("id"); + // Support: IE 6 - 7 only + // getElementById is not reliable as a find shortcut + Expr.find.ID = function (id, context) { + if (typeof context.getElementById !== "undefined" && documentIsHTML) { + var node, + i, + elems, + elem = context.getElementById(id); - if (node && node.value === id) { - return [elem]; - } + if (elem) { + // Verify the id attribute + node = elem.getAttributeNode("id"); + + if (node && node.value === id) { + return [elem]; + } - // Fall back on getElementsByName - elems = context.getElementsByName(id); - i = 0; + // Fall back on getElementsByName + elems = context.getElementsByName(id); - while (elem = elems[i++]) { - node = elem.getAttributeNode("id"); + i = 0; - if (node && node.value === id) { - return [elem]; - } + while (elem = elems[i++]) { + node = elem.getAttributeNode("id"); + + if (node && node.value === id) { + return [elem]; } } - - return []; } - }; - } - - // Tag - Expr.find.TAG = function (tag, context) { - if (typeof context.getElementsByTagName !== "undefined") { - return context.getElementsByTagName(tag); - } else { - return context.querySelectorAll(tag); // DocumentFragment nodes don't have gEBTN - } - }; - // Class - Expr.find.CLASS = function (className, context) { - if (typeof context.getElementsByClassName !== "undefined" && documentIsHTML) { - return context.getElementsByClassName(className); + return []; } }; + } - /* QSA/matchesSelector - ---------------------------------------------------------------------- */ - // QSA and matchesSelector support - rbuggyQSA = []; - - // Build QSA regex - // Regex strategy adopted from Diego Perini - assert(function (el) { - var input; - - documentElement.appendChild(el).innerHTML = "" + ""; + // Tag + Expr.find.TAG = function (tag, context) { + if (typeof context.getElementsByTagName !== "undefined") { + return context.getElementsByTagName(tag); - // Support: iOS <=7 - 8 only - // Boolean attributes and "value" are not treated correctly in some XML documents - if (!el.querySelectorAll("[selected]").length) { - rbuggyQSA.push("\\[" + whitespace + "*(?:value|" + booleans + ")"); - } + // DocumentFragment nodes don't have gEBTN + } else { + return context.querySelectorAll(tag); + } + }; - // Support: iOS <=7 - 8 only - if (!el.querySelectorAll("[id~=" + expando + "-]").length) { - rbuggyQSA.push("~="); - } + // Class + Expr.find.CLASS = function (className, context) { + if (typeof context.getElementsByClassName !== "undefined" && documentIsHTML) { + return context.getElementsByClassName(className); + } + }; - // Support: iOS 8 only - // https://bugs.webkit.org/show_bug.cgi?id=136851 - // In-page `selector#id sibling-combinator selector` fails - if (!el.querySelectorAll("a#" + expando + "+*").length) { - rbuggyQSA.push(".#.+[+~]"); - } + /* QSA/matchesSelector + ---------------------------------------------------------------------- */ + // QSA and matchesSelector support + rbuggyQSA = []; - // Support: Chrome <=105+, Firefox <=104+, Safari <=15.4+ - // In some of the document kinds, these selectors wouldn't work natively. - // This is probably OK but for backwards compatibility we want to maintain - // handling them through jQuery traversal in jQuery 3.x. - if (!el.querySelectorAll(":checked").length) { - rbuggyQSA.push(":checked"); - } + // Build QSA regex + // Regex strategy adopted from Diego Perini + assert(function (el) { + var input; - // Support: Windows 8 Native Apps - // The type and name attributes are restricted during .innerHTML assignment - input = document.createElement("input"); - input.setAttribute("type", "hidden"); - el.appendChild(input).setAttribute("name", "D"); - // Support: IE 9 - 11+ - // IE's :disabled selector does not pick up the children of disabled fieldsets - // Support: Chrome <=105+, Firefox <=104+, Safari <=15.4+ - // In some of the document kinds, these selectors wouldn't work natively. - // This is probably OK but for backwards compatibility we want to maintain - // handling them through jQuery traversal in jQuery 3.x. - documentElement.appendChild(el).disabled = true; + documentElement.appendChild(el).innerHTML = "" + ""; - if (el.querySelectorAll(":disabled").length !== 2) { - rbuggyQSA.push(":enabled", ":disabled"); - } + // Support: iOS <=7 - 8 only + // Boolean attributes and "value" are not treated correctly in some XML documents + if (!el.querySelectorAll("[selected]").length) { + rbuggyQSA.push("\\[" + whitespace + "*(?:value|" + booleans + ")"); + } - // Support: IE 11+, Edge 15 - 18+ - // IE 11/Edge don't find elements on a `[name='']` query in some cases. - // Adding a temporary attribute to the document before the selection works - // around the issue. - // Interestingly, IE 10 & older don't seem to have the issue. - input = document.createElement("input"); - input.setAttribute("name", ""); - el.appendChild(input); + // Support: iOS <=7 - 8 only + if (!el.querySelectorAll("[id~=" + expando + "-]").length) { + rbuggyQSA.push("~="); + } - if (!el.querySelectorAll("[name='']").length) { - rbuggyQSA.push("\\[" + whitespace + "*name" + whitespace + "*=" + whitespace + "*(?:''|\"\")"); - } - }); + // Support: iOS 8 only + // https://bugs.webkit.org/show_bug.cgi?id=136851 + // In-page `selector#id sibling-combinator selector` fails + if (!el.querySelectorAll("a#" + expando + "+*").length) { + rbuggyQSA.push(".#.+[+~]"); + } - if (!support.cssHas) { - // Support: Chrome 105 - 110+, Safari 15.4 - 16.3+ - // Our regular `try-catch` mechanism fails to detect natively-unsupported - // pseudo-classes inside `:has()` (such as `:has(:contains("Foo"))`) - // in browsers that parse the `:has()` argument as a forgiving selector list. - // https://drafts.csswg.org/selectors/#relational now requires the argument - // to be parsed unforgivingly, but browsers have not yet fully adjusted. - rbuggyQSA.push(":has"); - } - - rbuggyQSA = rbuggyQSA.length && new RegExp(rbuggyQSA.join("|")); - - /* Sorting - ---------------------------------------------------------------------- */ - // Document order sorting - sortOrder = function (a, b) { - // Flag for duplicate removal - if (a === b) { - hasDuplicate = true; - return 0; - } + // Support: Chrome <=105+, Firefox <=104+, Safari <=15.4+ + // In some of the document kinds, these selectors wouldn't work natively. + // This is probably OK but for backwards compatibility we want to maintain + // handling them through jQuery traversal in jQuery 3.x. + if (!el.querySelectorAll(":checked").length) { + rbuggyQSA.push(":checked"); + } - // Sort on method existence if only one input has compareDocumentPosition - var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; + // Support: Windows 8 Native Apps + // The type and name attributes are restricted during .innerHTML assignment + input = document.createElement("input"); - if (compare) { - return compare; - } + input.setAttribute("type", "hidden"); + el.appendChild(input).setAttribute("name", "D"); - // Calculate position if both inputs belong to the same document - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - compare = (a.ownerDocument || a) == (b.ownerDocument || b) ? a.compareDocumentPosition(b) : // Otherwise we know they are disconnected - 1; + // Support: IE 9 - 11+ + // IE's :disabled selector does not pick up the children of disabled fieldsets + // Support: Chrome <=105+, Firefox <=104+, Safari <=15.4+ + // In some of the document kinds, these selectors wouldn't work natively. + // This is probably OK but for backwards compatibility we want to maintain + // handling them through jQuery traversal in jQuery 3.x. + documentElement.appendChild(el).disabled = true; - // Disconnected nodes - if (compare & 1 || !support.sortDetached && b.compareDocumentPosition(a) === compare) { - // Choose the first element that is related to our preferred document - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - if (a === document || a.ownerDocument == preferredDoc && find.contains(preferredDoc, a)) { - return -1; - } + if (el.querySelectorAll(":disabled").length !== 2) { + rbuggyQSA.push(":enabled", ":disabled"); + } - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - if (b === document || b.ownerDocument == preferredDoc && find.contains(preferredDoc, b)) { - return 1; - } + // Support: IE 11+, Edge 15 - 18+ + // IE 11/Edge don't find elements on a `[name='']` query in some cases. + // Adding a temporary attribute to the document before the selection works + // around the issue. + // Interestingly, IE 10 & older don't seem to have the issue. + input = document.createElement("input"); - // Maintain original order - return sortInput ? indexOf.call(sortInput, a) - indexOf.call(sortInput, b) : 0; - } + input.setAttribute("name", ""); + el.appendChild(input); - return compare & 4 ? -1 : 1; - }; + if (!el.querySelectorAll("[name='']").length) { + rbuggyQSA.push("\\[" + whitespace + "*name" + whitespace + "*=" + whitespace + "*(?:''|\"\")"); + } + }); - return document; + if (!support.cssHas) { + // Support: Chrome 105 - 110+, Safari 15.4 - 16.3+ + // Our regular `try-catch` mechanism fails to detect natively-unsupported + // pseudo-classes inside `:has()` (such as `:has(:contains("Foo"))`) + // in browsers that parse the `:has()` argument as a forgiving selector list. + // https://drafts.csswg.org/selectors/#relational now requires the argument + // to be parsed unforgivingly, but browsers have not yet fully adjusted. + rbuggyQSA.push(":has"); } - find.matches = function (expr, elements) { - return find(expr, null, null, elements); - }; - - find.matchesSelector = function (elem, expr) { - setDocument(elem); + rbuggyQSA = rbuggyQSA.length && new RegExp(rbuggyQSA.join("|")); - if (documentIsHTML && !nonnativeSelectorCache[expr + " "] && (!rbuggyQSA || !rbuggyQSA.test(expr))) { - try { - var ret = matches.call(elem, expr); + /* Sorting + ---------------------------------------------------------------------- */ + // Document order sorting + sortOrder = function (a, b) { + // Flag for duplicate removal + if (a === b) { + hasDuplicate = true; - // IE 9's matchesSelector returns false on disconnected nodes - if (ret || support.disconnectedMatch || // As well, disconnected nodes are said to be in a document - // fragment in IE 9 - elem.document && elem.document.nodeType !== 11) { - return ret; - } - } catch(e) { - nonnativeSelectorCache(expr, true); - } + return 0; } - return find(expr, document, null, [elem]).length > 0; - }; + // Sort on method existence if only one input has compareDocumentPosition + var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; - find.contains = function (context, elem) { - // Set document vars if needed - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - if ((context.ownerDocument || context) != document) { - setDocument(context); + if (compare) { + return compare; } - return jQuery.contains(context, elem); - }; - - find.attr = function (elem, name) { - // Set document vars if needed + // Calculate position if both inputs belong to the same document // Support: IE 11+, Edge 17 - 18+ // IE/Edge sometimes throw a "Permission denied" error when strict-comparing // two documents; shallow comparisons work. // eslint-disable-next-line eqeqeq - if ((elem.ownerDocument || elem) != document) { - setDocument(elem); - } + compare = (a.ownerDocument || a) == (b.ownerDocument || b) + ? a.compareDocumentPosition(b) + : // Otherwise we know they are disconnected + 1; + + // Disconnected nodes + if (compare & 1 || !support.sortDetached && b.compareDocumentPosition(a) === compare) { + // Choose the first element that is related to our preferred document + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if (a === document || a.ownerDocument == preferredDoc && find.contains(preferredDoc, a)) { + return -1; + } - var fn = Expr.attrHandle[name.toLowerCase()], - // Don't get fooled by Object.prototype properties (see trac-13807) - val = fn && hasOwn.call(Expr.attrHandle, name.toLowerCase()) ? fn(elem, name, !documentIsHTML) : undefined; + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if (b === document || b.ownerDocument == preferredDoc && find.contains(preferredDoc, b)) { + return 1; + } - if (val !== undefined) { - return val; + // Maintain original order + return sortInput + ? indexOf.call(sortInput, a) - indexOf.call(sortInput, b) + : 0; } - return elem.getAttribute(name); + return compare & 4 ? -1 : 1; }; - find.error = function (msg) { - throw new Error("Syntax error, unrecognized expression: " + msg); - }; + return document; + } - /** - * Document sorting and removing duplicates - * @param {ArrayLike} results - */ - jQuery.uniqueSort = function (results) { - var elem, duplicates = [], j = 0, i = 0; + find.matches = function (expr, elements) { + return find(expr, null, null, elements); + }; - // Unless we *know* we can detect duplicates, assume their presence - // - // Support: Android <=4.0+ - // Testing for detecting duplicates is unpredictable so instead assume we can't - // depend on duplicate detection in all browsers without a stable sort. - hasDuplicate = !support.sortStable; - sortInput = !support.sortStable && slice.call(results, 0); - sort.call(results, sortOrder); - - if (hasDuplicate) { - while (elem = results[i++]) { - if (elem === results[i]) { - j = duplicates.push(i); - } - } + find.matchesSelector = function (elem, expr) { + setDocument(elem); - while (j--) { - splice.call(results, duplicates[j], 1); + if (documentIsHTML && !nonnativeSelectorCache[expr + " "] && (!rbuggyQSA || !rbuggyQSA.test(expr))) { + try { + var ret = matches.call(elem, expr); + + // IE 9's matchesSelector returns false on disconnected nodes + if (ret || support.disconnectedMatch || // As well, disconnected nodes are said to be in a document + // fragment in IE 9 + elem.document && elem.document.nodeType !== 11) { + return ret; } + } catch(e) { + nonnativeSelectorCache(expr, true); } + } - // Clear input after sorting to release objects - // See https://github.com/jquery/sizzle/pull/225 - sortInput = null; - return results; - }; + return find(expr, document, null, [elem]).length > 0; + }; - jQuery.fn.uniqueSort = function () { - return this.pushStack(jQuery.uniqueSort(slice.apply(this))); - }; + find.contains = function (context, elem) { + // Set document vars if needed + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ((context.ownerDocument || context) != document) { + setDocument(context); + } - Expr = jQuery.expr = { - // Can be adjusted by the user - cacheLength: 50, - createPseudo: markFunction, - match: matchExpr, - attrHandle: {}, - find: {}, - relative: { - ">": { dir: "parentNode", first: true }, - " ": { dir: "parentNode" }, - "+": { dir: "previousSibling", first: true }, - "~": { dir: "previousSibling" } - }, - preFilter: { - ATTR(match) { - match[1] = match[1].replace(runescape, funescape); - // Move the given value to match[3] whether quoted or unquoted - match[3] = (match[3] || match[4] || match[5] || "").replace(runescape, funescape); - - if (match[2] === "~=") { - match[3] = " " + match[3] + " "; - } + return jQuery.contains(context, elem); + }; - return match.slice(0, 4); - }, - CHILD(match) { - /* matches from matchExpr["CHILD"] - 1 type (only|nth|...) - 2 what (child|of-type) - 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) - 4 xn-component of xn+y argument ([+-]?\d*n|) - 5 sign of xn-component - 6 x of xn-component - 7 sign of y-component - 8 y of y-component - */ - match[1] = match[1].toLowerCase(); - - if (match[1].slice(0, 3) === "nth") { - // nth-* requires argument - if (!match[3]) { - find.error(match[0]); - } + find.attr = function (elem, name) { + // Set document vars if needed + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ((elem.ownerDocument || elem) != document) { + setDocument(elem); + } - // numeric x and y parameters for Expr.filter.CHILD - // remember that false/true cast respectively to 0/1 - match[4] = +(match[4] ? match[5] + (match[6] || 1) : 2 * (match[3] === "even" || match[3] === "odd")); - match[5] = +(match[7] + match[8] || match[3] === "odd"); - } else if (match[3]) { - find.error(match[0]); // other types prohibit arguments - } + var fn = Expr.attrHandle[name.toLowerCase()], + // Don't get fooled by Object.prototype properties (see trac-13807) + val = fn && hasOwn.call(Expr.attrHandle, name.toLowerCase()) ? fn(elem, name, !documentIsHTML) : undefined; - return match; - }, - PSEUDO(match) { - var excess, unquoted = !match[6] && match[2]; + if (val !== undefined) { + return val; + } - if (matchExpr.CHILD.test(match[0])) { - return null; - } + return elem.getAttribute(name); + }; - // Accept quoted arguments as-is - if (match[3]) { - match[2] = match[4] || match[5] || ""; - } else if (unquoted && rpseudo.test(unquoted) && (// Get excess from tokenize (recursively) - excess = tokenize( - unquoted, // Strip excess characters from unquoted arguments - true - )) && (// advance to the next closing parenthesis - excess = unquoted.indexOf(")", unquoted.length - excess) - unquoted.length)) { - // excess is a negative index - match[0] = match[0].slice(0, excess); - match[2] = unquoted.slice(0, excess); - } + find.error = function (msg) { + throw new Error("Syntax error, unrecognized expression: " + msg); + }; - // Return only captures needed by the pseudo filter method (type and argument) - return match.slice(0, 3); - } - }, - filter: { - TAG(nodeNameSelector) { - var expectedNodeName = nodeNameSelector.replace(runescape, funescape).toLowerCase(); + /** + * Document sorting and removing duplicates + * @param {ArrayLike} results + */ + jQuery.uniqueSort = function (results) { + var elem, duplicates = [], j = 0, i = 0; - return nodeNameSelector === "*" - ? function () { - return true; - } - : function (elem) { - return nodeName(elem, expectedNodeName); - }; - }, - CLASS(className) { - var pattern = classCache[className + " "]; + // Unless we *know* we can detect duplicates, assume their presence + // + // Support: Android <=4.0+ + // Testing for detecting duplicates is unpredictable so instead assume we can't + // depend on duplicate detection in all browsers without a stable sort. + hasDuplicate = !support.sortStable; - return pattern || (pattern = new RegExp("(^|" + whitespace + ")" + className + "(" + whitespace + "|$)")) && classCache(className, function (elem) { - return pattern.test(typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || ""); - }); - }, - ATTR(name, operator, check) { - return function (elem) { - var result = find.attr(elem, name); + sortInput = !support.sortStable && slice.call(results, 0); + sort.call(results, sortOrder); - if (result == null) { - return operator === "!="; - } + if (hasDuplicate) { + while (elem = results[i++]) { + if (elem === results[i]) { + j = duplicates.push(i); + } + } - if (!operator) { - return true; - } + while (j--) { + splice.call(results, duplicates[j], 1); + } + } - result += ""; + // Clear input after sorting to release objects + // See https://github.com/jquery/sizzle/pull/225 + sortInput = null; - if (operator === "=") { - return result === check; - } + return results; + }; - if (operator === "!=") { - return result !== check; - } + jQuery.fn.uniqueSort = function () { + return this.pushStack(jQuery.uniqueSort(slice.apply(this))); + }; - if (operator === "^=") { - return check && result.indexOf(check) === 0; - } + Expr = jQuery.expr = { + // Can be adjusted by the user + cacheLength: 50, - if (operator === "*=") { - return check && result.indexOf(check) > -1; - } + createPseudo: markFunction, + match: matchExpr, + attrHandle: {}, + find: {}, - if (operator === "$=") { - return check && result.slice(-check.length) === check; - } + relative: { + ">": { dir: "parentNode", first: true }, + " ": { dir: "parentNode" }, + "+": { dir: "previousSibling", first: true }, + "~": { dir: "previousSibling" } + }, - if (operator === "~=") { - return (" " + result.replace(rwhitespace, " ") + " ").indexOf(check) > -1; - } + preFilter: { + ATTR(match) { + match[1] = match[1].replace(runescape, funescape); - if (operator === "|=") { - return result === check || result.slice(0, check.length + 1) === check + "-"; - } + // Move the given value to match[3] whether quoted or unquoted + match[3] = (match[3] || match[4] || match[5] || "").replace(runescape, funescape); - return false; + if (match[2] === "~=") { + match[3] = " " + match[3] + " "; + } + + return match.slice(0, 4); + }, + + CHILD(match) { + /* matches from matchExpr["CHILD"] + 1 type (only|nth|...) + 2 what (child|of-type) + 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) + 4 xn-component of xn+y argument ([+-]?\d*n|) + 5 sign of xn-component + 6 x of xn-component + 7 sign of y-component + 8 y of y-component + */ + match[1] = match[1].toLowerCase(); + + if (match[1].slice(0, 3) === "nth") { + // nth-* requires argument + if (!match[3]) { + find.error(match[0]); + } + + // numeric x and y parameters for Expr.filter.CHILD + // remember that false/true cast respectively to 0/1 + match[4] = +(match[4] + ? match[5] + (match[6] || 1) + : 2 * (match[3] === "even" || match[3] === "odd")); + + match[5] = +(match[7] + match[8] || match[3] === "odd"); + + // other types prohibit arguments + } else if (match[3]) { + find.error(match[0]); + } + + return match; + }, + + PSEUDO(match) { + var excess, unquoted = !match[6] && match[2]; + + if (matchExpr.CHILD.test(match[0])) { + return null; + } + + // Accept quoted arguments as-is + if (match[3]) { + match[2] = match[4] || match[5] || ""; + + // Strip excess characters from unquoted arguments + } else if (unquoted && rpseudo.test(unquoted) && (// Get excess from tokenize (recursively) + excess = tokenize(unquoted, true)) && (// advance to the next closing parenthesis + excess = unquoted.indexOf(")", unquoted.length - excess) - unquoted.length)) { + // excess is a negative index + match[0] = match[0].slice(0, excess); + + match[2] = unquoted.slice(0, excess); + } + + // Return only captures needed by the pseudo filter method (type and argument) + return match.slice(0, 3); + } + }, + + filter: { + TAG(nodeNameSelector) { + var expectedNodeName = nodeNameSelector.replace(runescape, funescape).toLowerCase(); + + return nodeNameSelector === "*" + ? function () { + return true; + } + : function (elem) { + return nodeName(elem, expectedNodeName); }; - }, - CHILD(type, what, _argument, first, last) { - var simple = type.slice(0, 3) !== "nth", - forward = type.slice(-4) !== "last", - ofType = what === "of-type"; - - return first === 1 && last === 0 - ? // Shortcut for :nth-*(n) - function (elem) { - return !!elem.parentNode; - } - : function (elem, _context, xml) { - var cache, - outerCache, - node, - nodeIndex, - start, - dir = simple !== forward ? "nextSibling" : "previousSibling", - parent = elem.parentNode, - name = ofType && elem.nodeName.toLowerCase(), - useCache = !xml && !ofType, - diff = false; - - if (parent) { - // :(first|last|only)-(child|of-type) - if (simple) { - while (dir) { - node = elem; - - while (node = node[dir]) { - if (ofType ? nodeName(node, name) : node.nodeType === 1) { - return false; - } - } + }, + + CLASS(className) { + var pattern = classCache[className + " "]; + + return pattern || (pattern = new RegExp("(^|" + whitespace + ")" + className + "(" + whitespace + "|$)")) && classCache(className, function (elem) { + return pattern.test(typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || ""); + }); + }, + + ATTR(name, operator, check) { + return function (elem) { + var result = find.attr(elem, name); + + if (result == null) { + return operator === "!="; + } + + if (!operator) { + return true; + } + + result += ""; + + if (operator === "=") { + return result === check; + } + + if (operator === "!=") { + return result !== check; + } + + if (operator === "^=") { + return check && result.indexOf(check) === 0; + } + + if (operator === "*=") { + return check && result.indexOf(check) > -1; + } + + if (operator === "$=") { + return check && result.slice(-check.length) === check; + } + + if (operator === "~=") { + return (" " + result.replace(rwhitespace, " ") + " ").indexOf(check) > -1; + } + + if (operator === "|=") { + return result === check || result.slice(0, check.length + 1) === check + "-"; + } + + return false; + }; + }, - // Reverse direction for :only-* (if we haven't yet done so) - start = dir = type === "only" && !start && "nextSibling"; + CHILD(type, what, _argument, first, last) { + var simple = type.slice(0, 3) !== "nth", + forward = type.slice(-4) !== "last", + ofType = what === "of-type"; + + return first === 1 && last === 0 + ? // Shortcut for :nth-*(n) + function (elem) { + return !!elem.parentNode; + } + : function (elem, _context, xml) { + var cache, + outerCache, + node, + nodeIndex, + start, + dir = simple !== forward ? "nextSibling" : "previousSibling", + parent = elem.parentNode, + name = ofType && elem.nodeName.toLowerCase(), + useCache = !xml && !ofType, + diff = false; + + if (parent) { + // :(first|last|only)-(child|of-type) + if (simple) { + while (dir) { + node = elem; + + while (node = node[dir]) { + if (ofType ? nodeName(node, name) : node.nodeType === 1) { + return false; + } } - return true; + // Reverse direction for :only-* (if we haven't yet done so) + start = dir = type === "only" && !start && "nextSibling"; } - start = [forward ? parent.firstChild : parent.lastChild]; + return true; + } + + start = [forward ? parent.firstChild : parent.lastChild]; - // non-xml :nth-child(...) stores cache data on `parent` - if (forward && useCache) { - // Seek `elem` from a previously-cached index - outerCache = parent[expando] || (parent[expando] = {}); + // non-xml :nth-child(...) stores cache data on `parent` + if (forward && useCache) { + // Seek `elem` from a previously-cached index + outerCache = parent[expando] || (parent[expando] = {}); + + cache = outerCache[type] || []; + nodeIndex = cache[0] === dirruns && cache[1]; + diff = nodeIndex && cache[2]; + node = nodeIndex && parent.childNodes[nodeIndex]; + + while (node = ++nodeIndex && node && node[dir] || (// Fallback to seeking `elem` from the start + diff = nodeIndex = 0) || start.pop()) { + // When found, cache indexes on `parent` and break + if (node.nodeType === 1 && ++diff && node === elem) { + outerCache[type] = [dirruns, nodeIndex, diff]; + + break; + } + } + } else { + // Use previously-cached element index if available + if (useCache) { + outerCache = elem[expando] || (elem[expando] = {}); cache = outerCache[type] || []; nodeIndex = cache[0] === dirruns && cache[1]; - diff = nodeIndex && cache[2]; - node = nodeIndex && parent.childNodes[nodeIndex]; - - while (node = ++nodeIndex && node && node[dir] || (// Fallback to seeking `elem` from the start - diff = nodeIndex = 0) || start.pop()) { - // When found, cache indexes on `parent` and break - if (node.nodeType === 1 && ++diff && node === elem) { - outerCache[type] = [dirruns, nodeIndex, diff]; - break; - } - } - } else { - // Use previously-cached element index if available - if (useCache) { - outerCache = elem[expando] || (elem[expando] = {}); - cache = outerCache[type] || []; - nodeIndex = cache[0] === dirruns && cache[1]; - diff = nodeIndex; - } + diff = nodeIndex; + } - // xml :nth-child(...) - // or :nth-last-child(...) or :nth(-last)?-of-type(...) - if (diff === false) { - // Use the same loop as above to seek `elem` from the start - while (node = ++nodeIndex && node && node[dir] || (diff = nodeIndex = 0) || start.pop()) { - if ((ofType ? nodeName(node, name) : node.nodeType === 1) && ++diff) { - // Cache the index of each encountered element - if (useCache) { - outerCache = node[expando] || (node[expando] = {}); - outerCache[type] = [dirruns, diff]; - } + // xml :nth-child(...) + // or :nth-last-child(...) or :nth(-last)?-of-type(...) + if (diff === false) { + // Use the same loop as above to seek `elem` from the start + while (node = ++nodeIndex && node && node[dir] || (diff = nodeIndex = 0) || start.pop()) { + if ((ofType ? nodeName(node, name) : node.nodeType === 1) && ++diff) { + // Cache the index of each encountered element + if (useCache) { + outerCache = node[expando] || (node[expando] = {}); + outerCache[type] = [dirruns, diff]; + } - if (node === elem) { - break; - } + if (node === elem) { + break; } } } } - - // Incorporate the offset, then check against cycle size - diff -= last; - return diff === first || diff % first === 0 && diff / first >= 0; } - }; - }, - PSEUDO(pseudo, argument) { - // pseudo-class names are case-insensitive - // https://www.w3.org/TR/selectors/#pseudo-classes - // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters - // Remember that setFilters inherits from pseudos - var args, - fn = Expr.pseudos[pseudo] || Expr.setFilters[pseudo.toLowerCase()] || find.error("unsupported pseudo: " + pseudo); - - // The user may use createPseudo to indicate that - // arguments are needed to create the filter function - // just as jQuery does - if (fn[expando]) { - return fn(argument); - } - // But maintain support for old signatures - if (fn.length > 1) { - args = [pseudo, pseudo, "", argument]; - return Expr.setFilters.hasOwnProperty(pseudo.toLowerCase()) - ? markFunction(function (seed, matches) { - var idx, - matched = fn(seed, argument), - i = matched.length; - - while (i--) { - idx = indexOf.call(seed, matched[i]); - seed[idx] = !(matches[idx] = matched[i]); - } - }) - : function (elem) { - return fn(elem, 0, args); - }; - } + // Incorporate the offset, then check against cycle size + diff -= last; - return fn; - } + return diff === first || diff % first === 0 && diff / first >= 0; + } + }; }, - pseudos: { - // Potentially complex pseudos - not: markFunction(function (selector) { - // Trim the selector passed to compile - // to avoid treating leading and trailing - // spaces as combinators - var input = [], - results = [], - matcher = compile(selector.replace(rtrimCSS, "$1")); - - return matcher[expando] - ? markFunction(function (seed, matches, _context, xml) { - var elem, - unmatched = matcher(seed, null, xml, []), - i = seed.length; - - // Match elements unmatched by `matcher` + + PSEUDO(pseudo, argument) { + // pseudo-class names are case-insensitive + // https://www.w3.org/TR/selectors/#pseudo-classes + // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters + // Remember that setFilters inherits from pseudos + var args, + fn = Expr.pseudos[pseudo] || Expr.setFilters[pseudo.toLowerCase()] || find.error("unsupported pseudo: " + pseudo); + + // The user may use createPseudo to indicate that + // arguments are needed to create the filter function + // just as jQuery does + if (fn[expando]) { + return fn(argument); + } + + // But maintain support for old signatures + if (fn.length > 1) { + args = [pseudo, pseudo, "", argument]; + + return Expr.setFilters.hasOwnProperty(pseudo.toLowerCase()) + ? markFunction(function (seed, matches) { + var idx, + matched = fn(seed, argument), + i = matched.length; + while (i--) { - if (elem = unmatched[i]) { - seed[i] = !(matches[i] = elem); - } + idx = indexOf.call(seed, matched[i]); + seed[idx] = !(matches[idx] = matched[i]); } }) - : function (elem, _context, xml) { - input[0] = elem; - matcher(input, null, xml, results); - // Don't keep the element - // (see https://github.com/jquery/sizzle/issues/299) - input[0] = null; - return !results.pop(); + : function (elem) { + return fn(elem, 0, args); }; - }), - has: markFunction(function (selector) { - return function (elem) { - return find(selector, elem).length > 0; - }; - }), - contains: markFunction(function (text) { - text = text.replace(runescape, funescape); + } + + return fn; + } + }, + + pseudos: { + // Potentially complex pseudos + not: markFunction(function (selector) { + // Trim the selector passed to compile + // to avoid treating leading and trailing + // spaces as combinators + var input = [], + results = [], + matcher = compile(selector.replace(rtrimCSS, "$1")); + + return matcher[expando] + ? markFunction(function (seed, matches, _context, xml) { + var elem, + unmatched = matcher(seed, null, xml, []), + i = seed.length; + + // Match elements unmatched by `matcher` + while (i--) { + if (elem = unmatched[i]) { + seed[i] = !(matches[i] = elem); + } + } + }) + : function (elem, _context, xml) { + input[0] = elem; + matcher(input, null, xml, results); + + // Don't keep the element + // (see https://github.com/jquery/sizzle/issues/299) + input[0] = null; - return function (elem) { - return (elem.textContent || jQuery.text(elem)).indexOf(text) > -1; + return !results.pop(); }; - }), - // "Whether an element is represented by a :lang() selector - // is based solely on the element's language value - // being equal to the identifier C, - // or beginning with the identifier C immediately followed by "-". - // The matching of C against the element's language value is performed case-insensitively. - // The identifier C does not have to be a valid language name." - // https://www.w3.org/TR/selectors/#lang-pseudo - lang: markFunction(function (lang) { - // lang value must be a valid identifier - if (!ridentifier.test(lang || "")) { - find.error("unsupported lang: " + lang); - } + }), - lang = lang.replace(runescape, funescape).toLowerCase(); + has: markFunction(function (selector) { + return function (elem) { + return find(selector, elem).length > 0; + }; + }), - return function (elem) { - var elemLang; + contains: markFunction(function (text) { + text = text.replace(runescape, funescape); - do { - if (elemLang = documentIsHTML ? elem.lang : elem.getAttribute("xml:lang") || elem.getAttribute("lang")) { - elemLang = elemLang.toLowerCase(); - return elemLang === lang || elemLang.indexOf(lang + "-") === 0; - } - } while ((elem = elem.parentNode) && elem.nodeType === 1); + return function (elem) { + return (elem.textContent || jQuery.text(elem)).indexOf(text) > -1; + }; + }), - return false; - }; - }), - target(elem) { - var hash = window.location && window.location.hash; + // "Whether an element is represented by a :lang() selector + // is based solely on the element's language value + // being equal to the identifier C, + // or beginning with the identifier C immediately followed by "-". + // The matching of C against the element's language value is performed case-insensitively. + // The identifier C does not have to be a valid language name." + // https://www.w3.org/TR/selectors/#lang-pseudo + lang: markFunction(function (lang) { + // lang value must be a valid identifier + if (!ridentifier.test(lang || "")) { + find.error("unsupported lang: " + lang); + } - return hash && hash.slice(1) === elem.id; - }, - root(elem) { - return elem === documentElement; - }, - focus(elem) { - return elem === safeActiveElement() && document.hasFocus() && !!(elem.type || elem.href || ~elem.tabIndex); - }, - // Boolean properties - enabled: createDisabledPseudo(false), - disabled: createDisabledPseudo(true), - checked(elem) { - // In CSS3, :checked should return both checked and selected elements - // https://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked - return nodeName(elem, "input") && !!elem.checked || nodeName(elem, "option") && !!elem.selected; - }, - selected(elem) { - // Support: IE <=11+ - // Accessing the selectedIndex property - // forces the browser to treat the default option as - // selected when in an optgroup. - if (elem.parentNode) { - // eslint-disable-next-line no-unused-expressions - elem.parentNode.selectedIndex; - } + lang = lang.replace(runescape, funescape).toLowerCase(); - return elem.selected === true; - }, - empty(elem) { - // https://www.w3.org/TR/selectors/#empty-pseudo - // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), - // but not by others (comment: 8; processing instruction: 7; etc.) - // nodeType < 6 works because attributes (2) do not appear as children - for (elem = elem.firstChild; elem; elem = elem.nextSibling) { - if (elem.nodeType < 6) { - return false; + return function (elem) { + var elemLang; + + do { + if (elemLang = documentIsHTML + ? elem.lang + : elem.getAttribute("xml:lang") || elem.getAttribute("lang")) { + elemLang = elemLang.toLowerCase(); + + return elemLang === lang || elemLang.indexOf(lang + "-") === 0; } - } + } while ((elem = elem.parentNode) && elem.nodeType === 1); - return true; - }, - parent(elem) { - return !Expr.pseudos.empty(elem); - }, - header(elem) { - return rheader.test(elem.nodeName); - }, - input(elem) { - return rinputs.test(elem.nodeName); - }, - button(elem) { - return nodeName(elem, "input") && elem.type === "button" || nodeName(elem, "button"); - }, - text(elem) { - var attr; + return false; + }; + }), - return nodeName(elem, "input") && elem.type === "text" && (// Support: IE <10 only - // New HTML5 attribute values (e.g., "search") appear - // with elem.type === "text" - (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text"); - }, - // Position-in-collection - first: createPositionalPseudo(function () { - return [0]; - }), - last: createPositionalPseudo(function (_matchIndexes, length) { - return [length - 1]; - }), - eq: createPositionalPseudo(function (_matchIndexes, length, argument) { - return [argument < 0 ? argument + length : argument]; - }), - even: createPositionalPseudo(function (matchIndexes, length) { - var i = 0; - - for (; i < length; i += 2) { - matchIndexes.push(i); - } + // Miscellaneous + target(elem) { + var hash = window.location && window.location.hash; - return matchIndexes; - }), - odd: createPositionalPseudo(function (matchIndexes, length) { - var i = 1; + return hash && hash.slice(1) === elem.id; + }, - for (; i < length; i += 2) { - matchIndexes.push(i); - } + root(elem) { + return elem === documentElement; + }, - return matchIndexes; - }), - lt: createPositionalPseudo(function (matchIndexes, length, argument) { - var i; + focus(elem) { + return elem === safeActiveElement() && document.hasFocus() && !!(elem.type || elem.href || ~elem.tabIndex); + }, - if (argument < 0) { - i = argument + length; - } else if (argument > length) { - i = length; - } else { - i = argument; - } + // Boolean properties + enabled: createDisabledPseudo(false), - for (; --i >= 0; ) { - matchIndexes.push(i); - } + disabled: createDisabledPseudo(true), - return matchIndexes; - }), - gt: createPositionalPseudo(function (matchIndexes, length, argument) { - var i = argument < 0 ? argument + length : argument; + checked(elem) { + // In CSS3, :checked should return both checked and selected elements + // https://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + return nodeName(elem, "input") && !!elem.checked || nodeName(elem, "option") && !!elem.selected; + }, + + selected(elem) { + // Support: IE <=11+ + // Accessing the selectedIndex property + // forces the browser to treat the default option as + // selected when in an optgroup. + if (elem.parentNode) { + // eslint-disable-next-line no-unused-expressions + elem.parentNode.selectedIndex; + } - for (; ++i < length; ) { - matchIndexes.push(i); + return elem.selected === true; + }, + + // Contents + empty(elem) { + // https://www.w3.org/TR/selectors/#empty-pseudo + // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), + // but not by others (comment: 8; processing instruction: 7; etc.) + // nodeType < 6 works because attributes (2) do not appear as children + for (elem = elem.firstChild; elem; elem = elem.nextSibling) { + if (elem.nodeType < 6) { + return false; } + } - return matchIndexes; - }) - } - }; + return true; + }, - Expr.pseudos.nth = Expr.pseudos.eq; + parent(elem) { + return !Expr.pseudos.empty(elem); + }, - // Add button/input type pseudos - for (i in { - radio: true, - checkbox: true, - file: true, - password: true, - image: true - }) { - Expr.pseudos[i] = createInputPseudo(i); - } + // Element/input types + header(elem) { + return rheader.test(elem.nodeName); + }, - for (i in { submit: true, reset: true }) { - Expr.pseudos[i] = createButtonPseudo(i); - } + input(elem) { + return rinputs.test(elem.nodeName); + }, - // Easy API for creating new setFilters - function setFilters() {} - setFilters.prototype = Expr.filters = Expr.pseudos; - Expr.setFilters = new setFilters(); + button(elem) { + return nodeName(elem, "input") && elem.type === "button" || nodeName(elem, "button"); + }, - function tokenize(selector, parseOnly) { - var matched, - match, - tokens, - type, - soFar, - groups, - preFilters, - cached = tokenCache[selector + " "]; + text(elem) { + var attr; - if (cached) { - return parseOnly ? 0 : cached.slice(0); - } + return nodeName(elem, "input") && elem.type === "text" && (// Support: IE <10 only + // New HTML5 attribute values (e.g., "search") appear + // with elem.type === "text" + (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text"); + }, - soFar = selector; - groups = []; - preFilters = Expr.preFilter; + // Position-in-collection + first: createPositionalPseudo(function () { + return [0]; + }), - while (soFar) { - // Comma and first run - if (!matched || (match = rcomma.exec(soFar))) { - if (match) { - // Don't consume trailing commas as valid - soFar = soFar.slice(match[0].length) || soFar; - } + last: createPositionalPseudo(function (_matchIndexes, length) { + return [length - 1]; + }), + + eq: createPositionalPseudo(function (_matchIndexes, length, argument) { + return [argument < 0 ? argument + length : argument]; + }), + + even: createPositionalPseudo(function (matchIndexes, length) { + var i = 0; - groups.push(tokens = []); + for (; i < length; i += 2) { + matchIndexes.push(i); } - matched = false; + return matchIndexes; + }), - // Combinators - if (match = rleadingCombinator.exec(soFar)) { - matched = match.shift(); + odd: createPositionalPseudo(function (matchIndexes, length) { + var i = 1; - tokens.push({ - value: matched, - // Cast descendant combinators to space - type: match[0].replace(rtrimCSS, " ") - }); + for (; i < length; i += 2) { + matchIndexes.push(i); + } - soFar = soFar.slice(matched.length); + return matchIndexes; + }), + + lt: createPositionalPseudo(function (matchIndexes, length, argument) { + var i; + + if (argument < 0) { + i = argument + length; + } else if (argument > length) { + i = length; + } else { + i = argument; } - // Filters - for (type in Expr.filter) { - if ((match = matchExpr[type].exec(soFar)) && (!preFilters[type] || (match = preFilters[type](match)))) { - matched = match.shift(); - tokens.push({ value: matched, type, matches: match }); - soFar = soFar.slice(matched.length); - } + for (; --i >= 0; ) { + matchIndexes.push(i); } - if (!matched) { - break; + return matchIndexes; + }), + + gt: createPositionalPseudo(function (matchIndexes, length, argument) { + var i = argument < 0 ? argument + length : argument; + + for (; ++i < length; ) { + matchIndexes.push(i); + } + + return matchIndexes; + }) + } + }; + + Expr.pseudos.nth = Expr.pseudos.eq; + + // Add button/input type pseudos + for (i in { + radio: true, + checkbox: true, + file: true, + password: true, + image: true + }) { + Expr.pseudos[i] = createInputPseudo(i); + } + + for (i in { submit: true, reset: true }) { + Expr.pseudos[i] = createButtonPseudo(i); + } + + // Easy API for creating new setFilters + function setFilters() {} + + setFilters.prototype = Expr.filters = Expr.pseudos; + Expr.setFilters = new setFilters(); + + function tokenize(selector, parseOnly) { + var matched, + match, + tokens, + type, + soFar, + groups, + preFilters, + cached = tokenCache[selector + " "]; + + if (cached) { + return parseOnly ? 0 : cached.slice(0); + } + + soFar = selector; + groups = []; + preFilters = Expr.preFilter; + + while (soFar) { + // Comma and first run + if (!matched || (match = rcomma.exec(soFar))) { + if (match) { + // Don't consume trailing commas as valid + soFar = soFar.slice(match[0].length) || soFar; } + + groups.push(tokens = []); + } + + matched = false; + + // Combinators + if (match = rleadingCombinator.exec(soFar)) { + matched = match.shift(); + + tokens.push({ + value: matched, + + // Cast descendant combinators to space + type: match[0].replace(rtrimCSS, " ") + }); + + soFar = soFar.slice(matched.length); } - // Return the length of the invalid excess - // if we're just parsing - // Otherwise, throw an error or return tokens - if (parseOnly) { - return soFar.length; + // Filters + for (type in Expr.filter) { + if ((match = matchExpr[type].exec(soFar)) && (!preFilters[type] || (match = preFilters[type](match)))) { + matched = match.shift(); + tokens.push({ value: matched, type, matches: match }); + soFar = soFar.slice(matched.length); + } } - return soFar ? find.error(selector) : // Cache the tokens - tokenCache(selector, groups).slice(0); + if (!matched) { + break; + } } - function toSelector(tokens) { - var i = 0, len = tokens.length, selector = ""; + // Return the length of the invalid excess + // if we're just parsing + // Otherwise, throw an error or return tokens + if (parseOnly) { + return soFar.length; + } - for (; i < len; i++) { - selector += tokens[i].value; - } + return soFar + ? find.error(selector) + : // Cache the tokens + tokenCache(selector, groups).slice(0); + } + + function toSelector(tokens) { + var i = 0, len = tokens.length, selector = ""; - return selector; + for (; i < len; i++) { + selector += tokens[i].value; } - function addCombinator(matcher, combinator, base) { - var dir = combinator.dir, - skip = combinator.next, - key = skip || dir, - checkNonElements = base && key === "parentNode", - doneName = done++; + return selector; + } - return combinator.first - ? // Check against closest ancestor/preceding element - function (elem, context, xml) { + function addCombinator(matcher, combinator, base) { + var dir = combinator.dir, + skip = combinator.next, + key = skip || dir, + checkNonElements = base && key === "parentNode", + doneName = done++; + + return combinator.first + ? // Check against closest ancestor/preceding element + function (elem, context, xml) { + while (elem = elem[dir]) { + if (elem.nodeType === 1 || checkNonElements) { + return matcher(elem, context, xml); + } + } + + return false; + } + : // Check against all ancestor/preceding elements + function (elem, context, xml) { + var oldCache, + outerCache, + newCache = [dirruns, doneName]; + + // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching + if (xml) { while (elem = elem[dir]) { if (elem.nodeType === 1 || checkNonElements) { - return matcher(elem, context, xml); + if (matcher(elem, context, xml)) { + return true; + } } } + } else { + while (elem = elem[dir]) { + if (elem.nodeType === 1 || checkNonElements) { + outerCache = elem[expando] || (elem[expando] = {}); - return false; - } - : // Check against all ancestor/preceding elements - function (elem, context, xml) { - var oldCache, - outerCache, - newCache = [dirruns, doneName]; - - // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching - if (xml) { - while (elem = elem[dir]) { - if (elem.nodeType === 1 || checkNonElements) { - if (matcher(elem, context, xml)) { - return true; - } - } - } - } else { - while (elem = elem[dir]) { - if (elem.nodeType === 1 || checkNonElements) { - outerCache = elem[expando] || (elem[expando] = {}); - - if (skip && nodeName(elem, skip)) { - elem = elem[dir] || elem; - } else if ((oldCache = outerCache[key]) && oldCache[0] === dirruns && oldCache[1] === doneName) { - // Assign to newCache so results back-propagate to previous elements - return newCache[2] = oldCache[2]; - } else { - // Reuse newcache so results back-propagate to previous elements - outerCache[key] = newCache; + if (skip && nodeName(elem, skip)) { + elem = elem[dir] || elem; + } else if ((oldCache = outerCache[key]) && oldCache[0] === dirruns && oldCache[1] === doneName) { + // Assign to newCache so results back-propagate to previous elements + return newCache[2] = oldCache[2]; + } else { + // Reuse newcache so results back-propagate to previous elements + outerCache[key] = newCache; - // A match means we're done; a fail means we have to keep checking - if (newCache[2] = matcher(elem, context, xml)) { - return true; - } + // A match means we're done; a fail means we have to keep checking + if (newCache[2] = matcher(elem, context, xml)) { + return true; } } } } + } - return false; + return false; + }; + } + + function elementMatcher(matchers) { + return matchers.length > 1 + ? function (elem, context, xml) { + var i = matchers.length; + + while (i--) { + if (!matchers[i](elem, context, xml)) { + return false; + } + } + + return true; + } + : matchers[0]; + } + + function multipleContexts(selector, contexts, results) { + var i = 0, len = contexts.length; + + for (; i < len; i++) { + find(selector, contexts[i], results); + } + + return results; + } + + function condense(unmatched, map, filter, context, xml) { + var elem, + newUnmatched = [], + i = 0, + len = unmatched.length, + mapped = map != null; + + for (; i < len; i++) { + if (elem = unmatched[i]) { + if (!filter || filter(elem, context, xml)) { + newUnmatched.push(elem); + + if (mapped) { + map.push(i); + } + } + } + } + + return newUnmatched; + } + + function setMatcher( + preFilter, + selector, + matcher, + postFilter, + postFinder, + postSelector + ) { + if (postFilter && !postFilter[expando]) { + postFilter = setMatcher(postFilter); + } + + if (postFinder && !postFinder[expando]) { + postFinder = setMatcher(postFinder, postSelector); + } + + return markFunction(function (seed, results, context, xml) { + var temp, + i, + elem, + matcherOut, + preMap = [], + postMap = [], + preexisting = results.length, + // Get initial elements from seed or context + elems = seed || multipleContexts(selector || "*", context.nodeType ? [context] : context, []), + // Prefilter to get matcher input, preserving a map for seed-results synchronization + matcherIn = preFilter && (seed || !selector) + ? condense(elems, preMap, preFilter, context, xml) + : elems; + + if (matcher) { + // If we have a postFinder, or filtered seed, or non-seed postFilter + // or preexisting results, + matcherOut = postFinder || (seed ? preFilter : preexisting || postFilter) + ? // ...intermediate processing is necessary + [] + : // ...otherwise use results directly + results; + + // Find primary matches + matcher(matcherIn, matcherOut, context, xml); + } else { + matcherOut = matcherIn; + } + + // Apply postFilter + if (postFilter) { + temp = condense(matcherOut, postMap); + postFilter(temp, [], context, xml); + + // Un-match failing elements by moving them back to matcherIn + i = temp.length; + + while (i--) { + if (elem = temp[i]) { + matcherOut[postMap[i]] = !(matcherIn[postMap[i]] = elem); + } + } + } + + if (seed) { + if (postFinder || preFilter) { + if (postFinder) { + // Get the final matcherOut by condensing this intermediate into postFinder contexts + temp = []; + + i = matcherOut.length; + + while (i--) { + if (elem = matcherOut[i]) { + // Restore matcherIn since elem is not yet a final match + temp.push(matcherIn[i] = elem); + } + } + + postFinder(null, matcherOut = [], temp, xml); + } + + // Move matched elements from seed to results to keep them synchronized + i = matcherOut.length; + + while (i--) { + if ((elem = matcherOut[i]) && (temp = postFinder ? indexOf.call(seed, elem) : preMap[i]) > -1) { + seed[temp] = !(results[temp] = elem); + } + } + } + + // Add elements to results, through postFinder if defined + } else { + matcherOut = condense(matcherOut === results + ? matcherOut.splice(preexisting, matcherOut.length) + : matcherOut); + + if (postFinder) { + postFinder(null, results, matcherOut, xml); + } else { + push.apply(results, matcherOut); + } + } + }); + } + + function matcherFromTokens(tokens) { + var checkContext, + matcher, + j, + len = tokens.length, + leadingRelative = Expr.relative[tokens[0].type], + implicitRelative = leadingRelative || Expr.relative[" "], + i = leadingRelative ? 1 : 0, + // The foundational matcher ensures that elements are reachable from top-level context(s) + matchContext = addCombinator( + function (elem) { + return elem === checkContext; + }, + implicitRelative, + true + ), + matchAnyContext = addCombinator( + function (elem) { + return indexOf.call(checkContext, elem) > -1; + }, + implicitRelative, + true + ), + matchers = [ + function (elem, context, xml) { + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + var ret = !leadingRelative && (xml || context != outermostContext) || ((checkContext = context).nodeType + ? matchContext(elem, context, xml) + : matchAnyContext(elem, context, xml)); + + // Avoid hanging onto element + // (see https://github.com/jquery/sizzle/issues/299) + checkContext = null; + + return ret; + } + ]; + + for (; i < len; i++) { + if (matcher = Expr.relative[tokens[i].type]) { + matchers = [addCombinator(elementMatcher(matchers), matcher)]; + } else { + matcher = Expr.filter[tokens[i].type].apply(null, tokens[i].matches); + + // Return special upon seeing a positional matcher + if (matcher[expando]) { + // Find the next relative operator (if any) for proper handling + j = ++i; + + for (; j < len; j++) { + if (Expr.relative[tokens[j].type]) { + break; + } + } + + return setMatcher( + i > 1 && elementMatcher(matchers), + i > 1 && toSelector( + // If the preceding token was a descendant combinator, insert an implicit any-element `*` + tokens.slice(0, i - 1).concat({ value: tokens[i - 2].type === " " ? "*" : "" }) + ).replace(rtrimCSS, "$1"), + matcher, + i < j && matcherFromTokens(tokens.slice(i, j)), + j < len && matcherFromTokens(tokens = tokens.slice(j)), + j < len && toSelector(tokens) + ); + } + + matchers.push(matcher); + } + } + + return elementMatcher(matchers); + } + + function matcherFromGroupMatchers(elementMatchers, setMatchers) { + var bySet = setMatchers.length > 0, + byElement = elementMatchers.length > 0, + superMatcher = function (seed, context, xml, results, outermost) { + var elem, + j, + matcher, + matchedCount = 0, + i = "0", + unmatched = seed && [], + setMatched = [], + contextBackup = outermostContext, + // We must always have either seed elements or outermost context + elems = seed || byElement && Expr.find.TAG("*", outermost), + // Use integer dirruns iff this is the outermost matcher + dirrunsUnique = dirruns += contextBackup == null ? 1 : Math.random() || 0.1, + len = elems.length; + + if (outermost) { + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + outermostContext = context == document || context || outermost; + } + + // Add elements passing elementMatchers directly to results + // Support: iOS <=7 - 9 only + // Tolerate NodeList properties (IE: "length"; Safari: ) matching + // elements by id. (see trac-14142) + for (; i !== len && (elem = elems[i]) != null; i++) { + if (byElement && elem) { + j = 0; + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if (!context && elem.ownerDocument != document) { + setDocument(elem); + xml = !documentIsHTML; + } + + while (matcher = elementMatchers[j++]) { + if (matcher(elem, context || document, xml)) { + push.call(results, elem); + + break; + } + } + + if (outermost) { + dirruns = dirrunsUnique; + } + } + + // Track unmatched elements for set filters + if (bySet) { + // They will have gone through all possible matchers + if (elem = !matcher && elem) { + matchedCount--; + } + + // Lengthen the array for every element, matched or not + if (seed) { + unmatched.push(elem); + } + } + } + + // `i` is now the count of elements visited above, and adding it to `matchedCount` + // makes the latter nonnegative. + matchedCount += i; + + // Apply set filters to unmatched elements + // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount` + // equals `i`), unless we didn't visit _any_ elements in the above loop because we have + // no element matchers and no seed. + // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that + // case, which will result in a "00" `matchedCount` that differs from `i` but is also + // numerically zero. + if (bySet && i !== matchedCount) { + j = 0; + + while (matcher = setMatchers[j++]) { + matcher(unmatched, setMatched, context, xml); + } + + if (seed) { + // Reintegrate element matches to eliminate the need for sorting + if (matchedCount > 0) { + while (i--) { + if (!(unmatched[i] || setMatched[i])) { + setMatched[i] = pop.call(results); + } + } + } + + // Discard index placeholder values to get only actual matches + setMatched = condense(setMatched); + } + + // Add matches to results + push.apply(results, setMatched); + + // Seedless set matches succeeding multiple successful matchers stipulate sorting + if (outermost && !seed && setMatched.length > 0 && matchedCount + setMatchers.length > 1) { + jQuery.uniqueSort(results); + } + } + + // Override manipulation of globals by nested matchers + if (outermost) { + dirruns = dirrunsUnique; + outermostContext = contextBackup; + } + + return unmatched; + }; + + return bySet ? markFunction(superMatcher) : superMatcher; + } + + function compile(selector, match /* Internal Use Only */) { + var i, + setMatchers = [], + elementMatchers = [], + cached = compilerCache[selector + " "]; + + if (!cached) { + // Generate a function of recursive functions that can be used to check each element + if (!match) { + match = tokenize(selector); + } + + i = match.length; + + while (i--) { + cached = matcherFromTokens(match[i]); + + if (cached[expando]) { + setMatchers.push(cached); + } else { + elementMatchers.push(cached); + } + } + + // Cache the compiled function + cached = compilerCache(selector, matcherFromGroupMatchers(elementMatchers, setMatchers)); + + // Save selector and tokenization + cached.selector = selector; + } + + return cached; + } + + /** + * A low-level selection function that works with jQuery's compiled + * selector functions + * @param {String|Function} selector A selector or a pre-compiled + * selector function built with jQuery selector compile + * @param {Element} context + * @param {Array} [results] + * @param {Array} [seed] A set of elements to match against + */ + function select(selector, context, results, seed) { + var i, + tokens, + token, + type, + find, + compiled = typeof selector === "function" && selector, + match = !seed && tokenize(selector = compiled.selector || selector); + + results = results || []; + + // Try to minimize operations if there is only one selector in the list and no seed + // (the latter of which guarantees us context) + if (match.length === 1) { + // Reduce context if the leading compound selector is an ID + tokens = match[0] = match[0].slice(0); + + if (tokens.length > 2 && (token = tokens[0]).type === "ID" && context.nodeType === 9 && documentIsHTML && Expr.relative[tokens[1].type]) { + context = (Expr.find.ID(token.matches[0].replace(runescape, funescape), context) || [])[0]; + + if (!context) { + return results; + + // Precompiled matchers will still verify ancestry, so step up a level + } else if (compiled) { + context = context.parentNode; + } + + selector = selector.slice(tokens.shift().value.length); + } + + // Fetch a seed set for right-to-left matching + i = matchExpr.needsContext.test(selector) ? 0 : tokens.length; + + while (i--) { + token = tokens[i]; + + // Abort if we hit a combinator + if (Expr.relative[type = token.type]) { + break; + } + + if (find = Expr.find[type]) { + // Search, expanding context for leading sibling combinators + if (seed = find(token.matches[0].replace(runescape, funescape), rsibling.test(tokens[0].type) && testContext(context.parentNode) || context)) { + // If seed is empty or no tokens remain, we can return early + tokens.splice(i, 1); + + selector = seed.length && toSelector(tokens); + + if (!selector) { + push.apply(results, seed); + + return results; + } + + break; + } + } + } + } + + // Compile and execute a filtering function if one is not provided + // Provide `match` to avoid retokenization if we modified the selector above + (compiled || compile(selector, match))(seed, context, !documentIsHTML, results, !context || rsibling.test(selector) && testContext(context.parentNode) || context); + + return results; + } + + // One-time assignments + // Support: Android <=4.0 - 4.1+ + // Sort stability + support.sortStable = expando.split("").sort(sortOrder).join("") === expando; + + // Initialize against the default document + setDocument(); + + // Support: Android <=4.0 - 4.1+ + // Detached nodes confoundingly follow *each other* + support.sortDetached = assert(function (el) { + // Should return 1, but returns 4 (following) + return el.compareDocumentPosition(document.createElement("fieldset")) & 1; + }); + + jQuery.find = find; + + // Deprecated + jQuery.expr[":"] = jQuery.expr.pseudos; + + jQuery.unique = jQuery.uniqueSort; + + // These have always been private, but they used to be documented as part of + // Sizzle so let's maintain them for now for backwards compatibility purposes. + find.compile = compile; + + find.select = select; + find.setDocument = setDocument; + find.tokenize = tokenize; + find.escape = jQuery.escapeSelector; + find.getText = jQuery.text; + find.isXML = jQuery.isXMLDoc; + find.selectors = jQuery.expr; + find.support = jQuery.support; + find.uniqueSort = jQuery.uniqueSort; + + /* eslint-enable */ + })(); + + var dir = function (elem, dir, until) { + var matched = [], truncate = until !== undefined; + + while ((elem = elem[dir]) && elem.nodeType !== 9) { + if (elem.nodeType === 1) { + if (truncate && jQuery(elem).is(until)) { + break; + } + + matched.push(elem); + } + } + + return matched; + }; + + var siblings = function (n, elem) { + var matched = []; + + for (; n; n = n.nextSibling) { + if (n.nodeType === 1 && n !== elem) { + matched.push(n); + } + } + + return matched; + }; + + var rneedsContext = jQuery.expr.match.needsContext; + var rsingleTag = /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i; + + // Implement the identical functionality for filter and not + function winnow(elements, qualifier, not) { + if (isFunction(qualifier)) { + return jQuery.grep(elements, function (elem, i) { + return !!qualifier.call(elem, i, elem) !== not; + }); + } + + // Single element + if (qualifier.nodeType) { + return jQuery.grep(elements, function (elem) { + return elem === qualifier !== not; + }); + } + + // Arraylike of elements (jQuery, arguments, Array) + if (typeof qualifier !== "string") { + return jQuery.grep(elements, function (elem) { + return indexOf.call(qualifier, elem) > -1 !== not; + }); + } + + // Filtered directly for both simple and complex selectors + return jQuery.filter(qualifier, elements, not); + } + + jQuery.filter = function (expr, elems, not) { + var elem = elems[0]; + + if (not) { + expr = ":not(" + expr + ")"; + } + + if (elems.length === 1 && elem.nodeType === 1) { + return jQuery.find.matchesSelector(elem, expr) ? [elem] : []; + } + + return jQuery.find.matches(expr, jQuery.grep(elems, function (elem) { + return elem.nodeType === 1; + })); + }; + + jQuery.fn.extend({ + find(selector) { + var i, ret, len = this.length, self = this; + + if (typeof selector !== "string") { + return this.pushStack(jQuery(selector).filter(function () { + for (i = 0; i < len; i++) { + if (jQuery.contains(self[i], this)) { + return true; + } + } + })); + } + + ret = this.pushStack([]); + + for (i = 0; i < len; i++) { + jQuery.find(selector, self[i], ret); + } + + return len > 1 ? jQuery.uniqueSort(ret) : ret; + }, + + filter(selector) { + return this.pushStack(winnow(this, selector || [], false)); + }, + + not(selector) { + return this.pushStack(winnow(this, selector || [], true)); + }, + + is(selector) { + return !!winnow( + this, + // If this is a positional/relative selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + typeof selector === "string" && rneedsContext.test(selector) ? jQuery(selector) : selector || [], + false + ).length; + } + }); + + // Initialize a jQuery object + // A central reference to the root jQuery(document) + var rootjQuery, + // A simple way to check for HTML strings + // Prioritize #id over to avoid XSS via location.hash (trac-9521) + // Strict HTML recognition (trac-11290: must start with <) + // Shortcut simple #id case for speed + rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/, + init = jQuery.fn.init = function (selector, context, root) { + var match, elem; + + // HANDLE: $(""), $(null), $(undefined), $(false) + if (!selector) { + return this; + } + + // Method init() accepts an alternate rootjQuery + // so migrate can support jQuery.sub (gh-2101) + root = root || rootjQuery; + + // Handle HTML strings + if (typeof selector === "string") { + if (selector[0] === "<" && selector[selector.length - 1] === ">" && selector.length >= 3) { + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [null, selector, null]; + } else { + match = rquickExpr.exec(selector); + } + + // Match html or make sure no context is specified for #id + if (match && (match[1] || !context)) { + // HANDLE: $(html) -> $(array) + if (match[1]) { + context = context instanceof jQuery ? context[0] : context; + + // Option to run scripts is true for back-compat + // Intentionally let the error be thrown if parseHTML is not present + jQuery.merge(this, jQuery.parseHTML(match[1], context && context.nodeType ? context.ownerDocument || context : document, true)); + + // HANDLE: $(html, props) + if (rsingleTag.test(match[1]) && jQuery.isPlainObject(context)) { + for (match in context) { + // Properties of context are called as methods if possible + if (isFunction(this[match])) { + this[match](context[match]); + + // ...and otherwise set as attributes + } else { + this.attr(match, context[match]); + } + } + } + + return this; + + // HANDLE: $(#id) + } else { + elem = document.getElementById(match[2]); + + if (elem) { + // Inject the element directly into the jQuery object + this[0] = elem; + + this.length = 1; + } + + return this; + } + + // HANDLE: $(expr, $(...)) + } else if (!context || context.jquery) { + return (context || root).find(selector); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor(context).find(selector); + } + + // HANDLE: $(DOMElement) + } else if (selector.nodeType) { + this[0] = selector; + this.length = 1; + + return this; + + // HANDLE: $(function) + // Shortcut for document ready + } else if (isFunction(selector)) { + return root.ready !== undefined + ? root.ready(selector) + : // Execute immediately if ready is not present + selector(jQuery); + } + + return jQuery.makeArray(selector, this); + }; + + // Give the init function the jQuery prototype for later instantiation + init.prototype = jQuery.fn; + + // Initialize central reference + rootjQuery = jQuery(document); + + var rparentsprev = /^(?:parents|prev(?:Until|All))/, + // Methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { children: true, contents: true, next: true, prev: true }; + + jQuery.fn.extend({ + has(target) { + var targets = jQuery(target, this), + l = targets.length; + + return this.filter(function () { + var i = 0; + + for (; i < l; i++) { + if (jQuery.contains(this, targets[i])) { + return true; + } + } + }); + }, + + closest(selectors, context) { + var cur, + i = 0, + l = this.length, + matched = [], + targets = typeof selectors !== "string" && jQuery(selectors); + + // Positional selectors never match, since there's no _selection_ context + if (!rneedsContext.test(selectors)) { + for (; i < l; i++) { + for (cur = this[i]; cur && cur !== context; cur = cur.parentNode) { + // Always skip document fragments + if (cur.nodeType < 11 && (targets + ? targets.index(cur) > -1 + : // Don't pass non-elements to jQuery#find + cur.nodeType === 1 && jQuery.find.matchesSelector(cur, selectors))) { + matched.push(cur); + + break; + } + } + } + } + + return this.pushStack(matched.length > 1 ? jQuery.uniqueSort(matched) : matched); + }, + + // Determine the position of an element within the set + index(elem) { + // No argument, return index in parent + if (!elem) { + return this[0] && this[0].parentNode ? this.first().prevAll().length : -1; + } + + // Index in selector + if (typeof elem === "string") { + return indexOf.call(jQuery(elem), this[0]); + } + + // Locate the position of the desired element + return indexOf.call( + this, + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[0] : elem + ); + }, + + add(selector, context) { + return this.pushStack(jQuery.uniqueSort(jQuery.merge(this.get(), jQuery(selector, context)))); + }, + + addBack(selector) { + return this.add(selector == null ? this.prevObject : this.prevObject.filter(selector)); + } + }); + + function sibling(cur, dir) { + while ((cur = cur[dir]) && cur.nodeType !== 1) {} + + return cur; + } + + jQuery.each( + { + parent(elem) { + var parent = elem.parentNode; + + return parent && parent.nodeType !== 11 ? parent : null; + }, + + parents(elem) { + return dir(elem, "parentNode"); + }, + + parentsUntil(elem, _i, until) { + return dir(elem, "parentNode", until); + }, + + next(elem) { + return sibling(elem, "nextSibling"); + }, + + prev(elem) { + return sibling(elem, "previousSibling"); + }, + + nextAll(elem) { + return dir(elem, "nextSibling"); + }, + + prevAll(elem) { + return dir(elem, "previousSibling"); + }, + + nextUntil(elem, _i, until) { + return dir(elem, "nextSibling", until); + }, + + prevUntil(elem, _i, until) { + return dir(elem, "previousSibling", until); + }, + + siblings(elem) { + return siblings((elem.parentNode || {}).firstChild, elem); + }, + + children(elem) { + return siblings(elem.firstChild); + }, + + contents(elem) { + if (elem.contentDocument != null && // Support: IE 11+ + // elements with no `data` attribute has an object + // `contentDocument` with a `null` prototype. + getProto(elem.contentDocument)) { + return elem.contentDocument; + } + + // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only + // Treat the template element as a regular one in browsers that + // don't support it. + if (nodeName(elem, "template")) { + elem = elem.content || elem; + } + + return jQuery.merge([], elem.childNodes); + } + }, + function (name, fn) { + jQuery.fn[name] = function (until, selector) { + var matched = jQuery.map(this, fn, until); + + if (name.slice(-5) !== "Until") { + selector = until; + } + + if (selector && typeof selector === "string") { + matched = jQuery.filter(selector, matched); + } + + if (this.length > 1) { + // Remove duplicates + if (!guaranteedUnique[name]) { + jQuery.uniqueSort(matched); + } + + // Reverse order for parents* and prev-derivatives + if (rparentsprev.test(name)) { + matched.reverse(); + } + } + + return this.pushStack(matched); + }; + } + ); + + var rnothtmlwhite = /[^\x20\t\r\n\f]+/g; + + // Convert String-formatted options into Object-formatted ones + function createOptions(options) { + var object = {}; + + jQuery.each(options.match(rnothtmlwhite) || [], function (_, flag) { + object[flag] = true; + }); + + return object; + } + + /* + * Create a callback list using the following parameters: + * + * options: an optional list of space-separated options that will change how + * the callback list behaves or a more traditional option object + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible options: + * + * once: will ensure the callback list can only be fired once (like a Deferred) + * + * memory: will keep track of previous values and will call any callback added + * after the list has been fired right away with the latest "memorized" + * values (like a Deferred) + * + * unique: will ensure a callback can only be added once (no duplicate in the list) + * + * stopOnFalse: interrupt callings when a callback returns false + * + */ + jQuery.Callbacks = function (options) { + // Convert options from String-formatted to Object-formatted if needed + // (we check in cache first) + options = typeof options === "string" ? createOptions(options) : jQuery.extend({}, options); + + var // Flag to know if list is currently firing + firing, + // Last fire value for non-forgettable lists + memory, + // Flag to know if list was already fired + fired, + // Flag to prevent firing + locked, + // Actual callback list + list = [], + // Queue of execution data for repeatable lists + queue = [], + // Index of currently firing callback (modified by add/remove as needed) + firingIndex = -1, + // Fire callbacks + fire = function () { + // Enforce single-firing + locked = locked || options.once; + + // Execute callbacks for all pending executions, + // respecting firingIndex overrides and runtime changes + fired = firing = true; + + for (; queue.length; firingIndex = -1) { + memory = queue.shift(); + + while (++firingIndex < list.length) { + // Run callback and check for early termination + if (list[firingIndex].apply(memory[0], memory[1]) === false && options.stopOnFalse) { + // Jump to end and forget the data so .add doesn't re-fire + firingIndex = list.length; + + memory = false; + } + } + } + + // Forget the data if we're done with it + if (!options.memory) { + memory = false; + } + + firing = false; + + // Clean up if we're done firing for good + if (locked) { + // Keep an empty list if we have data for future add calls + if (memory) { + list = []; + + // Otherwise, this object is spent + } else { + list = ""; + } + } + }, + // Actual Callbacks object + self = { + // Add a callback or a collection of callbacks to the list + add() { + if (list) { + // If we have memory from a past run, we should fire after adding + if (memory && !firing) { + firingIndex = list.length - 1; + queue.push(memory); + } + + (function add(args) { + jQuery.each(args, function (_, arg) { + if (isFunction(arg)) { + if (!options.unique || !self.has(arg)) { + list.push(arg); + } + } else if (arg && arg.length && toType(arg) !== "string") { + // Inspect recursively + add(arg); + } + }); + })(arguments); + + if (memory && !firing) { + fire(); + } + } + + return this; + }, + + // Remove a callback from the list + remove() { + jQuery.each(arguments, function (_, arg) { + var index; + + while ((index = jQuery.inArray(arg, list, index)) > -1) { + list.splice(index, 1); + + // Handle firing indexes + if (index <= firingIndex) { + firingIndex--; + } + } + }); + + return this; + }, + + // Check if a given callback is in the list. + // If no argument is given, return whether or not list has callbacks attached. + has(fn) { + return fn ? jQuery.inArray(fn, list) > -1 : list.length > 0; + }, + + // Remove all callbacks from the list + empty() { + if (list) { + list = []; + } + + return this; + }, + + // Disable .fire and .add + // Abort any current/pending executions + // Clear all callbacks and values + disable() { + locked = queue = []; + list = memory = ""; + + return this; + }, + + disabled() { + return !list; + }, + + // Disable .fire + // Also disable .add unless we have memory (since it would have no effect) + // Abort any pending executions + lock() { + locked = queue = []; + + if (!memory && !firing) { + list = memory = ""; + } + + return this; + }, + + locked() { + return !!locked; + }, + + // Call all callbacks with the given context and arguments + fireWith(context, args) { + if (!locked) { + args = args || []; + args = [context, args.slice ? args.slice() : args]; + queue.push(args); + + if (!firing) { + fire(); + } + } + + return this; + }, + + // Call all the callbacks with the given arguments + fire() { + self.fireWith(this, arguments); + + return this; + }, + + // To know if the callbacks have already been called at least once + fired() { + return !!fired; + } + }; + + return self; + }; + + function Identity(v) { + return v; + } + + function Thrower(ex) { + throw ex; + } + + function adoptValue(value, resolve, reject, noValue) { + var method; + + try { + // Check for promise aspect first to privilege synchronous behavior + if (value && isFunction(method = value.promise)) { + method.call(value).done(resolve).fail(reject); + + // Other thenables + } else if (value && isFunction(method = value.then)) { + method.call(value, resolve, reject); + + // Other non-thenables + } else { + // Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer: + // * false: [ value ].slice( 0 ) => resolve( value ) + // * true: [ value ].slice( 1 ) => resolve() + resolve.apply(undefined, [value].slice(noValue)); + } + + // For Promises/A+, convert exceptions into rejections + // Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in + // Deferred#then to conditionally suppress rejection. + } catch(value) { + // Support: Android 4.0 only + // Strict mode functions invoked without .call/.apply get global-object context + reject.apply(undefined, [value]); + } + } + + jQuery.extend({ + Deferred(func) { + var tuples = [ + // action, add listener, callbacks, + // ... .then handlers, argument index, [final state] + [ + "notify", + "progress", + jQuery.Callbacks("memory"), + jQuery.Callbacks("memory"), + 2 + ], + + [ + "resolve", + "done", + jQuery.Callbacks("once memory"), + jQuery.Callbacks("once memory"), + 0, + "resolved" + ], + + [ + "reject", + "fail", + jQuery.Callbacks("once memory"), + jQuery.Callbacks("once memory"), + 1, + "rejected" + ] + ], + state = "pending", + promise = { + state() { + return state; + }, + + always() { + deferred.done(arguments).fail(arguments); + + return this; + }, + + "catch"(fn) { + return promise.then(null, fn); + }, + + // Keep pipe for back-compat + pipe(/* fnDone, fnFail, fnProgress */) { + var fns = arguments; + + return jQuery.Deferred(function (newDefer) { + jQuery.each(tuples, function (_i, tuple) { + // Map tuples (progress, done, fail) to arguments (done, fail, progress) + var fn = isFunction(fns[tuple[4]]) && fns[tuple[4]]; + + // deferred.progress(function() { bind to newDefer or newDefer.notify }) + // deferred.done(function() { bind to newDefer or newDefer.resolve }) + // deferred.fail(function() { bind to newDefer or newDefer.reject }) + deferred[tuple[1]](function () { + var returned = fn && fn.apply(this, arguments); + + if (returned && isFunction(returned.promise)) { + returned.promise().progress(newDefer.notify).done(newDefer.resolve).fail(newDefer.reject); + } else { + newDefer[tuple[0] + "With"](this, fn ? [returned] : arguments); + } + }); + }); + + fns = null; + }).promise(); + }, + + then(onFulfilled, onRejected, onProgress) { + var maxDepth = 0; + + function resolve(depth, deferred, handler, special) { + return function () { + var that = this, + args = arguments, + mightThrow = function () { + var returned, then; + + // Support: Promises/A+ section 2.3.3.3.3 + // https://promisesaplus.com/#point-59 + // Ignore double-resolution attempts + if (depth < maxDepth) { + return; + } + + returned = handler.apply(that, args); + + // Support: Promises/A+ section 2.3.1 + // https://promisesaplus.com/#point-48 + if (returned === deferred.promise()) { + throw new TypeError("Thenable self-resolution"); + } + + // Support: Promises/A+ sections 2.3.3.1, 3.5 + // https://promisesaplus.com/#point-54 + // https://promisesaplus.com/#point-75 + // Retrieve `then` only once + then = returned && (// Support: Promises/A+ section 2.3.4 + // https://promisesaplus.com/#point-64 + // Only check objects and functions for thenability + typeof returned === "object" || typeof returned === "function") && returned.then; + + // Handle a returned thenable + if (isFunction(then)) { + // Special processors (notify) just wait for resolution + if (special) { + then.call(returned, resolve(maxDepth, deferred, Identity, special), resolve(maxDepth, deferred, Thrower, special)); + + // Normal processors (resolve) also hook into progress + } else { + // ...and disregard older resolution values + maxDepth++; + + then.call(returned, resolve(maxDepth, deferred, Identity, special), resolve(maxDepth, deferred, Thrower, special), resolve(maxDepth, deferred, Identity, deferred.notifyWith)); + } + + // Handle all other returned values + } else { + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if (handler !== Identity) { + that = undefined; + args = [returned]; + } + + // Process the value(s) + // Default process is resolve + (special || deferred.resolveWith)(that, args); + } + }, + // Only normal processors (resolve) catch and reject exceptions + process = special + ? mightThrow + : function () { + try { + mightThrow(); + } catch(e) { + if (jQuery.Deferred.exceptionHook) { + jQuery.Deferred.exceptionHook(e, process.error); + } + + // Support: Promises/A+ section 2.3.3.3.4.1 + // https://promisesaplus.com/#point-61 + // Ignore post-resolution exceptions + if (depth + 1 >= maxDepth) { + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if (handler !== Thrower) { + that = undefined; + args = [e]; + } + + deferred.rejectWith(that, args); + } + } + }; + + // Support: Promises/A+ section 2.3.3.3.1 + // https://promisesaplus.com/#point-57 + // Re-resolve promises immediately to dodge false rejection from + // subsequent errors + if (depth) { + process(); + } else { + // Call an optional hook to record the error, in case of exception + // since it's otherwise lost when execution goes async + if (jQuery.Deferred.getErrorHook) { + process.error = jQuery.Deferred.getErrorHook(); + + // The deprecated alias of the above. While the name suggests + // returning the stack, not an error instance, jQuery just passes + // it directly to `console.warn` so both will work; an instance + // just better cooperates with source maps. + } else if (jQuery.Deferred.getStackHook) { + process.error = jQuery.Deferred.getStackHook(); + } + + window.setTimeout(process); + } + }; + } + + return jQuery.Deferred(function (newDefer) { + // progress_handlers.add( ... ) + tuples[0][3].add(resolve(0, newDefer, isFunction(onProgress) ? onProgress : Identity, newDefer.notifyWith)); + + // fulfilled_handlers.add( ... ) + tuples[1][3].add(resolve(0, newDefer, isFunction(onFulfilled) ? onFulfilled : Identity)); + + // rejected_handlers.add( ... ) + tuples[2][3].add(resolve(0, newDefer, isFunction(onRejected) ? onRejected : Thrower)); + }).promise(); + }, + + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise(obj) { + return obj != null ? jQuery.extend(obj, promise) : promise; + } + }, + deferred = {}; + + // Add list-specific methods + jQuery.each(tuples, function (i, tuple) { + var list = tuple[2], stateString = tuple[5]; + + // promise.progress = list.add + // promise.done = list.add + // promise.fail = list.add + promise[tuple[1]] = list.add; + + // Handle state + if (stateString) { + list.add( + function () { + // state = "resolved" (i.e., fulfilled) + // state = "rejected" + state = stateString; + }, + // rejected_callbacks.disable + // fulfilled_callbacks.disable + tuples[3 - i][2].disable, + // rejected_handlers.disable + // fulfilled_handlers.disable + tuples[3 - i][3].disable, + // progress_callbacks.lock + tuples[0][2].lock, + // progress_handlers.lock + tuples[0][3].lock + ); + } + + // progress_handlers.fire + // fulfilled_handlers.fire + // rejected_handlers.fire + list.add(tuple[3].fire); + + // deferred.notify = function() { deferred.notifyWith(...) } + // deferred.resolve = function() { deferred.resolveWith(...) } + // deferred.reject = function() { deferred.rejectWith(...) } + deferred[tuple[0]] = function () { + deferred[tuple[0] + "With"](this === deferred ? undefined : this, arguments); + + return this; + }; + + // deferred.notifyWith = list.fireWith + // deferred.resolveWith = list.fireWith + // deferred.rejectWith = list.fireWith + deferred[tuple[0] + "With"] = list.fireWith; + }); + + // Make the deferred a promise + promise.promise(deferred); + + // Call given func if any + if (func) { + func.call(deferred, deferred); + } + + // All done! + return deferred; + }, + + // Deferred helper + when(singleValue) { + var // count of uncompleted subordinates + remaining = arguments.length, + // count of unprocessed arguments + i = remaining, + // subordinate fulfillment data + resolveContexts = Array(i), + resolveValues = slice.call(arguments), + // the primary Deferred + primary = jQuery.Deferred(), + // subordinate callback factory + updateFunc = function (i) { + return function (value) { + resolveContexts[i] = this; + resolveValues[i] = arguments.length > 1 ? slice.call(arguments) : value; + + if (!--remaining) { + primary.resolveWith(resolveContexts, resolveValues); + } + }; + }; + + // Single- and empty arguments are adopted like Promise.resolve + if (remaining <= 1) { + adoptValue(singleValue, primary.done(updateFunc(i)).resolve, primary.reject, !remaining); + + // Use .then() to unwrap secondary thenables (cf. gh-3000) + if (primary.state() === "pending" || isFunction(resolveValues[i] && resolveValues[i].then)) { + return primary.then(); + } + } + + // Multiple arguments are aggregated like Promise.all array elements + while (i--) { + adoptValue(resolveValues[i], updateFunc(i), primary.reject); + } + + return primary.promise(); + } + }); + + // These usually indicate a programmer mistake during development, + // warn about them ASAP rather than swallowing them by default. + var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/; + + // If `jQuery.Deferred.getErrorHook` is defined, `asyncError` is an error + // captured before the async barrier to get the original error cause + // which may otherwise be hidden. + jQuery.Deferred.exceptionHook = function (error, asyncError) { + // Support: IE 8 - 9 only + // Console exists when dev tools are open, which can happen at any time + if (window.console && window.console.warn && error && rerrorNames.test(error.name)) { + window.console.warn("jQuery.Deferred exception: " + error.message, error.stack, asyncError); + } + }; + + jQuery.readyException = function (error) { + window.setTimeout(function () { + throw error; + }); + }; + + // The deferred used on DOM ready + var readyList = jQuery.Deferred(); + + jQuery.fn.ready = function (fn) { + readyList.then(fn).// Wrap jQuery.readyException in a function so that the lookup + // happens at the time of error handling instead of callback + // registration. + catch(function (error) { + jQuery.readyException(error); + }); + + return this; + }; + + jQuery.extend({ + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See trac-6781 + readyWait: 1, + + // Handle when the DOM is ready + ready(wait) { + // Abort if there are pending holds or we're already ready + if (wait === true ? --jQuery.readyWait : jQuery.isReady) { + return; + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if (wait !== true && --jQuery.readyWait > 0) { + return; + } + + // If there are functions bound, to execute + readyList.resolveWith(document, [jQuery]); + } + }); + + jQuery.ready.then = readyList.then; + + // The ready event handler and self cleanup method + function completed() { + document.removeEventListener("DOMContentLoaded", completed); + window.removeEventListener("load", completed); + jQuery.ready(); + } + + // Catch cases where $(document).ready() is called + // after the browser event has already occurred. + // Support: IE <=9 - 10 only + // Older IE sometimes signals "interactive" too soon + if (document.readyState === "complete" || document.readyState !== "loading" && !document.documentElement.doScroll) { + // Handle it asynchronously to allow scripts the opportunity to delay ready + window.setTimeout(jQuery.ready); + } else { + // Use the handy event callback + document.addEventListener("DOMContentLoaded", completed); + + // A fallback to window.onload, that will always work + window.addEventListener("load", completed); + } + + // Multifunctional method to get and set values of a collection + // The value/s can optionally be executed if it's a function + var access = function (elems, fn, key, value, chainable, emptyGet, raw) { + var i = 0, len = elems.length, bulk = key == null; + + // Sets many values + if (toType(key) === "object") { + chainable = true; + + for (i in key) { + access(elems, fn, i, key[i], true, emptyGet, raw); + } + + // Sets one value + } else if (value !== undefined) { + chainable = true; + + if (!isFunction(value)) { + raw = true; + } + + if (bulk) { + // Bulk operations run against the entire set + if (raw) { + fn.call(elems, value); + fn = null; + + // ...except when executing function values + } else { + bulk = fn; + + fn = function (elem, _key, value) { + return bulk.call(jQuery(elem), value); }; + } + } + + if (fn) { + for (; i < len; i++) { + fn(elems[i], key, raw ? value : value.call(elems[i], i, fn(elems[i], key))); + } + } + } + + if (chainable) { + return elems; + } + + // Gets + if (bulk) { + return fn.call(elems); + } + + return len ? fn(elems[0], key) : emptyGet; + }; + + // Matches dashed string for camelizing + var rmsPrefix = /^-ms-/, rdashAlpha = /-([a-z])/g; + + // Used by camelCase as callback to replace() + function fcamelCase(_all, letter) { + return letter.toUpperCase(); + } + + // Convert dashed to camelCase; used by the css and data modules + // Support: IE <=9 - 11, Edge 12 - 15 + // Microsoft forgot to hump their vendor prefix (trac-9572) + function camelCase(string) { + return string.replace(rmsPrefix, "ms-").replace(rdashAlpha, fcamelCase); + } + + var acceptData = function (owner) { + // Accepts only: + // - Node + // - Node.ELEMENT_NODE + // - Node.DOCUMENT_NODE + // - Object + // - Any + return owner.nodeType === 1 || owner.nodeType === 9 || !+owner.nodeType; + }; + + function Data() { + this.expando = jQuery.expando + Data.uid++; + } + + Data.uid = 1; + + Data.prototype = { + cache(owner) { + // Check if the owner object already has a cache + var value = owner[this.expando]; + + // If not, create one + if (!value) { + value = {}; + + // We can accept data for non-element nodes in modern browsers, + // but we should not, see trac-8335. + // Always return an empty object. + if (acceptData(owner)) { + // If it is a node unlikely to be stringify-ed or looped over + // use plain assignment + if (owner.nodeType) { + owner[this.expando] = value; + + // Otherwise secure it in a non-enumerable property + // configurable must be true to allow the property to be + // deleted when data is removed + } else { + Object.defineProperty(owner, this.expando, { value, configurable: true }); + } + } + } + + return value; + }, + + set(owner, data, value) { + var prop, cache = this.cache(owner); + + // Handle: [ owner, key, value ] args + // Always use camelCase key (gh-2257) + if (typeof data === "string") { + cache[camelCase(data)] = value; + + // Handle: [ owner, { properties } ] args + } else { + // Copy the properties one-by-one to the cache object + for (prop in data) { + cache[camelCase(prop)] = data[prop]; + } + } + + return cache; + }, + + get(owner, key) { + return key === undefined + ? this.cache(owner) + : // Always use camelCase key (gh-2257) + owner[this.expando] && owner[this.expando][camelCase(key)]; + }, + + access(owner, key, value) { + // In cases where either: + // + // 1. No key was specified + // 2. A string key was specified, but no value provided + // + // Take the "read" path and allow the get method to determine + // which value to return, respectively either: + // + // 1. The entire cache object + // 2. The data stored at the key + // + if (key === undefined || key && typeof key === "string" && value === undefined) { + return this.get(owner, key); } - function elementMatcher(matchers) { - return matchers.length > 1 - ? function (elem, context, xml) { - var i = matchers.length; + // When the key is not a string, or both a key and value + // are specified, set or extend (existing objects) with either: + // + // 1. An object of properties + // 2. A key and value + // + this.set(owner, key, value); + + // Since the "set" path can have two possible entry points + // return the expected data based on which path was taken[*] + return value !== undefined ? value : key; + }, - while (i--) { - if (!matchers[i](elem, context, xml)) { - return false; - } - } + remove(owner, key) { + var i, cache = owner[this.expando]; - return true; - } - : matchers[0]; + if (cache === undefined) { + return; } - function multipleContexts(selector, contexts, results) { - var i = 0, len = contexts.length; + if (key !== undefined) { + // Support array or space separated string of keys + if (Array.isArray(key)) { + // If key is an array of keys... + // We always set camelCase keys, so remove that. + key = key.map(camelCase); + } else { + key = camelCase(key); - for (; i < len; i++) { - find(selector, contexts[i], results); + // If a key with the spaces exists, use it. + // Otherwise, create an array by matching non-whitespace + key = key in cache ? [key] : key.match(rnothtmlwhite) || []; } - return results; - } - - function condense(unmatched, map, filter, context, xml) { - var elem, - newUnmatched = [], - i = 0, - len = unmatched.length, - mapped = map != null; - - for (; i < len; i++) { - if (elem = unmatched[i]) { - if (!filter || filter(elem, context, xml)) { - newUnmatched.push(elem); + i = key.length; - if (mapped) { - map.push(i); - } - } - } + while (i--) { + delete cache[key[i]]; } - - return newUnmatched; } - function setMatcher( - preFilter, - selector, - matcher, - postFilter, - postFinder, - postSelector - ) { - if (postFilter && !postFilter[expando]) { - postFilter = setMatcher(postFilter); + // Remove the expando if there's no more data + if (key === undefined || jQuery.isEmptyObject(cache)) { + // Support: Chrome <=35 - 45 + // Webkit & Blink performance suffers when deleting properties + // from DOM nodes, so set to undefined instead + // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted) + if (owner.nodeType) { + owner[this.expando] = undefined; + } else { + delete owner[this.expando]; } + } + }, - if (postFinder && !postFinder[expando]) { - postFinder = setMatcher(postFinder, postSelector); - } + hasData(owner) { + var cache = owner[this.expando]; - return markFunction(function (seed, results, context, xml) { - var temp, - i, - elem, - matcherOut, - preMap = [], - postMap = [], - preexisting = results.length, - // Get initial elements from seed or context - elems = seed || multipleContexts(selector || "*", context.nodeType ? [context] : context, []), - // Prefilter to get matcher input, preserving a map for seed-results synchronization - matcherIn = preFilter && (seed || !selector) ? condense(elems, preMap, preFilter, context, xml) : elems; - - if (matcher) { - // If we have a postFinder, or filtered seed, or non-seed postFilter - // or preexisting results, - matcherOut = postFinder || (seed ? preFilter : preexisting || postFilter) ? // ...intermediate processing is necessary - [] : // ...otherwise use results directly - results; - // Find primary matches - matcher(matcherIn, matcherOut, context, xml); - } else { - matcherOut = matcherIn; - } + return cache !== undefined && !jQuery.isEmptyObject(cache); + } + }; + + var dataPriv = new Data(); + var dataUser = new Data(); + + // Implementation Summary + // + // 1. Enforce API surface and semantic compatibility with 1.9.x branch + // 2. Improve the module's maintainability by reducing the storage + // paths to a single mechanism. + // 3. Use the same single mechanism to support "private" and "user" data. + // 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData) + // 5. Avoid exposing implementation details on user objects (eg. expando properties) + // 6. Provide a clear path for implementation upgrade to WeakMap in 2014 + var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, + rmultiDash = /[A-Z]/g; + + function getData(data) { + if (data === "true") { + return true; + } - // Apply postFilter - if (postFilter) { - temp = condense(matcherOut, postMap); - postFilter(temp, [], context, xml); - // Un-match failing elements by moving them back to matcherIn - i = temp.length; + if (data === "false") { + return false; + } - while (i--) { - if (elem = temp[i]) { - matcherOut[postMap[i]] = !(matcherIn[postMap[i]] = elem); - } - } - } + if (data === "null") { + return null; + } - if (seed) { - if (postFinder || preFilter) { - if (postFinder) { - // Get the final matcherOut by condensing this intermediate into postFinder contexts - temp = []; - i = matcherOut.length; + // Only convert to a number if it doesn't change the string + if (data === +data + "") { + return +data; + } - while (i--) { - if (elem = matcherOut[i]) { - // Restore matcherIn since elem is not yet a final match - temp.push(matcherIn[i] = elem); - } - } + if (rbrace.test(data)) { + return JSON.parse(data); + } - postFinder(null, matcherOut = [], temp, xml); - } + return data; + } - // Move matched elements from seed to results to keep them synchronized - i = matcherOut.length; + function dataAttr(elem, key, data) { + var name; - while (i--) { - if ((elem = matcherOut[i]) && (temp = postFinder ? indexOf.call(seed, elem) : preMap[i]) > -1) { - seed[temp] = !(results[temp] = elem); - } - } - } - } else { - matcherOut = condense(matcherOut === results - ? matcherOut.splice( - preexisting, // Add elements to results, through postFinder if defined - matcherOut.length - ) - : matcherOut); + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if (data === undefined && elem.nodeType === 1) { + name = "data-" + key.replace(rmultiDash, "-$&").toLowerCase(); + data = elem.getAttribute(name); - if (postFinder) { - postFinder(null, results, matcherOut, xml); - } else { - push.apply(results, matcherOut); - } - } - }); + if (typeof data === "string") { + try { + data = getData(data); + } catch(e) {} + + // Make sure we set the data so it isn't changed later + dataUser.set(elem, key, data); + } else { + data = undefined; } + } - function matcherFromTokens(tokens) { - var checkContext, - matcher, - j, - len = tokens.length, - leadingRelative = Expr.relative[tokens[0].type], - implicitRelative = leadingRelative || Expr.relative[" "], - i = leadingRelative ? 1 : 0, - // The foundational matcher ensures that elements are reachable from top-level context(s) - matchContext = addCombinator( - function (elem) { - return elem === checkContext; - }, - implicitRelative, - true - ), - matchAnyContext = addCombinator( - function (elem) { - return indexOf.call(checkContext, elem) > -1; - }, - implicitRelative, - true - ), - matchers = [ - function (elem, context, xml) { - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - var ret = !leadingRelative && (xml || context != outermostContext) || ((checkContext = context).nodeType ? matchContext(elem, context, xml) : matchAnyContext(elem, context, xml)); + return data; + } - // Avoid hanging onto element - // (see https://github.com/jquery/sizzle/issues/299) - checkContext = null; - return ret; - } - ]; + jQuery.extend({ + hasData(elem) { + return dataUser.hasData(elem) || dataPriv.hasData(elem); + }, - for (; i < len; i++) { - if (matcher = Expr.relative[tokens[i].type]) { - matchers = [ - addCombinator(elementMatcher(matchers), matcher) - ]; - } else { - matcher = Expr.filter[tokens[i].type].apply(null, tokens[i].matches); + data(elem, name, data) { + return dataUser.access(elem, name, data); + }, - // Return special upon seeing a positional matcher - if (matcher[expando]) { - // Find the next relative operator (if any) for proper handling - j = ++i; + removeData(elem, name) { + dataUser.remove(elem, name); + }, - for (; j < len; j++) { - if (Expr.relative[tokens[j].type]) { - break; + // TODO: Now that all calls to _data and _removeData have been replaced + // with direct calls to dataPriv methods, these can be deprecated. + _data(elem, name, data) { + return dataPriv.access(elem, name, data); + }, + + _removeData(elem, name) { + dataPriv.remove(elem, name); + } + }); + + jQuery.fn.extend({ + data(key, value) { + var i, + name, + data, + elem = this[0], + attrs = elem && elem.attributes; + + // Gets all values + if (key === undefined) { + if (this.length) { + data = dataUser.get(elem); + + if (elem.nodeType === 1 && !dataPriv.get(elem, "hasDataAttrs")) { + i = attrs.length; + + while (i--) { + // Support: IE 11 only + // The attrs elements can be null (trac-14894) + if (attrs[i]) { + name = attrs[i].name; + + if (name.indexOf("data-") === 0) { + name = camelCase(name.slice(5)); + dataAttr(elem, name, data[name]); } } - - return setMatcher(i > 1 && elementMatcher(matchers), i > 1 && toSelector(// If the preceding token was a descendant combinator, insert an implicit any-element `*` - tokens.slice(0, i - 1).concat({ value: tokens[i - 2].type === " " ? "*" : "" })).replace(rtrimCSS, "$1"), matcher, i < j && matcherFromTokens(tokens.slice(i, j)), j < len && matcherFromTokens(tokens = tokens.slice(j)), j < len && toSelector(tokens)); } - matchers.push(matcher); + dataPriv.set(elem, "hasDataAttrs", true); } } - return elementMatcher(matchers); + return data; } - function matcherFromGroupMatchers(elementMatchers, setMatchers) { - var bySet = setMatchers.length > 0, - byElement = elementMatchers.length > 0, - superMatcher = function (seed, context, xml, results, outermost) { - var elem, - j, - matcher, - matchedCount = 0, - i = "0", - unmatched = seed && [], - setMatched = [], - contextBackup = outermostContext, - // We must always have either seed elements or outermost context - elems = seed || byElement && Expr.find.TAG("*", outermost), - // Use integer dirruns iff this is the outermost matcher - dirrunsUnique = dirruns += contextBackup == null ? 1 : Math.random() || 0.1, - len = elems.length; - - if (outermost) { - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - outermostContext = context == document || context || outermost; - } + // Sets multiple values + if (typeof key === "object") { + return this.each(function () { + dataUser.set(this, key); + }); + } - // Add elements passing elementMatchers directly to results - // Support: iOS <=7 - 9 only - // Tolerate NodeList properties (IE: "length"; Safari: ) matching - // elements by id. (see trac-14142) - for (; i !== len && (elem = elems[i]) != null; i++) { - if (byElement && elem) { - j = 0; - - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - if (!context && elem.ownerDocument != document) { - setDocument(elem); - xml = !documentIsHTML; - } + return access( + this, + function (value) { + var data; - while (matcher = elementMatchers[j++]) { - if (matcher(elem, context || document, xml)) { - push.call(results, elem); - break; - } - } + // The calling jQuery object (element matches) is not empty + // (and therefore has an element appears at this[ 0 ]) and the + // `value` parameter was not undefined. An empty jQuery object + // will result in `undefined` for elem = this[ 0 ] which will + // throw an exception if an attempt to read a data cache is made. + if (elem && value === undefined) { + // Attempt to get data from the cache + // The key will always be camelCased in Data + data = dataUser.get(elem, key); - if (outermost) { - dirruns = dirrunsUnique; - } - } + if (data !== undefined) { + return data; + } - // Track unmatched elements for set filters - if (bySet) { - // They will have gone through all possible matchers - if (elem = !matcher && elem) { - matchedCount--; - } + // Attempt to "discover" the data in + // HTML5 custom data-* attrs + data = dataAttr(elem, key); - // Lengthen the array for every element, matched or not - if (seed) { - unmatched.push(elem); - } - } + if (data !== undefined) { + return data; } - // `i` is now the count of elements visited above, and adding it to `matchedCount` - // makes the latter nonnegative. - matchedCount += i; - - // Apply set filters to unmatched elements - // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount` - // equals `i`), unless we didn't visit _any_ elements in the above loop because we have - // no element matchers and no seed. - // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that - // case, which will result in a "00" `matchedCount` that differs from `i` but is also - // numerically zero. - if (bySet && i !== matchedCount) { - j = 0; + // We tried really hard, but the data doesn't exist. + return; + } - while (matcher = setMatchers[j++]) { - matcher(unmatched, setMatched, context, xml); - } + // Set the data... + this.each(function () { + // We always store the camelCased key + dataUser.set(this, key, value); + }); + }, + null, + value, + arguments.length > 1, + null, + true + ); + }, - if (seed) { - // Reintegrate element matches to eliminate the need for sorting - if (matchedCount > 0) { - while (i--) { - if (!(unmatched[i] || setMatched[i])) { - setMatched[i] = pop.call(results); - } - } - } + removeData(key) { + return this.each(function () { + dataUser.remove(this, key); + }); + } + }); - // Discard index placeholder values to get only actual matches - setMatched = condense(setMatched); - } + jQuery.extend({ + queue(elem, type, data) { + var queue; - // Add matches to results - push.apply(results, setMatched); + if (elem) { + type = (type || "fx") + "queue"; + queue = dataPriv.get(elem, type); - // Seedless set matches succeeding multiple successful matchers stipulate sorting - if (outermost && !seed && setMatched.length > 0 && matchedCount + setMatchers.length > 1) { - jQuery.uniqueSort(results); - } - } + // Speed up dequeue by getting out quickly if this is just a lookup + if (data) { + if (!queue || Array.isArray(data)) { + queue = dataPriv.access(elem, type, jQuery.makeArray(data)); + } else { + queue.push(data); + } + } - // Override manipulation of globals by nested matchers - if (outermost) { - dirruns = dirrunsUnique; - outermostContext = contextBackup; - } + return queue || []; + } + }, - return unmatched; - }; + dequeue(elem, type) { + type = type || "fx"; + + var queue = jQuery.queue(elem, type), + startLength = queue.length, + fn = queue.shift(), + hooks = jQuery._queueHooks(elem, type), + next = function () { + jQuery.dequeue(elem, type); + }; - return bySet ? markFunction(superMatcher) : superMatcher; + // If the fx queue is dequeued, always remove the progress sentinel + if (fn === "inprogress") { + fn = queue.shift(); + startLength--; } - function compile( - selector, - match /* Internal Use Only */ - ) { - var i, - setMatchers = [], - elementMatchers = [], - cached = compilerCache[selector + " "]; + if (fn) { + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if (type === "fx") { + queue.unshift("inprogress"); + } + + // Clear up the last queue stop function + delete hooks.stop; - if (!cached) { - // Generate a function of recursive functions that can be used to check each element - if (!match) { - match = tokenize(selector); - } + fn.call(elem, next, hooks); + } - i = match.length; + if (!startLength && hooks) { + hooks.empty.fire(); + } + }, - while (i--) { - cached = matcherFromTokens(match[i]); + // Not public - generate a queueHooks object, or return the current one + _queueHooks(elem, type) { + var key = type + "queueHooks"; - if (cached[expando]) { - setMatchers.push(cached); - } else { - elementMatchers.push(cached); - } - } + return dataPriv.get(elem, key) || dataPriv.access(elem, key, { + empty: jQuery.Callbacks("once memory").add(function () { + dataPriv.remove(elem, [type + "queue", key]); + }) + }); + } + }); - // Cache the compiled function - cached = compilerCache(selector, matcherFromGroupMatchers(elementMatchers, setMatchers)); - // Save selector and tokenization - cached.selector = selector; - } + jQuery.fn.extend({ + queue(type, data) { + var setter = 2; - return cached; + if (typeof type !== "string") { + data = type; + type = "fx"; + setter--; } - /** - * A low-level selection function that works with jQuery's compiled - * selector functions - * @param {String|Function} selector A selector or a pre-compiled - * selector function built with jQuery selector compile - * @param {Element} context - * @param {Array} [results] - * @param {Array} [seed] A set of elements to match against - */ - function select(selector, context, results, seed) { - var i, - tokens, - token, - type, - find, - compiled = typeof selector === "function" && selector, - match = !seed && tokenize(selector = compiled.selector || selector); - - results = results || []; + if (arguments.length < setter) { + return jQuery.queue(this[0], type); + } - // Try to minimize operations if there is only one selector in the list and no seed - // (the latter of which guarantees us context) - if (match.length === 1) { - // Reduce context if the leading compound selector is an ID - tokens = match[0] = match[0].slice(0); + return data === undefined + ? this + : this.each(function () { + var queue = jQuery.queue(this, type, data); - if (tokens.length > 2 && (token = tokens[0]).type === "ID" && context.nodeType === 9 && documentIsHTML && Expr.relative[tokens[1].type]) { - context = (Expr.find.ID(token.matches[0].replace(runescape, funescape), context) || [])[0]; + // Ensure a hooks for this queue + jQuery._queueHooks(this, type); - if (!context) { - return results; - } else if (compiled) { - context = context.parentNode; // Precompiled matchers will still verify ancestry, so step up a level - } + if (type === "fx" && queue[0] !== "inprogress") { + jQuery.dequeue(this, type); + } + }); + }, - selector = selector.slice(tokens.shift().value.length); + dequeue(type) { + return this.each(function () { + jQuery.dequeue(this, type); + }); + }, + + clearQueue(type) { + return this.queue(type || "fx", []); + }, + + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise(type, obj) { + var tmp, + count = 1, + defer = jQuery.Deferred(), + elements = this, + i = this.length, + resolve = function () { + if (!--count) { + defer.resolveWith(elements, [elements]); } + }; - // Fetch a seed set for right-to-left matching - i = matchExpr.needsContext.test(selector) ? 0 : tokens.length; + if (typeof type !== "string") { + obj = type; + type = undefined; + } - while (i--) { - token = tokens[i]; + type = type || "fx"; - // Abort if we hit a combinator - if (Expr.relative[type = token.type]) { - break; - } + while (i--) { + tmp = dataPriv.get(elements[i], type + "queueHooks"); - if (find = Expr.find[type]) { - // Search, expanding context for leading sibling combinators - if (seed = find(token.matches[0].replace(runescape, funescape), rsibling.test(tokens[0].type) && testContext(context.parentNode) || context)) { - // If seed is empty or no tokens remain, we can return early - tokens.splice(i, 1); - selector = seed.length && toSelector(tokens); + if (tmp && tmp.empty) { + count++; + tmp.empty.add(resolve); + } + } - if (!selector) { - push.apply(results, seed); - return results; - } + resolve(); - break; - } - } - } - } + return defer.promise(obj); + } + }); + + var pnum = (/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/).source; + var rcssNum = new RegExp("^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i"); + var cssExpand = ["Top", "Right", "Bottom", "Left"]; + var documentElement = document.documentElement; + + var isAttached = function (elem) { + return jQuery.contains(elem.ownerDocument, elem); + }, + composed = { composed: true }; + + // Support: IE 9 - 11+, Edge 12 - 18+, iOS 10.0 - 10.2 only + // Check attachment across shadow DOM boundaries when possible (gh-3504) + // Support: iOS 10.0-10.2 only + // Early iOS 10 versions support `attachShadow` but not `getRootNode`, + // leading to errors. We need to check for `getRootNode`. + if (documentElement.getRootNode) { + isAttached = function (elem) { + return jQuery.contains(elem.ownerDocument, elem) || elem.getRootNode(composed) === elem.ownerDocument; + }; + } - // Compile and execute a filtering function if one is not provided - // Provide `match` to avoid retokenization if we modified the selector above - (compiled || compile(selector, match))(seed, context, !documentIsHTML, results, !context || rsibling.test(selector) && testContext(context.parentNode) || context); - return results; - } + var isHiddenWithinTree = function (elem, el) { + // isHiddenWithinTree might be called from jQuery#filter function; + // in that case, element will be second argument + elem = el || elem; + + // Inline style trumps all + return elem.style.display === "none" || elem.style.display === "" && // Otherwise, check computed style + // Support: Firefox <=43 - 45 + // Disconnected elements can have computed display: none, so first confirm that elem is + // in the document. + isAttached(elem) && jQuery.css(elem, "display") === "none"; + }; + + function adjustCSS(elem, prop, valueParts, tween) { + var adjusted, + scale, + maxIterations = 20, + currentValue = tween + ? function () { + return tween.cur(); + } + : function () { + return jQuery.css(elem, prop, ""); + }, + initial = currentValue(), + unit = valueParts && valueParts[3] || (jQuery.cssNumber[prop] ? "" : "px"), + // Starting value computation is required for potential unit mismatches + initialInUnit = elem.nodeType && (jQuery.cssNumber[prop] || unit !== "px" && +initial) && rcssNum.exec(jQuery.css(elem, prop)); - // One-time assignments - // Support: Android <=4.0 - 4.1+ - // Sort stability - support.sortStable = expando.split("").sort(sortOrder).join("") === expando; - // Initialize against the default document - setDocument(); + if (initialInUnit && initialInUnit[3] !== unit) { + // Support: Firefox <=54 + // Halve the iteration target value to prevent interference from CSS upper bounds (gh-2144) + initial = initial / 2; - // Support: Android <=4.0 - 4.1+ - // Detached nodes confoundingly follow *each other* - support.sortDetached = assert(function (el) { - // Should return 1, but returns 4 (following) - return el.compareDocumentPosition(document.createElement("fieldset")) & 1; - }); + // Trust units reported by jQuery.css + unit = unit || initialInUnit[3]; - jQuery.find = find; - // Deprecated - jQuery.expr[":"] = jQuery.expr.pseudos; - jQuery.unique = jQuery.uniqueSort; - // These have always been private, but they used to be documented as part of - // Sizzle so let's maintain them for now for backwards compatibility purposes. - find.compile = compile; - find.select = select; - find.setDocument = setDocument; - find.tokenize = tokenize; - find.escape = jQuery.escapeSelector; - find.getText = jQuery.text; - find.isXML = jQuery.isXMLDoc; - find.selectors = jQuery.expr; - find.support = jQuery.support; - find.uniqueSort = jQuery.uniqueSort; - })(); /* eslint-enable */ - - var dir = function (elem, dir, until) { - var matched = [], truncate = until !== undefined; - - while ((elem = elem[dir]) && elem.nodeType !== 9) { - if (elem.nodeType === 1) { - if (truncate && jQuery(elem).is(until)) { - break; - } + // Iteratively approximate from a nonzero starting point + initialInUnit = +initial || 1; + + while (maxIterations--) { + // Evaluate and update our best guess (doubling guesses that zero out). + // Finish if the scale equals or crosses 1 (making the old*new product non-positive). + jQuery.style(elem, prop, initialInUnit + unit); - matched.push(elem); + if ((1 - scale) * (1 - (scale = currentValue() / initial || 0.5)) <= 0) { + maxIterations = 0; } + + initialInUnit = initialInUnit / scale; } - return matched; - }; + initialInUnit = initialInUnit * 2; + jQuery.style(elem, prop, initialInUnit + unit); + + // Make sure we update the tween properties later on + valueParts = valueParts || []; + } - var siblings = function (n, elem) { - var matched = []; + if (valueParts) { + initialInUnit = +initialInUnit || +initial || 0; - for (; n; n = n.nextSibling) { - if (n.nodeType === 1 && n !== elem) { - matched.push(n); - } + // Apply relative offset (+=/-=) if specified + adjusted = valueParts[1] + ? initialInUnit + (valueParts[1] + 1) * valueParts[2] + : +valueParts[2]; + + if (tween) { + tween.unit = unit; + tween.start = initialInUnit; + tween.end = adjusted; } + } - return matched; - }; + return adjusted; + } - var rneedsContext = jQuery.expr.match.needsContext; - var rsingleTag = /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i; + var defaultDisplayMap = {}; - // Implement the identical functionality for filter and not - function winnow(elements, qualifier, not) { - if (isFunction(qualifier)) { - return jQuery.grep(elements, function (elem, i) { - return !!qualifier.call(elem, i, elem) !== not; - }); - } + function getDefaultDisplay(elem) { + var temp, + doc = elem.ownerDocument, + nodeName = elem.nodeName, + display = defaultDisplayMap[nodeName]; - // Single element - if (qualifier.nodeType) { - return jQuery.grep(elements, function (elem) { - return elem === qualifier !== not; - }); - } + if (display) { + return display; + } - // Arraylike of elements (jQuery, arguments, Array) - if (typeof qualifier !== "string") { - return jQuery.grep(elements, function (elem) { - return indexOf.call(qualifier, elem) > -1 !== not; - }); - } + temp = doc.body.appendChild(doc.createElement(nodeName)); + display = jQuery.css(temp, "display"); + temp.parentNode.removeChild(temp); - // Filtered directly for both simple and complex selectors - return jQuery.filter(qualifier, elements, not); + if (display === "none") { + display = "block"; } - jQuery.filter = function (expr, elems, not) { - var elem = elems[0]; + defaultDisplayMap[nodeName] = display; - if (not) { - expr = ":not(" + expr + ")"; - } + return display; + } - if (elems.length === 1 && elem.nodeType === 1) { - return jQuery.find.matchesSelector(elem, expr) ? [elem] : []; + function showHide(elements, show) { + var display, + elem, + values = [], + index = 0, + length = elements.length; + + // Determine new display value for elements that need to change + for (; index < length; index++) { + elem = elements[index]; + + if (!elem.style) { + continue; } - return jQuery.find.matches(expr, jQuery.grep(elems, function (elem) { - return elem.nodeType === 1; - })); - }; + display = elem.style.display; - jQuery.fn.extend({ - find(selector) { - var i, ret, len = this.length, self = this; + if (show) { + // Since we force visibility upon cascade-hidden elements, an immediate (and slow) + // check is required in this first loop unless we have a nonempty display value (either + // inline or about-to-be-restored) + if (display === "none") { + values[index] = dataPriv.get(elem, "display") || null; - if (typeof selector !== "string") { - return this.pushStack(jQuery(selector).filter(function () { - for (i = 0; i < len; i++) { - if (jQuery.contains(self[i], this)) { - return true; - } - } - })); + if (!values[index]) { + elem.style.display = ""; + } } - ret = this.pushStack([]); + if (elem.style.display === "" && isHiddenWithinTree(elem)) { + values[index] = getDefaultDisplay(elem); + } + } else { + if (display !== "none") { + values[index] = "none"; - for (i = 0; i < len; i++) { - jQuery.find(selector, self[i], ret); + // Remember what we're overwriting + dataPriv.set(elem, "display", display); } + } + } - return len > 1 ? jQuery.uniqueSort(ret) : ret; - }, - filter(selector) { - return this.pushStack(winnow(this, selector || [], false)); - }, - not(selector) { - return this.pushStack(winnow(this, selector || [], true)); - }, - is(selector) { - return !!winnow(this, // If this is a positional/relative selector, check membership in the returned set - // so $("p:first").is("p:last") won't return true for a doc with two "p". - typeof selector === "string" && rneedsContext.test(selector) ? jQuery(selector) : selector || [], false).length; + // Set the display of the elements in a second loop to avoid constant reflow + for (index = 0; index < length; index++) { + if (values[index] != null) { + elements[index].style.display = values[index]; } - }); + } - // Initialize a jQuery object - // A central reference to the root jQuery(document) - var rootjQuery, - // A simple way to check for HTML strings - // Prioritize #id over to avoid XSS via location.hash (trac-9521) - // Strict HTML recognition (trac-11290: must start with <) - // Shortcut simple #id case for speed - rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/, - init = jQuery.fn.init = function (selector, context, root) { - var match, elem; - - // HANDLE: $(""), $(null), $(undefined), $(false) - if (!selector) { - return this; + return elements; + } + + jQuery.fn.extend({ + show() { + return showHide(this, true); + }, + + hide() { + return showHide(this); + }, + + toggle(state) { + if (typeof state === "boolean") { + return state ? this.show() : this.hide(); + } + + return this.each(function () { + if (isHiddenWithinTree(this)) { + jQuery(this).show(); + } else { + jQuery(this).hide(); } + }); + } + }); - // Method init() accepts an alternate rootjQuery - // so migrate can support jQuery.sub (gh-2101) - root = root || rootjQuery; + var rcheckableType = /^(?:checkbox|radio)$/i; + var rtagName = /<([a-z][^\/\0>\x20\t\r\n\f]*)/i; + var rscriptType = /^$|^module$|\/(?:java|ecma)script/i; - // Handle HTML strings - if (typeof selector === "string") { - if (selector[0] === "<" && selector[selector.length - 1] === ">" && selector.length >= 3) { - // Assume that strings that start and end with <> are HTML and skip the regex check - match = [null, selector, null]; - } else { - match = rquickExpr.exec(selector); - } - - // Match html or make sure no context is specified for #id - if (match && (match[1] || !context)) { - // HANDLE: $(html) -> $(array) - if (match[1]) { - context = context instanceof jQuery ? context[0] : context; - // Option to run scripts is true for back-compat - // Intentionally let the error be thrown if parseHTML is not present - jQuery.merge(this, jQuery.parseHTML(match[1], context && context.nodeType ? context.ownerDocument || context : document, true)); - - // HANDLE: $(html, props) - if (rsingleTag.test(match[1]) && jQuery.isPlainObject(context)) { - for (match in context) { - // Properties of context are called as methods if possible - if (isFunction(this[match])) { - this[match](context[match]); - } else { - this.attr( - match, // ...and otherwise set as attributes - context[match] - ); - } - } - } + (function () { + var fragment = document.createDocumentFragment(), + div = fragment.appendChild(document.createElement("div")), + input = document.createElement("input"); - return this; - } else { - elem = document.getElementById(match[2]); // HANDLE: $(#id) + // Support: Android 4.0 - 4.3 only + // Check state lost if the name is set (trac-11217) + // Support: Windows Web Apps (WWA) + // `name` and `type` must use .setAttribute for WWA (trac-14901) + input.setAttribute("type", "radio"); - if (elem) { - // Inject the element directly into the jQuery object - this[0] = elem; - this.length = 1; - } + input.setAttribute("checked", "checked"); + input.setAttribute("name", "t"); + div.appendChild(input); - return this; - } - } else if (!context || context.jquery) { - return (context || root).find(selector); // HANDLE: $(expr, $(...)) - } else // (which is just equivalent to: $(context).find(expr) - { - return this.constructor(context).find(selector); // HANDLE: $(expr, context) - } - } else if (selector.nodeType) { - this[0] = selector; // HANDLE: $(DOMElement) - this.length = 1; - return this; - } else // Shortcut for document ready - if (isFunction(selector)) { - return root.ready !== undefined ? root.ready(selector) : // Execute immediately if ready is not present - selector(jQuery); // HANDLE: $(function) - } + // Support: Android <=4.1 only + // Older WebKit doesn't clone checked state correctly in fragments + support.checkClone = div.cloneNode(true).cloneNode(true).lastChild.checked; - return jQuery.makeArray(selector, this); - }; + // Support: IE <=11 only + // Make sure textarea (and checkbox) defaultValue is properly cloned + div.innerHTML = ""; - // Give the init function the jQuery prototype for later instantiation - init.prototype = jQuery.fn; - // Initialize central reference - rootjQuery = jQuery(document); - - var rparentsprev = /^(?:parents|prev(?:Until|All))/, - // Methods guaranteed to produce a unique set when starting from a unique set - guaranteedUnique = { - children: true, - contents: true, - next: true, - prev: true - }; + support.noCloneChecked = !!div.cloneNode(true).lastChild.defaultValue; - jQuery.fn.extend({ - has(target) { - var targets = jQuery(target, this), - l = targets.length; + // Support: IE <=9 only + // IE <=9 replaces "; + + support.option = !!div.lastChild; + })(); + + // We have to close these tags to support XHTML (trac-13200) + var wrapMap = { + // XHTML parsers do not magically insert elements in the + // same way that tag soup parsers do. So we cannot shorten + // this by omitting or other required elements. + thead: [1, "", "
"], + + col: [2, "", "
"], + tr: [2, "", "
"], + td: [3, "", "
"], + _default: [0, "", ""] + }; + + wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; + wrapMap.th = wrapMap.td; + + // Support: IE <=9 only + if (!support.option) { + wrapMap.optgroup = wrapMap.option = [1, ""]; + } - return this.filter(function () { - var i = 0; + function getAll(context, tag) { + // Support: IE <=9 - 11 only + // Use typeof to avoid zero-argument method invocation on host objects (trac-15151) + var ret; - for (; i < l; i++) { - if (jQuery.contains(this, targets[i])) { - return true; - } - } - }); - }, - closest(selectors, context) { - var cur, - i = 0, - l = this.length, - matched = [], - targets = typeof selectors !== "string" && jQuery(selectors); - - // Positional selectors never match, since there's no _selection_ context - if (!rneedsContext.test(selectors)) { - for (; i < l; i++) { - for (cur = this[i]; cur && cur !== context; cur = cur.parentNode) { - // Always skip document fragments - if (cur.nodeType < 11 && (targets ? targets.index(cur) > -1 : // Don't pass non-elements to jQuery#find - cur.nodeType === 1 && jQuery.find.matchesSelector(cur, selectors))) { - matched.push(cur); - break; - } - } - } - } + if (typeof context.getElementsByTagName !== "undefined") { + ret = context.getElementsByTagName(tag || "*"); + } else if (typeof context.querySelectorAll !== "undefined") { + ret = context.querySelectorAll(tag || "*"); + } else { + ret = []; + } - return this.pushStack(matched.length > 1 ? jQuery.uniqueSort(matched) : matched); - }, - index(elem) { - // No argument, return index in parent - if (!elem) { - return this[0] && this[0].parentNode ? this.first().prevAll().length : -1; - } + if (tag === undefined || tag && nodeName(context, tag)) { + return jQuery.merge([context], ret); + } - // Index in selector - if (typeof elem === "string") { - return indexOf.call(jQuery(elem), this[0]); - } + return ret; + } - // Locate the position of the desired element - return indexOf.call(this, // If it receives a jQuery object, the first element is used - elem.jquery ? elem[0] : elem); - }, - add(selector, context) { - return this.pushStack(jQuery.uniqueSort(jQuery.merge(this.get(), jQuery(selector, context)))); - }, - addBack(selector) { - return this.add(selector == null ? this.prevObject : this.prevObject.filter(selector)); - } - }); + // Mark scripts as having already been evaluated + function setGlobalEval(elems, refElements) { + var i = 0, l = elems.length; - function sibling(cur, dir) { - while ((cur = cur[dir]) && cur.nodeType !== 1) {} - return cur; + for (; i < l; i++) { + dataPriv.set(elems[i], "globalEval", !refElements || dataPriv.get(refElements[i], "globalEval")); } + } - jQuery.each( - { - parent(elem) { - var parent = elem.parentNode; + var rhtml = /<|&#?\w+;/; + + function buildFragment(elems, context, scripts, selection, ignored) { + var elem, + tmp, + tag, + wrap, + attached, + j, + fragment = context.createDocumentFragment(), + nodes = [], + i = 0, + l = elems.length; + + for (; i < l; i++) { + elem = elems[i]; + + if (elem || elem === 0) { + // Add nodes directly + if (toType(elem) === "object") { + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge(nodes, elem.nodeType ? [elem] : elem); + + // Convert non-html into a text node + } else if (!rhtml.test(elem)) { + nodes.push(context.createTextNode(elem)); + + // Convert html into DOM nodes + } else { + tmp = tmp || fragment.appendChild(context.createElement("div")); - return parent && parent.nodeType !== 11 ? parent : null; - }, - parents(elem) { - return dir(elem, "parentNode"); - }, - parentsUntil(elem, _i, until) { - return dir(elem, "parentNode", until); - }, - next(elem) { - return sibling(elem, "nextSibling"); - }, - prev(elem) { - return sibling(elem, "previousSibling"); - }, - nextAll(elem) { - return dir(elem, "nextSibling"); - }, - prevAll(elem) { - return dir(elem, "previousSibling"); - }, - nextUntil(elem, _i, until) { - return dir(elem, "nextSibling", until); - }, - prevUntil(elem, _i, until) { - return dir(elem, "previousSibling", until); - }, - siblings(elem) { - return siblings((elem.parentNode || {}).firstChild, elem); - }, - children(elem) { - return siblings(elem.firstChild); - }, - contents(elem) { - if (elem.contentDocument != null && // Support: IE 11+ - // elements with no `data` attribute has an object - // `contentDocument` with a `null` prototype. - getProto(elem.contentDocument)) { - return elem.contentDocument; - } + // Deserialize a standard representation + tag = (rtagName.exec(elem) || ["", ""])[1].toLowerCase(); - // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only - // Treat the template element as a regular one in browsers that - // don't support it. - if (nodeName(elem, "template")) { - elem = elem.content || elem; - } + wrap = wrapMap[tag] || wrapMap._default; + tmp.innerHTML = wrap[1] + jQuery.htmlPrefilter(elem) + wrap[2]; - return jQuery.merge([], elem.childNodes); - } - }, - function (name, fn) { - jQuery.fn[name] = function (until, selector) { - var matched = jQuery.map(this, fn, until); + // Descend through wrappers to the right content + j = wrap[0]; - if (name.slice(-5) !== "Until") { - selector = until; + while (j--) { + tmp = tmp.lastChild; } - if (selector && typeof selector === "string") { - matched = jQuery.filter(selector, matched); - } + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge(nodes, tmp.childNodes); - if (this.length > 1) { - // Remove duplicates - if (!guaranteedUnique[name]) { - jQuery.uniqueSort(matched); - } + // Remember the top-level container + tmp = fragment.firstChild; - // Reverse order for parents* and prev-derivatives - if (rparentsprev.test(name)) { - matched.reverse(); - } - } + // Ensure the created nodes are orphaned (trac-12392) + tmp.textContent = ""; + } + } + } - return this.pushStack(matched); - }; + // Remove wrapper from fragment + fragment.textContent = ""; + + i = 0; + + while (elem = nodes[i++]) { + // Skip elements already in the context collection (trac-4087) + if (selection && jQuery.inArray(elem, selection) > -1) { + if (ignored) { + ignored.push(elem); + } + + continue; } - ); - var rnothtmlwhite = /[^\x20\t\r\n\f]+/g; + attached = isAttached(elem); - // Convert String-formatted options into Object-formatted ones - function createOptions(options) { - var object = {}; + // Append to fragment + tmp = getAll(fragment.appendChild(elem), "script"); - jQuery.each(options.match(rnothtmlwhite) || [], function (_, flag) { - object[flag] = true; - }); + // Preserve script evaluation history + if (attached) { + setGlobalEval(tmp); + } - return object; - } - - /* - * Create a callback list using the following parameters: - * - * options: an optional list of space-separated options that will change how - * the callback list behaves or a more traditional option object - * - * By default a callback list will act like an event callback list and can be - * "fired" multiple times. - * - * Possible options: - * - * once: will ensure the callback list can only be fired once (like a Deferred) - * - * memory: will keep track of previous values and will call any callback added - * after the list has been fired right away with the latest "memorized" - * values (like a Deferred) - * - * unique: will ensure a callback can only be added once (no duplicate in the list) - * - * stopOnFalse: interrupt callings when a callback returns false - * - */ - jQuery.Callbacks = function (options) { - // Convert options from String-formatted to Object-formatted if needed - // (we check in cache first) - options = typeof options === "string" ? createOptions(options) : jQuery.extend({}, options); - - var // Flag to know if list is currently firing - firing, - // Last fire value for non-forgettable lists - memory, - // Flag to know if list was already fired - fired, - // Flag to prevent firing - locked, - // Actual callback list - list = [], - // Queue of execution data for repeatable lists - queue = [], - // Index of currently firing callback (modified by add/remove as needed) - firingIndex = -1, - // Fire callbacks - fire = function () { - // Enforce single-firing - locked = locked || options.once; - // Execute callbacks for all pending executions, - // respecting firingIndex overrides and runtime changes - fired = firing = true; - - for (; queue.length; firingIndex = -1) { - memory = queue.shift(); - - while (++firingIndex < list.length) { - // Run callback and check for early termination - if (list[firingIndex].apply(memory[0], memory[1]) === false && options.stopOnFalse) { - // Jump to end and forget the data so .add doesn't re-fire - firingIndex = list.length; - memory = false; - } - } - } + // Capture executables + if (scripts) { + j = 0; - // Forget the data if we're done with it - if (!options.memory) { - memory = false; + while (elem = tmp[j++]) { + if (rscriptType.test(elem.type || "")) { + scripts.push(elem); } + } + } + } - firing = false; + return fragment; + } - // Clean up if we're done firing for good - if (locked) { - // Keep an empty list if we have data for future add calls - if (memory) { - list = []; - } else { - list = ""; // Otherwise, this object is spent - } - } - }, - // Actual Callbacks object - self = { - add() { - if (list) { - // If we have memory from a past run, we should fire after adding - if (memory && !firing) { - firingIndex = list.length - 1; - queue.push(memory); - } + var rtypenamespace = /^([^.]*)(?:\.(.+)|)/; - (function add(args) { - jQuery.each(args, function (_, arg) { - if (isFunction(arg)) { - if (!options.unique || !self.has(arg)) { - list.push(arg); - } - } else if (arg && arg.length && toType(arg) !== "string") { - // Inspect recursively - add(arg); - } - }); - })(arguments); + function returnTrue() { + return true; + } - if (memory && !firing) { - fire(); - } - } + function returnFalse() { + return false; + } - return this; - }, - remove() { - jQuery.each(arguments, function (_, arg) { - var index; + function on(elem, types, selector, data, fn, one) { + var origFn, type; - while ((index = jQuery.inArray(arg, list, index)) > -1) { - list.splice(index, 1); + // Types can be a map of types/handlers + if (typeof types === "object") { + // ( types-Object, selector, data ) + if (typeof selector !== "string") { + // ( types-Object, data ) + data = data || selector; - // Handle firing indexes - if (index <= firingIndex) { - firingIndex--; - } - } - }); + selector = undefined; + } - return this; - }, - has(fn) { - return fn ? jQuery.inArray(fn, list) > -1 : list.length > 0; - }, - empty() { - if (list) { - list = []; - } + for (type in types) { + on(elem, type, selector, data, types[type], one); + } - return this; - }, - disable() { - locked = queue = []; - list = memory = ""; - return this; - }, - disabled() { - return !list; - }, - lock() { - locked = queue = []; + return elem; + } - if (!memory && !firing) { - list = memory = ""; - } + if (data == null && fn == null) { + // ( types, fn ) + fn = selector; - return this; - }, - locked() { - return !!locked; - }, - fireWith(context, args) { - if (!locked) { - args = args || []; - args = [context, args.slice ? args.slice() : args]; - queue.push(args); - - if (!firing) { - fire(); - } - } + data = selector = undefined; + } else if (fn == null) { + if (typeof selector === "string") { + // ( types, selector, fn ) + fn = data; - return this; - }, - fire() { - self.fireWith(this, arguments); - return this; - }, - fired() { - return !!fired; - } - }; + data = undefined; + } else { + // ( types, data, fn ) + fn = data; - return self; - }; + data = selector; + selector = undefined; + } + } - function Identity(v) { - return v; + if (fn === false) { + fn = returnFalse; + } else if (!fn) { + return elem; } - function Thrower(ex) { - throw ex; + if (one === 1) { + origFn = fn; + + fn = function (event) { + // Can use an empty set, since event contains the info + jQuery().off(event); + + return origFn.apply(this, arguments); + }; + + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || (origFn.guid = jQuery.guid++); } - function adoptValue(value, resolve, reject, noValue) { - var method; + return elem.each(function () { + jQuery.event.add(this, types, fn, data, selector); + }); + } - try { - // Check for promise aspect first to privilege synchronous behavior - if (value && isFunction(method = value.promise)) { - method.call(value).done(resolve).fail(reject); - } else if (value && isFunction(method = value.then)) { - method.call( - value, // Other thenables - resolve, - reject - ); - } else { - // Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer: - // * false: [ value ].slice( 0 ) => resolve( value ) - // * true: [ value ].slice( 1 ) => resolve() - resolve.apply( - undefined, // Other non-thenables - [value].slice(noValue) - ); - } - } catch(value) { - // Support: Android 4.0 only - // Strict mode functions invoked without .call/.apply get global-object context - reject.apply( - undefined, // For Promises/A+, convert exceptions into rejections - [value] - ); + /* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ + jQuery.event = { + global: {}, + + add(elem, types, handler, data, selector) { + var handleObjIn, + eventHandle, + tmp, + events, + t, + handleObj, + special, + handlers, + type, + namespaces, + origType, + elemData = dataPriv.get(elem); + + // Only attach events to objects that accept data + if (!acceptData(elem)) { + return; } - } - jQuery.extend({ - Deferred(func) { - var tuples = [ - // action, add listener, callbacks, - // ... .then handlers, argument index, [final state] - [ - "notify", - "progress", - jQuery.Callbacks("memory"), - jQuery.Callbacks("memory"), - 2 - ], - [ - "resolve", - "done", - jQuery.Callbacks("once memory"), - jQuery.Callbacks("once memory"), - 0, - "resolved" - ], - [ - "reject", - "fail", - jQuery.Callbacks("once memory"), - jQuery.Callbacks("once memory"), - 1, - "rejected" - ] - ], - state = "pending", - promise = { - state() { - return state; - }, - always() { - deferred.done(arguments).fail(arguments); - return this; - }, - "catch"(fn) { - return promise.then(null, fn); - }, - pipe() /* fnDone, fnFail, fnProgress */ { - var fns = arguments; - - return jQuery.Deferred(function (newDefer) { - jQuery.each(tuples, function (_i, tuple) { - // Map tuples (progress, done, fail) to arguments (done, fail, progress) - var fn = isFunction(fns[tuple[4]]) && fns[tuple[4]]; - - // deferred.progress(function() { bind to newDefer or newDefer.notify }) - // deferred.done(function() { bind to newDefer or newDefer.resolve }) - // deferred.fail(function() { bind to newDefer or newDefer.reject }) - deferred[tuple[1]](function () { - var returned = fn && fn.apply(this, arguments); - - if (returned && isFunction(returned.promise)) { - returned.promise().progress(newDefer.notify).done(newDefer.resolve).fail(newDefer.reject); - } else { - newDefer[tuple[0] + "With"](this, fn ? [returned] : arguments); - } - }); - }); + // Caller can pass in an object of custom data in lieu of the handler + if (handler.handler) { + handleObjIn = handler; + handler = handleObjIn.handler; + selector = handleObjIn.selector; + } - fns = null; - }).promise(); - }, - then(onFulfilled, onRejected, onProgress) { - var maxDepth = 0; - - function resolve(depth, deferred, handler, special) { - return function () { - var that = this, - args = arguments, - mightThrow = function () { - var returned, then; - - // Support: Promises/A+ section 2.3.3.3.3 - // https://promisesaplus.com/#point-59 - // Ignore double-resolution attempts - if (depth < maxDepth) { - return; - } + // Ensure that invalid selectors throw exceptions at attach time + // Evaluate against documentElement in case elem is a non-element node (e.g., document) + if (selector) { + jQuery.find.matchesSelector(documentElement, selector); + } - returned = handler.apply(that, args); + // Make sure that the handler has a unique ID, used to find/remove it later + if (!handler.guid) { + handler.guid = jQuery.guid++; + } - // Support: Promises/A+ section 2.3.1 - // https://promisesaplus.com/#point-48 - if (returned === deferred.promise()) { - throw new TypeError("Thenable self-resolution"); - } + // Init the element's event structure and main handler, if this is the first + if (!(events = elemData.events)) { + events = elemData.events = Object.create(null); + } - // Support: Promises/A+ sections 2.3.3.1, 3.5 - // https://promisesaplus.com/#point-54 - // https://promisesaplus.com/#point-75 - // Retrieve `then` only once - then = returned && (// Support: Promises/A+ section 2.3.4 - // https://promisesaplus.com/#point-64 - // Only check objects and functions for thenability - typeof returned === "object" || typeof returned === "function") && returned.then; - - // Handle a returned thenable - if (isFunction(then)) { - // Special processors (notify) just wait for resolution - if (special) { - then.call(returned, resolve(maxDepth, deferred, Identity, special), resolve(maxDepth, deferred, Thrower, special)); - } else { - // ...and disregard older resolution values - maxDepth++; // Normal processors (resolve) also hook into progress - then.call(returned, resolve(maxDepth, deferred, Identity, special), resolve(maxDepth, deferred, Thrower, special), resolve(maxDepth, deferred, Identity, deferred.notifyWith)); - } - } else { - // Only substitute handlers pass on context - // and multiple values (non-spec behavior) - if (handler !== Identity) { - that = undefined; // Handle all other returned values - args = [returned]; - } + if (!(eventHandle = elemData.handle)) { + eventHandle = elemData.handle = function (e) { + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type + ? jQuery.event.dispatch.apply(elem, arguments) + : undefined; + }; + } - // Process the value(s) - // Default process is resolve - (special || deferred.resolveWith)(that, args); - } - }, - // Only normal processors (resolve) catch and reject exceptions - process = special - ? mightThrow - : function () { - try { - mightThrow(); - } catch(e) { - if (jQuery.Deferred.exceptionHook) { - jQuery.Deferred.exceptionHook(e, process.error); - } + // Handle multiple events separated by a space + types = (types || "").match(rnothtmlwhite) || [""]; - // Support: Promises/A+ section 2.3.3.3.4.1 - // https://promisesaplus.com/#point-61 - // Ignore post-resolution exceptions - if (depth + 1 >= maxDepth) { - // Only substitute handlers pass on context - // and multiple values (non-spec behavior) - if (handler !== Thrower) { - that = undefined; - args = [e]; - } - - deferred.rejectWith(that, args); - } - } - }; - - // Support: Promises/A+ section 2.3.3.3.1 - // https://promisesaplus.com/#point-57 - // Re-resolve promises immediately to dodge false rejection from - // subsequent errors - if (depth) { - process(); - } else { - // Call an optional hook to record the error, in case of exception - // since it's otherwise lost when execution goes async - if (jQuery.Deferred.getErrorHook) { - process.error = jQuery.Deferred.getErrorHook(); - } else // returning the stack, not an error instance, jQuery just passes - // it directly to `console.warn` so both will work; an instance - // just better cooperates with source maps. - if (jQuery.Deferred.getStackHook) { - process.error = jQuery.Deferred.getStackHook(); // The deprecated alias of the above. While the name suggests - } + t = types.length; - window.setTimeout(process); - } - }; - } + while (t--) { + tmp = rtypenamespace.exec(types[t]) || []; + type = origType = tmp[1]; + namespaces = (tmp[2] || "").split(".").sort(); - return jQuery.Deferred(function (newDefer) { - // progress_handlers.add( ... ) - tuples[0][3].add(resolve(0, newDefer, isFunction(onProgress) ? onProgress : Identity, newDefer.notifyWith)); - // fulfilled_handlers.add( ... ) - tuples[1][3].add(resolve(0, newDefer, isFunction(onFulfilled) ? onFulfilled : Identity)); - // rejected_handlers.add( ... ) - tuples[2][3].add(resolve(0, newDefer, isFunction(onRejected) ? onRejected : Thrower)); - }).promise(); - }, - promise(obj) { - return obj != null ? jQuery.extend(obj, promise) : promise; - } - }, - deferred = {}; - - // Add list-specific methods - jQuery.each(tuples, function (i, tuple) { - var list = tuple[2], stateString = tuple[5]; - - // promise.progress = list.add - // promise.done = list.add - // promise.fail = list.add - promise[tuple[1]] = list.add; - - // Handle state - if (stateString) { - list.add( - function () { - // state = "resolved" (i.e., fulfilled) - // state = "rejected" - state = stateString; - }, - // rejected_callbacks.disable - // fulfilled_callbacks.disable - tuples[3 - i][2].disable, - // rejected_handlers.disable - // fulfilled_handlers.disable - tuples[3 - i][3].disable, - // progress_callbacks.lock - tuples[0][2].lock, - // progress_handlers.lock - tuples[0][3].lock - ); - } + // There *must* be a type, no attaching namespace-only handlers + if (!type) { + continue; + } - // progress_handlers.fire - // fulfilled_handlers.fire - // rejected_handlers.fire - list.add(tuple[3].fire); + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[type] || {}; - // deferred.notify = function() { deferred.notifyWith(...) } - // deferred.resolve = function() { deferred.resolveWith(...) } - // deferred.reject = function() { deferred.rejectWith(...) } - deferred[tuple[0]] = function () { - deferred[tuple[0] + "With"](this === deferred ? undefined : this, arguments); - return this; - }; + // If selector defined, determine special event api type, otherwise given type + type = (selector ? special.delegateType : special.bindType) || type; - // deferred.notifyWith = list.fireWith - // deferred.resolveWith = list.fireWith - // deferred.rejectWith = list.fireWith - deferred[tuple[0] + "With"] = list.fireWith; - }); + // Update special based on newly reset type + special = jQuery.event.special[type] || {}; - // Make the deferred a promise - promise.promise(deferred); + // handleObj is passed to all event handlers + handleObj = jQuery.extend( + { + type, + origType, + data, + handler, + guid: handler.guid, + selector, + needsContext: selector && jQuery.expr.match.needsContext.test(selector), + namespace: namespaces.join(".") + }, + handleObjIn + ); - // Call given func if any - if (func) { - func.call(deferred, deferred); - } + // Init the event handler queue if we're the first + if (!(handlers = events[type])) { + handlers = events[type] = []; + handlers.delegateCount = 0; - // All done! - return deferred; - }, - when(singleValue) { - var // count of uncompleted subordinates - remaining = arguments.length, - // count of unprocessed arguments - i = remaining, - // subordinate fulfillment data - resolveContexts = Array(i), - resolveValues = slice.call(arguments), - // the primary Deferred - primary = jQuery.Deferred(), - // subordinate callback factory - updateFunc = function (i) { - return function (value) { - resolveContexts[i] = this; - resolveValues[i] = arguments.length > 1 ? slice.call(arguments) : value; - - if (!--remaining) { - primary.resolveWith(resolveContexts, resolveValues); - } - }; - }; + // Only use addEventListener if the special events handler returns false + if (!special.setup || special.setup.call(elem, data, namespaces, eventHandle) === false) { + if (elem.addEventListener) { + elem.addEventListener(type, eventHandle); + } + } + } - // Single- and empty arguments are adopted like Promise.resolve - if (remaining <= 1) { - adoptValue(singleValue, primary.done(updateFunc(i)).resolve, primary.reject, !remaining); + if (special.add) { + special.add.call(elem, handleObj); - // Use .then() to unwrap secondary thenables (cf. gh-3000) - if (primary.state() === "pending" || isFunction(resolveValues[i] && resolveValues[i].then)) { - return primary.then(); + if (!handleObj.handler.guid) { + handleObj.handler.guid = handler.guid; } } - // Multiple arguments are aggregated like Promise.all array elements - while (i--) { - adoptValue(resolveValues[i], updateFunc(i), primary.reject); + // Add to the element's handler list, delegates in front + if (selector) { + handlers.splice(handlers.delegateCount++, 0, handleObj); + } else { + handlers.push(handleObj); } - return primary.promise(); + // Keep track of which events have ever been used, for event optimization + jQuery.event.global[type] = true; } - }); + }, - // These usually indicate a programmer mistake during development, - // warn about them ASAP rather than swallowing them by default. - var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/; + // Detach an event or set of events from an element + remove(elem, types, handler, selector, mappedTypes) { + var j, + origCount, + tmp, + events, + t, + handleObj, + special, + handlers, + type, + namespaces, + origType, + elemData = dataPriv.hasData(elem) && dataPriv.get(elem); - // If `jQuery.Deferred.getErrorHook` is defined, `asyncError` is an error - // captured before the async barrier to get the original error cause - // which may otherwise be hidden. - jQuery.Deferred.exceptionHook = function (error, asyncError) { - // Support: IE 8 - 9 only - // Console exists when dev tools are open, which can happen at any time - if (window.console && window.console.warn && error && rerrorNames.test(error.name)) { - window.console.warn("jQuery.Deferred exception: " + error.message, error.stack, asyncError); + if (!elemData || !(events = elemData.events)) { + return; } - }; - jQuery.readyException = function (error) { - window.setTimeout(function () { - throw error; - }); - }; + // Once for each type.namespace in types; type may be omitted + types = (types || "").match(rnothtmlwhite) || [""]; - // The deferred used on DOM ready - var readyList = jQuery.Deferred(); + t = types.length; - jQuery.fn.ready = function (fn) { - readyList.then(fn).// Wrap jQuery.readyException in a function so that the lookup - // happens at the time of error handling instead of callback - // registration. - catch(function (error) { - jQuery.readyException(error); - }); + while (t--) { + tmp = rtypenamespace.exec(types[t]) || []; + type = origType = tmp[1]; + namespaces = (tmp[2] || "").split(".").sort(); - return this; - }; + // Unbind all events (on this namespace, if provided) for the element + if (!type) { + for (type in events) { + jQuery.event.remove(elem, type + types[t], handler, selector, true); + } - jQuery.extend({ - // Is the DOM ready to be used? Set to true once it occurs. - isReady: false, - // A counter to track how many items to wait for before - // the ready event fires. See trac-6781 - readyWait: 1, - ready(wait) { - // Abort if there are pending holds or we're already ready - if (wait === true ? --jQuery.readyWait : jQuery.isReady) { - return; + continue; } - // Remember that the DOM is ready - jQuery.isReady = true; + special = jQuery.event.special[type] || {}; + type = (selector ? special.delegateType : special.bindType) || type; + handlers = events[type] || []; + tmp = tmp[2] && new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)"); - // If a normal DOM Ready event fired, decrement, and wait if need be - if (wait !== true && --jQuery.readyWait > 0) { - return; - } + // Remove matching events + origCount = j = handlers.length; - // If there are functions bound, to execute - readyList.resolveWith(document, [jQuery]); - } - }); + while (j--) { + handleObj = handlers[j]; - jQuery.ready.then = readyList.then; + if ((mappedTypes || origType === handleObj.origType) && (!handler || handler.guid === handleObj.guid) && (!tmp || tmp.test(handleObj.namespace)) && (!selector || selector === handleObj.selector || selector === "**" && handleObj.selector)) { + handlers.splice(j, 1); - // The ready event handler and self cleanup method - function completed() { - document.removeEventListener("DOMContentLoaded", completed); - window.removeEventListener("load", completed); - jQuery.ready(); - } + if (handleObj.selector) { + handlers.delegateCount--; + } - // Catch cases where $(document).ready() is called - // after the browser event has already occurred. - // Support: IE <=9 - 10 only - // Older IE sometimes signals "interactive" too soon - if (document.readyState === "complete" || document.readyState !== "loading" && !document.documentElement.doScroll) { - // Handle it asynchronously to allow scripts the opportunity to delay ready - window.setTimeout(jQuery.ready); - } else { - // Use the handy event callback - document.addEventListener("DOMContentLoaded", completed); - // A fallback to window.onload, that will always work - window.addEventListener("load", completed); - } - - // Multifunctional method to get and set values of a collection - // The value/s can optionally be executed if it's a function - var access = function ( - elems, - fn, - key, - value, - chainable, - emptyGet, - raw - ) { - var i = 0, - len = elems.length, - bulk = key == null; + if (special.remove) { + special.remove.call(elem, handleObj); + } + } + } - // Sets many values - if (toType(key) === "object") { - chainable = true; + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if (origCount && !handlers.length) { + if (!special.teardown || special.teardown.call(elem, namespaces, elemData.handle) === false) { + jQuery.removeEvent(elem, type, elemData.handle); + } - for (i in key) { - access(elems, fn, i, key[i], true, emptyGet, raw); + delete events[type]; } - } else if (value !== undefined) { - chainable = true; // Sets one value + } - if (!isFunction(value)) { - raw = true; - } + // Remove data and the expando if it's no longer used + if (jQuery.isEmptyObject(events)) { + dataPriv.remove(elem, "handle events"); + } + }, - if (bulk) { - // Bulk operations run against the entire set - if (raw) { - fn.call(elems, value); - fn = null; - } else { - bulk = fn; // ...except when executing function values + dispatch(nativeEvent) { + var i, + j, + ret, + matched, + handleObj, + handlerQueue, + args = new Array(arguments.length), + // Make a writable jQuery.Event from the native event object + event = jQuery.event.fix(nativeEvent), + handlers = (dataPriv.get(this, "events") || Object.create(null))[event.type] || [], + special = jQuery.event.special[event.type] || {}; - fn = function (elem, _key, value) { - return bulk.call(jQuery(elem), value); - }; - } - } + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[0] = event; - if (fn) { - for (; i < len; i++) { - fn(elems[i], key, raw ? value : value.call(elems[i], i, fn(elems[i], key))); - } - } + for (i = 1; i < arguments.length; i++) { + args[i] = arguments[i]; } - if (chainable) { - return elems; - } + event.delegateTarget = this; - // Gets - if (bulk) { - return fn.call(elems); + // Call the preDispatch hook for the mapped type, and let it bail if desired + if (special.preDispatch && special.preDispatch.call(this, event) === false) { + return; } - return len ? fn(elems[0], key) : emptyGet; - }; + // Determine handlers + handlerQueue = jQuery.event.handlers.call(this, event, handlers); - // Matches dashed string for camelizing - var rmsPrefix = /^-ms-/, - rdashAlpha = /-([a-z])/g; + // Run delegates first; they may want to stop propagation beneath us + i = 0; - // Used by camelCase as callback to replace() - function fcamelCase(_all, letter) { - return letter.toUpperCase(); - } + while ((matched = handlerQueue[i++]) && !event.isPropagationStopped()) { + event.currentTarget = matched.elem; + j = 0; - // Convert dashed to camelCase; used by the css and data modules - // Support: IE <=9 - 11, Edge 12 - 15 - // Microsoft forgot to hump their vendor prefix (trac-9572) - function camelCase(string) { - return string.replace(rmsPrefix, "ms-").replace(rdashAlpha, fcamelCase); - } + while ((handleObj = matched.handlers[j++]) && !event.isImmediatePropagationStopped()) { + // If the event is namespaced, then each handler is only invoked if it is + // specially universal or its namespaces are a superset of the event's. + if (!event.rnamespace || handleObj.namespace === false || event.rnamespace.test(handleObj.namespace)) { + event.handleObj = handleObj; + event.data = handleObj.data; + ret = ((jQuery.event.special[handleObj.origType] || {}).handle || handleObj.handler).apply(matched.elem, args); - var acceptData = function (owner) { - // Accepts only: - // - Node - // - Node.ELEMENT_NODE - // - Node.DOCUMENT_NODE - // - Object - // - Any - return owner.nodeType === 1 || owner.nodeType === 9 || !+owner.nodeType; - }; + if (ret !== undefined) { + if ((event.result = ret) === false) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } - function Data() { - this.expando = jQuery.expando + Data.uid++; - } + // Call the postDispatch hook for the mapped type + if (special.postDispatch) { + special.postDispatch.call(this, event); + } - Data.uid = 1; + return event.result; + }, - Data.prototype = { - cache(owner) { - // Check if the owner object already has a cache - var value = owner[this.expando]; + handlers(event, handlers) { + var i, + handleObj, + sel, + matchedHandlers, + matchedSelectors, + handlerQueue = [], + delegateCount = handlers.delegateCount, + cur = event.target; + + // Find delegate handlers + if (delegateCount && // Support: IE <=9 + // Black-hole SVG instance trees (trac-13180) + cur.nodeType && // Support: Firefox <=42 + // Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861) + // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click + // Support: IE 11 only + // ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343) + !(event.type === "click" && event.button >= 1)) { + for (; cur !== this; cur = cur.parentNode || this) { + // Don't check non-elements (trac-13208) + // Don't process clicks on disabled elements (trac-6911, trac-8165, trac-11382, trac-11764) + if (cur.nodeType === 1 && !(event.type === "click" && cur.disabled === true)) { + matchedHandlers = []; + matchedSelectors = {}; + + for (i = 0; i < delegateCount; i++) { + handleObj = handlers[i]; + + // Don't conflict with Object.prototype properties (trac-13203) + sel = handleObj.selector + " "; + + if (matchedSelectors[sel] === undefined) { + matchedSelectors[sel] = handleObj.needsContext + ? jQuery(sel, this).index(cur) > -1 + : jQuery.find(sel, this, null, [cur]).length; + } - // If not, create one - if (!value) { - value = {}; + if (matchedSelectors[sel]) { + matchedHandlers.push(handleObj); + } + } - // We can accept data for non-element nodes in modern browsers, - // but we should not, see trac-8335. - // Always return an empty object. - if (acceptData(owner)) { - // If it is a node unlikely to be stringify-ed or looped over - // use plain assignment - if (owner.nodeType) { - owner[this.expando] = value; - } else // configurable must be true to allow the property to be - // deleted when data is removed - { - Object.defineProperty( - owner, // Otherwise secure it in a non-enumerable property - this.expando, - { value, configurable: true } - ); + if (matchedHandlers.length) { + handlerQueue.push({ elem: cur, handlers: matchedHandlers }); } } } + } - return value; - }, - set(owner, data, value) { - var prop, cache = this.cache(owner); + // Add the remaining (directly-bound) handlers + cur = this; - // Handle: [ owner, key, value ] args - // Always use camelCase key (gh-2257) - if (typeof data === "string") { - cache[camelCase(data)] = value; - } else { - // Copy the properties one-by-one to the cache object - for (prop in data) { - cache[camelCase(prop)] = data[prop]; // Handle: [ owner, { properties } ] args - } - } + if (delegateCount < handlers.length) { + handlerQueue.push({ elem: cur, handlers: handlers.slice(delegateCount) }); + } - return cache; - }, - get(owner, key) { - return key === undefined ? this.cache(owner) : // Always use camelCase key (gh-2257) - owner[this.expando] && owner[this.expando][camelCase(key)]; - }, - access(owner, key, value) { - // In cases where either: - // - // 1. No key was specified - // 2. A string key was specified, but no value provided - // - // Take the "read" path and allow the get method to determine - // which value to return, respectively either: - // - // 1. The entire cache object - // 2. The data stored at the key - // - if (key === undefined || key && typeof key === "string" && value === undefined) { - return this.get(owner, key); + return handlerQueue; + }, + + addProp(name, hook) { + Object.defineProperty(jQuery.Event.prototype, name, { + enumerable: true, + configurable: true, + + get: isFunction(hook) + ? function () { + if (this.originalEvent) { + return hook(this.originalEvent); + } + } + : function () { + if (this.originalEvent) { + return this.originalEvent[name]; + } + }, + + set(value) { + Object.defineProperty(this, name, { enumerable: true, configurable: true, writable: true, value }); } + }); + }, - // When the key is not a string, or both a key and value - // are specified, set or extend (existing objects) with either: - // - // 1. An object of properties - // 2. A key and value - // - this.set(owner, key, value); - // Since the "set" path can have two possible entry points - // return the expected data based on which path was taken[*] - return value !== undefined ? value : key; + fix(originalEvent) { + return originalEvent[jQuery.expando] ? originalEvent : new jQuery.Event(originalEvent); + }, + + special: { + load: { + // Prevent triggered image.load events from bubbling to window.load + noBubble: true }, - remove(owner, key) { - var i, cache = owner[this.expando]; - if (cache === undefined) { - return; - } + click: { + // Utilize native event to ensure correct state for checkable inputs + setup(data) { + // For mutual compressibility with _default, replace `this` access with a local var. + // `|| data` is dead code meant only to preserve the variable through minification. + var el = this || data; - if (key !== undefined) { - // Support array or space separated string of keys - if (Array.isArray(key)) { - // If key is an array of keys... - // We always set camelCase keys, so remove that. - key = key.map(camelCase); - } else { - key = camelCase(key); - // If a key with the spaces exists, use it. - // Otherwise, create an array by matching non-whitespace - key = key in cache ? [key] : key.match(rnothtmlwhite) || []; + // Claim the first handler + if (rcheckableType.test(el.type) && el.click && nodeName(el, "input")) { + // dataPriv.set( el, "click", ... ) + leverageNative(el, "click", true); } - i = key.length; + // Return false to allow normal processing in the caller + return false; + }, + + trigger(data) { + // For mutual compressibility with _default, replace `this` access with a local var. + // `|| data` is dead code meant only to preserve the variable through minification. + var el = this || data; - while (i--) { - delete cache[key[i]]; + // Force setup before triggering a click + if (rcheckableType.test(el.type) && el.click && nodeName(el, "input")) { + leverageNative(el, "click"); } + + // Return non-false to allow normal event-path propagation + return true; + }, + + // For cross-browser consistency, suppress native .click() on links + // Also prevent it if we're currently inside a leveraged native-event stack + _default(event) { + var target = event.target; + + return rcheckableType.test(target.type) && target.click && nodeName(target, "input") && dataPriv.get(target, "click") || nodeName(target, "a"); } + }, - // Remove the expando if there's no more data - if (key === undefined || jQuery.isEmptyObject(cache)) { - // Support: Chrome <=35 - 45 - // Webkit & Blink performance suffers when deleting properties - // from DOM nodes, so set to undefined instead - // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted) - if (owner.nodeType) { - owner[this.expando] = undefined; - } else { - delete owner[this.expando]; + beforeunload: { + postDispatch(event) { + // Support: Firefox 20+ + // Firefox doesn't alert if the returnValue field is not set. + if (event.result !== undefined && event.originalEvent) { + event.originalEvent.returnValue = event.result; } } - }, - hasData(owner) { - var cache = owner[this.expando]; + } + } + }; - return cache !== undefined && !jQuery.isEmptyObject(cache); + // Ensure the presence of an event listener that handles manually-triggered + // synthetic events by interrupting progress until reinvoked in response to + // *native* events that it fires directly, ensuring that state changes have + // already occurred before other listeners are invoked. + function leverageNative(el, type, isSetup) { + // Missing `isSetup` indicates a trigger call, which must force setup through jQuery.event.add + if (!isSetup) { + if (dataPriv.get(el, type) === undefined) { + jQuery.event.add(el, type, returnTrue); } - }; - var dataPriv = new Data(); - var dataUser = new Data(); + return; + } - // Implementation Summary - // - // 1. Enforce API surface and semantic compatibility with 1.9.x branch - // 2. Improve the module's maintainability by reducing the storage - // paths to a single mechanism. - // 3. Use the same single mechanism to support "private" and "user" data. - // 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData) - // 5. Avoid exposing implementation details on user objects (eg. expando properties) - // 6. Provide a clear path for implementation upgrade to WeakMap in 2014 - var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, - rmultiDash = /[A-Z]/g; - - function getData(data) { - if (data === "true") { - return true; - } + // Register the controller as a special universal handler for all event namespaces + dataPriv.set(el, type, false); - if (data === "false") { - return false; - } + jQuery.event.add(el, type, { + namespace: false, - if (data === "null") { - return null; - } + handler(event) { + var result, saved = dataPriv.get(this, type); - // Only convert to a number if it doesn't change the string - if (data === +data + "") { - return +data; - } + if (event.isTrigger & 1 && this[type]) { + // Interrupt processing of the outer synthetic .trigger()ed event + if (!saved) { + // Store arguments for use when handling the inner native event + // There will always be at least one argument (an event object), so this array + // will not be confused with a leftover capture object. + saved = slice.call(arguments); - if (rbrace.test(data)) { - return JSON.parse(data); - } + dataPriv.set(this, type, saved); - return data; - } + // Trigger the native event and capture its result + this[type](); - function dataAttr(elem, key, data) { - var name; + result = dataPriv.get(this, type); + dataPriv.set(this, type, false); - // If nothing was found internally, try to fetch any - // data from the HTML5 data-* attribute - if (data === undefined && elem.nodeType === 1) { - name = "data-" + key.replace(rmultiDash, "-$&").toLowerCase(); - data = elem.getAttribute(name); + if (saved !== result) { + // Cancel the outer synthetic event + event.stopImmediatePropagation(); - if (typeof data === "string") { - try { - data = getData(data); - } catch(e) {} + event.preventDefault(); - // Make sure we set the data so it isn't changed later - dataUser.set(elem, key, data); - } else { - data = undefined; + return result; + } + + // If this is an inner synthetic event for an event with a bubbling surrogate + // (focus or blur), assume that the surrogate already propagated from triggering + // the native event and prevent that from happening again here. + // This technically gets the ordering wrong w.r.t. to `.trigger()` (in which the + // bubbling surrogate propagates *after* the non-bubbling base), but that seems + // less bad than duplication. + } else if ((jQuery.event.special[type] || {}).delegateType) { + event.stopPropagation(); + } + + // If this is a native event triggered above, everything is now in order + // Fire an inner synthetic event with the original arguments + } else if (saved) { + // ...and capture the result + dataPriv.set(this, type, jQuery.event.trigger(saved[0], saved.slice(1), this)); + + // Abort handling of the native event by all jQuery handlers while allowing + // native handlers on the same element to run. On target, this is achieved + // by stopping immediate propagation just on the jQuery event. However, + // the native event is re-wrapped by a jQuery one on each level of the + // propagation so the only way to stop it for jQuery is to stop it for + // everyone via native `stopPropagation()`. This is not a problem for + // focus/blur which don't bubble, but it does also stop click on checkboxes + // and radios. We accept this limitation. + event.stopPropagation(); + + event.isImmediatePropagationStopped = returnTrue; } } + }); + } - return data; + jQuery.removeEvent = function (elem, type, handle) { + // This "if" is needed for plain objects + if (elem.removeEventListener) { + elem.removeEventListener(type, handle); } + }; - jQuery.extend({ - hasData(elem) { - return dataUser.hasData(elem) || dataPriv.hasData(elem); - }, - data(elem, name, data) { - return dataUser.access(elem, name, data); - }, - removeData(elem, name) { - dataUser.remove(elem, name); - }, - _data(elem, name, data) { - return dataPriv.access(elem, name, data); - }, - _removeData(elem, name) { - dataPriv.remove(elem, name); - } - }); + jQuery.Event = function (src, props) { + // Allow instantiation without the 'new' keyword + if (!(this instanceof jQuery.Event)) { + return new jQuery.Event(src, props); + } - jQuery.fn.extend({ - data(key, value) { - var i, - name, - data, - elem = this[0], - attrs = elem && elem.attributes; + // Event object + if (src && src.type) { + this.originalEvent = src; + this.type = src.type; - // Gets all values - if (key === undefined) { - if (this.length) { - data = dataUser.get(elem); + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = src.defaultPrevented || src.defaultPrevented === undefined && // Support: Android <=2.3 only + src.returnValue === false ? returnTrue : returnFalse; - if (elem.nodeType === 1 && !dataPriv.get(elem, "hasDataAttrs")) { - i = attrs.length; + // Create target properties + // Support: Safari <=6 - 7 only + // Target should not be a text node (trac-504, trac-13143) + this.target = src.target && src.target.nodeType === 3 ? src.target.parentNode : src.target; - while (i--) { - // Support: IE 11 only - // The attrs elements can be null (trac-14894) - if (attrs[i]) { - name = attrs[i].name; - - if (name.indexOf("data-") === 0) { - name = camelCase(name.slice(5)); - dataAttr(elem, name, data[name]); - } - } - } + this.currentTarget = src.currentTarget; + this.relatedTarget = src.relatedTarget; - dataPriv.set(elem, "hasDataAttrs", true); - } - } + // Event type + } else { + this.type = src; + } - return data; - } + // Put explicitly provided properties onto the event object + if (props) { + jQuery.extend(this, props); + } - // Sets multiple values - if (typeof key === "object") { - return this.each(function () { - dataUser.set(this, key); - }); - } + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || Date.now(); - return access( - this, - function (value) { - var data; - - // The calling jQuery object (element matches) is not empty - // (and therefore has an element appears at this[ 0 ]) and the - // `value` parameter was not undefined. An empty jQuery object - // will result in `undefined` for elem = this[ 0 ] which will - // throw an exception if an attempt to read a data cache is made. - if (elem && value === undefined) { - // Attempt to get data from the cache - // The key will always be camelCased in Data - data = dataUser.get(elem, key); - - if (data !== undefined) { - return data; - } + // Mark it as fixed + this[jQuery.expando] = true; + }; - // Attempt to "discover" the data in - // HTML5 custom data-* attrs - data = dataAttr(elem, key); + // jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding + // https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html + jQuery.Event.prototype = { + constructor: jQuery.Event, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse, + isSimulated: false, - if (data !== undefined) { - return data; - } + preventDefault() { + var e = this.originalEvent; - // We tried really hard, but the data doesn't exist. - return; - } + this.isDefaultPrevented = returnTrue; - // Set the data... - this.each(function () { - // We always store the camelCased key - dataUser.set(this, key, value); - }); - }, - null, - value, - arguments.length > 1, - null, - true - ); - }, - removeData(key) { - return this.each(function () { - dataUser.remove(this, key); - }); + if (e && !this.isSimulated) { + e.preventDefault(); } - }); - - jQuery.extend({ - queue(elem, type, data) { - var queue; + }, - if (elem) { - type = (type || "fx") + "queue"; - queue = dataPriv.get(elem, type); + stopPropagation() { + var e = this.originalEvent; - // Speed up dequeue by getting out quickly if this is just a lookup - if (data) { - if (!queue || Array.isArray(data)) { - queue = dataPriv.access(elem, type, jQuery.makeArray(data)); - } else { - queue.push(data); - } - } + this.isPropagationStopped = returnTrue; - return queue || []; - } - }, - dequeue(elem, type) { - type = type || "fx"; + if (e && !this.isSimulated) { + e.stopPropagation(); + } + }, - var queue = jQuery.queue(elem, type), - startLength = queue.length, - fn = queue.shift(), - hooks = jQuery._queueHooks(elem, type), - next = function () { - jQuery.dequeue(elem, type); - }; + stopImmediatePropagation() { + var e = this.originalEvent; - // If the fx queue is dequeued, always remove the progress sentinel - if (fn === "inprogress") { - fn = queue.shift(); - startLength--; - } + this.isImmediatePropagationStopped = returnTrue; - if (fn) { - // Add a progress sentinel to prevent the fx queue from being - // automatically dequeued - if (type === "fx") { - queue.unshift("inprogress"); - } + if (e && !this.isSimulated) { + e.stopImmediatePropagation(); + } - // Clear up the last queue stop function - delete hooks.stop; - fn.call(elem, next, hooks); + this.stopPropagation(); + } + }; + + // Includes all common event props including KeyEvent and MouseEvent specific props + jQuery.each( + { + altKey: true, + bubbles: true, + cancelable: true, + changedTouches: true, + ctrlKey: true, + detail: true, + eventPhase: true, + metaKey: true, + pageX: true, + pageY: true, + shiftKey: true, + view: true, + "char": true, + code: true, + charCode: true, + key: true, + keyCode: true, + button: true, + buttons: true, + clientX: true, + clientY: true, + offsetX: true, + offsetY: true, + pointerId: true, + pointerType: true, + screenX: true, + screenY: true, + targetTouches: true, + toElement: true, + touches: true, + which: true + }, + jQuery.event.addProp + ); + + jQuery.each({ focus: "focusin", blur: "focusout" }, function (type, delegateType) { + function focusMappedHandler(nativeEvent) { + if (document.documentMode) { + // Support: IE 11+ + // Attach a single focusin/focusout handler on the document while someone wants + // focus/blur. This is because the former are synchronous in IE while the latter + // are async. In other browsers, all those handlers are invoked synchronously. + // `handle` from private data would already wrap the event, but we need + // to change the `type` here. + var handle = dataPriv.get(this, "handle"), + event = jQuery.event.fix(nativeEvent); + + event.type = nativeEvent.type === "focusin" ? "focus" : "blur"; + event.isSimulated = true; + + // First, handle focusin/focusout + handle(nativeEvent); + + // ...then, handle focus/blur + // + // focus/blur don't bubble while focusin/focusout do; simulate the former by only + // invoking the handler at the lower level. + if (event.target === event.currentTarget) { + // The setup part calls `leverageNative`, which, in turn, calls + // `jQuery.event.add`, so event handle will already have been set + // by this point. + handle(event); } + } else { + // For non-IE browsers, attach a single capturing handler on the document + // while someone wants focusin/focusout. + jQuery.event.simulate(delegateType, nativeEvent.target, jQuery.event.fix(nativeEvent)); + } + } - if (!startLength && hooks) { - hooks.empty.fire(); - } - }, - _queueHooks(elem, type) { - var key = type + "queueHooks"; + jQuery.event.special[type] = { + // Utilize native event if possible so blur/focus sequence is correct + setup() { + var attaches; - return dataPriv.get(elem, key) || dataPriv.access(elem, key, { - empty: jQuery.Callbacks("once memory").add(function () { - dataPriv.remove(elem, [type + "queue", key]); - }) - }); - } - }); + // Claim the first handler + // dataPriv.set( this, "focus", ... ) + // dataPriv.set( this, "blur", ... ) + leverageNative(this, type, true); - jQuery.fn.extend({ - queue(type, data) { - var setter = 2; + if (document.documentMode) { + // Support: IE 9 - 11+ + // We use the same native handler for focusin & focus (and focusout & blur) + // so we need to coordinate setup & teardown parts between those events. + // Use `delegateType` as the key as `type` is already used by `leverageNative`. + attaches = dataPriv.get(this, delegateType); - if (typeof type !== "string") { - data = type; - type = "fx"; - setter--; - } + if (!attaches) { + this.addEventListener(delegateType, focusMappedHandler); + } - if (arguments.length < setter) { - return jQuery.queue(this[0], type); + dataPriv.set(this, delegateType, (attaches || 0) + 1); + } else { + // Return false to allow normal processing in the caller + return false; } + }, - return data === undefined - ? this - : this.each(function () { - var queue = jQuery.queue(this, type, data); - - // Ensure a hooks for this queue - jQuery._queueHooks(this, type); + trigger() { + // Force setup before trigger + leverageNative(this, type); - if (type === "fx" && queue[0] !== "inprogress") { - jQuery.dequeue(this, type); - } - }); - }, - dequeue(type) { - return this.each(function () { - jQuery.dequeue(this, type); - }); - }, - clearQueue(type) { - return this.queue(type || "fx", []); + // Return non-false to allow normal event-path propagation + return true; }, - promise(type, obj) { - var tmp, - count = 1, - defer = jQuery.Deferred(), - elements = this, - i = this.length, - resolve = function () { - if (!--count) { - defer.resolveWith(elements, [elements]); - } - }; - if (typeof type !== "string") { - obj = type; - type = undefined; - } - - type = type || "fx"; + teardown() { + var attaches; - while (i--) { - tmp = dataPriv.get(elements[i], type + "queueHooks"); + if (document.documentMode) { + attaches = dataPriv.get(this, delegateType) - 1; - if (tmp && tmp.empty) { - count++; - tmp.empty.add(resolve); + if (!attaches) { + this.removeEventListener(delegateType, focusMappedHandler); + dataPriv.remove(this, delegateType); + } else { + dataPriv.set(this, delegateType, attaches); } + } else { + // Return false to indicate standard teardown should be applied + return false; } + }, - resolve(); - return defer.promise(obj); - } - }); - - var pnum = (/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/).source; - var rcssNum = new RegExp("^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i"); - var cssExpand = ["Top", "Right", "Bottom", "Left"]; - var documentElement = document.documentElement; - - var isAttached = function (elem) { - return jQuery.contains(elem.ownerDocument, elem); + // Suppress native focus or blur if we're currently inside + // a leveraged native-event stack + _default(event) { + return dataPriv.get(event.target, type); }, - composed = { composed: true }; - - // Support: IE 9 - 11+, Edge 12 - 18+, iOS 10.0 - 10.2 only - // Check attachment across shadow DOM boundaries when possible (gh-3504) - // Support: iOS 10.0-10.2 only - // Early iOS 10 versions support `attachShadow` but not `getRootNode`, - // leading to errors. We need to check for `getRootNode`. - if (documentElement.getRootNode) { - isAttached = function (elem) { - return jQuery.contains(elem.ownerDocument, elem) || elem.getRootNode(composed) === elem.ownerDocument; - }; - } - var isHiddenWithinTree = function (elem, el) { - // isHiddenWithinTree might be called from jQuery#filter function; - // in that case, element will be second argument - elem = el || elem; - // Inline style trumps all - return elem.style.display === "none" || elem.style.display === "" && // Otherwise, check computed style - // Support: Firefox <=43 - 45 - // Disconnected elements can have computed display: none, so first confirm that elem is - // in the document. - isAttached(elem) && jQuery.css(elem, "display") === "none"; + delegateType }; - function adjustCSS(elem, prop, valueParts, tween) { - var adjusted, - scale, - maxIterations = 20, - currentValue = tween - ? function () { - return tween.cur(); + // Support: Firefox <=44 + // Firefox doesn't have focus(in | out) events + // Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787 + // + // Support: Chrome <=48 - 49, Safari <=9.0 - 9.1 + // focus(in | out) events fire after focus & blur events, + // which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order + // Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857 + // + // Support: IE 9 - 11+ + // To preserve relative focusin/focus & focusout/blur event order guaranteed on the 3.x branch, + // attach a single handler for both events in IE. + jQuery.event.special[delegateType] = { + setup() { + // Handle: regular nodes (via `this.ownerDocument`), window + // (via `this.document`) & document (via `this`). + var doc = this.ownerDocument || this.document || this, + dataHolder = document.documentMode ? this : doc, + attaches = dataPriv.get(dataHolder, delegateType); + + // Support: IE 9 - 11+ + // We use the same native handler for focusin & focus (and focusout & blur) + // so we need to coordinate setup & teardown parts between those events. + // Use `delegateType` as the key as `type` is already used by `leverageNative`. + if (!attaches) { + if (document.documentMode) { + this.addEventListener(delegateType, focusMappedHandler); + } else { + doc.addEventListener(type, focusMappedHandler, true); } - : function () { - return jQuery.css(elem, prop, ""); - }, - initial = currentValue(), - unit = valueParts && valueParts[3] || (jQuery.cssNumber[prop] ? "" : "px"), - // Starting value computation is required for potential unit mismatches - initialInUnit = elem.nodeType && (jQuery.cssNumber[prop] || unit !== "px" && +initial) && rcssNum.exec(jQuery.css(elem, prop)); + } - if (initialInUnit && initialInUnit[3] !== unit) { - // Support: Firefox <=54 - // Halve the iteration target value to prevent interference from CSS upper bounds (gh-2144) - initial = initial / 2; - // Trust units reported by jQuery.css - unit = unit || initialInUnit[3]; - // Iteratively approximate from a nonzero starting point - initialInUnit = +initial || 1; + dataPriv.set(dataHolder, delegateType, (attaches || 0) + 1); + }, - while (maxIterations--) { - // Evaluate and update our best guess (doubling guesses that zero out). - // Finish if the scale equals or crosses 1 (making the old*new product non-positive). - jQuery.style(elem, prop, initialInUnit + unit); + teardown() { + var doc = this.ownerDocument || this.document || this, + dataHolder = document.documentMode ? this : doc, + attaches = dataPriv.get(dataHolder, delegateType) - 1; - if ((1 - scale) * (1 - (scale = currentValue() / initial || 0.5)) <= 0) { - maxIterations = 0; + if (!attaches) { + if (document.documentMode) { + this.removeEventListener(delegateType, focusMappedHandler); + } else { + doc.removeEventListener(type, focusMappedHandler, true); } - initialInUnit = initialInUnit / scale; + dataPriv.remove(dataHolder, delegateType); + } else { + dataPriv.set(dataHolder, delegateType, attaches); } - - initialInUnit = initialInUnit * 2; - jQuery.style(elem, prop, initialInUnit + unit); - // Make sure we update the tween properties later on - valueParts = valueParts || []; } + }; + }); + + // Create mouseenter/leave events using mouseover/out and event-time checks + // so that event delegation works in jQuery. + // Do the same for pointerenter/pointerleave and pointerover/pointerout + // + // Support: Safari 7 only + // Safari sends mouseenter too often; see: + // https://bugs.chromium.org/p/chromium/issues/detail?id=470258 + // for the description of the bug (it existed in older Chrome versions as well). + jQuery.each( + { + mouseenter: "mouseover", + mouseleave: "mouseout", + pointerenter: "pointerover", + pointerleave: "pointerout" + }, + function (orig, fix) { + jQuery.event.special[orig] = { + delegateType: fix, + bindType: fix, + + handle(event) { + var ret, + target = this, + related = event.relatedTarget, + handleObj = event.handleObj; + + // For mouseenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if (!related || related !== target && !jQuery.contains(target, related)) { + event.type = handleObj.origType; + ret = handleObj.handler.apply(this, arguments); + event.type = fix; + } - if (valueParts) { - initialInUnit = +initialInUnit || +initial || 0; - // Apply relative offset (+=/-=) if specified - adjusted = valueParts[1] ? initialInUnit + (valueParts[1] + 1) * valueParts[2] : +valueParts[2]; - - if (tween) { - tween.unit = unit; - tween.start = initialInUnit; - tween.end = adjusted; + return ret; } - } - - return adjusted; + }; } + ); + + jQuery.fn.extend({ + on(types, selector, data, fn) { + return on(this, types, selector, data, fn); + }, + + one(types, selector, data, fn) { + return on(this, types, selector, data, fn, 1); + }, + + off(types, selector, fn) { + var handleObj, type; + + if (types && types.preventDefault && types.handleObj) { + // ( event ) dispatched jQuery.Event + handleObj = types.handleObj; + + jQuery(types.delegateTarget).off( + handleObj.namespace + ? handleObj.origType + "." + handleObj.namespace + : handleObj.origType, + handleObj.selector, + handleObj.handler + ); - var defaultDisplayMap = {}; + return this; + } - function getDefaultDisplay(elem) { - var temp, - doc = elem.ownerDocument, - nodeName = elem.nodeName, - display = defaultDisplayMap[nodeName]; + if (typeof types === "object") { + // ( types-object [, selector] ) + for (type in types) { + this.off(type, selector, types[type]); + } - if (display) { - return display; + return this; } - temp = doc.body.appendChild(doc.createElement(nodeName)); - display = jQuery.css(temp, "display"); - temp.parentNode.removeChild(temp); + if (selector === false || typeof selector === "function") { + // ( types [, fn] ) + fn = selector; - if (display === "none") { - display = "block"; + selector = undefined; } - defaultDisplayMap[nodeName] = display; - return display; + if (fn === false) { + fn = returnFalse; + } + + return this.each(function () { + jQuery.event.remove(this, types, fn, selector); + }); + } + }); + + var // Support: IE <=10 - 11, Edge 12 - 13 only + // In IE/Edge using regex groups here causes severe slowdowns. + // See https://connect.microsoft.com/IE/feedback/details/1736512/ + rnoInnerhtml = /\s*$/g; + + // Prefer a tbody over its parent table for containing new rows + function manipulationTarget(elem, content) { + if (nodeName(elem, "table") && nodeName(content.nodeType !== 11 ? content : content.firstChild, "tr")) { + return jQuery(elem).children("tbody")[0] || elem; } - function showHide(elements, show) { - var display, - elem, - values = [], - index = 0, - length = elements.length; + return elem; + } - // Determine new display value for elements that need to change - for (; index < length; index++) { - elem = elements[index]; + // Replace/restore the type attribute of script elements for safe DOM manipulation + function disableScript(elem) { + elem.type = (elem.getAttribute("type") !== null) + "/" + elem.type; - if (!elem.style) { - continue; - } + return elem; + } - display = elem.style.display; + function restoreScript(elem) { + if ((elem.type || "").slice(0, 5) === "true/") { + elem.type = elem.type.slice(5); + } else { + elem.removeAttribute("type"); + } - if (show) { - // Since we force visibility upon cascade-hidden elements, an immediate (and slow) - // check is required in this first loop unless we have a nonempty display value (either - // inline or about-to-be-restored) - if (display === "none") { - values[index] = dataPriv.get(elem, "display") || null; + return elem; + } - if (!values[index]) { - elem.style.display = ""; - } - } + function cloneCopyEvent(src, dest) { + var i, + l, + type, + pdataOld, + udataOld, + udataCur, + events; + + if (dest.nodeType !== 1) { + return; + } - if (elem.style.display === "" && isHiddenWithinTree(elem)) { - values[index] = getDefaultDisplay(elem); - } - } else { - if (display !== "none") { - values[index] = "none"; - // Remember what we're overwriting - dataPriv.set(elem, "display", display); - } - } - } + // 1. Copy private data: events, handlers, etc. + if (dataPriv.hasData(src)) { + pdataOld = dataPriv.get(src); + events = pdataOld.events; - // Set the display of the elements in a second loop to avoid constant reflow - for (index = 0; index < length; index++) { - if (values[index] != null) { - elements[index].style.display = values[index]; + if (events) { + dataPriv.remove(dest, "handle events"); + + for (type in events) { + for ((i = 0, l = events[type].length); i < l; i++) { + jQuery.event.add(dest, type, events[type][i]); + } } } - - return elements; } - jQuery.fn.extend({ - show() { - return showHide(this, true); - }, - hide() { - return showHide(this); - }, - toggle(state) { - if (typeof state === "boolean") { - return state ? this.show() : this.hide(); - } + // 2. Copy user data + if (dataUser.hasData(src)) { + udataOld = dataUser.access(src); + udataCur = jQuery.extend({}, udataOld); + dataUser.set(dest, udataCur); + } + } - return this.each(function () { - if (isHiddenWithinTree(this)) { - jQuery(this).show(); - } else { - jQuery(this).hide(); - } - }); - } - }); + // Fix IE bugs, see support tests + function fixInput(src, dest) { + var nodeName = dest.nodeName.toLowerCase(); - var rcheckableType = /^(?:checkbox|radio)$/i; - var rtagName = /<([a-z][^\/\0>\x20\t\r\n\f]*)/i; - var rscriptType = /^$|^module$|\/(?:java|ecma)script/i; + // Fails to persist the checked state of a cloned checkbox or radio button. + if (nodeName === "input" && rcheckableType.test(src.type)) { + dest.checked = src.checked; - (function () { - var fragment = document.createDocumentFragment(), - div = fragment.appendChild(document.createElement("div")), - input = document.createElement("input"); + // Fails to return the selected option to the default selected state when cloning options + } else if (nodeName === "input" || nodeName === "textarea") { + dest.defaultValue = src.defaultValue; + } + } - // Support: Android 4.0 - 4.3 only - // Check state lost if the name is set (trac-11217) - // Support: Windows Web Apps (WWA) - // `name` and `type` must use .setAttribute for WWA (trac-14901) - input.setAttribute("type", "radio"); - input.setAttribute("checked", "checked"); - input.setAttribute("name", "t"); - div.appendChild(input); - // Support: Android <=4.1 only - // Older WebKit doesn't clone checked state correctly in fragments - support.checkClone = div.cloneNode(true).cloneNode(true).lastChild.checked; - // Support: IE <=11 only - // Make sure textarea (and checkbox) defaultValue is properly cloned - div.innerHTML = ""; - support.noCloneChecked = !!div.cloneNode(true).lastChild.defaultValue; - // Support: IE <=9 only - // IE <=9 replaces "; - support.option = !!div.lastChild; - })(); - - // We have to close these tags to support XHTML (trac-13200) - var wrapMap = { - // XHTML parsers do not magically insert elements in the - // same way that tag soup parsers do. So we cannot shorten - // this by omitting or other required elements. - thead: [1, "", "
"], - col: [ - 2, - "", - "
" - ], - tr: [2, "", "
"], - td: [ - 3, - "", - "
" - ], - _default: [0, "", ""] - }; + function domManip(collection, args, callback, ignored) { + // Flatten any nested arrays + args = flat(args); - wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; - wrapMap.th = wrapMap.td; + var fragment, + first, + scripts, + hasScripts, + node, + doc, + i = 0, + l = collection.length, + iNoClone = l - 1, + value = args[0], + valueIsFunction = isFunction(value); - // Support: IE <=9 only - if (!support.option) { - wrapMap.optgroup = wrapMap.option = [ - 1, - "" - ]; - } - - function getAll(context, tag) { - // Support: IE <=9 - 11 only - // Use typeof to avoid zero-argument method invocation on host objects (trac-15151) - var ret; - - if (typeof context.getElementsByTagName !== "undefined") { - ret = context.getElementsByTagName(tag || "*"); - } else if (typeof context.querySelectorAll !== "undefined") { - ret = context.querySelectorAll(tag || "*"); - } else { - ret = []; - } + // We can't cloneNode fragments that contain checked, in WebKit + if (valueIsFunction || l > 1 && typeof value === "string" && !support.checkClone && rchecked.test(value)) { + return collection.each(function (index) { + var self = collection.eq(index); - if (tag === undefined || tag && nodeName(context, tag)) { - return jQuery.merge([context], ret); - } + if (valueIsFunction) { + args[0] = value.call(this, index, self.html()); + } - return ret; + domManip(self, args, callback, ignored); + }); } - // Mark scripts as having already been evaluated - function setGlobalEval(elems, refElements) { - var i = 0, l = elems.length; + if (l) { + fragment = buildFragment(args, collection[0].ownerDocument, false, collection, ignored); + first = fragment.firstChild; - for (; i < l; i++) { - dataPriv.set(elems[i], "globalEval", !refElements || dataPriv.get(refElements[i], "globalEval")); + if (fragment.childNodes.length === 1) { + fragment = first; } - } - var rhtml = /<|&#?\w+;/; + // Require either new content or an interest in ignored elements to invoke the callback + if (first || ignored) { + scripts = jQuery.map(getAll(fragment, "script"), disableScript); + hasScripts = scripts.length; - function buildFragment( - elems, - context, - scripts, - selection, - ignored - ) { - var elem, - tmp, - tag, - wrap, - attached, - j, - fragment = context.createDocumentFragment(), - nodes = [], - i = 0, - l = elems.length; - - for (; i < l; i++) { - elem = elems[i]; - - if (elem || elem === 0) { - // Add nodes directly - if (toType(elem) === "object") { - // Support: Android <=4.0 only, PhantomJS 1 only - // push.apply(_, arraylike) throws on ancient WebKit - jQuery.merge(nodes, elem.nodeType ? [elem] : elem); - } else if (!rhtml.test(elem)) { - nodes.push(context.createTextNode(elem)); // Convert non-html into a text node - } else { - tmp = tmp || fragment.appendChild(context.createElement("div")); // Convert html into DOM nodes - // Deserialize a standard representation - tag = (rtagName.exec(elem) || ["", ""])[1].toLowerCase(); - wrap = wrapMap[tag] || wrapMap._default; - tmp.innerHTML = wrap[1] + jQuery.htmlPrefilter(elem) + wrap[2]; - // Descend through wrappers to the right content - j = wrap[0]; - - while (j--) { - tmp = tmp.lastChild; - } + // Use the original fragment for the last item + // instead of the first because it can end up + // being emptied incorrectly in certain situations (trac-8070). + for (; i < l; i++) { + node = fragment; + + if (i !== iNoClone) { + node = jQuery.clone(node, true, true); - // Support: Android <=4.0 only, PhantomJS 1 only - // push.apply(_, arraylike) throws on ancient WebKit - jQuery.merge(nodes, tmp.childNodes); - // Remember the top-level container - tmp = fragment.firstChild; - // Ensure the created nodes are orphaned (trac-12392) - tmp.textContent = ""; + // Keep references to cloned scripts for later restoration + if (hasScripts) { + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge(scripts, getAll(node, "script")); + } } + + callback.call(collection[i], node, i); } - } - // Remove wrapper from fragment - fragment.textContent = ""; - i = 0; + if (hasScripts) { + doc = scripts[scripts.length - 1].ownerDocument; - while (elem = nodes[i++]) { - // Skip elements already in the context collection (trac-4087) - if (selection && jQuery.inArray(elem, selection) > -1) { - if (ignored) { - ignored.push(elem); - } + // Re-enable scripts + jQuery.map(scripts, restoreScript); - continue; + // Evaluate executable scripts on first document insertion + for (i = 0; i < hasScripts; i++) { + node = scripts[i]; + + if (rscriptType.test(node.type || "") && !dataPriv.access(node, "globalEval") && jQuery.contains(doc, node)) { + if (node.src && (node.type || "").toLowerCase() !== "module") { + // Optional AJAX dependency, but won't run scripts if not present + if (jQuery._evalUrl && !node.noModule) { + jQuery._evalUrl(node.src, { nonce: node.nonce || node.getAttribute("nonce") }, doc); + } + } else { + // Unwrap a CDATA section containing script contents. This shouldn't be + // needed as in XML documents they're already not visible when + // inspecting element contents and in HTML documents they have no + // meaning but we're preserving that logic for backwards compatibility. + // This will be removed completely in 4.0. See gh-4904. + DOMEval(node.textContent.replace(rcleanScript, ""), node, doc); + } + } + } } + } + } - attached = isAttached(elem); - // Append to fragment - tmp = getAll(fragment.appendChild(elem), "script"); + return collection; + } - // Preserve script evaluation history - if (attached) { - setGlobalEval(tmp); - } + function remove(elem, selector, keepData) { + var node, + nodes = selector ? jQuery.filter(selector, elem) : elem, + i = 0; - // Capture executables - if (scripts) { - j = 0; + for (; (node = nodes[i]) != null; i++) { + if (!keepData && node.nodeType === 1) { + jQuery.cleanData(getAll(node)); + } - while (elem = tmp[j++]) { - if (rscriptType.test(elem.type || "")) { - scripts.push(elem); - } - } + if (node.parentNode) { + if (keepData && isAttached(node)) { + setGlobalEval(getAll(node, "script")); } - } - return fragment; + node.parentNode.removeChild(node); + } } - var rtypenamespace = /^([^.]*)(?:\.(.+)|)/; + return elem; + } - function returnTrue() { - return true; - } + jQuery.extend({ + htmlPrefilter(html) { + return html; + }, - function returnFalse() { - return false; - } + clone(elem, dataAndEvents, deepDataAndEvents) { + var i, + l, + srcElements, + destElements, + clone = elem.cloneNode(true), + inPage = isAttached(elem); - function on(elem, types, selector, data, fn, one) { - var origFn, type; + // Fix IE cloning issues + if (!support.noCloneChecked && (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem)) { + // We eschew jQuery#find here for performance reasons: + // https://jsperf.com/getall-vs-sizzle/2 + destElements = getAll(clone); - // Types can be a map of types/handlers - if (typeof types === "object") { - // ( types-Object, selector, data ) - if (typeof selector !== "string") { - // ( types-Object, data ) - data = data || selector; - selector = undefined; - } + srcElements = getAll(elem); - for (type in types) { - on(elem, type, selector, data, types[type], one); + for ((i = 0, l = srcElements.length); i < l; i++) { + fixInput(srcElements[i], destElements[i]); } - - return elem; } - if (data == null && fn == null) { - // ( types, fn ) - fn = selector; - data = selector = undefined; - } else if (fn == null) { - if (typeof selector === "string") { - // ( types, selector, fn ) - fn = data; - data = undefined; + // Copy the events from the original to the clone + if (dataAndEvents) { + if (deepDataAndEvents) { + srcElements = srcElements || getAll(elem); + destElements = destElements || getAll(clone); + + for ((i = 0, l = srcElements.length); i < l; i++) { + cloneCopyEvent(srcElements[i], destElements[i]); + } } else { - // ( types, data, fn ) - fn = data; - data = selector; - selector = undefined; + cloneCopyEvent(elem, clone); } } - if (fn === false) { - fn = returnFalse; - } else if (!fn) { - return elem; + // Preserve script evaluation history + destElements = getAll(clone, "script"); + + if (destElements.length > 0) { + setGlobalEval(destElements, !inPage && getAll(elem, "script")); } - if (one === 1) { - origFn = fn; + // Return the cloned set + return clone; + }, - fn = function (event) { - // Can use an empty set, since event contains the info - jQuery().off(event); - return origFn.apply(this, arguments); - }; + cleanData(elems) { + var data, + elem, + type, + special = jQuery.event.special, + i = 0; - // Use same guid so caller can remove using origFn - fn.guid = origFn.guid || (origFn.guid = jQuery.guid++); - } + for (; (elem = elems[i]) !== undefined; i++) { + if (acceptData(elem)) { + if (data = elem[dataPriv.expando]) { + if (data.events) { + for (type in data.events) { + if (special[type]) { + jQuery.event.remove(elem, type); - return elem.each(function () { - jQuery.event.add(this, types, fn, data, selector); - }); - } + // This is a shortcut to avoid jQuery.event.remove's overhead + } else { + jQuery.removeEvent(elem, type, data.handle); + } + } + } - /* - * Helper functions for managing events -- not part of the public interface. - * Props to Dean Edwards' addEvent library for many of the ideas. - */ - jQuery.event = { - global: {}, - add(elem, types, handler, data, selector) { - var handleObjIn, - eventHandle, - tmp, - events, - t, - handleObj, - special, - handlers, - type, - namespaces, - origType, - elemData = dataPriv.get(elem); + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[dataPriv.expando] = undefined; + } - // Only attach events to objects that accept data - if (!acceptData(elem)) { - return; + if (elem[dataUser.expando]) { + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[dataUser.expando] = undefined; + } } + } + } + }); + + jQuery.fn.extend({ + detach(selector) { + return remove(this, selector, true); + }, + + remove(selector) { + return remove(this, selector); + }, + + text(value) { + return access( + this, + function (value) { + return value === undefined + ? jQuery.text(this) + : this.empty().each(function () { + if (this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9) { + this.textContent = value; + } + }); + }, + null, + value, + arguments.length + ); + }, + + append() { + return domManip(this, arguments, function (elem) { + if (this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9) { + var target = manipulationTarget(this, elem); - // Caller can pass in an object of custom data in lieu of the handler - if (handler.handler) { - handleObjIn = handler; - handler = handleObjIn.handler; - selector = handleObjIn.selector; + target.appendChild(elem); } + }); + }, - // Ensure that invalid selectors throw exceptions at attach time - // Evaluate against documentElement in case elem is a non-element node (e.g., document) - if (selector) { - jQuery.find.matchesSelector(documentElement, selector); + prepend() { + return domManip(this, arguments, function (elem) { + if (this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9) { + var target = manipulationTarget(this, elem); + + target.insertBefore(elem, target.firstChild); } + }); + }, - // Make sure that the handler has a unique ID, used to find/remove it later - if (!handler.guid) { - handler.guid = jQuery.guid++; + before() { + return domManip(this, arguments, function (elem) { + if (this.parentNode) { + this.parentNode.insertBefore(elem, this); } + }); + }, - // Init the element's event structure and main handler, if this is the first - if (!(events = elemData.events)) { - events = elemData.events = Object.create(null); + after() { + return domManip(this, arguments, function (elem) { + if (this.parentNode) { + this.parentNode.insertBefore(elem, this.nextSibling); } + }); + }, - if (!(eventHandle = elemData.handle)) { - eventHandle = elemData.handle = function (e) { - // Discard the second event of a jQuery.event.trigger() and - // when an event is called after a page has unloaded - return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ? jQuery.event.dispatch.apply(elem, arguments) : undefined; - }; + empty() { + var elem, i = 0; + + for (; (elem = this[i]) != null; i++) { + if (elem.nodeType === 1) { + // Prevent memory leaks + jQuery.cleanData(getAll(elem, false)); + + // Remove any remaining nodes + elem.textContent = ""; } + } + + return this; + }, + + clone(dataAndEvents, deepDataAndEvents) { + dataAndEvents = dataAndEvents == null ? false : dataAndEvents; + deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; - // Handle multiple events separated by a space - types = (types || "").match(rnothtmlwhite) || [""]; - t = types.length; + return this.map(function () { + return jQuery.clone(this, dataAndEvents, deepDataAndEvents); + }); + }, - while (t--) { - tmp = rtypenamespace.exec(types[t]) || []; - type = origType = tmp[1]; - namespaces = (tmp[2] || "").split(".").sort(); + html(value) { + return access( + this, + function (value) { + var elem = this[0] || {}, i = 0, l = this.length; - // There *must* be a type, no attaching namespace-only handlers - if (!type) { - continue; + if (value === undefined && elem.nodeType === 1) { + return elem.innerHTML; } - // If event changes its type, use the special event handlers for the changed type - special = jQuery.event.special[type] || {}; - // If selector defined, determine special event api type, otherwise given type - type = (selector ? special.delegateType : special.bindType) || type; - // Update special based on newly reset type - special = jQuery.event.special[type] || {}; - - // handleObj is passed to all event handlers - handleObj = jQuery.extend( - { - type, - origType, - data, - handler, - guid: handler.guid, - selector, - needsContext: selector && jQuery.expr.match.needsContext.test(selector), - namespace: namespaces.join(".") - }, - handleObjIn - ); + // See if we can take a shortcut and just use innerHTML + if (typeof value === "string" && !rnoInnerhtml.test(value) && !wrapMap[(rtagName.exec(value) || ["", ""])[1].toLowerCase()]) { + value = jQuery.htmlPrefilter(value); - // Init the event handler queue if we're the first - if (!(handlers = events[type])) { - handlers = events[type] = []; - handlers.delegateCount = 0; + try { + for (; i < l; i++) { + elem = this[i] || {}; - // Only use addEventListener if the special events handler returns false - if (!special.setup || special.setup.call(elem, data, namespaces, eventHandle) === false) { - if (elem.addEventListener) { - elem.addEventListener(type, eventHandle); + // Remove element nodes and prevent memory leaks + if (elem.nodeType === 1) { + jQuery.cleanData(getAll(elem, false)); + elem.innerHTML = value; + } } - } - } - if (special.add) { - special.add.call(elem, handleObj); + elem = 0; - if (!handleObj.handler.guid) { - handleObj.handler.guid = handler.guid; - } + // If using innerHTML throws an exception, use the fallback method + } catch(e) {} } - // Add to the element's handler list, delegates in front - if (selector) { - handlers.splice(handlers.delegateCount++, 0, handleObj); - } else { - handlers.push(handleObj); + if (elem) { + this.empty().append(value); } + }, + null, + value, + arguments.length + ); + }, - // Keep track of which events have ever been used, for event optimization - jQuery.event.global[type] = true; - } - }, - remove( - elem, - types, - handler, - selector, - mappedTypes - ) { - var j, - origCount, - tmp, - events, - t, - handleObj, - special, - handlers, - type, - namespaces, - origType, - elemData = dataPriv.hasData(elem) && dataPriv.get(elem); - - if (!elemData || !(events = elemData.events)) { - return; - } + replaceWith() { + var ignored = []; - // Once for each type.namespace in types; type may be omitted - types = (types || "").match(rnothtmlwhite) || [""]; - t = types.length; + // Make the changes, replacing each non-ignored context element with the new content + return domManip( + this, + arguments, + function (elem) { + var parent = this.parentNode; - while (t--) { - tmp = rtypenamespace.exec(types[t]) || []; - type = origType = tmp[1]; - namespaces = (tmp[2] || "").split(".").sort(); + if (jQuery.inArray(this, ignored) < 0) { + jQuery.cleanData(getAll(this)); - // Unbind all events (on this namespace, if provided) for the element - if (!type) { - for (type in events) { - jQuery.event.remove(elem, type + types[t], handler, selector, true); + if (parent) { + parent.replaceChild(elem, this); } - - continue; } - special = jQuery.event.special[type] || {}; - type = (selector ? special.delegateType : special.bindType) || type; - handlers = events[type] || []; - tmp = tmp[2] && new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)"); - // Remove matching events - origCount = j = handlers.length; + // Force callback invocation + }, + ignored + ); + } + }); + + jQuery.each( + { + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" + }, + function (name, original) { + jQuery.fn[name] = function (selector) { + var elems, + ret = [], + insert = jQuery(selector), + last = insert.length - 1, + i = 0; - while (j--) { - handleObj = handlers[j]; + for (; i <= last; i++) { + elems = i === last ? this : this.clone(true); + jQuery(insert[i])[original](elems); - if ((mappedTypes || origType === handleObj.origType) && (!handler || handler.guid === handleObj.guid) && (!tmp || tmp.test(handleObj.namespace)) && (!selector || selector === handleObj.selector || selector === "**" && handleObj.selector)) { - handlers.splice(j, 1); + // Support: Android <=4.0 only, PhantomJS 1 only + // .get() because push.apply(_, arraylike) throws on ancient WebKit + push.apply(ret, elems.get()); + } - if (handleObj.selector) { - handlers.delegateCount--; - } + return this.pushStack(ret); + }; + } + ); - if (special.remove) { - special.remove.call(elem, handleObj); - } - } - } + var rnumnonpx = new RegExp("^(" + pnum + ")(?!px)[a-z%]+$", "i"); + var rcustomProp = /^--/; - // Remove generic event handler if we removed something and no more handlers exist - // (avoids potential for endless recursion during removal of special event handlers) - if (origCount && !handlers.length) { - if (!special.teardown || special.teardown.call(elem, namespaces, elemData.handle) === false) { - jQuery.removeEvent(elem, type, elemData.handle); - } + var getStyles = function (elem) { + // Support: IE <=11 only, Firefox <=30 (trac-15098, trac-14150) + // IE throws on elements created in popups + // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" + var view = elem.ownerDocument.defaultView; - delete events[type]; - } - } + if (!view || !view.opener) { + view = window; + } - // Remove data and the expando if it's no longer used - if (jQuery.isEmptyObject(events)) { - dataPriv.remove(elem, "handle events"); - } - }, - dispatch(nativeEvent) { - var i, - j, - ret, - matched, - handleObj, - handlerQueue, - args = new Array(arguments.length), - // Make a writable jQuery.Event from the native event object - event = jQuery.event.fix(nativeEvent), - handlers = (dataPriv.get(this, "events") || Object.create(null))[event.type] || [], - special = jQuery.event.special[event.type] || {}; - - // Use the fix-ed jQuery.Event rather than the (read-only) native event - args[0] = event; - - for (i = 1; i < arguments.length; i++) { - args[i] = arguments[i]; - } - - event.delegateTarget = this; - - // Call the preDispatch hook for the mapped type, and let it bail if desired - if (special.preDispatch && special.preDispatch.call(this, event) === false) { - return; - } + return view.getComputedStyle(elem); + }; - // Determine handlers - handlerQueue = jQuery.event.handlers.call(this, event, handlers); - // Run delegates first; they may want to stop propagation beneath us - i = 0; + var swap = function (elem, options, callback) { + var ret, name, old = {}; - while ((matched = handlerQueue[i++]) && !event.isPropagationStopped()) { - event.currentTarget = matched.elem; - j = 0; - - while ((handleObj = matched.handlers[j++]) && !event.isImmediatePropagationStopped()) { - // If the event is namespaced, then each handler is only invoked if it is - // specially universal or its namespaces are a superset of the event's. - if (!event.rnamespace || handleObj.namespace === false || event.rnamespace.test(handleObj.namespace)) { - event.handleObj = handleObj; - event.data = handleObj.data; - ret = ((jQuery.event.special[handleObj.origType] || {}).handle || handleObj.handler).apply(matched.elem, args); - - if (ret !== undefined) { - if ((event.result = ret) === false) { - event.preventDefault(); - event.stopPropagation(); - } - } - } - } - } + // Remember the old values, and insert the new ones + for (name in options) { + old[name] = elem.style[name]; + elem.style[name] = options[name]; + } - // Call the postDispatch hook for the mapped type - if (special.postDispatch) { - special.postDispatch.call(this, event); - } + ret = callback.call(elem); - return event.result; - }, - handlers(event, handlers) { - var i, - handleObj, - sel, - matchedHandlers, - matchedSelectors, - handlerQueue = [], - delegateCount = handlers.delegateCount, - cur = event.target; - - // Find delegate handlers - if (delegateCount && // Support: IE <=9 - // Black-hole SVG instance trees (trac-13180) - cur.nodeType && // Support: Firefox <=42 - // Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861) - // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click - // Support: IE 11 only - // ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343) - !(event.type === "click" && event.button >= 1)) { - for (; cur !== this; cur = cur.parentNode || this) { - // Don't check non-elements (trac-13208) - // Don't process clicks on disabled elements (trac-6911, trac-8165, trac-11382, trac-11764) - if (cur.nodeType === 1 && !(event.type === "click" && cur.disabled === true)) { - matchedHandlers = []; - matchedSelectors = {}; - - for (i = 0; i < delegateCount; i++) { - handleObj = handlers[i]; - // Don't conflict with Object.prototype properties (trac-13203) - sel = handleObj.selector + " "; - - if (matchedSelectors[sel] === undefined) { - matchedSelectors[sel] = handleObj.needsContext ? jQuery(sel, this).index(cur) > -1 : jQuery.find(sel, this, null, [cur]).length; - } + // Revert the old values + for (name in options) { + elem.style[name] = old[name]; + } - if (matchedSelectors[sel]) { - matchedHandlers.push(handleObj); - } - } + return ret; + }; - if (matchedHandlers.length) { - handlerQueue.push({ elem: cur, handlers: matchedHandlers }); - } - } - } - } + var rboxStyle = new RegExp(cssExpand.join("|"), "i"); + + (function () { + // Executing both pixelPosition & boxSizingReliable tests require only one layout + // so they're executed at the same time to save the second computation. + function computeStyleTests() { + // This is a singleton, we need to execute it only once + if (!div) { + return; + } - // Add the remaining (directly-bound) handlers - cur = this; + container.style.cssText = "position:absolute;left:-11111px;width:60px;" + "margin-top:1px;padding:0;border:0"; + div.style.cssText = "position:relative;display:block;box-sizing:border-box;overflow:scroll;" + "margin:auto;border:1px;padding:1px;" + "width:60%;top:1%"; + documentElement.appendChild(container).appendChild(div); - if (delegateCount < handlers.length) { - handlerQueue.push({ - elem: cur, - handlers: handlers.slice(delegateCount) - }); - } + var divStyle = window.getComputedStyle(div); - return handlerQueue; - }, - addProp(name, hook) { - Object.defineProperty(jQuery.Event.prototype, name, { - enumerable: true, - configurable: true, - get: isFunction(hook) - ? function () { - if (this.originalEvent) { - return hook(this.originalEvent); - } - } - : function () { - if (this.originalEvent) { - return this.originalEvent[name]; - } - }, - set(value) { - Object.defineProperty(this, name, { - enumerable: true, - configurable: true, - writable: true, - value - }); - } - }); - }, - fix(originalEvent) { - return originalEvent[jQuery.expando] ? originalEvent : new jQuery.Event(originalEvent); - }, - special: { - load: { // Prevent triggered image.load events from bubbling to window.load - noBubble: true }, - click: { - setup(data) { - // For mutual compressibility with _default, replace `this` access with a local var. - // `|| data` is dead code meant only to preserve the variable through minification. - var el = this || data; - - // Claim the first handler - if (rcheckableType.test(el.type) && el.click && nodeName(el, "input")) { - // dataPriv.set( el, "click", ... ) - leverageNative(el, "click", true); - } + pixelPositionVal = divStyle.top !== "1%"; - // Return false to allow normal processing in the caller - return false; - }, - trigger(data) { - // For mutual compressibility with _default, replace `this` access with a local var. - // `|| data` is dead code meant only to preserve the variable through minification. - var el = this || data; - - // Force setup before triggering a click - if (rcheckableType.test(el.type) && el.click && nodeName(el, "input")) { - leverageNative(el, "click"); - } + // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44 + reliableMarginLeftVal = roundPixelMeasures(divStyle.marginLeft) === 12; - // Return non-false to allow normal event-path propagation - return true; - }, - _default(event) { - var target = event.target; + // Support: Android 4.0 - 4.3 only, Safari <=9.1 - 10.1, iOS <=7.0 - 9.3 + // Some styles come back with percentage values, even though they shouldn't + div.style.right = "60%"; - return rcheckableType.test(target.type) && target.click && nodeName(target, "input") && dataPriv.get(target, "click") || nodeName(target, "a"); - } - }, - beforeunload: { - postDispatch(event) { - // Support: Firefox 20+ - // Firefox doesn't alert if the returnValue field is not set. - if (event.result !== undefined && event.originalEvent) { - event.originalEvent.returnValue = event.result; - } - } - } - } - }; + pixelBoxStylesVal = roundPixelMeasures(divStyle.right) === 36; - // Ensure the presence of an event listener that handles manually-triggered - // synthetic events by interrupting progress until reinvoked in response to - // *native* events that it fires directly, ensuring that state changes have - // already occurred before other listeners are invoked. - function leverageNative(el, type, isSetup) { - // Missing `isSetup` indicates a trigger call, which must force setup through jQuery.event.add - if (!isSetup) { - if (dataPriv.get(el, type) === undefined) { - jQuery.event.add(el, type, returnTrue); - } + // Support: IE 9 - 11 only + // Detect misreporting of content dimensions for box-sizing:border-box elements + boxSizingReliableVal = roundPixelMeasures(divStyle.width) === 36; - return; - } + // Support: IE 9 only + // Detect overflow:scroll screwiness (gh-3699) + // Support: Chrome <=64 + // Don't get tricked when zoom affects offsetWidth (gh-4029) + div.style.position = "absolute"; - // Register the controller as a special universal handler for all event namespaces - dataPriv.set(el, type, false); - - jQuery.event.add(el, type, { - namespace: false, - handler(event) { - var result, saved = dataPriv.get(this, type); - - if (event.isTrigger & 1 && this[type]) { - // Interrupt processing of the outer synthetic .trigger()ed event - if (!saved) { - // Store arguments for use when handling the inner native event - // There will always be at least one argument (an event object), so this array - // will not be confused with a leftover capture object. - saved = slice.call(arguments); - dataPriv.set(this, type, saved); - // Trigger the native event and capture its result - this[type](); - result = dataPriv.get(this, type); - dataPriv.set(this, type, false); - - if (saved !== result) { - // Cancel the outer synthetic event - event.stopImmediatePropagation(); - event.preventDefault(); - return result; - } - } else // (focus or blur), assume that the surrogate already propagated from triggering - // the native event and prevent that from happening again here. - // This technically gets the ordering wrong w.r.t. to `.trigger()` (in which the - // bubbling surrogate propagates *after* the non-bubbling base), but that seems - // less bad than duplication. - if ((jQuery.event.special[type] || {}).delegateType) { - event.stopPropagation(); // If this is an inner synthetic event for an event with a bubbling surrogate - } - } else // Fire an inner synthetic event with the original arguments - if (saved) { - // ...and capture the result - dataPriv.set( - this, // If this is a native event triggered above, everything is now in order - type, - jQuery.event.trigger(saved[0], saved.slice(1), this) - ); + scrollboxSizeVal = roundPixelMeasures(div.offsetWidth / 3) === 12; + documentElement.removeChild(container); - // Abort handling of the native event by all jQuery handlers while allowing - // native handlers on the same element to run. On target, this is achieved - // by stopping immediate propagation just on the jQuery event. However, - // the native event is re-wrapped by a jQuery one on each level of the - // propagation so the only way to stop it for jQuery is to stop it for - // everyone via native `stopPropagation()`. This is not a problem for - // focus/blur which don't bubble, but it does also stop click on checkboxes - // and radios. We accept this limitation. - event.stopPropagation(); - event.isImmediatePropagationStopped = returnTrue; - } - } - }); + // Nullify the div so it wouldn't be stored in the memory and + // it will also be a sign that checks already performed + div = null; } - jQuery.removeEvent = function (elem, type, handle) { - // This "if" is needed for plain objects - if (elem.removeEventListener) { - elem.removeEventListener(type, handle); - } - }; + function roundPixelMeasures(measure) { + return Math.round(parseFloat(measure)); + } - jQuery.Event = function (src, props) { - // Allow instantiation without the 'new' keyword - if (!(this instanceof jQuery.Event)) { - return new jQuery.Event(src, props); - } - - // Event object - if (src && src.type) { - this.originalEvent = src; - this.type = src.type; - // Events bubbling up the document may have been marked as prevented - // by a handler lower down the tree; reflect the correct value. - this.isDefaultPrevented = src.defaultPrevented || src.defaultPrevented === undefined && // Support: Android <=2.3 only - src.returnValue === false ? returnTrue : returnFalse; - // Create target properties - // Support: Safari <=6 - 7 only - // Target should not be a text node (trac-504, trac-13143) - this.target = src.target && src.target.nodeType === 3 ? src.target.parentNode : src.target; - this.currentTarget = src.currentTarget; - this.relatedTarget = src.relatedTarget; - } else { - this.type = src; // Event type - } + var pixelPositionVal, + boxSizingReliableVal, + scrollboxSizeVal, + pixelBoxStylesVal, + reliableTrDimensionsVal, + reliableMarginLeftVal, + container = document.createElement("div"), + div = document.createElement("div"); + + // Finish early in limited (non-browser) environments + if (!div.style) { + return; + } - // Put explicitly provided properties onto the event object - if (props) { - jQuery.extend(this, props); - } + // Support: IE <=9 - 11 only + // Style of cloned element affects source element cloned (trac-8908) + div.style.backgroundClip = "content-box"; - // Create a timestamp if incoming event doesn't have one - this.timeStamp = src && src.timeStamp || Date.now(); - // Mark it as fixed - this[jQuery.expando] = true; - }; + div.cloneNode(true).style.backgroundClip = ""; + support.clearCloneStyle = div.style.backgroundClip === "content-box"; + + jQuery.extend(support, { + boxSizingReliable() { + computeStyleTests(); - // jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding - // https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html - jQuery.Event.prototype = { - constructor: jQuery.Event, - isDefaultPrevented: returnFalse, - isPropagationStopped: returnFalse, - isImmediatePropagationStopped: returnFalse, - isSimulated: false, - preventDefault() { - var e = this.originalEvent; + return boxSizingReliableVal; + }, - this.isDefaultPrevented = returnTrue; + pixelBoxStyles() { + computeStyleTests(); - if (e && !this.isSimulated) { - e.preventDefault(); - } + return pixelBoxStylesVal; }, - stopPropagation() { - var e = this.originalEvent; - this.isPropagationStopped = returnTrue; + pixelPosition() { + computeStyleTests(); - if (e && !this.isSimulated) { - e.stopPropagation(); - } + return pixelPositionVal; }, - stopImmediatePropagation() { - var e = this.originalEvent; - this.isImmediatePropagationStopped = returnTrue; + reliableMarginLeft() { + computeStyleTests(); - if (e && !this.isSimulated) { - e.stopImmediatePropagation(); - } + return reliableMarginLeftVal; + }, - this.stopPropagation(); - } - }; + scrollboxSize() { + computeStyleTests(); - // Includes all common event props including KeyEvent and MouseEvent specific props - jQuery.each( - { - altKey: true, - bubbles: true, - cancelable: true, - changedTouches: true, - ctrlKey: true, - detail: true, - eventPhase: true, - metaKey: true, - pageX: true, - pageY: true, - shiftKey: true, - view: true, - "char": true, - code: true, - charCode: true, - key: true, - keyCode: true, - button: true, - buttons: true, - clientX: true, - clientY: true, - offsetX: true, - offsetY: true, - pointerId: true, - pointerType: true, - screenX: true, - screenY: true, - targetTouches: true, - toElement: true, - touches: true, - which: true + return scrollboxSizeVal; }, - jQuery.event.addProp - ); - jQuery.each({ focus: "focusin", blur: "focusout" }, function (type, delegateType) { - function focusMappedHandler(nativeEvent) { - if (document.documentMode) { - // Support: IE 11+ - // Attach a single focusin/focusout handler on the document while someone wants - // focus/blur. This is because the former are synchronous in IE while the latter - // are async. In other browsers, all those handlers are invoked synchronously. - // `handle` from private data would already wrap the event, but we need - // to change the `type` here. - var handle = dataPriv.get(this, "handle"), - event = jQuery.event.fix(nativeEvent); - - event.type = nativeEvent.type === "focusin" ? "focus" : "blur"; - event.isSimulated = true; - // First, handle focusin/focusout - handle(nativeEvent); - - // ...then, handle focus/blur - // - // focus/blur don't bubble while focusin/focusout do; simulate the former by only - // invoking the handler at the lower level. - if (event.target === event.currentTarget) { - // The setup part calls `leverageNative`, which, in turn, calls - // `jQuery.event.add`, so event handle will already have been set - // by this point. - handle(event); - } - } else { - // For non-IE browsers, attach a single capturing handler on the document - // while someone wants focusin/focusout. - jQuery.event.simulate(delegateType, nativeEvent.target, jQuery.event.fix(nativeEvent)); - } + // Support: IE 9 - 11+, Edge 15 - 18+ + // IE/Edge misreport `getComputedStyle` of table rows with width/height + // set in CSS while `offset*` properties report correct values. + // Behavior in IE 9 is more subtle than in newer versions & it passes + // some versions of this test; make sure not to make it pass there! + // + // Support: Firefox 70+ + // Only Firefox includes border widths + // in computed dimensions. (gh-4529) + reliableTrDimensions() { + var table, tr, trChild, trStyle; + + if (reliableTrDimensionsVal == null) { + table = document.createElement("table"); + tr = document.createElement("tr"); + trChild = document.createElement("div"); + table.style.cssText = "position:absolute;left:-11111px;border-collapse:separate"; + tr.style.cssText = "box-sizing:content-box;border:1px solid"; + + // Support: Chrome 86+ + // Height set through cssText does not get applied. + // Computed height then comes back as 0. + tr.style.height = "1px"; + + trChild.style.height = "9px"; + + // Support: Android 8 Chrome 86+ + // In our bodyBackground.html iframe, + // display for all div elements is set to "inline", + // which causes a problem only in Android 8 Chrome 86. + // Ensuring the div is `display: block` + // gets around this issue. + trChild.style.display = "block"; + + documentElement.appendChild(table).appendChild(tr).appendChild(trChild); + trStyle = window.getComputedStyle(tr); + reliableTrDimensionsVal = parseInt(trStyle.height, 10) + parseInt(trStyle.borderTopWidth, 10) + parseInt(trStyle.borderBottomWidth, 10) === tr.offsetHeight; + documentElement.removeChild(table); + } + + return reliableTrDimensionsVal; + } + }); + })(); + + function curCSS(elem, name, computed) { + var width, + minWidth, + maxWidth, + ret, + isCustomProp = rcustomProp.test(name), + // Support: Firefox 51+ + // Retrieving style before computed somehow + // fixes an issue with getting wrong values + // on detached elements + style = elem.style; + + computed = computed || getStyles(elem); + + // getPropertyValue is needed for: + // .css('filter') (IE 9 only, trac-12537) + // .css('--customProperty) (gh-3144) + if (computed) { + // Support: IE <=9 - 11+ + // IE only supports `"float"` in `getPropertyValue`; in computed styles + // it's only available as `"cssFloat"`. We no longer modify properties + // sent to `.css()` apart from camelCasing, so we need to check both. + // Normally, this would create difference in behavior: if + // `getPropertyValue` returns an empty string, the value returned + // by `.css()` would be `undefined`. This is usually the case for + // disconnected elements. However, in IE even disconnected elements + // with no styles return `"none"` for `getPropertyValue( "float" )` + ret = computed.getPropertyValue(name) || computed[name]; + + if (isCustomProp && ret) { + // Support: Firefox 105+, Chrome <=105+ + // Spec requires trimming whitespace for custom properties (gh-4926). + // Firefox only trims leading whitespace. Chrome just collapses + // both leading & trailing whitespace to a single space. + // + // Fall back to `undefined` if empty string returned. + // This collapses a missing definition with property defined + // and set to an empty string but there's no standard API + // allowing us to differentiate them without a performance penalty + // and returning `undefined` aligns with older jQuery. + // + // rtrimCSS treats U+000D CARRIAGE RETURN and U+000C FORM FEED + // as whitespace while CSS does not, but this is not a problem + // because CSS preprocessing replaces them with U+000A LINE FEED + // (which *is* CSS whitespace) + // https://www.w3.org/TR/css-syntax-3/#input-preprocessing + ret = ret.replace(rtrimCSS, "$1") || undefined; } - jQuery.event.special[type] = { - setup() { - var attaches; + if (ret === "" && !isAttached(elem)) { + ret = jQuery.style(elem, name); + } - // Claim the first handler - // dataPriv.set( this, "focus", ... ) - // dataPriv.set( this, "blur", ... ) - leverageNative(this, type, true); + // A tribute to the "awesome hack by Dean Edwards" + // Android Browser returns percentage for some values, + // but width seems to be reliably pixels. + // This is against the CSSOM draft spec: + // https://drafts.csswg.org/cssom/#resolved-values + if (!support.pixelBoxStyles() && rnumnonpx.test(ret) && rboxStyle.test(name)) { + // Remember the original values + width = style.width; - if (document.documentMode) { - // Support: IE 9 - 11+ - // We use the same native handler for focusin & focus (and focusout & blur) - // so we need to coordinate setup & teardown parts between those events. - // Use `delegateType` as the key as `type` is already used by `leverageNative`. - attaches = dataPriv.get(this, delegateType); - - if (!attaches) { - this.addEventListener(delegateType, focusMappedHandler); - } + minWidth = style.minWidth; + maxWidth = style.maxWidth; - dataPriv.set(this, delegateType, (attaches || 0) + 1); - } else { - // Return false to allow normal processing in the caller - return false; - } - }, - trigger() { - // Force setup before trigger - leverageNative(this, type); - // Return non-false to allow normal event-path propagation - return true; - }, - teardown() { - var attaches; + // Put in the new values to get a computed value out + style.minWidth = style.maxWidth = style.width = ret; - if (document.documentMode) { - attaches = dataPriv.get(this, delegateType) - 1; + ret = computed.width; - if (!attaches) { - this.removeEventListener(delegateType, focusMappedHandler); - dataPriv.remove(this, delegateType); - } else { - dataPriv.set(this, delegateType, attaches); - } - } else { - // Return false to indicate standard teardown should be applied - return false; - } - }, - _default(event) { - return dataPriv.get(event.target, type); - }, - delegateType - }; + // Revert the changed values + style.width = width; - // Support: Firefox <=44 - // Firefox doesn't have focus(in | out) events - // Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787 - // - // Support: Chrome <=48 - 49, Safari <=9.0 - 9.1 - // focus(in | out) events fire after focus & blur events, - // which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order - // Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857 - // - // Support: IE 9 - 11+ - // To preserve relative focusin/focus & focusout/blur event order guaranteed on the 3.x branch, - // attach a single handler for both events in IE. - jQuery.event.special[delegateType] = { - setup() { - // Handle: regular nodes (via `this.ownerDocument`), window - // (via `this.document`) & document (via `this`). - var doc = this.ownerDocument || this.document || this, - dataHolder = document.documentMode ? this : doc, - attaches = dataPriv.get(dataHolder, delegateType); + style.minWidth = minWidth; + style.maxWidth = maxWidth; + } + } - // Support: IE 9 - 11+ - // We use the same native handler for focusin & focus (and focusout & blur) - // so we need to coordinate setup & teardown parts between those events. - // Use `delegateType` as the key as `type` is already used by `leverageNative`. - if (!attaches) { - if (document.documentMode) { - this.addEventListener(delegateType, focusMappedHandler); - } else { - doc.addEventListener(type, focusMappedHandler, true); - } - } + return ret !== undefined + ? // Support: IE <=9 - 11 only + // IE returns zIndex value as an integer. + ret + "" + : ret; + } - dataPriv.set(dataHolder, delegateType, (attaches || 0) + 1); - }, - teardown() { - var doc = this.ownerDocument || this.document || this, - dataHolder = document.documentMode ? this : doc, - attaches = dataPriv.get(dataHolder, delegateType) - 1; + function addGetHookIf(conditionFn, hookFn) { + // Define the hook, we'll check on the first run if it's really needed. + return { + get() { + if (conditionFn()) { + // Hook not needed (or it's not possible to use it due + // to missing dependency), remove it. + delete this.get; + + return; + } + + // Hook needed; redefine it so that the support test is not executed again. + return (this.get = hookFn).apply(this, arguments); + } + }; + } + + var cssPrefixes = ["Webkit", "Moz", "ms"], + emptyStyle = document.createElement("div").style, + vendorProps = {}; + + // Return a vendor-prefixed property or undefined + function vendorPropName(name) { + // Check for vendor prefixed names + var capName = name[0].toUpperCase() + name.slice(1), + i = cssPrefixes.length; + + while (i--) { + name = cssPrefixes[i] + capName; + + if (name in emptyStyle) { + return name; + } + } + } + + // Return a potentially-mapped jQuery.cssProps or vendor prefixed property + function finalPropName(name) { + var final = jQuery.cssProps[name] || vendorProps[name]; + + if (final) { + return final; + } + + if (name in emptyStyle) { + return name; + } + + return vendorProps[name] = vendorPropName(name) || name; + } - if (!attaches) { - if (document.documentMode) { - this.removeEventListener(delegateType, focusMappedHandler); - } else { - doc.removeEventListener(type, focusMappedHandler, true); - } + var // Swappable if display is none or starts with table + // except "table", "table-cell", or "table-caption" + // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display + rdisplayswap = /^(none|table(?!-c[ea]).+)/, + cssShow = { position: "absolute", visibility: "hidden", display: "block" }, + cssNormalTransform = { letterSpacing: "0", fontWeight: "400" }; + + function setPositiveNumber(_elem, value, subtract) { + // Any relative (+/-) values have already been + // normalized at this point + var matches = rcssNum.exec(value); + + return matches + ? // Guard against undefined "subtract", e.g., when used as in cssHooks + Math.max(0, matches[2] - (subtract || 0)) + (matches[3] || "px") + : value; + } - dataPriv.remove(dataHolder, delegateType); - } else { - dataPriv.set(dataHolder, delegateType, attaches); - } - } - }; - }); + function boxModelAdjustment(elem, dimension, box, isBorderBox, styles, computedVal) { + var i = dimension === "width" ? 1 : 0, + extra = 0, + delta = 0, + marginDelta = 0; - // Create mouseenter/leave events using mouseover/out and event-time checks - // so that event delegation works in jQuery. - // Do the same for pointerenter/pointerleave and pointerover/pointerout - // - // Support: Safari 7 only - // Safari sends mouseenter too often; see: - // https://bugs.chromium.org/p/chromium/issues/detail?id=470258 - // for the description of the bug (it existed in older Chrome versions as well). - jQuery.each( - { - mouseenter: "mouseover", - mouseleave: "mouseout", - pointerenter: "pointerover", - pointerleave: "pointerout" - }, - function (orig, fix) { - jQuery.event.special[orig] = { - delegateType: fix, - bindType: fix, - handle(event) { - var ret, - target = this, - related = event.relatedTarget, - handleObj = event.handleObj; - - // For mouseenter/leave call the handler if related is outside the target. - // NB: No relatedTarget if the mouse left/entered the browser window - if (!related || related !== target && !jQuery.contains(target, related)) { - event.type = handleObj.origType; - ret = handleObj.handler.apply(this, arguments); - event.type = fix; - } + // Adjustment may not be necessary + if (box === (isBorderBox ? "border" : "content")) { + return 0; + } - return ret; - } - }; + for (; i < 4; i += 2) { + // Both box models exclude margin + // Count margin delta separately to only add it after scroll gutter adjustment. + // This is needed to make negative margins work with `outerHeight( true )` (gh-3982). + if (box === "margin") { + marginDelta += jQuery.css(elem, box + cssExpand[i], true, styles); } - ); - - jQuery.fn.extend({ - on(types, selector, data, fn) { - return on(this, types, selector, data, fn); - }, - one(types, selector, data, fn) { - return on(this, types, selector, data, fn, 1); - }, - off(types, selector, fn) { - var handleObj, type; - if (types && types.preventDefault && types.handleObj) { - // ( event ) dispatched jQuery.Event - handleObj = types.handleObj; - jQuery(types.delegateTarget).off(handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType, handleObj.selector, handleObj.handler); - return this; - } + // If we get here with a content-box, we're seeking "padding" or "border" or "margin" + if (!isBorderBox) { + // Add padding + delta += jQuery.css(elem, "padding" + cssExpand[i], true, styles); - if (typeof types === "object") { - // ( types-object [, selector] ) - for (type in types) { - this.off(type, selector, types[type]); - } + // For "border" or "margin", add border + if (box !== "padding") { + delta += jQuery.css(elem, "border" + cssExpand[i] + "Width", true, styles); - return this; + // But still keep track of it otherwise + } else { + extra += jQuery.css(elem, "border" + cssExpand[i] + "Width", true, styles); } - if (selector === false || typeof selector === "function") { - // ( types [, fn] ) - fn = selector; - selector = undefined; + // If we get here with a border-box (content + padding + border), we're seeking "content" or + // "padding" or "margin" + } else { + // For "content", subtract padding + if (box === "content") { + delta -= jQuery.css(elem, "padding" + cssExpand[i], true, styles); } - if (fn === false) { - fn = returnFalse; + // For "content" or "padding", subtract border + if (box !== "margin") { + delta -= jQuery.css(elem, "border" + cssExpand[i] + "Width", true, styles); } - - return this.each(function () { - jQuery.event.remove(this, types, fn, selector); - }); } - }); + } + + // Account for positive content-box scroll gutter when requested by providing computedVal + if (!isBorderBox && computedVal >= 0) { + // offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border + // Assuming integer scroll gutter, subtract the rest and round down + delta += Math.max(0, Math.ceil(elem["offset" + dimension[0].toUpperCase() + dimension.slice(1)] - computedVal - delta - extra - 0.5)) || // If offsetWidth/offsetHeight is unknown, then we can't determine content-box scroll gutter + // Use an explicit zero to avoid NaN (gh-3964) + 0; + } - var // Support: IE <=10 - 11, Edge 12 - 13 only - // In IE/Edge using regex groups here causes severe slowdowns. - // See https://connect.microsoft.com/IE/feedback/details/1736512/ - rnoInnerhtml = /\s*$/g; + return delta + marginDelta; + } - // Prefer a tbody over its parent table for containing new rows - function manipulationTarget(elem, content) { - if (nodeName(elem, "table") && nodeName(content.nodeType !== 11 ? content : content.firstChild, "tr")) { - return jQuery(elem).children("tbody")[0] || elem; + function getWidthOrHeight(elem, dimension, extra) { + // Start with computed style + var styles = getStyles(elem), + // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-4322). + // Fake content-box until we know it's needed to know the true value. + boxSizingNeeded = !support.boxSizingReliable() || extra, + isBorderBox = boxSizingNeeded && jQuery.css(elem, "boxSizing", false, styles) === "border-box", + valueIsBorderBox = isBorderBox, + val = curCSS(elem, dimension, styles), + offsetProp = "offset" + dimension[0].toUpperCase() + dimension.slice(1); + + // Support: Firefox <=54 + // Return a confounding non-pixel value or feign ignorance, as appropriate. + if (rnumnonpx.test(val)) { + if (!extra) { + return val; } - return elem; + val = "auto"; } - // Replace/restore the type attribute of script elements for safe DOM manipulation - function disableScript(elem) { - elem.type = (elem.getAttribute("type") !== null) + "/" + elem.type; - return elem; + // Support: IE 9 - 11 only + // Use offsetWidth/offsetHeight for when box sizing is unreliable. + // In those cases, the computed value can be trusted to be border-box. + if ((!support.boxSizingReliable() && isBorderBox || // Support: IE 10 - 11+, Edge 15 - 18+ + // IE/Edge misreport `getComputedStyle` of table rows with width/height + // set in CSS while `offset*` properties report correct values. + // Interestingly, in some cases IE 9 doesn't suffer from this issue. + !support.reliableTrDimensions() && nodeName(elem, "tr") || // Fall back to offsetWidth/offsetHeight when value is "auto" + // This happens for inline elements with no explicit setting (gh-3571) + val === "auto" || // Support: Android <=4.1 - 4.3 only + // Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602) + !parseFloat(val) && jQuery.css(elem, "display", false, styles) === "inline") && // Make sure the element is visible & connected + elem.getClientRects().length) { + isBorderBox = jQuery.css(elem, "boxSizing", false, styles) === "border-box"; + + // Where available, offsetWidth/offsetHeight approximate border box dimensions. + // Where not available (e.g., SVG), assume unreliable box-sizing and interpret the + // retrieved value as a content box dimension. + valueIsBorderBox = offsetProp in elem; + + if (valueIsBorderBox) { + val = elem[offsetProp]; + } } - function restoreScript(elem) { - if ((elem.type || "").slice(0, 5) === "true/") { - elem.type = elem.type.slice(5); - } else { - elem.removeAttribute("type"); - } + // Normalize "" and auto + val = parseFloat(val) || 0; - return elem; - } + // Adjust for the element's box model + return val + boxModelAdjustment( + elem, + dimension, + extra || (isBorderBox ? "border" : "content"), + valueIsBorderBox, + styles, + // Provide the current computed size to request scroll gutter calculation (gh-3589) + val + ) + "px"; + } - function cloneCopyEvent(src, dest) { - var i, - l, + jQuery.extend({ + // Add in style property hooks for overriding the default + // behavior of getting and setting a style property + cssHooks: { + opacity: { + get(elem, computed) { + if (computed) { + // We should always get a number back from opacity + var ret = curCSS(elem, "opacity"); + + return ret === "" ? "1" : ret; + } + } + } + }, + + // Don't automatically add "px" to these possibly-unitless properties + cssNumber: { + animationIterationCount: true, + aspectRatio: true, + borderImageSlice: true, + columnCount: true, + flexGrow: true, + flexShrink: true, + fontWeight: true, + gridArea: true, + gridColumn: true, + gridColumnEnd: true, + gridColumnStart: true, + gridRow: true, + gridRowEnd: true, + gridRowStart: true, + lineHeight: true, + opacity: true, + order: true, + orphans: true, + scale: true, + widows: true, + zIndex: true, + zoom: true, + + // SVG-related + fillOpacity: true, + + floodOpacity: true, + stopOpacity: true, + strokeMiterlimit: true, + strokeOpacity: true + }, + + // Add in properties whose names you wish to fix before + // setting or getting the value + cssProps: {}, + + // Get and set the style property on a DOM Node + style(elem, name, value, extra) { + // Don't set styles on text and comment nodes + if (!elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style) { + return; + } + + // Make sure that we're working with the right name + var ret, type, - pdataOld, - udataOld, - udataCur, - events; + hooks, + origName = camelCase(name), + isCustomProp = rcustomProp.test(name), + style = elem.style; - if (dest.nodeType !== 1) { - return; + // Make sure that we're working with the right name. We don't + // want to query the value if it is a CSS custom property + // since they are user-defined. + if (!isCustomProp) { + name = finalPropName(origName); } - // 1. Copy private data: events, handlers, etc. - if (dataPriv.hasData(src)) { - pdataOld = dataPriv.get(src); - events = pdataOld.events; + // Gets hook for the prefixed version, then unprefixed version + hooks = jQuery.cssHooks[name] || jQuery.cssHooks[origName]; - if (events) { - dataPriv.remove(dest, "handle events"); + // Check if we're setting a value + if (value !== undefined) { + type = typeof value; - for (type in events) { - for ((i = 0, l = events[type].length); i < l; i++) { - jQuery.event.add(dest, type, events[type][i]); - } + // Convert "+=" or "-=" to relative numbers (trac-7345) + if (type === "string" && (ret = rcssNum.exec(value)) && ret[1]) { + value = adjustCSS(elem, name, ret); + + // Fixes bug trac-9237 + type = "number"; + } + + // Make sure that null and NaN values aren't set (trac-7116) + if (value == null || value !== value) { + return; + } + + // If a number was passed in, add the unit (except for certain CSS properties) + // The isCustomProp check can be removed in jQuery 4.0 when we only auto-append + // "px" to a few hardcoded values. + if (type === "number" && !isCustomProp) { + value += ret && ret[3] || (jQuery.cssNumber[origName] ? "" : "px"); + } + + // background-* props affect original clone's values + if (!support.clearCloneStyle && value === "" && name.indexOf("background") === 0) { + style[name] = "inherit"; + } + + // If a hook was provided, use that value, otherwise just set the specified value + if (!hooks || !("set" in hooks) || (value = hooks.set(elem, value, extra)) !== undefined) { + if (isCustomProp) { + style.setProperty(name, value); + } else { + style[name] = value; } } - } + } else { + // If a hook was provided get the non-computed value from there + if (hooks && "get" in hooks && (ret = hooks.get(elem, false, extra)) !== undefined) { + return ret; + } - // 2. Copy user data - if (dataUser.hasData(src)) { - udataOld = dataUser.access(src); - udataCur = jQuery.extend({}, udataOld); - dataUser.set(dest, udataCur); + // Otherwise just get the value from the style object + return style[name]; } - } + }, - // Fix IE bugs, see support tests - function fixInput(src, dest) { - var nodeName = dest.nodeName.toLowerCase(); + css(elem, name, extra, styles) { + var val, + num, + hooks, + origName = camelCase(name), + isCustomProp = rcustomProp.test(name); - // Fails to persist the checked state of a cloned checkbox or radio button. - if (nodeName === "input" && rcheckableType.test(src.type)) { - dest.checked = src.checked; - } else if (nodeName === "input" || nodeName === "textarea") { - dest.defaultValue = src.defaultValue; // Fails to return the selected option to the default selected state when cloning options + // Make sure that we're working with the right name. We don't + // want to modify the value if it is a CSS custom property + // since they are user-defined. + if (!isCustomProp) { + name = finalPropName(origName); } - } - function domManip(collection, args, callback, ignored) { - // Flatten any nested arrays - args = flat(args); + // Try prefixed name followed by the unprefixed name + hooks = jQuery.cssHooks[name] || jQuery.cssHooks[origName]; - var fragment, - first, - scripts, - hasScripts, - node, - doc, - i = 0, - l = collection.length, - iNoClone = l - 1, - value = args[0], - valueIsFunction = isFunction(value); + // If a hook was provided get the computed value from there + if (hooks && "get" in hooks) { + val = hooks.get(elem, true, extra); + } - // We can't cloneNode fragments that contain checked, in WebKit - if (valueIsFunction || l > 1 && typeof value === "string" && !support.checkClone && rchecked.test(value)) { - return collection.each(function (index) { - var self = collection.eq(index); + // Otherwise, if a way to get the computed value exists, use that + if (val === undefined) { + val = curCSS(elem, name, styles); + } - if (valueIsFunction) { - args[0] = value.call(this, index, self.html()); - } + // Convert "normal" to computed value + if (val === "normal" && name in cssNormalTransform) { + val = cssNormalTransform[name]; + } - domManip(self, args, callback, ignored); - }); + // Make numeric if forced or a qualifier was provided and val looks numeric + if (extra === "" || extra) { + num = parseFloat(val); + + return extra === true || isFinite(num) ? num || 0 : val; } - if (l) { - fragment = buildFragment(args, collection[0].ownerDocument, false, collection, ignored); - first = fragment.firstChild; + return val; + } + }); - if (fragment.childNodes.length === 1) { - fragment = first; + jQuery.each(["height", "width"], function (_i, dimension) { + jQuery.cssHooks[dimension] = { + get(elem, computed, extra) { + if (computed) { + // Certain elements can have dimension info if we invisibly show them + // but it must have a current display style that would benefit + return rdisplayswap.test(jQuery.css(elem, "display")) && (// Support: Safari 8+ + // Table columns in Safari have non-zero offsetWidth & zero + // getBoundingClientRect().width unless display is changed. + // Support: IE <=11 only + // Running getBoundingClientRect on a disconnected node + // in IE throws an error. + !elem.getClientRects().length || !elem.getBoundingClientRect().width) + ? swap(elem, cssShow, function () { + return getWidthOrHeight(elem, dimension, extra); + }) + : getWidthOrHeight(elem, dimension, extra); } + }, - // Require either new content or an interest in ignored elements to invoke the callback - if (first || ignored) { - scripts = jQuery.map(getAll(fragment, "script"), disableScript); - hasScripts = scripts.length; - - // Use the original fragment for the last item - // instead of the first because it can end up - // being emptied incorrectly in certain situations (trac-8070). - for (; i < l; i++) { - node = fragment; + set(elem, value, extra) { + var matches, + styles = getStyles(elem), + // Only read styles.position if the test has a chance to fail + // to avoid forcing a reflow. + scrollboxSizeBuggy = !support.scrollboxSize() && styles.position === "absolute", + // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-3991) + boxSizingNeeded = scrollboxSizeBuggy || extra, + isBorderBox = boxSizingNeeded && jQuery.css(elem, "boxSizing", false, styles) === "border-box", + subtract = extra + ? boxModelAdjustment(elem, dimension, extra, isBorderBox, styles) + : 0; - if (i !== iNoClone) { - node = jQuery.clone(node, true, true); + // Account for unreliable border-box dimensions by comparing offset* to computed and + // faking a content-box to get border and padding (gh-3699) + if (isBorderBox && scrollboxSizeBuggy) { + subtract -= Math.ceil(elem["offset" + dimension[0].toUpperCase() + dimension.slice(1)] - parseFloat(styles[dimension]) - boxModelAdjustment(elem, dimension, "border", false, styles) - 0.5); + } - // Keep references to cloned scripts for later restoration - if (hasScripts) { - // Support: Android <=4.0 only, PhantomJS 1 only - // push.apply(_, arraylike) throws on ancient WebKit - jQuery.merge(scripts, getAll(node, "script")); - } - } + // Convert to pixels if value adjustment is needed + if (subtract && (matches = rcssNum.exec(value)) && (matches[3] || "px") !== "px") { + elem.style[dimension] = value; + value = jQuery.css(elem, dimension); + } - callback.call(collection[i], node, i); - } + return setPositiveNumber(elem, value, subtract); + } + }; + }); - if (hasScripts) { - doc = scripts[scripts.length - 1].ownerDocument; - // Re-enable scripts - jQuery.map(scripts, restoreScript); + jQuery.cssHooks.marginLeft = addGetHookIf(support.reliableMarginLeft, function (elem, computed) { + if (computed) { + return (parseFloat(curCSS(elem, "marginLeft")) || elem.getBoundingClientRect().left - swap(elem, { marginLeft: 0 }, function () { + return elem.getBoundingClientRect().left; + })) + "px"; + } + }); - // Evaluate executable scripts on first document insertion - for (i = 0; i < hasScripts; i++) { - node = scripts[i]; + // These hooks are used by animate to expand properties + jQuery.each({ margin: "", padding: "", border: "Width" }, function (prefix, suffix) { + jQuery.cssHooks[prefix + suffix] = { + expand(value) { + var i = 0, + expanded = {}, + // Assumes a single number if not a string + parts = typeof value === "string" ? value.split(" ") : [value]; - if (rscriptType.test(node.type || "") && !dataPriv.access(node, "globalEval") && jQuery.contains(doc, node)) { - if (node.src && (node.type || "").toLowerCase() !== "module") { - // Optional AJAX dependency, but won't run scripts if not present - if (jQuery._evalUrl && !node.noModule) { - jQuery._evalUrl( - node.src, - { - nonce: node.nonce || node.getAttribute("nonce") - }, - doc - ); - } - } else { - // Unwrap a CDATA section containing script contents. This shouldn't be - // needed as in XML documents they're already not visible when - // inspecting element contents and in HTML documents they have no - // meaning but we're preserving that logic for backwards compatibility. - // This will be removed completely in 4.0. See gh-4904. - DOMEval(node.textContent.replace(rcleanScript, ""), node, doc); - } - } - } - } + for (; i < 4; i++) { + expanded[prefix + cssExpand[i] + suffix] = parts[i] || parts[i - 2] || parts[0]; } + + return expanded; } + }; - return collection; + if (prefix !== "margin") { + jQuery.cssHooks[prefix + suffix].set = setPositiveNumber; } + }); - function remove(elem, selector, keepData) { - var node, - nodes = selector ? jQuery.filter(selector, elem) : elem, - i = 0; + jQuery.fn.extend({ + css(name, value) { + return access( + this, + function (elem, name, value) { + var styles, len, map = {}, i = 0; - for (; (node = nodes[i]) != null; i++) { - if (!keepData && node.nodeType === 1) { - jQuery.cleanData(getAll(node)); - } + if (Array.isArray(name)) { + styles = getStyles(elem); + len = name.length; - if (node.parentNode) { - if (keepData && isAttached(node)) { - setGlobalEval(getAll(node, "script")); - } + for (; i < len; i++) { + map[name[i]] = jQuery.css(elem, name[i], false, styles); + } - node.parentNode.removeChild(node); - } - } + return map; + } - return elem; + return value !== undefined + ? jQuery.style(elem, name, value) + : jQuery.css(elem, name); + }, + name, + value, + arguments.length > 1 + ); } + }); - jQuery.extend({ - htmlPrefilter(html) { - return html; - }, - clone(elem, dataAndEvents, deepDataAndEvents) { - var i, - l, - srcElements, - destElements, - clone = elem.cloneNode(true), - inPage = isAttached(elem); - - // Fix IE cloning issues - if (!support.noCloneChecked && (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem)) { - // We eschew jQuery#find here for performance reasons: - // https://jsperf.com/getall-vs-sizzle/2 - destElements = getAll(clone); - srcElements = getAll(elem); + function Tween(elem, options, prop, end, easing) { + return new Tween.prototype.init(elem, options, prop, end, easing); + } - for ((i = 0, l = srcElements.length); i < l; i++) { - fixInput(srcElements[i], destElements[i]); - } - } + jQuery.Tween = Tween; - // Copy the events from the original to the clone - if (dataAndEvents) { - if (deepDataAndEvents) { - srcElements = srcElements || getAll(elem); - destElements = destElements || getAll(clone); + Tween.prototype = { + constructor: Tween, - for ((i = 0, l = srcElements.length); i < l; i++) { - cloneCopyEvent(srcElements[i], destElements[i]); - } - } else { - cloneCopyEvent(elem, clone); - } - } + init(elem, options, prop, end, easing, unit) { + this.elem = elem; + this.prop = prop; + this.easing = easing || jQuery.easing._default; + this.options = options; + this.start = this.now = this.cur(); + this.end = end; + this.unit = unit || (jQuery.cssNumber[prop] ? "" : "px"); + }, - // Preserve script evaluation history - destElements = getAll(clone, "script"); + cur() { + var hooks = Tween.propHooks[this.prop]; - if (destElements.length > 0) { - setGlobalEval(destElements, !inPage && getAll(elem, "script")); - } + return hooks && hooks.get ? hooks.get(this) : Tween.propHooks._default.get(this); + }, - // Return the cloned set - return clone; - }, - cleanData(elems) { - var data, - elem, - type, - special = jQuery.event.special, - i = 0; + run(percent) { + var eased, hooks = Tween.propHooks[this.prop]; - for (; (elem = elems[i]) !== undefined; i++) { - if (acceptData(elem)) { - if (data = elem[dataPriv.expando]) { - if (data.events) { - for (type in data.events) { - if (special[type]) { - jQuery.event.remove(elem, type); - } else { - jQuery.removeEvent( - elem, // This is a shortcut to avoid jQuery.event.remove's overhead - type, - data.handle - ); - } - } - } + if (this.options.duration) { + this.pos = eased = jQuery.easing[this.easing](percent, this.options.duration * percent, 0, 1, this.options.duration); + } else { + this.pos = eased = percent; + } - // Support: Chrome <=35 - 45+ - // Assign undefined instead of using delete, see Data#remove - elem[dataPriv.expando] = undefined; - } + this.now = (this.end - this.start) * eased + this.start; - if (elem[dataUser.expando]) { - // Support: Chrome <=35 - 45+ - // Assign undefined instead of using delete, see Data#remove - elem[dataUser.expando] = undefined; - } - } - } + if (this.options.step) { + this.options.step.call(this.elem, this.now, this); } - }); - jQuery.fn.extend({ - detach(selector) { - return remove(this, selector, true); - }, - remove(selector) { - return remove(this, selector); - }, - text(value) { - return access( - this, - function (value) { - return value === undefined - ? jQuery.text(this) - : this.empty().each(function () { - if (this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9) { - this.textContent = value; - } - }); - }, - null, - value, - arguments.length - ); - }, - append() { - return domManip(this, arguments, function (elem) { - if (this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9) { - var target = manipulationTarget(this, elem); + if (hooks && hooks.set) { + hooks.set(this); + } else { + Tween.propHooks._default.set(this); + } - target.appendChild(elem); - } - }); - }, - prepend() { - return domManip(this, arguments, function (elem) { - if (this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9) { - var target = manipulationTarget(this, elem); + return this; + } + }; - target.insertBefore(elem, target.firstChild); - } - }); - }, - before() { - return domManip(this, arguments, function (elem) { - if (this.parentNode) { - this.parentNode.insertBefore(elem, this); - } - }); - }, - after() { - return domManip(this, arguments, function (elem) { - if (this.parentNode) { - this.parentNode.insertBefore(elem, this.nextSibling); - } - }); - }, - empty() { - var elem, i = 0; + Tween.prototype.init.prototype = Tween.prototype; - for (; (elem = this[i]) != null; i++) { - if (elem.nodeType === 1) { - // Prevent memory leaks - jQuery.cleanData(getAll(elem, false)); - // Remove any remaining nodes - elem.textContent = ""; - } + Tween.propHooks = { + _default: { + get(tween) { + var result; + + // Use a property on the element directly when it is not a DOM element, + // or when there is no matching style property that exists. + if (tween.elem.nodeType !== 1 || tween.elem[tween.prop] != null && tween.elem.style[tween.prop] == null) { + return tween.elem[tween.prop]; } - return this; - }, - clone(dataAndEvents, deepDataAndEvents) { - dataAndEvents = dataAndEvents == null ? false : dataAndEvents; - deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; + // Passing an empty string as a 3rd parameter to .css will automatically + // attempt a parseFloat and fallback to a string if the parse fails. + // Simple values such as "10px" are parsed to Float; + // complex values such as "rotate(1rad)" are returned as-is. + result = jQuery.css(tween.elem, tween.prop, ""); - return this.map(function () { - return jQuery.clone(this, dataAndEvents, deepDataAndEvents); - }); + // Empty strings, null, undefined and "auto" are converted to 0. + return !result || result === "auto" ? 0 : result; }, - html(value) { - return access( - this, - function (value) { - var elem = this[0] || {}, i = 0, l = this.length; - if (value === undefined && elem.nodeType === 1) { - return elem.innerHTML; - } + set(tween) { + // Use step hook for back compat. + // Use cssHook if its there. + // Use .style if available and use plain properties where available. + if (jQuery.fx.step[tween.prop]) { + jQuery.fx.step[tween.prop](tween); + } else if (tween.elem.nodeType === 1 && (jQuery.cssHooks[tween.prop] || tween.elem.style[finalPropName(tween.prop)] != null)) { + jQuery.style(tween.elem, tween.prop, tween.now + tween.unit); + } else { + tween.elem[tween.prop] = tween.now; + } + } + } + }; - // See if we can take a shortcut and just use innerHTML - if (typeof value === "string" && !rnoInnerhtml.test(value) && !wrapMap[(rtagName.exec(value) || ["", ""])[1].toLowerCase()]) { - value = jQuery.htmlPrefilter(value); + // Support: IE <=9 only + // Panic based approach to setting things on disconnected nodes + Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { + set(tween) { + if (tween.elem.nodeType && tween.elem.parentNode) { + tween.elem[tween.prop] = tween.now; + } + } + }; - try { - for (; i < l; i++) { - elem = this[i] || {}; + jQuery.easing = { + linear(p) { + return p; + }, - // Remove element nodes and prevent memory leaks - if (elem.nodeType === 1) { - jQuery.cleanData(getAll(elem, false)); - elem.innerHTML = value; - } - } + swing(p) { + return 0.5 - Math.cos(p * Math.PI) / 2; + }, - elem = 0; - } catch(e) {} // If using innerHTML throws an exception, use the fallback method - } + _default: "swing" + }; - if (elem) { - this.empty().append(value); - } - }, - null, - value, - arguments.length - ); - }, - replaceWith() { - var ignored = []; + jQuery.fx = Tween.prototype.init; - // Make the changes, replacing each non-ignored context element with the new content - return domManip( - this, - arguments, - function (elem) { - var parent = this.parentNode; + // Back compat <1.8 extension point + jQuery.fx.step = {}; - if (jQuery.inArray(this, ignored) < 0) { - jQuery.cleanData(getAll(this)); + var fxNow, + inProgress, + rfxtypes = /^(?:toggle|show|hide)$/, + rrun = /queueHooks$/; - if (parent) { - parent.replaceChild(elem, this); - } - } - }, // Force callback invocation - ignored - ); + function schedule() { + if (inProgress) { + if (document.hidden === false && window.requestAnimationFrame) { + window.requestAnimationFrame(schedule); + } else { + window.setTimeout(schedule, jQuery.fx.interval); } - }); - jQuery.each( - { - appendTo: "append", - prependTo: "prepend", - insertBefore: "before", - insertAfter: "after", - replaceAll: "replaceWith" - }, - function (name, original) { - jQuery.fn[name] = function (selector) { - var elems, - ret = [], - insert = jQuery(selector), - last = insert.length - 1, - i = 0; - - for (; i <= last; i++) { - elems = i === last ? this : this.clone(true); - jQuery(insert[i])[original](elems); - // Support: Android <=4.0 only, PhantomJS 1 only - // .get() because push.apply(_, arraylike) throws on ancient WebKit - push.apply(ret, elems.get()); - } - - return this.pushStack(ret); - }; - } - ); + jQuery.fx.tick(); + } + } - var rnumnonpx = new RegExp("^(" + pnum + ")(?!px)[a-z%]+$", "i"); - var rcustomProp = /^--/; + // Animations created synchronously will run synchronously + function createFxNow() { + window.setTimeout(function () { + fxNow = undefined; + }); - var getStyles = function (elem) { - // Support: IE <=11 only, Firefox <=30 (trac-15098, trac-14150) - // IE throws on elements created in popups - // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" - var view = elem.ownerDocument.defaultView; + return fxNow = Date.now(); + } - if (!view || !view.opener) { - view = window; - } + // Generate parameters to create a standard animation + function genFx(type, includeWidth) { + var which, i = 0, attrs = { height: type }; - return view.getComputedStyle(elem); - }; + // If we include width, step value is 1 to do all cssExpand values, + // otherwise step value is 2 to skip over Left and Right + includeWidth = includeWidth ? 1 : 0; - var swap = function (elem, options, callback) { - var ret, name, old = {}; + for (; i < 4; i += 2 - includeWidth) { + which = cssExpand[i]; + attrs["margin" + which] = attrs["padding" + which] = type; + } - // Remember the old values, and insert the new ones - for (name in options) { - old[name] = elem.style[name]; - elem.style[name] = options[name]; - } + if (includeWidth) { + attrs.opacity = attrs.width = type; + } + + return attrs; + } - ret = callback.call(elem); + function createTween(value, prop, animation) { + var tween, + collection = (Animation.tweeners[prop] || []).concat(Animation.tweeners["*"]), + index = 0, + length = collection.length; - // Revert the old values - for (name in options) { - elem.style[name] = old[name]; + for (; index < length; index++) { + if (tween = collection[index].call(animation, prop, value)) { + // We're done with this property + return tween; } + } + } - return ret; - }; + function defaultPrefilter(elem, props, opts) { + var prop, + value, + toggle, + hooks, + oldfire, + propTween, + restoreDisplay, + display, + isBox = "width" in props || "height" in props, + anim = this, + orig = {}, + style = elem.style, + hidden = elem.nodeType && isHiddenWithinTree(elem), + dataShow = dataPriv.get(elem, "fxshow"); + + // Queue-skipping animations hijack the fx hooks + if (!opts.queue) { + hooks = jQuery._queueHooks(elem, "fx"); + + if (hooks.unqueued == null) { + hooks.unqueued = 0; + oldfire = hooks.empty.fire; + + hooks.empty.fire = function () { + if (!hooks.unqueued) { + oldfire(); + } + }; + } - var rboxStyle = new RegExp(cssExpand.join("|"), "i"); + hooks.unqueued++; - (function () { - // Executing both pixelPosition & boxSizingReliable tests require only one layout - // so they're executed at the same time to save the second computation. - function computeStyleTests() { - // This is a singleton, we need to execute it only once - if (!div) { - return; - } + anim.always(function () { + // Ensure the complete handler is called before this completes + anim.always(function () { + hooks.unqueued--; - container.style.cssText = "position:absolute;left:-11111px;width:60px;" + "margin-top:1px;padding:0;border:0"; - div.style.cssText = "position:relative;display:block;box-sizing:border-box;overflow:scroll;" + "margin:auto;border:1px;padding:1px;" + "width:60%;top:1%"; - documentElement.appendChild(container).appendChild(div); - - var divStyle = window.getComputedStyle(div); - - pixelPositionVal = divStyle.top !== "1%"; - // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44 - reliableMarginLeftVal = roundPixelMeasures(divStyle.marginLeft) === 12; - // Support: Android 4.0 - 4.3 only, Safari <=9.1 - 10.1, iOS <=7.0 - 9.3 - // Some styles come back with percentage values, even though they shouldn't - div.style.right = "60%"; - pixelBoxStylesVal = roundPixelMeasures(divStyle.right) === 36; - // Support: IE 9 - 11 only - // Detect misreporting of content dimensions for box-sizing:border-box elements - boxSizingReliableVal = roundPixelMeasures(divStyle.width) === 36; - // Support: IE 9 only - // Detect overflow:scroll screwiness (gh-3699) - // Support: Chrome <=64 - // Don't get tricked when zoom affects offsetWidth (gh-4029) - div.style.position = "absolute"; - scrollboxSizeVal = roundPixelMeasures(div.offsetWidth / 3) === 12; - documentElement.removeChild(container); - // Nullify the div so it wouldn't be stored in the memory and - // it will also be a sign that checks already performed - div = null; - } - - function roundPixelMeasures(measure) { - return Math.round(parseFloat(measure)); - } - - var pixelPositionVal, - boxSizingReliableVal, - scrollboxSizeVal, - pixelBoxStylesVal, - reliableTrDimensionsVal, - reliableMarginLeftVal, - container = document.createElement("div"), - div = document.createElement("div"); - - // Finish early in limited (non-browser) environments - if (!div.style) { - return; - } + if (!jQuery.queue(elem, "fx").length) { + hooks.empty.fire(); + } + }); + }); + } - // Support: IE <=9 - 11 only - // Style of cloned element affects source element cloned (trac-8908) - div.style.backgroundClip = "content-box"; - div.cloneNode(true).style.backgroundClip = ""; - support.clearCloneStyle = div.style.backgroundClip === "content-box"; + // Detect show/hide animations + for (prop in props) { + value = props[prop]; - jQuery.extend(support, { - boxSizingReliable() { - computeStyleTests(); - return boxSizingReliableVal; - }, - pixelBoxStyles() { - computeStyleTests(); - return pixelBoxStylesVal; - }, - pixelPosition() { - computeStyleTests(); - return pixelPositionVal; - }, - reliableMarginLeft() { - computeStyleTests(); - return reliableMarginLeftVal; - }, - scrollboxSize() { - computeStyleTests(); - return scrollboxSizeVal; - }, - reliableTrDimensions() { - var table, tr, trChild, trStyle; - - if (reliableTrDimensionsVal == null) { - table = document.createElement("table"); - tr = document.createElement("tr"); - trChild = document.createElement("div"); - table.style.cssText = "position:absolute;left:-11111px;border-collapse:separate"; - tr.style.cssText = "box-sizing:content-box;border:1px solid"; - // Support: Chrome 86+ - // Height set through cssText does not get applied. - // Computed height then comes back as 0. - tr.style.height = "1px"; - trChild.style.height = "9px"; - // Support: Android 8 Chrome 86+ - // In our bodyBackground.html iframe, - // display for all div elements is set to "inline", - // which causes a problem only in Android 8 Chrome 86. - // Ensuring the div is `display: block` - // gets around this issue. - trChild.style.display = "block"; - documentElement.appendChild(table).appendChild(tr).appendChild(trChild); - trStyle = window.getComputedStyle(tr); - reliableTrDimensionsVal = parseInt(trStyle.height, 10) + parseInt(trStyle.borderTopWidth, 10) + parseInt(trStyle.borderBottomWidth, 10) === tr.offsetHeight; - documentElement.removeChild(table); - } - - return reliableTrDimensionsVal; - } - }); - })(); + if (rfxtypes.test(value)) { + delete props[prop]; + toggle = toggle || value === "toggle"; - function curCSS(elem, name, computed) { - var width, - minWidth, - maxWidth, - ret, - isCustomProp = rcustomProp.test(name), - // Support: Firefox 51+ - // Retrieving style before computed somehow - // fixes an issue with getting wrong values - // on detached elements - style = elem.style; + if (value === (hidden ? "hide" : "show")) { + // Pretend to be hidden if this is a "show" and + // there is still data from a stopped show/hide + if (value === "show" && dataShow && dataShow[prop] !== undefined) { + hidden = true; - computed = computed || getStyles(elem); + // Ignore all other no-op show/hide data + } else { + continue; + } + } - // getPropertyValue is needed for: - // .css('filter') (IE 9 only, trac-12537) - // .css('--customProperty) (gh-3144) - if (computed) { - // Support: IE <=9 - 11+ - // IE only supports `"float"` in `getPropertyValue`; in computed styles - // it's only available as `"cssFloat"`. We no longer modify properties - // sent to `.css()` apart from camelCasing, so we need to check both. - // Normally, this would create difference in behavior: if - // `getPropertyValue` returns an empty string, the value returned - // by `.css()` would be `undefined`. This is usually the case for - // disconnected elements. However, in IE even disconnected elements - // with no styles return `"none"` for `getPropertyValue( "float" )` - ret = computed.getPropertyValue(name) || computed[name]; - - if (isCustomProp && ret) { - // Support: Firefox 105+, Chrome <=105+ - // Spec requires trimming whitespace for custom properties (gh-4926). - // Firefox only trims leading whitespace. Chrome just collapses - // both leading & trailing whitespace to a single space. - // - // Fall back to `undefined` if empty string returned. - // This collapses a missing definition with property defined - // and set to an empty string but there's no standard API - // allowing us to differentiate them without a performance penalty - // and returning `undefined` aligns with older jQuery. - // - // rtrimCSS treats U+000D CARRIAGE RETURN and U+000C FORM FEED - // as whitespace while CSS does not, but this is not a problem - // because CSS preprocessing replaces them with U+000A LINE FEED - // (which *is* CSS whitespace) - // https://www.w3.org/TR/css-syntax-3/#input-preprocessing - ret = ret.replace(rtrimCSS, "$1") || undefined; - } - - if (ret === "" && !isAttached(elem)) { - ret = jQuery.style(elem, name); - } - - // A tribute to the "awesome hack by Dean Edwards" - // Android Browser returns percentage for some values, - // but width seems to be reliably pixels. - // This is against the CSSOM draft spec: - // https://drafts.csswg.org/cssom/#resolved-values - if (!support.pixelBoxStyles() && rnumnonpx.test(ret) && rboxStyle.test(name)) { - // Remember the original values - width = style.width; - minWidth = style.minWidth; - maxWidth = style.maxWidth; - // Put in the new values to get a computed value out - style.minWidth = style.maxWidth = style.width = ret; - ret = computed.width; - // Revert the changed values - style.width = width; - style.minWidth = minWidth; - style.maxWidth = maxWidth; - } - } - - return ret !== undefined ? // Support: IE <=9 - 11 only - // IE returns zIndex value as an integer. - ret + "" : ret; + orig[prop] = dataShow && dataShow[prop] || jQuery.style(elem, prop); + } } - function addGetHookIf(conditionFn, hookFn) { - // Define the hook, we'll check on the first run if it's really needed. - return { - get() { - if (conditionFn()) { - // Hook not needed (or it's not possible to use it due - // to missing dependency), remove it. - delete this.get; - return; - } + // Bail out if this is a no-op like .hide().hide() + propTween = !jQuery.isEmptyObject(props); - // Hook needed; redefine it so that the support test is not executed again. - return (this.get = hookFn).apply(this, arguments); - } - }; + if (!propTween && jQuery.isEmptyObject(orig)) { + return; } - var cssPrefixes = ["Webkit", "Moz", "ms"], - emptyStyle = document.createElement("div").style, - vendorProps = {}; + // Restrict "overflow" and "display" styles during box animations + if (isBox && elem.nodeType === 1) { + // Support: IE <=9 - 11, Edge 12 - 15 + // Record all 3 overflow attributes because IE does not infer the shorthand + // from identically-valued overflowX and overflowY and Edge just mirrors + // the overflowX value there. + opts.overflow = [style.overflow, style.overflowX, style.overflowY]; - // Return a vendor-prefixed property or undefined - function vendorPropName(name) { - // Check for vendor prefixed names - var capName = name[0].toUpperCase() + name.slice(1), - i = cssPrefixes.length; + // Identify a display type, preferring old show/hide data over the CSS cascade + restoreDisplay = dataShow && dataShow.display; - while (i--) { - name = cssPrefixes[i] + capName; + if (restoreDisplay == null) { + restoreDisplay = dataPriv.get(elem, "display"); + } + + display = jQuery.css(elem, "display"); + + if (display === "none") { + if (restoreDisplay) { + display = restoreDisplay; + } else { + // Get nonempty value(s) by temporarily forcing visibility + showHide([elem], true); - if (name in emptyStyle) { - return name; + restoreDisplay = elem.style.display || restoreDisplay; + display = jQuery.css(elem, "display"); + showHide([elem]); } } - } - // Return a potentially-mapped jQuery.cssProps or vendor prefixed property - function finalPropName(name) { - var final = jQuery.cssProps[name] || vendorProps[name]; + // Animate inline elements as inline-block + if (display === "inline" || display === "inline-block" && restoreDisplay != null) { + if (jQuery.css(elem, "float") === "none") { + // Restore the original display value at the end of pure show/hide animations + if (!propTween) { + anim.done(function () { + style.display = restoreDisplay; + }); - if (final) { - return final; - } + if (restoreDisplay == null) { + display = style.display; + restoreDisplay = display === "none" ? "" : display; + } + } - if (name in emptyStyle) { - return name; + style.display = "inline-block"; + } } - - return vendorProps[name] = vendorPropName(name) || name; } - var // Swappable if display is none or starts with table - // except "table", "table-cell", or "table-caption" - // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display - rdisplayswap = /^(none|table(?!-c[ea]).+)/, - cssShow = { - position: "absolute", - visibility: "hidden", - display: "block" - }, - cssNormalTransform = { letterSpacing: "0", fontWeight: "400" }; - - function setPositiveNumber(_elem, value, subtract) { - // Any relative (+/-) values have already been - // normalized at this point - var matches = rcssNum.exec(value); + if (opts.overflow) { + style.overflow = "hidden"; - return matches ? // Guard against undefined "subtract", e.g., when used as in cssHooks - Math.max(0, matches[2] - (subtract || 0)) + (matches[3] || "px") : value; + anim.always(function () { + style.overflow = opts.overflow[0]; + style.overflowX = opts.overflow[1]; + style.overflowY = opts.overflow[2]; + }); } - function boxModelAdjustment( - elem, - dimension, - box, - isBorderBox, - styles, - computedVal - ) { - var i = dimension === "width" ? 1 : 0, - extra = 0, - delta = 0, - marginDelta = 0; + // Implement show/hide animations + propTween = false; - // Adjustment may not be necessary - if (box === (isBorderBox ? "border" : "content")) { - return 0; - } + for (prop in orig) { + // General show/hide setup for this element animation + if (!propTween) { + if (dataShow) { + if ("hidden" in dataShow) { + hidden = dataShow.hidden; + } + } else { + dataShow = dataPriv.access(elem, "fxshow", { display: restoreDisplay }); + } - for (; i < 4; i += 2) { - // Both box models exclude margin - // Count margin delta separately to only add it after scroll gutter adjustment. - // This is needed to make negative margins work with `outerHeight( true )` (gh-3982). - if (box === "margin") { - marginDelta += jQuery.css(elem, box + cssExpand[i], true, styles); + // Store hidden/visible for toggle so `.stop().toggle()` "reverses" + if (toggle) { + dataShow.hidden = !hidden; } - // If we get here with a content-box, we're seeking "padding" or "border" or "margin" - if (!isBorderBox) { - // Add padding - delta += jQuery.css(elem, "padding" + cssExpand[i], true, styles); + // Show elements before animating them + if (hidden) { + showHide([elem], true); + } - // For "border" or "margin", add border - if (box !== "padding") { - delta += jQuery.css(elem, "border" + cssExpand[i] + "Width", true, styles); - } else { - extra += jQuery.css( - elem, // But still keep track of it otherwise - "border" + cssExpand[i] + "Width", - true, - styles - ); - } - } else // "padding" or "margin" - { - // For "content", subtract padding - if (box === "content") { - delta -= jQuery.css( - elem, // If we get here with a border-box (content + padding + border), we're seeking "content" or - "padding" + cssExpand[i], - true, - styles - ); + /* eslint-disable no-loop-func */ + anim.done(function () { + /* eslint-enable no-loop-func */ + // The final step of a "hide" animation is actually hiding the element + if (!hidden) { + showHide([elem]); } - // For "content" or "padding", subtract border - if (box !== "margin") { - delta -= jQuery.css(elem, "border" + cssExpand[i] + "Width", true, styles); + dataPriv.remove(elem, "fxshow"); + + for (prop in orig) { + jQuery.style(elem, prop, orig[prop]); } - } + }); } - // Account for positive content-box scroll gutter when requested by providing computedVal - if (!isBorderBox && computedVal >= 0) { - // offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border - // Assuming integer scroll gutter, subtract the rest and round down - delta += Math.max(0, Math.ceil(elem["offset" + dimension[0].toUpperCase() + dimension.slice(1)] - computedVal - delta - extra - 0.5)) || 0; // If offsetWidth/offsetHeight is unknown, then we can't determine content-box scroll gutter - // Use an explicit zero to avoid NaN (gh-3964) - } + // Per-property setup + propTween = createTween(hidden ? dataShow[prop] : 0, prop, anim); + + if (!(prop in dataShow)) { + dataShow[prop] = propTween.start; - return delta + marginDelta; + if (hidden) { + propTween.end = propTween.start; + propTween.start = 0; + } + } } + } - function getWidthOrHeight(elem, dimension, extra) { - // Start with computed style - var styles = getStyles(elem), - // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-4322). - // Fake content-box until we know it's needed to know the true value. - boxSizingNeeded = !support.boxSizingReliable() || extra, - isBorderBox = boxSizingNeeded && jQuery.css(elem, "boxSizing", false, styles) === "border-box", - valueIsBorderBox = isBorderBox, - val = curCSS(elem, dimension, styles), - offsetProp = "offset" + dimension[0].toUpperCase() + dimension.slice(1); + function propFilter(props, specialEasing) { + var index, name, easing, value, hooks; - // Support: Firefox <=54 - // Return a confounding non-pixel value or feign ignorance, as appropriate. - if (rnumnonpx.test(val)) { - if (!extra) { - return val; - } + // camelCase, specialEasing and expand cssHook pass + for (index in props) { + name = camelCase(index); + easing = specialEasing[name]; + value = props[index]; - val = "auto"; + if (Array.isArray(value)) { + easing = value[1]; + value = props[index] = value[0]; } - // Support: IE 9 - 11 only - // Use offsetWidth/offsetHeight for when box sizing is unreliable. - // In those cases, the computed value can be trusted to be border-box. - if ((!support.boxSizingReliable() && isBorderBox || // Support: IE 10 - 11+, Edge 15 - 18+ - // IE/Edge misreport `getComputedStyle` of table rows with width/height - // set in CSS while `offset*` properties report correct values. - // Interestingly, in some cases IE 9 doesn't suffer from this issue. - !support.reliableTrDimensions() && nodeName(elem, "tr") || // Fall back to offsetWidth/offsetHeight when value is "auto" - // This happens for inline elements with no explicit setting (gh-3571) - val === "auto" || // Support: Android <=4.1 - 4.3 only - // Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602) - !parseFloat(val) && jQuery.css(elem, "display", false, styles) === "inline") && // Make sure the element is visible & connected - elem.getClientRects().length) { - isBorderBox = jQuery.css(elem, "boxSizing", false, styles) === "border-box"; - // Where available, offsetWidth/offsetHeight approximate border box dimensions. - // Where not available (e.g., SVG), assume unreliable box-sizing and interpret the - // retrieved value as a content box dimension. - valueIsBorderBox = offsetProp in elem; - - if (valueIsBorderBox) { - val = elem[offsetProp]; - } - } - - // Normalize "" and auto - val = parseFloat(val) || 0; - // Adjust for the element's box model - return val + boxModelAdjustment(elem, dimension, extra || (isBorderBox ? "border" : "content"), valueIsBorderBox, styles, // Provide the current computed size to request scroll gutter calculation (gh-3589) - val) + "px"; - } - - jQuery.extend({ - // Add in style property hooks for overriding the default - // behavior of getting and setting a style property - cssHooks: { - opacity: { - get(elem, computed) { - if (computed) { - // We should always get a number back from opacity - var ret = curCSS(elem, "opacity"); - - return ret === "" ? "1" : ret; - } + if (index !== name) { + props[name] = value; + delete props[index]; + } + + hooks = jQuery.cssHooks[name]; + + if (hooks && "expand" in hooks) { + value = hooks.expand(value); + delete props[name]; + + // Not quite $.extend, this won't overwrite existing keys. + // Reusing 'index' because we have the correct "name" + for (index in value) { + if (!(index in props)) { + props[index] = value[index]; + specialEasing[index] = easing; } } - }, - // Don't automatically add "px" to these possibly-unitless properties - cssNumber: { - animationIterationCount: true, - aspectRatio: true, - borderImageSlice: true, - columnCount: true, - flexGrow: true, - flexShrink: true, - fontWeight: true, - gridArea: true, - gridColumn: true, - gridColumnEnd: true, - gridColumnStart: true, - gridRow: true, - gridRowEnd: true, - gridRowStart: true, - lineHeight: true, - opacity: true, - order: true, - orphans: true, - scale: true, - widows: true, - zIndex: true, - zoom: true, - // SVG-related - fillOpacity: true, - floodOpacity: true, - stopOpacity: true, - strokeMiterlimit: true, - strokeOpacity: true - }, - // Add in properties whose names you wish to fix before - // setting or getting the value - cssProps: {}, - style(elem, name, value, extra) { - // Don't set styles on text and comment nodes - if (!elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style) { - return; + } else { + specialEasing[name] = easing; + } + } + } + + function Animation(elem, properties, options) { + var result, + stopped, + index = 0, + length = Animation.prefilters.length, + deferred = jQuery.Deferred().always(function () { + // Don't match elem in the :animated selector + delete tick.elem; + }), + tick = function () { + if (stopped) { + return false; } - // Make sure that we're working with the right name - var ret, - type, - hooks, - origName = camelCase(name), - isCustomProp = rcustomProp.test(name), - style = elem.style; + var currentTime = fxNow || createFxNow(), + remaining = Math.max(0, animation.startTime + animation.duration - currentTime), + // Support: Android 2.3 only + // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (trac-12497) + temp = remaining / animation.duration || 0, + percent = 1 - temp, + index = 0, + length = animation.tweens.length; - // Make sure that we're working with the right name. We don't - // want to query the value if it is a CSS custom property - // since they are user-defined. - if (!isCustomProp) { - name = finalPropName(origName); + for (; index < length; index++) { + animation.tweens[index].run(percent); } - // Gets hook for the prefixed version, then unprefixed version - hooks = jQuery.cssHooks[name] || jQuery.cssHooks[origName]; + deferred.notifyWith(elem, [animation, percent, remaining]); - // Check if we're setting a value - if (value !== undefined) { - type = typeof value; + // If there's more to do, yield + if (percent < 1 && length) { + return remaining; + } - // Convert "+=" or "-=" to relative numbers (trac-7345) - if (type === "string" && (ret = rcssNum.exec(value)) && ret[1]) { - value = adjustCSS(elem, name, ret); - // Fixes bug trac-9237 - type = "number"; - } + // If this was an empty animation, synthesize a final progress notification + if (!length) { + deferred.notifyWith(elem, [animation, 1, 0]); + } - // Make sure that null and NaN values aren't set (trac-7116) - if (value == null || value !== value) { - return; - } + // Resolve the animation and report its conclusion + deferred.resolveWith(elem, [animation]); - // If a number was passed in, add the unit (except for certain CSS properties) - // The isCustomProp check can be removed in jQuery 4.0 when we only auto-append - // "px" to a few hardcoded values. - if (type === "number" && !isCustomProp) { - value += ret && ret[3] || (jQuery.cssNumber[origName] ? "" : "px"); - } + return false; + }, + animation = deferred.promise({ + elem, + props: jQuery.extend({}, properties), + opts: jQuery.extend(true, { specialEasing: {}, easing: jQuery.easing._default }, options), + originalProperties: properties, + originalOptions: options, + startTime: fxNow || createFxNow(), + duration: options.duration, + tweens: [], + + createTween(prop, end) { + var tween = jQuery.Tween(elem, animation.opts, prop, end, animation.opts.specialEasing[prop] || animation.opts.easing); + + animation.tweens.push(tween); + + return tween; + }, + + stop(gotoEnd) { + var index = 0, + // If we are going to the end, we want to run all the tweens + // otherwise we skip this part + length = gotoEnd ? animation.tweens.length : 0; - // background-* props affect original clone's values - if (!support.clearCloneStyle && value === "" && name.indexOf("background") === 0) { - style[name] = "inherit"; + if (stopped) { + return this; } - // If a hook was provided, use that value, otherwise just set the specified value - if (!hooks || !("set" in hooks) || (value = hooks.set(elem, value, extra)) !== undefined) { - if (isCustomProp) { - style.setProperty(name, value); - } else { - style[name] = value; - } + stopped = true; + + for (; index < length; index++) { + animation.tweens[index].run(1); } - } else { - // If a hook was provided get the non-computed value from there - if (hooks && "get" in hooks && (ret = hooks.get(elem, false, extra)) !== undefined) { - return ret; + + // Resolve when we played the last frame; otherwise, reject + if (gotoEnd) { + deferred.notifyWith(elem, [animation, 1, 0]); + deferred.resolveWith(elem, [animation, gotoEnd]); + } else { + deferred.rejectWith(elem, [animation, gotoEnd]); } - // Otherwise just get the value from the style object - return style[name]; + return this; } - }, - css(elem, name, extra, styles) { - var val, - num, - hooks, - origName = camelCase(name), - isCustomProp = rcustomProp.test(name); + }), + props = animation.props; - // Make sure that we're working with the right name. We don't - // want to modify the value if it is a CSS custom property - // since they are user-defined. - if (!isCustomProp) { - name = finalPropName(origName); - } + propFilter(props, animation.opts.specialEasing); - // Try prefixed name followed by the unprefixed name - hooks = jQuery.cssHooks[name] || jQuery.cssHooks[origName]; + for (; index < length; index++) { + result = Animation.prefilters[index].call(animation, elem, props, animation.opts); - // If a hook was provided get the computed value from there - if (hooks && "get" in hooks) { - val = hooks.get(elem, true, extra); + if (result) { + if (isFunction(result.stop)) { + jQuery._queueHooks(animation.elem, animation.opts.queue).stop = result.stop.bind(result); } - // Otherwise, if a way to get the computed value exists, use that - if (val === undefined) { - val = curCSS(elem, name, styles); - } + return result; + } + } - // Convert "normal" to computed value - if (val === "normal" && name in cssNormalTransform) { - val = cssNormalTransform[name]; - } + jQuery.map(props, createTween, animation); - // Make numeric if forced or a qualifier was provided and val looks numeric - if (extra === "" || extra) { - num = parseFloat(val); - return extra === true || isFinite(num) ? num || 0 : val; - } + if (isFunction(animation.opts.start)) { + animation.opts.start.call(elem, animation); + } - return val; - } - }); + // Attach callbacks from options + animation.progress(animation.opts.progress).done(animation.opts.done, animation.opts.complete).fail(animation.opts.fail).always(animation.opts.always); - jQuery.each(["height", "width"], function (_i, dimension) { - jQuery.cssHooks[dimension] = { - get(elem, computed, extra) { - if (computed) { - // Certain elements can have dimension info if we invisibly show them - // but it must have a current display style that would benefit - return rdisplayswap.test(jQuery.css(elem, "display")) && (// Support: Safari 8+ - // Table columns in Safari have non-zero offsetWidth & zero - // getBoundingClientRect().width unless display is changed. - // Support: IE <=11 only - // Running getBoundingClientRect on a disconnected node - // in IE throws an error. - !elem.getClientRects().length || !elem.getBoundingClientRect().width) - ? swap(elem, cssShow, function () { - return getWidthOrHeight(elem, dimension, extra); - }) - : getWidthOrHeight(elem, dimension, extra); - } - }, - set(elem, value, extra) { - var matches, - styles = getStyles(elem), - // Only read styles.position if the test has a chance to fail - // to avoid forcing a reflow. - scrollboxSizeBuggy = !support.scrollboxSize() && styles.position === "absolute", - // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-3991) - boxSizingNeeded = scrollboxSizeBuggy || extra, - isBorderBox = boxSizingNeeded && jQuery.css(elem, "boxSizing", false, styles) === "border-box", - subtract = extra ? boxModelAdjustment(elem, dimension, extra, isBorderBox, styles) : 0; + jQuery.fx.timer(jQuery.extend(tick, { elem, anim: animation, queue: animation.opts.queue })); - // Account for unreliable border-box dimensions by comparing offset* to computed and - // faking a content-box to get border and padding (gh-3699) - if (isBorderBox && scrollboxSizeBuggy) { - subtract -= Math.ceil(elem["offset" + dimension[0].toUpperCase() + dimension.slice(1)] - parseFloat(styles[dimension]) - boxModelAdjustment(elem, dimension, "border", false, styles) - 0.5); - } + return animation; + } - // Convert to pixels if value adjustment is needed - if (subtract && (matches = rcssNum.exec(value)) && (matches[3] || "px") !== "px") { - elem.style[dimension] = value; - value = jQuery.css(elem, dimension); - } + jQuery.Animation = jQuery.extend(Animation, { + tweeners: { + "*": [ + function (prop, value) { + var tween = this.createTween(prop, value); - return setPositiveNumber(elem, value, subtract); + adjustCSS(tween.elem, prop, rcssNum.exec(value), tween); + + return tween; } - }; - }); + ] + }, - jQuery.cssHooks.marginLeft = addGetHookIf(support.reliableMarginLeft, function (elem, computed) { - if (computed) { - return (parseFloat(curCSS(elem, "marginLeft")) || elem.getBoundingClientRect().left - swap(elem, { marginLeft: 0 }, function () { - return elem.getBoundingClientRect().left; - })) + "px"; + tweener(props, callback) { + if (isFunction(props)) { + callback = props; + props = ["*"]; + } else { + props = props.match(rnothtmlwhite); } - }); - // These hooks are used by animate to expand properties - jQuery.each({ margin: "", padding: "", border: "Width" }, function (prefix, suffix) { - jQuery.cssHooks[prefix + suffix] = { - expand(value) { - var i = 0, - expanded = {}, - // Assumes a single number if not a string - parts = typeof value === "string" ? value.split(" ") : [value]; + var prop, index = 0, length = props.length; - for (; i < 4; i++) { - expanded[prefix + cssExpand[i] + suffix] = parts[i] || parts[i - 2] || parts[0]; - } + for (; index < length; index++) { + prop = props[index]; + Animation.tweeners[prop] = Animation.tweeners[prop] || []; + Animation.tweeners[prop].unshift(callback); + } + }, - return expanded; - } - }; + prefilters: [defaultPrefilter], - if (prefix !== "margin") { - jQuery.cssHooks[prefix + suffix].set = setPositiveNumber; + prefilter(callback, prepend) { + if (prepend) { + Animation.prefilters.unshift(callback); + } else { + Animation.prefilters.push(callback); } - }); + } + }); + + jQuery.speed = function (speed, easing, fn) { + var opt = speed && typeof speed === "object" + ? jQuery.extend({}, speed) + : { + complete: fn || !fn && easing || isFunction(speed) && speed, + duration: speed, + easing: fn && easing || easing && !isFunction(easing) && easing + }; - jQuery.fn.extend({ - css(name, value) { - return access( - this, - function (elem, name, value) { - var styles, len, map = {}, i = 0; + // Go to the end state if fx are off + if (jQuery.fx.off) { + opt.duration = 0; + } else { + if (typeof opt.duration !== "number") { + if (opt.duration in jQuery.fx.speeds) { + opt.duration = jQuery.fx.speeds[opt.duration]; + } else { + opt.duration = jQuery.fx.speeds._default; + } + } + } - if (Array.isArray(name)) { - styles = getStyles(elem); - len = name.length; + // Normalize opt.queue - true/undefined/null -> "fx" + if (opt.queue == null || opt.queue === true) { + opt.queue = "fx"; + } - for (; i < len; i++) { - map[name[i]] = jQuery.css(elem, name[i], false, styles); - } + // Queueing + opt.old = opt.complete; - return map; - } + opt.complete = function () { + if (isFunction(opt.old)) { + opt.old.call(this); + } - return value !== undefined ? jQuery.style(elem, name, value) : jQuery.css(elem, name); - }, - name, - value, - arguments.length > 1 - ); + if (opt.queue) { + jQuery.dequeue(this, opt.queue); } - }); + }; - function Tween(elem, options, prop, end, easing) { - return new Tween.prototype.init(elem, options, prop, end, easing); - } + return opt; + }; - jQuery.Tween = Tween; + jQuery.fn.extend({ + fadeTo(speed, to, easing, callback) { + // Show any hidden elements after setting opacity to 0 + return this.filter(isHiddenWithinTree).css("opacity", 0).show().// Animate to the value specified + end().animate({ opacity: to }, speed, easing, callback); + }, - Tween.prototype = { - constructor: Tween, - init(elem, options, prop, end, easing, unit) { - this.elem = elem; - this.prop = prop; - this.easing = easing || jQuery.easing._default; - this.options = options; - this.start = this.now = this.cur(); - this.end = end; - this.unit = unit || (jQuery.cssNumber[prop] ? "" : "px"); - }, - cur() { - var hooks = Tween.propHooks[this.prop]; + animate(prop, speed, easing, callback) { + var empty = jQuery.isEmptyObject(prop), + optall = jQuery.speed(speed, easing, callback), + doAnimation = function () { + // Operate on a copy of prop so per-property easing won't be lost + var anim = Animation(this, jQuery.extend({}, prop), optall); - return hooks && hooks.get ? hooks.get(this) : Tween.propHooks._default.get(this); - }, - run(percent) { - var eased, hooks = Tween.propHooks[this.prop]; + // Empty animations, or finishing resolves immediately + if (empty || dataPriv.get(this, "finish")) { + anim.stop(true); + } + }; - if (this.options.duration) { - this.pos = eased = jQuery.easing[this.easing](percent, this.options.duration * percent, 0, 1, this.options.duration); - } else { - this.pos = eased = percent; - } + doAnimation.finish = doAnimation; - this.now = (this.end - this.start) * eased + this.start; + return empty || optall.queue === false + ? this.each(doAnimation) + : this.queue(optall.queue, doAnimation); + }, - if (this.options.step) { - this.options.step.call(this.elem, this.now, this); - } + stop(type, clearQueue, gotoEnd) { + var stopQueue = function (hooks) { + var stop = hooks.stop; - if (hooks && hooks.set) { - hooks.set(this); - } else { - Tween.propHooks._default.set(this); - } + delete hooks.stop; + stop(gotoEnd); + }; - return this; + if (typeof type !== "string") { + gotoEnd = clearQueue; + clearQueue = type; + type = undefined; } - }; - Tween.prototype.init.prototype = Tween.prototype; + if (clearQueue) { + this.queue(type || "fx", []); + } - Tween.propHooks = { - _default: { - get(tween) { - var result; + return this.each(function () { + var dequeue = true, + index = type != null && type + "queueHooks", + timers = jQuery.timers, + data = dataPriv.get(this); - // Use a property on the element directly when it is not a DOM element, - // or when there is no matching style property that exists. - if (tween.elem.nodeType !== 1 || tween.elem[tween.prop] != null && tween.elem.style[tween.prop] == null) { - return tween.elem[tween.prop]; + if (index) { + if (data[index] && data[index].stop) { + stopQueue(data[index]); + } + } else { + for (index in data) { + if (data[index] && data[index].stop && rrun.test(index)) { + stopQueue(data[index]); + } } + } - // Passing an empty string as a 3rd parameter to .css will automatically - // attempt a parseFloat and fallback to a string if the parse fails. - // Simple values such as "10px" are parsed to Float; - // complex values such as "rotate(1rad)" are returned as-is. - result = jQuery.css(tween.elem, tween.prop, ""); - // Empty strings, null, undefined and "auto" are converted to 0. - return !result || result === "auto" ? 0 : result; - }, - set(tween) { - // Use step hook for back compat. - // Use cssHook if its there. - // Use .style if available and use plain properties where available. - if (jQuery.fx.step[tween.prop]) { - jQuery.fx.step[tween.prop](tween); - } else if (tween.elem.nodeType === 1 && (jQuery.cssHooks[tween.prop] || tween.elem.style[finalPropName(tween.prop)] != null)) { - jQuery.style(tween.elem, tween.prop, tween.now + tween.unit); - } else { - tween.elem[tween.prop] = tween.now; + for (index = timers.length; index--; ) { + if (timers[index].elem === this && (type == null || timers[index].queue === type)) { + timers[index].anim.stop(gotoEnd); + dequeue = false; + timers.splice(index, 1); } } - } - }; - // Support: IE <=9 only - // Panic based approach to setting things on disconnected nodes - Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { - set(tween) { - if (tween.elem.nodeType && tween.elem.parentNode) { - tween.elem[tween.prop] = tween.now; + // Start the next in the queue if the last step wasn't forced. + // Timers currently will call their complete callbacks, which + // will dequeue but only if they were gotoEnd. + if (dequeue || !gotoEnd) { + jQuery.dequeue(this, type); } + }); + }, + + finish(type) { + if (type !== false) { + type = type || "fx"; } - }; - jQuery.easing = { - linear(p) { - return p; - }, - swing(p) { - return 0.5 - Math.cos(p * Math.PI) / 2; - }, - _default: "swing" - }; + return this.each(function () { + var index, + data = dataPriv.get(this), + queue = data[type + "queue"], + hooks = data[type + "queueHooks"], + timers = jQuery.timers, + length = queue ? queue.length : 0; - jQuery.fx = Tween.prototype.init; - // Back compat <1.8 extension point - jQuery.fx.step = {}; + // Enable finishing flag on private data + data.finish = true; - var fxNow, - inProgress, - rfxtypes = /^(?:toggle|show|hide)$/, - rrun = /queueHooks$/; + // Empty the queue first + jQuery.queue(this, type, []); - function schedule() { - if (inProgress) { - if (document.hidden === false && window.requestAnimationFrame) { - window.requestAnimationFrame(schedule); - } else { - window.setTimeout(schedule, jQuery.fx.interval); + if (hooks && hooks.stop) { + hooks.stop.call(this, true); } - jQuery.fx.tick(); - } - } + // Look for any active animations, and finish them + for (index = timers.length; index--; ) { + if (timers[index].elem === this && timers[index].queue === type) { + timers[index].anim.stop(true); + timers.splice(index, 1); + } + } - // Animations created synchronously will run synchronously - function createFxNow() { - window.setTimeout(function () { - fxNow = undefined; - }); + // Look for any animations in the old queue and finish them + for (index = 0; index < length; index++) { + if (queue[index] && queue[index].finish) { + queue[index].finish.call(this); + } + } - return fxNow = Date.now(); + // Turn off finishing flag + delete data.finish; + }); } + }); - // Generate parameters to create a standard animation - function genFx(type, includeWidth) { - var which, i = 0, attrs = { height: type }; + jQuery.each(["toggle", "show", "hide"], function (_i, name) { + var cssFn = jQuery.fn[name]; - // If we include width, step value is 1 to do all cssExpand values, - // otherwise step value is 2 to skip over Left and Right - includeWidth = includeWidth ? 1 : 0; + jQuery.fn[name] = function (speed, easing, callback) { + return speed == null || typeof speed === "boolean" + ? cssFn.apply(this, arguments) + : this.animate(genFx(name, true), speed, easing, callback); + }; + }); + + // Generate shortcuts for custom animations + jQuery.each( + { + slideDown: genFx("show"), + slideUp: genFx("hide"), + slideToggle: genFx("toggle"), + fadeIn: { opacity: "show" }, + fadeOut: { opacity: "hide" }, + fadeToggle: { opacity: "toggle" } + }, + function (name, props) { + jQuery.fn[name] = function (speed, easing, callback) { + return this.animate(props, speed, easing, callback); + }; + } + ); - for (; i < 4; i += 2 - includeWidth) { - which = cssExpand[i]; - attrs["margin" + which] = attrs["padding" + which] = type; - } + jQuery.timers = []; - if (includeWidth) { - attrs.opacity = attrs.width = type; - } + jQuery.fx.tick = function () { + var timer, i = 0, timers = jQuery.timers; - return attrs; - } + fxNow = Date.now(); - function createTween(value, prop, animation) { - var tween, - collection = (Animation.tweeners[prop] || []).concat(Animation.tweeners["*"]), - index = 0, - length = collection.length; + for (; i < timers.length; i++) { + timer = timers[i]; - for (; index < length; index++) { - if (tween = collection[index].call(animation, prop, value)) { - // We're done with this property - return tween; - } + // Run the timer and safely remove it when done (allowing for external removal) + if (!timer() && timers[i] === timer) { + timers.splice(i--, 1); } } - function defaultPrefilter(elem, props, opts) { - var prop, - value, - toggle, - hooks, - oldfire, - propTween, - restoreDisplay, - display, - isBox = "width" in props || "height" in props, - anim = this, - orig = {}, - style = elem.style, - hidden = elem.nodeType && isHiddenWithinTree(elem), - dataShow = dataPriv.get(elem, "fxshow"); - - // Queue-skipping animations hijack the fx hooks - if (!opts.queue) { - hooks = jQuery._queueHooks(elem, "fx"); - - if (hooks.unqueued == null) { - hooks.unqueued = 0; - oldfire = hooks.empty.fire; - - hooks.empty.fire = function () { - if (!hooks.unqueued) { - oldfire(); - } - }; - } + if (!timers.length) { + jQuery.fx.stop(); + } - hooks.unqueued++; + fxNow = undefined; + }; - anim.always(function () { - // Ensure the complete handler is called before this completes - anim.always(function () { - hooks.unqueued--; + jQuery.fx.timer = function (timer) { + jQuery.timers.push(timer); + jQuery.fx.start(); + }; - if (!jQuery.queue(elem, "fx").length) { - hooks.empty.fire(); - } - }); - }); - } + jQuery.fx.interval = 13; - // Detect show/hide animations - for (prop in props) { - value = props[prop]; + jQuery.fx.start = function () { + if (inProgress) { + return; + } - if (rfxtypes.test(value)) { - delete props[prop]; - toggle = toggle || value === "toggle"; + inProgress = true; + schedule(); + }; - if (value === (hidden ? "hide" : "show")) { - // Pretend to be hidden if this is a "show" and - // there is still data from a stopped show/hide - if (value === "show" && dataShow && dataShow[prop] !== undefined) { - hidden = true; - } else { - continue; // Ignore all other no-op show/hide data - } - } + jQuery.fx.stop = function () { + inProgress = null; + }; - orig[prop] = dataShow && dataShow[prop] || jQuery.style(elem, prop); - } - } + jQuery.fx.speeds = { + slow: 600, + fast: 200, - // Bail out if this is a no-op like .hide().hide() - propTween = !jQuery.isEmptyObject(props); + // Default speed + _default: 400 + }; - if (!propTween && jQuery.isEmptyObject(orig)) { - return; - } + // Based off of the plugin by Clint Helfers, with permission. + jQuery.fn.delay = function (time, type) { + time = jQuery.fx ? jQuery.fx.speeds[time] || time : time; + type = type || "fx"; - // Restrict "overflow" and "display" styles during box animations - if (isBox && elem.nodeType === 1) { - // Support: IE <=9 - 11, Edge 12 - 15 - // Record all 3 overflow attributes because IE does not infer the shorthand - // from identically-valued overflowX and overflowY and Edge just mirrors - // the overflowX value there. - opts.overflow = [ - style.overflow, - style.overflowX, - style.overflowY - ]; + return this.queue(type, function (next, hooks) { + var timeout = window.setTimeout(next, time); - // Identify a display type, preferring old show/hide data over the CSS cascade - restoreDisplay = dataShow && dataShow.display; + hooks.stop = function () { + window.clearTimeout(timeout); + }; + }); + }; - if (restoreDisplay == null) { - restoreDisplay = dataPriv.get(elem, "display"); - } + (function () { + var input = document.createElement("input"), + select = document.createElement("select"), + opt = select.appendChild(document.createElement("option")); - display = jQuery.css(elem, "display"); + input.type = "checkbox"; - if (display === "none") { - if (restoreDisplay) { - display = restoreDisplay; - } else { - // Get nonempty value(s) by temporarily forcing visibility - showHide([elem], true); - restoreDisplay = elem.style.display || restoreDisplay; - display = jQuery.css(elem, "display"); - showHide([elem]); - } - } + // Support: Android <=4.3 only + // Default value for a checkbox should be "on" + support.checkOn = input.value !== ""; - // Animate inline elements as inline-block - if (display === "inline" || display === "inline-block" && restoreDisplay != null) { - if (jQuery.css(elem, "float") === "none") { - // Restore the original display value at the end of pure show/hide animations - if (!propTween) { - anim.done(function () { - style.display = restoreDisplay; - }); + // Support: IE <=11 only + // Must access selectedIndex to make default options select + support.optSelected = opt.selected; - if (restoreDisplay == null) { - display = style.display; - restoreDisplay = display === "none" ? "" : display; - } - } + // Support: IE <=11 only + // An input loses its value after becoming a radio + input = document.createElement("input"); - style.display = "inline-block"; - } - } - } + input.value = "t"; + input.type = "radio"; + support.radioValue = input.value === "t"; + })(); - if (opts.overflow) { - style.overflow = "hidden"; + var boolHook, attrHandle = jQuery.expr.attrHandle; - anim.always(function () { - style.overflow = opts.overflow[0]; - style.overflowX = opts.overflow[1]; - style.overflowY = opts.overflow[2]; - }); - } + jQuery.fn.extend({ + attr(name, value) { + return access(this, jQuery.attr, name, value, arguments.length > 1); + }, - // Implement show/hide animations - propTween = false; + removeAttr(name) { + return this.each(function () { + jQuery.removeAttr(this, name); + }); + } + }); - for (prop in orig) { - // General show/hide setup for this element animation - if (!propTween) { - if (dataShow) { - if ("hidden" in dataShow) { - hidden = dataShow.hidden; - } - } else { - dataShow = dataPriv.access(elem, "fxshow", { display: restoreDisplay }); - } + jQuery.extend({ + attr(elem, name, value) { + var ret, hooks, nType = elem.nodeType; - // Store hidden/visible for toggle so `.stop().toggle()` "reverses" - if (toggle) { - dataShow.hidden = !hidden; - } + // Don't get/set attributes on text, comment and attribute nodes + if (nType === 3 || nType === 8 || nType === 2) { + return; + } - // Show elements before animating them - if (hidden) { - showHide([elem], true); - } + // Fallback to prop when attributes are not supported + if (typeof elem.getAttribute === "undefined") { + return jQuery.prop(elem, name, value); + } - /* eslint-disable no-loop-func */ - anim.done(function () { - /* eslint-enable no-loop-func */ - // The final step of a "hide" animation is actually hiding the element - if (!hidden) { - showHide([elem]); - } + // Attribute hooks are determined by the lowercase version + // Grab necessary hook if one is defined + if (nType !== 1 || !jQuery.isXMLDoc(elem)) { + hooks = jQuery.attrHooks[name.toLowerCase()] || (jQuery.expr.match.bool.test(name) ? boolHook : undefined); + } - dataPriv.remove(elem, "fxshow"); + if (value !== undefined) { + if (value === null) { + jQuery.removeAttr(elem, name); - for (prop in orig) { - jQuery.style(elem, prop, orig[prop]); - } - }); + return; } - // Per-property setup - propTween = createTween(hidden ? dataShow[prop] : 0, prop, anim); - - if (!(prop in dataShow)) { - dataShow[prop] = propTween.start; - - if (hidden) { - propTween.end = propTween.start; - propTween.start = 0; - } + if (hooks && "set" in hooks && (ret = hooks.set(elem, value, name)) !== undefined) { + return ret; } - } - } - function propFilter(props, specialEasing) { - var index, name, easing, value, hooks; + elem.setAttribute(name, value + ""); + + return value; + } - // camelCase, specialEasing and expand cssHook pass - for (index in props) { - name = camelCase(index); - easing = specialEasing[name]; - value = props[index]; + if (hooks && "get" in hooks && (ret = hooks.get(elem, name)) !== null) { + return ret; + } - if (Array.isArray(value)) { - easing = value[1]; - value = props[index] = value[0]; - } + ret = jQuery.find.attr(elem, name); - if (index !== name) { - props[name] = value; - delete props[index]; - } + // Non-existent attributes return null, we normalize to undefined + return ret == null ? undefined : ret; + }, - hooks = jQuery.cssHooks[name]; + attrHooks: { + type: { + set(elem, value) { + if (!support.radioValue && value === "radio" && nodeName(elem, "input")) { + var val = elem.value; - if (hooks && "expand" in hooks) { - value = hooks.expand(value); - delete props[name]; + elem.setAttribute("type", value); - // Not quite $.extend, this won't overwrite existing keys. - // Reusing 'index' because we have the correct "name" - for (index in value) { - if (!(index in props)) { - props[index] = value[index]; - specialEasing[index] = easing; + if (val) { + elem.value = val; } + + return value; } - } else { - specialEasing[name] = easing; } } - } + }, - function Animation(elem, properties, options) { - var result, - stopped, - index = 0, - length = Animation.prefilters.length, - deferred = jQuery.Deferred().always(function () { - // Don't match elem in the :animated selector - delete tick.elem; - }), - tick = function () { - if (stopped) { - return false; - } + removeAttr(elem, value) { + var name, + i = 0, + // Attribute names can contain non-HTML whitespace characters + // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 + attrNames = value && value.match(rnothtmlwhite); - var currentTime = fxNow || createFxNow(), - remaining = Math.max(0, animation.startTime + animation.duration - currentTime), - // Support: Android 2.3 only - // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (trac-12497) - temp = remaining / animation.duration || 0, - percent = 1 - temp, - index = 0, - length = animation.tweens.length; + if (attrNames && elem.nodeType === 1) { + while (name = attrNames[i++]) { + elem.removeAttribute(name); + } + } + } + }); + + // Hooks for boolean attributes + boolHook = { + set(elem, value, name) { + if (value === false) { + // Remove boolean attributes when set to false + jQuery.removeAttr(elem, name); + } else { + elem.setAttribute(name, name); + } - for (; index < length; index++) { - animation.tweens[index].run(percent); - } + return name; + } + }; - deferred.notifyWith(elem, [animation, percent, remaining]); + jQuery.each(jQuery.expr.match.bool.source.match(/\w+/g), function (_i, name) { + var getter = attrHandle[name] || jQuery.find.attr; - // If there's more to do, yield - if (percent < 1 && length) { - return remaining; - } + attrHandle[name] = function (elem, name, isXML) { + var ret, + handle, + lowercaseName = name.toLowerCase(); - // If this was an empty animation, synthesize a final progress notification - if (!length) { - deferred.notifyWith(elem, [animation, 1, 0]); - } + if (!isXML) { + // Avoid an infinite loop by temporarily removing this function from the getter + handle = attrHandle[lowercaseName]; - // Resolve the animation and report its conclusion - deferred.resolveWith(elem, [animation]); - return false; - }, - animation = deferred.promise({ - elem, - props: jQuery.extend({}, properties), - opts: jQuery.extend( - true, - { - specialEasing: {}, - easing: jQuery.easing._default - }, - options - ), - originalProperties: properties, - originalOptions: options, - startTime: fxNow || createFxNow(), - duration: options.duration, - tweens: [], - createTween(prop, end) { - var tween = jQuery.Tween(elem, animation.opts, prop, end, animation.opts.specialEasing[prop] || animation.opts.easing); - - animation.tweens.push(tween); - return tween; - }, - stop(gotoEnd) { - var index = 0, - // If we are going to the end, we want to run all the tweens - // otherwise we skip this part - length = gotoEnd ? animation.tweens.length : 0; - - if (stopped) { - return this; - } + attrHandle[lowercaseName] = ret; + ret = getter(elem, name, isXML) != null ? lowercaseName : null; + attrHandle[lowercaseName] = handle; + } - stopped = true; + return ret; + }; + }); - for (; index < length; index++) { - animation.tweens[index].run(1); - } + var rfocusable = /^(?:input|select|textarea|button)$/i, + rclickable = /^(?:a|area)$/i; - // Resolve when we played the last frame; otherwise, reject - if (gotoEnd) { - deferred.notifyWith(elem, [animation, 1, 0]); - deferred.resolveWith(elem, [animation, gotoEnd]); - } else { - deferred.rejectWith(elem, [animation, gotoEnd]); - } + jQuery.fn.extend({ + prop(name, value) { + return access(this, jQuery.prop, name, value, arguments.length > 1); + }, - return this; - } - }), - props = animation.props; + removeProp(name) { + return this.each(function () { + delete this[jQuery.propFix[name] || name]; + }); + } + }); - propFilter(props, animation.opts.specialEasing); + jQuery.extend({ + prop(elem, name, value) { + var ret, hooks, nType = elem.nodeType; - for (; index < length; index++) { - result = Animation.prefilters[index].call(animation, elem, props, animation.opts); + // Don't get/set properties on text, comment and attribute nodes + if (nType === 3 || nType === 8 || nType === 2) { + return; + } - if (result) { - if (isFunction(result.stop)) { - jQuery._queueHooks(animation.elem, animation.opts.queue).stop = result.stop.bind(result); - } + if (nType !== 1 || !jQuery.isXMLDoc(elem)) { + // Fix name and attach hooks + name = jQuery.propFix[name] || name; - return result; - } + hooks = jQuery.propHooks[name]; } - jQuery.map(props, createTween, animation); + if (value !== undefined) { + if (hooks && "set" in hooks && (ret = hooks.set(elem, value, name)) !== undefined) { + return ret; + } - if (isFunction(animation.opts.start)) { - animation.opts.start.call(elem, animation); + return elem[name] = value; } - // Attach callbacks from options - animation.progress(animation.opts.progress).done(animation.opts.done, animation.opts.complete).fail(animation.opts.fail).always(animation.opts.always); + if (hooks && "get" in hooks && (ret = hooks.get(elem, name)) !== null) { + return ret; + } - jQuery.fx.timer(jQuery.extend(tick, { - elem, - anim: animation, - queue: animation.opts.queue - })); + return elem[name]; + }, - return animation; - } + propHooks: { + tabIndex: { + get(elem) { + // Support: IE <=9 - 11 only + // elem.tabIndex doesn't always return the + // correct value when it hasn't been explicitly set + // Use proper attribute retrieval (trac-12072) + var tabindex = jQuery.find.attr(elem, "tabindex"); - jQuery.Animation = jQuery.extend(Animation, { - tweeners: { - "*": [ - function (prop, value) { - var tween = this.createTween(prop, value); + if (tabindex) { + return parseInt(tabindex, 10); + } - adjustCSS(tween.elem, prop, rcssNum.exec(value), tween); - return tween; + if (rfocusable.test(elem.nodeName) || rclickable.test(elem.nodeName) && elem.href) { + return 0; } - ] - }, - tweener(props, callback) { - if (isFunction(props)) { - callback = props; - props = ["*"]; - } else { - props = props.match(rnothtmlwhite); + + return -1; } + } + }, - var prop, index = 0, length = props.length; + propFix: { "for": "htmlFor", "class": "className" } + }); - for (; index < length; index++) { - prop = props[index]; - Animation.tweeners[prop] = Animation.tweeners[prop] || []; - Animation.tweeners[prop].unshift(callback); + // Support: IE <=11 only + // Accessing the selectedIndex property + // forces the browser to respect setting selected + // on the option + // The getter ensures a default option is selected + // when in an optgroup + // eslint rule "no-unused-expressions" is disabled for this code + // since it considers such accessions noop + if (!support.optSelected) { + jQuery.propHooks.selected = { + get(elem) { + /* eslint no-unused-expressions: "off" */ + var parent = elem.parentNode; + + if (parent && parent.parentNode) { + parent.parentNode.selectedIndex; } + + return null; }, - prefilters: [defaultPrefilter], - prefilter(callback, prepend) { - if (prepend) { - Animation.prefilters.unshift(callback); - } else { - Animation.prefilters.push(callback); - } - } - }); - jQuery.speed = function (speed, easing, fn) { - var opt = speed && typeof speed === "object" - ? jQuery.extend({}, speed) - : { - complete: fn || !fn && easing || isFunction(speed) && speed, - duration: speed, - easing: fn && easing || easing && !isFunction(easing) && easing - }; + set(elem) { + /* eslint no-unused-expressions: "off" */ + var parent = elem.parentNode; - // Go to the end state if fx are off - if (jQuery.fx.off) { - opt.duration = 0; - } else { - if (typeof opt.duration !== "number") { - if (opt.duration in jQuery.fx.speeds) { - opt.duration = jQuery.fx.speeds[opt.duration]; - } else { - opt.duration = jQuery.fx.speeds._default; + if (parent) { + parent.selectedIndex; + + if (parent.parentNode) { + parent.parentNode.selectedIndex; } } } + }; + } - // Normalize opt.queue - true/undefined/null -> "fx" - if (opt.queue == null || opt.queue === true) { - opt.queue = "fx"; - } - - // Queueing - opt.old = opt.complete; + jQuery.each( + [ + "tabIndex", + "readOnly", + "maxLength", + "cellSpacing", + "cellPadding", + "rowSpan", + "colSpan", + "useMap", + "frameBorder", + "contentEditable" + ], + function () { + jQuery.propFix[this.toLowerCase()] = this; + } + ); - opt.complete = function () { - if (isFunction(opt.old)) { - opt.old.call(this); - } + // Strip and collapse whitespace according to HTML spec + // https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace + function stripAndCollapse(value) { + var tokens = value.match(rnothtmlwhite) || []; - if (opt.queue) { - jQuery.dequeue(this, opt.queue); - } - }; + return tokens.join(" "); + } - return opt; - }; + function getClass(elem) { + return elem.getAttribute && elem.getAttribute("class") || ""; + } - jQuery.fn.extend({ - fadeTo(speed, to, easing, callback) { - // Show any hidden elements after setting opacity to 0 - return this.filter(isHiddenWithinTree).css("opacity", 0).show().// Animate to the value specified - end().animate({ opacity: to }, speed, easing, callback); - }, - animate(prop, speed, easing, callback) { - var empty = jQuery.isEmptyObject(prop), - optall = jQuery.speed(speed, easing, callback), - doAnimation = function () { - // Operate on a copy of prop so per-property easing won't be lost - var anim = Animation(this, jQuery.extend({}, prop), optall); - - // Empty animations, or finishing resolves immediately - if (empty || dataPriv.get(this, "finish")) { - anim.stop(true); - } - }; + function classesToArray(value) { + if (Array.isArray(value)) { + return value; + } - doAnimation.finish = doAnimation; - return empty || optall.queue === false ? this.each(doAnimation) : this.queue(optall.queue, doAnimation); - }, - stop(type, clearQueue, gotoEnd) { - var stopQueue = function (hooks) { - var stop = hooks.stop; + if (typeof value === "string") { + return value.match(rnothtmlwhite) || []; + } - delete hooks.stop; - stop(gotoEnd); - }; + return []; + } - if (typeof type !== "string") { - gotoEnd = clearQueue; - clearQueue = type; - type = undefined; - } + jQuery.fn.extend({ + addClass(value) { + var classNames, + cur, + curValue, + className, + i, + finalValue; + + if (isFunction(value)) { + return this.each(function (j) { + jQuery(this).addClass(value.call(this, j, getClass(this))); + }); + } - if (clearQueue) { - this.queue(type || "fx", []); - } + classNames = classesToArray(value); + if (classNames.length) { return this.each(function () { - var dequeue = true, - index = type != null && type + "queueHooks", - timers = jQuery.timers, - data = dataPriv.get(this); + curValue = getClass(this); + cur = this.nodeType === 1 && " " + stripAndCollapse(curValue) + " "; - if (index) { - if (data[index] && data[index].stop) { - stopQueue(data[index]); - } - } else { - for (index in data) { - if (data[index] && data[index].stop && rrun.test(index)) { - stopQueue(data[index]); - } - } - } + if (cur) { + for (i = 0; i < classNames.length; i++) { + className = classNames[i]; - for (index = timers.length; index--; ) { - if (timers[index].elem === this && (type == null || timers[index].queue === type)) { - timers[index].anim.stop(gotoEnd); - dequeue = false; - timers.splice(index, 1); + if (cur.indexOf(" " + className + " ") < 0) { + cur += className + " "; + } } - } - - // Start the next in the queue if the last step wasn't forced. - // Timers currently will call their complete callbacks, which - // will dequeue but only if they were gotoEnd. - if (dequeue || !gotoEnd) { - jQuery.dequeue(this, type); - } - }); - }, - finish(type) { - if (type !== false) { - type = type || "fx"; - } - return this.each(function () { - var index, - data = dataPriv.get(this), - queue = data[type + "queue"], - hooks = data[type + "queueHooks"], - timers = jQuery.timers, - length = queue ? queue.length : 0; - - // Enable finishing flag on private data - data.finish = true; - // Empty the queue first - jQuery.queue(this, type, []); - - if (hooks && hooks.stop) { - hooks.stop.call(this, true); - } - - // Look for any active animations, and finish them - for (index = timers.length; index--; ) { - if (timers[index].elem === this && timers[index].queue === type) { - timers[index].anim.stop(true); - timers.splice(index, 1); - } - } + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse(cur); - // Look for any animations in the old queue and finish them - for (index = 0; index < length; index++) { - if (queue[index] && queue[index].finish) { - queue[index].finish.call(this); + if (curValue !== finalValue) { + this.setAttribute("class", finalValue); } } - - // Turn off finishing flag - delete data.finish; }); } - }); - jQuery.each(["toggle", "show", "hide"], function (_i, name) { - var cssFn = jQuery.fn[name]; - - jQuery.fn[name] = function (speed, easing, callback) { - return speed == null || typeof speed === "boolean" ? cssFn.apply(this, arguments) : this.animate(genFx(name, true), speed, easing, callback); - }; - }); + return this; + }, + + removeClass(value) { + var classNames, + cur, + curValue, + className, + i, + finalValue; + + if (isFunction(value)) { + return this.each(function (j) { + jQuery(this).removeClass(value.call(this, j, getClass(this))); + }); + } - // Generate shortcuts for custom animations - jQuery.each( - { - slideDown: genFx("show"), - slideUp: genFx("hide"), - slideToggle: genFx("toggle"), - fadeIn: { opacity: "show" }, - fadeOut: { opacity: "hide" }, - fadeToggle: { opacity: "toggle" } - }, - function (name, props) { - jQuery.fn[name] = function (speed, easing, callback) { - return this.animate(props, speed, easing, callback); - }; + if (!arguments.length) { + return this.attr("class", ""); } - ); - jQuery.timers = []; + classNames = classesToArray(value); - jQuery.fx.tick = function () { - var timer, i = 0, timers = jQuery.timers; + if (classNames.length) { + return this.each(function () { + curValue = getClass(this); - fxNow = Date.now(); + // This expression is here for better compressibility (see addClass) + cur = this.nodeType === 1 && " " + stripAndCollapse(curValue) + " "; - for (; i < timers.length; i++) { - timer = timers[i]; + if (cur) { + for (i = 0; i < classNames.length; i++) { + className = classNames[i]; - // Run the timer and safely remove it when done (allowing for external removal) - if (!timer() && timers[i] === timer) { - timers.splice(i--, 1); - } - } + // Remove *all* instances + while (cur.indexOf(" " + className + " ") > -1) { + cur = cur.replace(" " + className + " ", " "); + } + } - if (!timers.length) { - jQuery.fx.stop(); + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse(cur); + + if (curValue !== finalValue) { + this.setAttribute("class", finalValue); + } + } + }); } - fxNow = undefined; - }; + return this; + }, - jQuery.fx.timer = function (timer) { - jQuery.timers.push(timer); - jQuery.fx.start(); - }; + toggleClass(value, stateVal) { + var classNames, + className, + i, + self, + type = typeof value, + isValidValue = type === "string" || Array.isArray(value); - jQuery.fx.interval = 13; + if (isFunction(value)) { + return this.each(function (i) { + jQuery(this).toggleClass(value.call(this, i, getClass(this), stateVal), stateVal); + }); + } - jQuery.fx.start = function () { - if (inProgress) { - return; + if (typeof stateVal === "boolean" && isValidValue) { + return stateVal ? this.addClass(value) : this.removeClass(value); } - inProgress = true; - schedule(); - }; + classNames = classesToArray(value); - jQuery.fx.stop = function () { - inProgress = null; - }; + return this.each(function () { + if (isValidValue) { + // Toggle individual class names + self = jQuery(this); - jQuery.fx.speeds = { slow: 600, fast: 200, // Default speed - _default: 400 }; + for (i = 0; i < classNames.length; i++) { + className = classNames[i]; - // Based off of the plugin by Clint Helfers, with permission. - jQuery.fn.delay = function (time, type) { - time = jQuery.fx ? jQuery.fx.speeds[time] || time : time; - type = type || "fx"; + // Check each className given, space separated list + if (self.hasClass(className)) { + self.removeClass(className); + } else { + self.addClass(className); + } + } - return this.queue(type, function (next, hooks) { - var timeout = window.setTimeout(next, time); + // Toggle whole class name + } else if (value === undefined || type === "boolean") { + className = getClass(this); - hooks.stop = function () { - window.clearTimeout(timeout); - }; - }); - }; + if (className) { + // Store className if set + dataPriv.set(this, "__className__", className); + } - (function () { - var input = document.createElement("input"), - select = document.createElement("select"), - opt = select.appendChild(document.createElement("option")); + // If the element has a class name or if we're passed `false`, + // then remove the whole classname (if there was one, the above saved it). + // Otherwise bring back whatever was previously saved (if anything), + // falling back to the empty string if nothing was stored. + if (this.setAttribute) { + this.setAttribute("class", className || value === false ? "" : dataPriv.get(this, "__className__") || ""); + } + } + }); + }, - input.type = "checkbox"; - // Support: Android <=4.3 only - // Default value for a checkbox should be "on" - support.checkOn = input.value !== ""; - // Support: IE <=11 only - // Must access selectedIndex to make default options select - support.optSelected = opt.selected; - // Support: IE <=11 only - // An input loses its value after becoming a radio - input = document.createElement("input"); - input.value = "t"; - input.type = "radio"; - support.radioValue = input.value === "t"; - })(); + hasClass(selector) { + var className, elem, i = 0; - var boolHook, - attrHandle = jQuery.expr.attrHandle; + className = " " + selector + " "; - jQuery.fn.extend({ - attr(name, value) { - return access(this, jQuery.attr, name, value, arguments.length > 1); - }, - removeAttr(name) { - return this.each(function () { - jQuery.removeAttr(this, name); - }); + while (elem = this[i++]) { + if (elem.nodeType === 1 && (" " + stripAndCollapse(getClass(elem)) + " ").indexOf(className) > -1) { + return true; + } } - }); - jQuery.extend({ - attr(elem, name, value) { - var ret, hooks, nType = elem.nodeType; - - // Don't get/set attributes on text, comment and attribute nodes - if (nType === 3 || nType === 8 || nType === 2) { - return; - } + return false; + } + }); - // Fallback to prop when attributes are not supported - if (typeof elem.getAttribute === "undefined") { - return jQuery.prop(elem, name, value); - } + var rreturn = /\r/g; - // Attribute hooks are determined by the lowercase version - // Grab necessary hook if one is defined - if (nType !== 1 || !jQuery.isXMLDoc(elem)) { - hooks = jQuery.attrHooks[name.toLowerCase()] || (jQuery.expr.match.bool.test(name) ? boolHook : undefined); - } + jQuery.fn.extend({ + val(value) { + var hooks, ret, valueIsFunction, elem = this[0]; - if (value !== undefined) { - if (value === null) { - jQuery.removeAttr(elem, name); - return; - } + if (!arguments.length) { + if (elem) { + hooks = jQuery.valHooks[elem.type] || jQuery.valHooks[elem.nodeName.toLowerCase()]; - if (hooks && "set" in hooks && (ret = hooks.set(elem, value, name)) !== undefined) { + if (hooks && "get" in hooks && (ret = hooks.get(elem, "value")) !== undefined) { return ret; } - elem.setAttribute(name, value + ""); - return value; - } + ret = elem.value; - if (hooks && "get" in hooks && (ret = hooks.get(elem, name)) !== null) { - return ret; - } + // Handle most common string cases + if (typeof ret === "string") { + return ret.replace(rreturn, ""); + } - ret = jQuery.find.attr(elem, name); - // Non-existent attributes return null, we normalize to undefined - return ret == null ? undefined : ret; - }, - attrHooks: { - type: { - set(elem, value) { - if (!support.radioValue && value === "radio" && nodeName(elem, "input")) { - var val = elem.value; + // Handle cases where value is null/undef or number + return ret == null ? "" : ret; + } - elem.setAttribute("type", value); + return; + } - if (val) { - elem.value = val; - } + valueIsFunction = isFunction(value); - return value; - } - } - } - }, - removeAttr(elem, value) { - var name, - i = 0, - // Attribute names can contain non-HTML whitespace characters - // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 - attrNames = value && value.match(rnothtmlwhite); + return this.each(function (i) { + var val; - if (attrNames && elem.nodeType === 1) { - while (name = attrNames[i++]) { - elem.removeAttribute(name); - } + if (this.nodeType !== 1) { + return; } - } - }); - // Hooks for boolean attributes - boolHook = { - set(elem, value, name) { - if (value === false) { - // Remove boolean attributes when set to false - jQuery.removeAttr(elem, name); + if (valueIsFunction) { + val = value.call(this, i, jQuery(this).val()); } else { - elem.setAttribute(name, name); + val = value; } - return name; - } - }; - - jQuery.each(jQuery.expr.match.bool.source.match(/\w+/g), function (_i, name) { - var getter = attrHandle[name] || jQuery.find.attr; + // Treat null/undefined as ""; convert numbers to string + if (val == null) { + val = ""; + } else if (typeof val === "number") { + val += ""; + } else if (Array.isArray(val)) { + val = jQuery.map(val, function (value) { + return value == null ? "" : value + ""; + }); + } - attrHandle[name] = function (elem, name, isXML) { - var ret, - handle, - lowercaseName = name.toLowerCase(); + hooks = jQuery.valHooks[this.type] || jQuery.valHooks[this.nodeName.toLowerCase()]; - if (!isXML) { - // Avoid an infinite loop by temporarily removing this function from the getter - handle = attrHandle[lowercaseName]; - attrHandle[lowercaseName] = ret; - ret = getter(elem, name, isXML) != null ? lowercaseName : null; - attrHandle[lowercaseName] = handle; + // If set returns undefined, fall back to normal setting + if (!hooks || !("set" in hooks) || hooks.set(this, val, "value") === undefined) { + this.value = val; } + }); + } + }); - return ret; - }; - }); - - var rfocusable = /^(?:input|select|textarea|button)$/i, - rclickable = /^(?:a|area)$/i; + jQuery.extend({ + valHooks: { + option: { + get(elem) { + var val = jQuery.find.attr(elem, "value"); - jQuery.fn.extend({ - prop(name, value) { - return access(this, jQuery.prop, name, value, arguments.length > 1); + return val != null + ? val + : // Support: IE <=10 - 11 only + // option.text throws exceptions (trac-14686, trac-14858) + // Strip and collapse whitespace + // https://html.spec.whatwg.org/#strip-and-collapse-whitespace + stripAndCollapse(jQuery.text(elem)); + } }, - removeProp(name) { - return this.each(function () { - delete this[jQuery.propFix[name] || name]; - }); - } - }); - jQuery.extend({ - prop(elem, name, value) { - var ret, hooks, nType = elem.nodeType; + select: { + get(elem) { + var value, + option, + i, + options = elem.options, + index = elem.selectedIndex, + one = elem.type === "select-one", + values = one ? null : [], + max = one ? index + 1 : options.length; + + if (index < 0) { + i = max; + } else { + i = one ? index : 0; + } + + // Loop through all the selected options + for (; i < max; i++) { + option = options[i]; - // Don't get/set properties on text, comment and attribute nodes - if (nType === 3 || nType === 8 || nType === 2) { - return; - } + // Support: IE <=9 only + // IE8-9 doesn't update selected after form reset (trac-2551) + if ((option.selected || i === index) && // Don't return options that are disabled or in a disabled optgroup + !option.disabled && (!option.parentNode.disabled || !nodeName(option.parentNode, "optgroup"))) { + // Get the specific value for the option + value = jQuery(option).val(); - if (nType !== 1 || !jQuery.isXMLDoc(elem)) { - // Fix name and attach hooks - name = jQuery.propFix[name] || name; - hooks = jQuery.propHooks[name]; - } + // We don't need an array for one selects + if (one) { + return value; + } - if (value !== undefined) { - if (hooks && "set" in hooks && (ret = hooks.set(elem, value, name)) !== undefined) { - return ret; + // Multi-Selects return an array + values.push(value); + } } - return elem[name] = value; - } + return values; + }, - if (hooks && "get" in hooks && (ret = hooks.get(elem, name)) !== null) { - return ret; - } + set(elem, value) { + var optionSet, + option, + options = elem.options, + values = jQuery.makeArray(value), + i = options.length; - return elem[name]; - }, - propHooks: { - tabIndex: { - get(elem) { - // Support: IE <=9 - 11 only - // elem.tabIndex doesn't always return the - // correct value when it hasn't been explicitly set - // Use proper attribute retrieval (trac-12072) - var tabindex = jQuery.find.attr(elem, "tabindex"); - - if (tabindex) { - return parseInt(tabindex, 10); - } + while (i--) { + option = options[i]; - if (rfocusable.test(elem.nodeName) || rclickable.test(elem.nodeName) && elem.href) { - return 0; + /* eslint-disable no-cond-assign */ + if (option.selected = jQuery.inArray(jQuery.valHooks.option.get(option), values) > -1) { + optionSet = true; } - return -1; + /* eslint-enable no-cond-assign */ } - } - }, - propFix: { "for": "htmlFor", "class": "className" } - }); - - // Support: IE <=11 only - // Accessing the selectedIndex property - // forces the browser to respect setting selected - // on the option - // The getter ensures a default option is selected - // when in an optgroup - // eslint rule "no-unused-expressions" is disabled for this code - // since it considers such accessions noop - if (!support.optSelected) { - jQuery.propHooks.selected = { - get(elem) { - /* eslint no-unused-expressions: "off" */ - var parent = elem.parentNode; - if (parent && parent.parentNode) { - parent.parentNode.selectedIndex; + // Force browsers to behave consistently when non-matching value is set + if (!optionSet) { + elem.selectedIndex = -1; } - return null; - }, - set(elem) { - /* eslint no-unused-expressions: "off" */ - var parent = elem.parentNode; - - if (parent) { - parent.selectedIndex; - - if (parent.parentNode) { - parent.parentNode.selectedIndex; - } - } + return values; + } + } + } + }); + + // Radios and checkboxes getter/setter + jQuery.each(["radio", "checkbox"], function () { + jQuery.valHooks[this] = { + set(elem, value) { + if (Array.isArray(value)) { + return elem.checked = jQuery.inArray(jQuery(elem).val(), value) > -1; } + } + }; + + if (!support.checkOn) { + jQuery.valHooks[this].get = function (elem) { + return elem.getAttribute("value") === null ? "on" : elem.value; }; } + }); - jQuery.each( - [ - "tabIndex", - "readOnly", - "maxLength", - "cellSpacing", - "cellPadding", - "rowSpan", - "colSpan", - "useMap", - "frameBorder", - "contentEditable" - ], - function () { - jQuery.propFix[this.toLowerCase()] = this; - } - ); + // Return jQuery for attributes-only inclusion + var location = window.location; - // Strip and collapse whitespace according to HTML spec - // https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace - function stripAndCollapse(value) { - var tokens = value.match(rnothtmlwhite) || []; + var nonce = { guid: Date.now() }; + var rquery = /\?/; - return tokens.join(" "); - } + // Cross-browser xml parsing + jQuery.parseXML = function (data) { + var xml, parserErrorElem; - function getClass(elem) { - return elem.getAttribute && elem.getAttribute("class") || ""; + if (!data || typeof data !== "string") { + return null; } - function classesToArray(value) { - if (Array.isArray(value)) { - return value; - } + // Support: IE 9 - 11 only + // IE throws on parseFromString with invalid input. + try { + xml = new window.DOMParser().parseFromString(data, "text/xml"); + } catch(e) {} - if (typeof value === "string") { - return value.match(rnothtmlwhite) || []; - } + parserErrorElem = xml && xml.getElementsByTagName("parsererror")[0]; - return []; + if (!xml || parserErrorElem) { + jQuery.error("Invalid XML: " + (parserErrorElem + ? jQuery.map(parserErrorElem.childNodes, function (el) { + return el.textContent; + }).join("\n") + : data)); } - jQuery.fn.extend({ - addClass(value) { - var classNames, - cur, - curValue, - className, - i, - finalValue; - - if (isFunction(value)) { - return this.each(function (j) { - jQuery(this).addClass(value.call(this, j, getClass(this))); - }); - } + return xml; + }; - classNames = classesToArray(value); + var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, + stopPropagationCallback = function (e) { + e.stopPropagation(); + }; - if (classNames.length) { - return this.each(function () { - curValue = getClass(this); - cur = this.nodeType === 1 && " " + stripAndCollapse(curValue) + " "; + jQuery.extend(jQuery.event, { + trigger(event, data, elem, onlyHandlers) { + var i, + cur, + tmp, + bubbleType, + ontype, + handle, + special, + lastElement, + eventPath = [elem || document], + type = hasOwn.call(event, "type") ? event.type : event, + namespaces = hasOwn.call(event, "namespace") ? event.namespace.split(".") : []; + + cur = lastElement = tmp = elem = elem || document; + + // Don't do events on text and comment nodes + if (elem.nodeType === 3 || elem.nodeType === 8) { + return; + } - if (cur) { - for (i = 0; i < classNames.length; i++) { - className = classNames[i]; + // focus/blur morphs to focusin/out; ensure we're not firing them right now + if (rfocusMorph.test(type + jQuery.event.triggered)) { + return; + } - if (cur.indexOf(" " + className + " ") < 0) { - cur += className + " "; - } - } + if (type.indexOf(".") > -1) { + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split("."); - // Only assign if different to avoid unneeded rendering. - finalValue = stripAndCollapse(cur); + type = namespaces.shift(); + namespaces.sort(); + } - if (curValue !== finalValue) { - this.setAttribute("class", finalValue); - } - } - }); - } + ontype = type.indexOf(":") < 0 && "on" + type; - return this; - }, - removeClass(value) { - var classNames, - cur, - curValue, - className, - i, - finalValue; + // Caller can pass in a jQuery.Event object, Object, or just an event type string + event = event[jQuery.expando] + ? event + : new jQuery.Event(type, typeof event === "object" && event); - if (isFunction(value)) { - return this.each(function (j) { - jQuery(this).removeClass(value.call(this, j, getClass(this))); - }); - } + // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) + event.isTrigger = onlyHandlers ? 2 : 3; - if (!arguments.length) { - return this.attr("class", ""); - } + event.namespace = namespaces.join("."); - classNames = classesToArray(value); + event.rnamespace = event.namespace + ? new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)") + : null; - if (classNames.length) { - return this.each(function () { - curValue = getClass(this); - // This expression is here for better compressibility (see addClass) - cur = this.nodeType === 1 && " " + stripAndCollapse(curValue) + " "; + // Clean up the event in case it is being reused + event.result = undefined; - if (cur) { - for (i = 0; i < classNames.length; i++) { - className = classNames[i]; + if (!event.target) { + event.target = elem; + } - // Remove *all* instances - while (cur.indexOf(" " + className + " ") > -1) { - cur = cur.replace(" " + className + " ", " "); - } - } + // Clone any incoming data and prepend the event, creating the handler arg list + data = data == null ? [event] : jQuery.makeArray(data, [event]); - // Only assign if different to avoid unneeded rendering. - finalValue = stripAndCollapse(cur); + // Allow special events to draw outside the lines + special = jQuery.event.special[type] || {}; - if (curValue !== finalValue) { - this.setAttribute("class", finalValue); - } - } - }); - } + if (!onlyHandlers && special.trigger && special.trigger.apply(elem, data) === false) { + return; + } - return this; - }, - toggleClass(value, stateVal) { - var classNames, - className, - i, - self, - type = typeof value, - isValidValue = type === "string" || Array.isArray(value); + // Determine event propagation path in advance, per W3C events spec (trac-9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (trac-9724) + if (!onlyHandlers && !special.noBubble && !isWindow(elem)) { + bubbleType = special.delegateType || type; - if (isFunction(value)) { - return this.each(function (i) { - jQuery(this).toggleClass(value.call(this, i, getClass(this), stateVal), stateVal); - }); + if (!rfocusMorph.test(bubbleType + type)) { + cur = cur.parentNode; } - if (typeof stateVal === "boolean" && isValidValue) { - return stateVal ? this.addClass(value) : this.removeClass(value); + for (; cur; cur = cur.parentNode) { + eventPath.push(cur); + tmp = cur; } - classNames = classesToArray(value); + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if (tmp === (elem.ownerDocument || document)) { + eventPath.push(tmp.defaultView || tmp.parentWindow || window); + } + } - return this.each(function () { - if (isValidValue) { - // Toggle individual class names - self = jQuery(this); + // Fire handlers on the event path + i = 0; - for (i = 0; i < classNames.length; i++) { - className = classNames[i]; + while ((cur = eventPath[i++]) && !event.isPropagationStopped()) { + lastElement = cur; + event.type = i > 1 ? bubbleType : special.bindType || type; - // Check each className given, space separated list - if (self.hasClass(className)) { - self.removeClass(className); - } else { - self.addClass(className); - } - } - } else if (value === undefined || type === "boolean") { - className = getClass(this); // Toggle whole class name + // jQuery handler + handle = (dataPriv.get(cur, "events") || Object.create(null))[event.type] && dataPriv.get(cur, "handle"); - if (className) { - // Store className if set - dataPriv.set(this, "__className__", className); - } + if (handle) { + handle.apply(cur, data); + } - // If the element has a class name or if we're passed `false`, - // then remove the whole classname (if there was one, the above saved it). - // Otherwise bring back whatever was previously saved (if anything), - // falling back to the empty string if nothing was stored. - if (this.setAttribute) { - this.setAttribute("class", className || value === false ? "" : dataPriv.get(this, "__className__") || ""); - } - } - }); - }, - hasClass(selector) { - var className, elem, i = 0; + // Native handler + handle = ontype && cur[ontype]; - className = " " + selector + " "; + if (handle && handle.apply && acceptData(cur)) { + event.result = handle.apply(cur, data); - while (elem = this[i++]) { - if (elem.nodeType === 1 && (" " + stripAndCollapse(getClass(elem)) + " ").indexOf(className) > -1) { - return true; + if (event.result === false) { + event.preventDefault(); } } - - return false; } - }); - var rreturn = /\r/g; + event.type = type; - jQuery.fn.extend({ - val(value) { - var hooks, ret, valueIsFunction, elem = this[0]; + // If nobody prevented the default action, do it now + if (!onlyHandlers && !event.isDefaultPrevented()) { + if ((!special._default || special._default.apply(eventPath.pop(), data) === false) && acceptData(elem)) { + // Call a native DOM method on the target with the same name as the event. + // Don't do default actions on window, that's where global variables be (trac-6170) + if (ontype && isFunction(elem[type]) && !isWindow(elem)) { + // Don't re-trigger an onFOO event when we call its FOO() method + tmp = elem[ontype]; - if (!arguments.length) { - if (elem) { - hooks = jQuery.valHooks[elem.type] || jQuery.valHooks[elem.nodeName.toLowerCase()]; + if (tmp) { + elem[ontype] = null; + } - if (hooks && "get" in hooks && (ret = hooks.get(elem, "value")) !== undefined) { - return ret; + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + + if (event.isPropagationStopped()) { + lastElement.addEventListener(type, stopPropagationCallback); } - ret = elem.value; + elem[type](); - // Handle most common string cases - if (typeof ret === "string") { - return ret.replace(rreturn, ""); + if (event.isPropagationStopped()) { + lastElement.removeEventListener(type, stopPropagationCallback); } - // Handle cases where value is null/undef or number - return ret == null ? "" : ret; - } + jQuery.event.triggered = undefined; - return; + if (tmp) { + elem[ontype] = tmp; + } + } } + } - valueIsFunction = isFunction(value); - - return this.each(function (i) { - var val; + return event.result; + }, - if (this.nodeType !== 1) { - return; - } + // Piggyback on a donor event to simulate a different one + // Used only for `focus(in | out)` events + simulate(type, elem, event) { + var e = jQuery.extend(new jQuery.Event(), event, { type, isSimulated: true }); - if (valueIsFunction) { - val = value.call(this, i, jQuery(this).val()); - } else { - val = value; - } + jQuery.event.trigger(e, null, elem); + } + }); - // Treat null/undefined as ""; convert numbers to string - if (val == null) { - val = ""; - } else if (typeof val === "number") { - val += ""; - } else if (Array.isArray(val)) { - val = jQuery.map(val, function (value) { - return value == null ? "" : value + ""; - }); - } + jQuery.fn.extend({ + trigger(type, data) { + return this.each(function () { + jQuery.event.trigger(type, data, this); + }); + }, - hooks = jQuery.valHooks[this.type] || jQuery.valHooks[this.nodeName.toLowerCase()]; + triggerHandler(type, data) { + var elem = this[0]; - // If set returns undefined, fall back to normal setting - if (!hooks || !("set" in hooks) || hooks.set(this, val, "value") === undefined) { - this.value = val; - } - }); + if (elem) { + return jQuery.event.trigger(type, data, elem, true); } - }); - - jQuery.extend({ - valHooks: { - option: { - get(elem) { - var val = jQuery.find.attr(elem, "value"); + } + }); + + var rbracket = /\[\]$/, + rCRLF = /\r?\n/g, + rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, + rsubmittable = /^(?:input|select|textarea|keygen)/i; + + function buildParams(prefix, obj, traditional, add) { + var name; + + if (Array.isArray(obj)) { + // Serialize array item. + jQuery.each(obj, function (i, v) { + if (traditional || rbracket.test(prefix)) { + // Treat each array item as a scalar. + add(prefix, v); + } else { + // Item is non-scalar (array or object), encode its numeric index. + buildParams(prefix + "[" + (typeof v === "object" && v != null ? i : "") + "]", v, traditional, add); + } + }); + } else if (!traditional && toType(obj) === "object") { + // Serialize object item. + for (name in obj) { + buildParams(prefix + "[" + name + "]", obj[name], traditional, add); + } + } else { + // Serialize scalar item. + add(prefix, obj); + } + } - return val != null ? val : // Support: IE <=10 - 11 only - // option.text throws exceptions (trac-14686, trac-14858) - // Strip and collapse whitespace - // https://html.spec.whatwg.org/#strip-and-collapse-whitespace - stripAndCollapse(jQuery.text(elem)); - } - }, - select: { - get(elem) { - var value, - option, - i, - options = elem.options, - index = elem.selectedIndex, - one = elem.type === "select-one", - values = one ? null : [], - max = one ? index + 1 : options.length; - - if (index < 0) { - i = max; - } else { - i = one ? index : 0; - } + // Serialize an array of form elements or a set of + // key/values into a query string + jQuery.param = function (a, traditional) { + var prefix, + s = [], + add = function (key, valueOrFunction) { + // If value is a function, invoke it and use its return value + var value = isFunction(valueOrFunction) ? valueOrFunction() : valueOrFunction; - // Loop through all the selected options - for (; i < max; i++) { - option = options[i]; + s[s.length] = encodeURIComponent(key) + "=" + encodeURIComponent(value == null ? "" : value); + }; - // Support: IE <=9 only - // IE8-9 doesn't update selected after form reset (trac-2551) - if ((option.selected || i === index) && // Don't return options that are disabled or in a disabled optgroup - !option.disabled && (!option.parentNode.disabled || !nodeName(option.parentNode, "optgroup"))) { - // Get the specific value for the option - value = jQuery(option).val(); + if (a == null) { + return ""; + } - // We don't need an array for one selects - if (one) { - return value; - } + // If an array was passed in, assume that it is an array of form elements. + if (Array.isArray(a) || a.jquery && !jQuery.isPlainObject(a)) { + // Serialize the form elements + jQuery.each(a, function () { + add(this.name, this.value); + }); + } else { + // If traditional, encode the "old" way (the way 1.3.2 or older + // did it), otherwise encode params recursively. + for (prefix in a) { + buildParams(prefix, a[prefix], traditional, add); + } + } - // Multi-Selects return an array - values.push(value); - } - } + // Return the resulting serialization + return s.join("&"); + }; - return values; - }, - set(elem, value) { - var optionSet, - option, - options = elem.options, - values = jQuery.makeArray(value), - i = options.length; + jQuery.fn.extend({ + serialize() { + return jQuery.param(this.serializeArray()); + }, - while (i--) { - option = options[i]; + serializeArray() { + return this.map(function () { + // Can add propHook for "elements" to filter or add form elements + var elements = jQuery.prop(this, "elements"); - /* eslint-disable no-cond-assign */ - if (option.selected = jQuery.inArray(jQuery.valHooks.option.get(option), values) > -1) { - optionSet = true; - } - } /* eslint-enable no-cond-assign */ + return elements ? jQuery.makeArray(elements) : this; + }).filter(function () { + var type = this.type; - // Force browsers to behave consistently when non-matching value is set - if (!optionSet) { - elem.selectedIndex = -1; - } + // Use .is( ":disabled" ) so that fieldset[disabled] works + return this.name && !jQuery(this).is(":disabled") && rsubmittable.test(this.nodeName) && !rsubmitterTypes.test(type) && (this.checked || !rcheckableType.test(type)); + }).map(function (_i, elem) { + var val = jQuery(this).val(); - return values; - } + if (val == null) { + return null; } - } - }); - // Radios and checkboxes getter/setter - jQuery.each(["radio", "checkbox"], function () { - jQuery.valHooks[this] = { - set(elem, value) { - if (Array.isArray(value)) { - return elem.checked = jQuery.inArray(jQuery(elem).val(), value) > -1; - } + if (Array.isArray(val)) { + return jQuery.map(val, function (val) { + return { name: elem.name, value: val.replace(rCRLF, "\r\n") }; + }); } - }; - if (!support.checkOn) { - jQuery.valHooks[this].get = function (elem) { - return elem.getAttribute("value") === null ? "on" : elem.value; - }; - } - }); - - // Return jQuery for attributes-only inclusion - var location = window.location; - var nonce = { guid: Date.now() }; - var rquery = /\?/; + return { name: elem.name, value: val.replace(rCRLF, "\r\n") }; + }).get(); + } + }); + + var r20 = /%20/g, + rhash = /#.*$/, + rantiCache = /([?&])_=[^&]*/, + rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg, + // trac-7653, trac-8125, trac-8152: local protocol detection + rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, + rnoContent = /^(?:GET|HEAD)$/, + rprotocol = /^\/\//, + /* Prefilters + * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) + * 2) These are called: + * - BEFORE asking for a transport + * - AFTER param serialization (s.data is a string if s.processData is true) + * 3) key is the dataType + * 4) the catchall symbol "*" can be used + * 5) execution will start with transport dataType and THEN continue down to "*" if needed + */ + prefilters = {}, + /* Transports bindings + * 1) key is the dataType + * 2) the catchall symbol "*" can be used + * 3) selection will start with transport dataType and THEN go to "*" if needed + */ + transports = {}, + // Avoid comment-prolog char sequence (trac-10098); must appease lint and evade compression + allTypes = ("*/").concat("*"), + // Anchor tag for parsing the document origin + originAnchor = document.createElement("a"); - // Cross-browser xml parsing - jQuery.parseXML = function (data) { - var xml, parserErrorElem; + originAnchor.href = location.href; - if (!data || typeof data !== "string") { - return null; + // Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport + function addToPrefiltersOrTransports(structure) { + // dataTypeExpression is optional and defaults to "*" + return function (dataTypeExpression, func) { + if (typeof dataTypeExpression !== "string") { + func = dataTypeExpression; + dataTypeExpression = "*"; } - // Support: IE 9 - 11 only - // IE throws on parseFromString with invalid input. - try { - xml = new window.DOMParser().parseFromString(data, "text/xml"); - } catch(e) {} + var dataType, + i = 0, + dataTypes = dataTypeExpression.toLowerCase().match(rnothtmlwhite) || []; - parserErrorElem = xml && xml.getElementsByTagName("parsererror")[0]; + if (isFunction(func)) { + // For each dataType in the dataTypeExpression + while (dataType = dataTypes[i++]) { + // Prepend if requested + if (dataType[0] === "+") { + dataType = dataType.slice(1) || "*"; + (structure[dataType] = structure[dataType] || []).unshift(func); - if (!xml || parserErrorElem) { - jQuery.error("Invalid XML: " + (parserErrorElem - ? jQuery.map(parserErrorElem.childNodes, function (el) { - return el.textContent; - }).join("\n") - : data)); + // Otherwise append + } else { + (structure[dataType] = structure[dataType] || []).push(func); + } + } } - - return xml; }; + } - var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, - stopPropagationCallback = function (e) { - e.stopPropagation(); - }; + // Base inspection function for prefilters and transports + function inspectPrefiltersOrTransports(structure, options, originalOptions, jqXHR) { + var inspected = {}, + seekingTransport = structure === transports; - jQuery.extend(jQuery.event, { - trigger(event, data, elem, onlyHandlers) { - var i, - cur, - tmp, - bubbleType, - ontype, - handle, - special, - lastElement, - eventPath = [elem || document], - type = hasOwn.call(event, "type") ? event.type : event, - namespaces = hasOwn.call(event, "namespace") ? event.namespace.split(".") : []; - - cur = lastElement = tmp = elem = elem || document; - - // Don't do events on text and comment nodes - if (elem.nodeType === 3 || elem.nodeType === 8) { - return; - } + function inspect(dataType) { + var selected; - // focus/blur morphs to focusin/out; ensure we're not firing them right now - if (rfocusMorph.test(type + jQuery.event.triggered)) { - return; - } + inspected[dataType] = true; - if (type.indexOf(".") > -1) { - // Namespaced trigger; create a regexp to match event type in handle() - namespaces = type.split("."); - type = namespaces.shift(); - namespaces.sort(); - } + jQuery.each(structure[dataType] || [], function (_, prefilterOrFactory) { + var dataTypeOrTransport = prefilterOrFactory(options, originalOptions, jqXHR); - ontype = type.indexOf(":") < 0 && "on" + type; - // Caller can pass in a jQuery.Event object, Object, or just an event type string - event = event[jQuery.expando] ? event : new jQuery.Event(type, typeof event === "object" && event); - // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) - event.isTrigger = onlyHandlers ? 2 : 3; - event.namespace = namespaces.join("."); - event.rnamespace = event.namespace ? new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)") : null; - // Clean up the event in case it is being reused - event.result = undefined; + if (typeof dataTypeOrTransport === "string" && !seekingTransport && !inspected[dataTypeOrTransport]) { + options.dataTypes.unshift(dataTypeOrTransport); + inspect(dataTypeOrTransport); - if (!event.target) { - event.target = elem; + return false; + } else if (seekingTransport) { + return !(selected = dataTypeOrTransport); } + }); - // Clone any incoming data and prepend the event, creating the handler arg list - data = data == null ? [event] : jQuery.makeArray(data, [event]); - // Allow special events to draw outside the lines - special = jQuery.event.special[type] || {}; + return selected; + } - if (!onlyHandlers && special.trigger && special.trigger.apply(elem, data) === false) { - return; - } + return inspect(options.dataTypes[0]) || !inspected["*"] && inspect("*"); + } - // Determine event propagation path in advance, per W3C events spec (trac-9951) - // Bubble up to document, then to window; watch for a global ownerDocument var (trac-9724) - if (!onlyHandlers && !special.noBubble && !isWindow(elem)) { - bubbleType = special.delegateType || type; + // A special extend for ajax options + // that takes "flat" options (not to be deep extended) + // Fixes trac-9887 + function ajaxExtend(target, src) { + var key, + deep, + flatOptions = jQuery.ajaxSettings.flatOptions || {}; - if (!rfocusMorph.test(bubbleType + type)) { - cur = cur.parentNode; - } + for (key in src) { + if (src[key] !== undefined) { + (flatOptions[key] ? target : deep || (deep = {}))[key] = src[key]; + } + } - for (; cur; cur = cur.parentNode) { - eventPath.push(cur); - tmp = cur; - } + if (deep) { + jQuery.extend(true, target, deep); + } - // Only add window if we got to document (e.g., not plain obj or detached DOM) - if (tmp === (elem.ownerDocument || document)) { - eventPath.push(tmp.defaultView || tmp.parentWindow || window); - } - } + return target; + } - // Fire handlers on the event path - i = 0; + /* Handles responses to an ajax request: + * - finds the right dataType (mediates between content-type and expected dataType) + * - returns the corresponding response + */ + function ajaxHandleResponses(s, jqXHR, responses) { + var ct, + type, + finalDataType, + firstDataType, + contents = s.contents, + dataTypes = s.dataTypes; + + // Remove auto dataType and get content-type in the process + while (dataTypes[0] === "*") { + dataTypes.shift(); + + if (ct === undefined) { + ct = s.mimeType || jqXHR.getResponseHeader("Content-Type"); + } + } - while ((cur = eventPath[i++]) && !event.isPropagationStopped()) { - lastElement = cur; - event.type = i > 1 ? bubbleType : special.bindType || type; - // jQuery handler - handle = (dataPriv.get(cur, "events") || Object.create(null))[event.type] && dataPriv.get(cur, "handle"); + // Check if we're dealing with a known content-type + if (ct) { + for (type in contents) { + if (contents[type] && contents[type].test(ct)) { + dataTypes.unshift(type); - if (handle) { - handle.apply(cur, data); - } + break; + } + } + } - // Native handler - handle = ontype && cur[ontype]; + // Check to see if we have a response for the expected dataType + if (dataTypes[0] in responses) { + finalDataType = dataTypes[0]; + } else { + // Try convertible dataTypes + for (type in responses) { + if (!dataTypes[0] || s.converters[type + " " + dataTypes[0]]) { + finalDataType = type; - if (handle && handle.apply && acceptData(cur)) { - event.result = handle.apply(cur, data); + break; + } - if (event.result === false) { - event.preventDefault(); - } - } + if (!firstDataType) { + firstDataType = type; } + } - event.type = type; + // Or just use first one + finalDataType = finalDataType || firstDataType; + } - // If nobody prevented the default action, do it now - if (!onlyHandlers && !event.isDefaultPrevented()) { - if ((!special._default || special._default.apply(eventPath.pop(), data) === false) && acceptData(elem)) { - // Call a native DOM method on the target with the same name as the event. - // Don't do default actions on window, that's where global variables be (trac-6170) - if (ontype && isFunction(elem[type]) && !isWindow(elem)) { - // Don't re-trigger an onFOO event when we call its FOO() method - tmp = elem[ontype]; + // If we found a dataType + // We add the dataType to the list if needed + // and return the corresponding response + if (finalDataType) { + if (finalDataType !== dataTypes[0]) { + dataTypes.unshift(finalDataType); + } - if (tmp) { - elem[ontype] = null; - } + return responses[finalDataType]; + } + } - // Prevent re-triggering of the same event, since we already bubbled it above - jQuery.event.triggered = type; + /* Chain conversions given the request and the original response + * Also sets the responseXXX fields on the jqXHR instance + */ + function ajaxConvert(s, response, jqXHR, isSuccess) { + var conv2, + current, + conv, + tmp, + prev, + converters = {}, + // Work with a copy of dataTypes in case we need to modify it for conversion + dataTypes = s.dataTypes.slice(); + + // Create converters map with lowercased keys + if (dataTypes[1]) { + for (conv in s.converters) { + converters[conv.toLowerCase()] = s.converters[conv]; + } + } - if (event.isPropagationStopped()) { - lastElement.addEventListener(type, stopPropagationCallback); - } + current = dataTypes.shift(); + + // Convert to each sequential dataType + while (current) { + if (s.responseFields[current]) { + jqXHR[s.responseFields[current]] = response; + } - elem[type](); + // Apply the dataFilter if provided + if (!prev && isSuccess && s.dataFilter) { + response = s.dataFilter(response, s.dataType); + } - if (event.isPropagationStopped()) { - lastElement.removeEventListener(type, stopPropagationCallback); - } + prev = current; + current = dataTypes.shift(); - jQuery.event.triggered = undefined; + if (current) { + // There's only work to do if current dataType is non-auto + if (current === "*") { + current = prev; + + // Convert response if prev dataType is non-auto and differs from current + } else if (prev !== "*" && prev !== current) { + // Seek a direct converter + conv = converters[prev + " " + current] || converters["* " + current]; + + // If none found, seek a pair + if (!conv) { + for (conv2 in converters) { + // If conv2 outputs current + tmp = conv2.split(" "); + + if (tmp[1] === current) { + // If prev can be converted to accepted input + conv = converters[prev + " " + tmp[0]] || converters["* " + tmp[0]]; + + if (conv) { + // Condense equivalence converters + if (conv === true) { + conv = converters[conv2]; + + // Otherwise, insert the intermediate dataType + } else if (converters[conv2] !== true) { + current = tmp[0]; + dataTypes.unshift(tmp[1]); + } + + break; + } + } + } + } - if (tmp) { - elem[ontype] = tmp; + // Apply converter (if not an equivalence) + if (conv !== true) { + // Unless errors are allowed to bubble, catch and return them + if (conv && s.throws) { + response = conv(response); + } else { + try { + response = conv(response); + } catch(e) { + return { + state: "parsererror", + error: conv ? e : "No conversion from " + prev + " to " + current + }; } } } } + } + } + + return { state: "success", data: response }; + } - return event.result; + jQuery.extend({ + // Counter for holding the number of active queries + active: 0, + + // Last-Modified header cache for next request + lastModified: {}, + + etag: {}, + + ajaxSettings: { + url: location.href, + type: "GET", + isLocal: rlocalProtocol.test(location.protocol), + global: true, + processData: true, + async: true, + contentType: "application/x-www-form-urlencoded; charset=UTF-8", + + /* + timeout: 0, + data: null, + dataType: null, + username: null, + password: null, + cache: null, + throws: false, + traditional: false, + headers: {}, + */ + accepts: { + "*": allTypes, + text: "text/plain", + html: "text/html", + xml: "application/xml, text/xml", + json: "application/json, text/javascript" }, - simulate(type, elem, event) { - var e = jQuery.extend(new jQuery.Event(), event, { type, isSimulated: true }); - jQuery.event.trigger(e, null, elem); - } - }); + contents: { xml: /\bxml\b/, html: /\bhtml/, json: /\bjson\b/ }, - jQuery.fn.extend({ - trigger(type, data) { - return this.each(function () { - jQuery.event.trigger(type, data, this); - }); + responseFields: { + xml: "responseXML", + text: "responseText", + json: "responseJSON" }, - triggerHandler(type, data) { - var elem = this[0]; - if (elem) { - return jQuery.event.trigger(type, data, elem, true); - } - } - }); + // Data converters + // Keys separate source (or catchall "*") and destination types with a single space + converters: { + // Convert anything to text + "* text": String, - var rbracket = /\[\]$/, - rCRLF = /\r?\n/g, - rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, - rsubmittable = /^(?:input|select|textarea|keygen)/i; + // Text to html (true = no transformation) + "text html": true, - function buildParams(prefix, obj, traditional, add) { - var name; + // Evaluate text as a json expression + "text json": JSON.parse, - if (Array.isArray(obj)) { - // Serialize array item. - jQuery.each(obj, function (i, v) { - if (traditional || rbracket.test(prefix)) { - // Treat each array item as a scalar. - add(prefix, v); - } else { - // Item is non-scalar (array or object), encode its numeric index. - buildParams(prefix + "[" + (typeof v === "object" && v != null ? i : "") + "]", v, traditional, add); - } - }); - } else if (!traditional && toType(obj) === "object") { - // Serialize object item. - for (name in obj) { - buildParams(prefix + "[" + name + "]", obj[name], traditional, add); - } - } else { - // Serialize scalar item. - add(prefix, obj); - } - } + // Parse text as xml + "text xml": jQuery.parseXML + }, - // Serialize an array of form elements or a set of - // key/values into a query string - jQuery.param = function (a, traditional) { - var prefix, - s = [], - add = function (key, valueOrFunction) { - // If value is a function, invoke it and use its return value - var value = isFunction(valueOrFunction) ? valueOrFunction() : valueOrFunction; + // For options that shouldn't be deep extended: + // you can add your own custom options here if + // and when you create one that shouldn't be + // deep extended (see ajaxExtend) + flatOptions: { url: true, context: true } + }, + + // Creates a full fledged settings object into target + // with both ajaxSettings and settings fields. + // If target is omitted, writes into ajaxSettings. + ajaxSetup(target, settings) { + return settings + ? // Building a settings object + ajaxExtend(ajaxExtend(target, jQuery.ajaxSettings), settings) + : // Extending ajaxSettings + ajaxExtend(jQuery.ajaxSettings, target); + }, + + ajaxPrefilter: addToPrefiltersOrTransports(prefilters), + ajaxTransport: addToPrefiltersOrTransports(transports), + + // Main method + ajax(url, options) { + // If url is an object, simulate pre-1.5 signature + if (typeof url === "object") { + options = url; + url = undefined; + } + + // Force options to be an object + options = options || {}; + + var transport, + // URL without anti-cache param + cacheURL, + // Response headers + responseHeadersString, + responseHeaders, + // timeout handle + timeoutTimer, + // Url cleanup var + urlAnchor, + // Request state (becomes false upon send and true upon completion) + completed, + // To know if global events are to be dispatched + fireGlobals, + // Loop variable + i, + // uncached part of the url + uncached, + // Create the final options object + s = jQuery.ajaxSetup({}, options), + // Callbacks context + callbackContext = s.context || s, + // Context for global events is callbackContext if it is a DOM node or jQuery collection + globalEventContext = s.context && (callbackContext.nodeType || callbackContext.jquery) ? jQuery(callbackContext) : jQuery.event, + // Deferreds + deferred = jQuery.Deferred(), + completeDeferred = jQuery.Callbacks("once memory"), + // Status-dependent callbacks + statusCode = s.statusCode || {}, + // Headers (they are sent all at once) + requestHeaders = {}, + requestHeadersNames = {}, + // Default abort message + strAbort = "canceled", + // Fake xhr + jqXHR = { + readyState: 0, + + // Builds headers hashtable if needed + getResponseHeader(key) { + var match; - s[s.length] = encodeURIComponent(key) + "=" + encodeURIComponent(value == null ? "" : value); - }; + if (completed) { + if (!responseHeaders) { + responseHeaders = {}; - if (a == null) { - return ""; - } + while (match = rheaders.exec(responseHeadersString)) { + responseHeaders[match[1].toLowerCase() + " "] = (responseHeaders[match[1].toLowerCase() + " "] || []).concat(match[2]); + } + } - // If an array was passed in, assume that it is an array of form elements. - if (Array.isArray(a) || a.jquery && !jQuery.isPlainObject(a)) { - // Serialize the form elements - jQuery.each(a, function () { - add(this.name, this.value); - }); - } else { - // If traditional, encode the "old" way (the way 1.3.2 or older - // did it), otherwise encode params recursively. - for (prefix in a) { - buildParams(prefix, a[prefix], traditional, add); - } - } + match = responseHeaders[key.toLowerCase() + " "]; + } - // Return the resulting serialization - return s.join("&"); - }; + return match == null ? null : match.join(", "); + }, + + // Raw string + getAllResponseHeaders() { + return completed ? responseHeadersString : null; + }, + + // Caches the header + setRequestHeader(name, value) { + if (completed == null) { + name = requestHeadersNames[name.toLowerCase()] = requestHeadersNames[name.toLowerCase()] || name; + requestHeaders[name] = value; + } + + return this; + }, + + // Overrides response content-type header + overrideMimeType(type) { + if (completed == null) { + s.mimeType = type; + } + + return this; + }, + + // Status-dependent callbacks + statusCode(map) { + var code; + + if (map) { + if (completed) { + // Execute the appropriate callbacks + jqXHR.always(map[jqXHR.status]); + } else { + // Lazy-add the new callbacks in a way that preserves old ones + for (code in map) { + statusCode[code] = [statusCode[code], map[code]]; + } + } + } - jQuery.fn.extend({ - serialize() { - return jQuery.param(this.serializeArray()); - }, - serializeArray() { - return this.map(function () { - // Can add propHook for "elements" to filter or add form elements - var elements = jQuery.prop(this, "elements"); + return this; + }, - return elements ? jQuery.makeArray(elements) : this; - }).filter(function () { - var type = this.type; + // Cancel the request + abort(statusText) { + var finalText = statusText || strAbort; - // Use .is( ":disabled" ) so that fieldset[disabled] works - return this.name && !jQuery(this).is(":disabled") && rsubmittable.test(this.nodeName) && !rsubmitterTypes.test(type) && (this.checked || !rcheckableType.test(type)); - }).map(function (_i, elem) { - var val = jQuery(this).val(); + if (transport) { + transport.abort(finalText); + } - if (val == null) { - return null; - } + done(0, finalText); - if (Array.isArray(val)) { - return jQuery.map(val, function (val) { - return { - name: elem.name, - value: val.replace(rCRLF, "\r\n") - }; - }); + return this; } + }; - return { - name: elem.name, - value: val.replace(rCRLF, "\r\n") - }; - }).get(); - } - }); + // Attach deferreds + deferred.promise(jqXHR); - var r20 = /%20/g, - rhash = /#.*$/, - rantiCache = /([?&])_=[^&]*/, - rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg, - // trac-7653, trac-8125, trac-8152: local protocol detection - rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, - rnoContent = /^(?:GET|HEAD)$/, - rprotocol = /^\/\//, - /* Prefilters - * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) - * 2) These are called: - * - BEFORE asking for a transport - * - AFTER param serialization (s.data is a string if s.processData is true) - * 3) key is the dataType - * 4) the catchall symbol "*" can be used - * 5) execution will start with transport dataType and THEN continue down to "*" if needed - */ - prefilters = {}, - /* Transports bindings - * 1) key is the dataType - * 2) the catchall symbol "*" can be used - * 3) selection will start with transport dataType and THEN go to "*" if needed - */ - transports = {}, - // Avoid comment-prolog char sequence (trac-10098); must appease lint and evade compression - allTypes = ("*/").concat("*"), - // Anchor tag for parsing the document origin - originAnchor = document.createElement("a"); - - originAnchor.href = location.href; - - // Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport - function addToPrefiltersOrTransports(structure) { - // dataTypeExpression is optional and defaults to "*" - return function (dataTypeExpression, func) { - if (typeof dataTypeExpression !== "string") { - func = dataTypeExpression; - dataTypeExpression = "*"; - } - - var dataType, - i = 0, - dataTypes = dataTypeExpression.toLowerCase().match(rnothtmlwhite) || []; - - if (isFunction(func)) { - // For each dataType in the dataTypeExpression - while (dataType = dataTypes[i++]) { - // Prepend if requested - if (dataType[0] === "+") { - dataType = dataType.slice(1) || "*"; - (structure[dataType] = structure[dataType] || []).unshift(func); - } else { - (structure[dataType] = structure[dataType] || []).push(func); // Otherwise append - } - } - } - }; - } + // Add protocol if not provided (prefilters might expect it) + // Handle falsy url in the settings object (trac-10093: consistency with old signature) + // We also use the url parameter if available + s.url = ((url || s.url || location.href) + "").replace(rprotocol, location.protocol + "//"); - // Base inspection function for prefilters and transports - function inspectPrefiltersOrTransports(structure, options, originalOptions, jqXHR) { - var inspected = {}, - seekingTransport = structure === transports; + // Alias method option to type as per ticket trac-12004 + s.type = options.method || options.type || s.method || s.type; - function inspect(dataType) { - var selected; + // Extract dataTypes list + s.dataTypes = (s.dataType || "*").toLowerCase().match(rnothtmlwhite) || [""]; - inspected[dataType] = true; + // A cross-domain request is in order when the origin doesn't match the current origin. + if (s.crossDomain == null) { + urlAnchor = document.createElement("a"); - jQuery.each(structure[dataType] || [], function (_, prefilterOrFactory) { - var dataTypeOrTransport = prefilterOrFactory(options, originalOptions, jqXHR); + // Support: IE <=8 - 11, Edge 12 - 15 + // IE throws exception on accessing the href property if url is malformed, + // e.g. http://example.com:80x/ + try { + urlAnchor.href = s.url; - if (typeof dataTypeOrTransport === "string" && !seekingTransport && !inspected[dataTypeOrTransport]) { - options.dataTypes.unshift(dataTypeOrTransport); - inspect(dataTypeOrTransport); - return false; - } else if (seekingTransport) { - return !(selected = dataTypeOrTransport); - } - }); + // Support: IE <=8 - 11 only + // Anchor's host property isn't correctly set when s.url is relative + urlAnchor.href = urlAnchor.href; - return selected; + s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !== urlAnchor.protocol + "//" + urlAnchor.host; + } catch(e) { + // If there is an error parsing the URL, assume it is crossDomain, + // it can be rejected by the transport if it is invalid + s.crossDomain = true; + } } - return inspect(options.dataTypes[0]) || !inspected["*"] && inspect("*"); - } + // Convert data if not already a string + if (s.data && s.processData && typeof s.data !== "string") { + s.data = jQuery.param(s.data, s.traditional); + } - // A special extend for ajax options - // that takes "flat" options (not to be deep extended) - // Fixes trac-9887 - function ajaxExtend(target, src) { - var key, - deep, - flatOptions = jQuery.ajaxSettings.flatOptions || {}; + // Apply prefilters + inspectPrefiltersOrTransports(prefilters, s, options, jqXHR); - for (key in src) { - if (src[key] !== undefined) { - (flatOptions[key] ? target : deep || (deep = {}))[key] = src[key]; - } + // If request was aborted inside a prefilter, stop there + if (completed) { + return jqXHR; } - if (deep) { - jQuery.extend(true, target, deep); - } + // We can fire global events as of now if asked to + // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (trac-15118) + fireGlobals = jQuery.event && s.global; - return target; - } + // Watch for a new set of requests + if (fireGlobals && jQuery.active++ === 0) { + jQuery.event.trigger("ajaxStart"); + } - /* Handles responses to an ajax request: - * - finds the right dataType (mediates between content-type and expected dataType) - * - returns the corresponding response - */ - function ajaxHandleResponses(s, jqXHR, responses) { - var ct, - type, - finalDataType, - firstDataType, - contents = s.contents, - dataTypes = s.dataTypes; + // Uppercase the type + s.type = s.type.toUpperCase(); - // Remove auto dataType and get content-type in the process - while (dataTypes[0] === "*") { - dataTypes.shift(); + // Determine if request has content + s.hasContent = !rnoContent.test(s.type); - if (ct === undefined) { - ct = s.mimeType || jqXHR.getResponseHeader("Content-Type"); - } - } + // Save the URL in case we're toying with the If-Modified-Since + // and/or If-None-Match header later on + // Remove hash to simplify url manipulation + cacheURL = s.url.replace(rhash, ""); - // Check if we're dealing with a known content-type - if (ct) { - for (type in contents) { - if (contents[type] && contents[type].test(ct)) { - dataTypes.unshift(type); - break; - } - } - } + // More options handling for requests with no content + if (!s.hasContent) { + // Remember the hash so we can put it back + uncached = s.url.slice(cacheURL.length); - // Check to see if we have a response for the expected dataType - if (dataTypes[0] in responses) { - finalDataType = dataTypes[0]; - } else { - // Try convertible dataTypes - for (type in responses) { - if (!dataTypes[0] || s.converters[type + " " + dataTypes[0]]) { - finalDataType = type; - break; - } + // If data is available and should be processed, append data to url + if (s.data && (s.processData || typeof s.data === "string")) { + cacheURL += (rquery.test(cacheURL) ? "&" : "?") + s.data; - if (!firstDataType) { - firstDataType = type; - } + // trac-9682: remove data so that it's not used in an eventual retry + delete s.data; } - // Or just use first one - finalDataType = finalDataType || firstDataType; - } - - // If we found a dataType - // We add the dataType to the list if needed - // and return the corresponding response - if (finalDataType) { - if (finalDataType !== dataTypes[0]) { - dataTypes.unshift(finalDataType); + // Add or update anti-cache param if needed + if (s.cache === false) { + cacheURL = cacheURL.replace(rantiCache, "$1"); + uncached = (rquery.test(cacheURL) ? "&" : "?") + "_=" + nonce.guid++ + uncached; } - return responses[finalDataType]; + // Put hash and anti-cache on the URL that will be requested (gh-1732) + s.url = cacheURL + uncached; + + // Change '%20' to '+' if this is encoded form body content (gh-2658) + } else if (s.data && s.processData && (s.contentType || "").indexOf("application/x-www-form-urlencoded") === 0) { + s.data = s.data.replace(r20, "+"); } - } - /* Chain conversions given the request and the original response - * Also sets the responseXXX fields on the jqXHR instance - */ - function ajaxConvert(s, response, jqXHR, isSuccess) { - var conv2, - current, - conv, - tmp, - prev, - converters = {}, - // Work with a copy of dataTypes in case we need to modify it for conversion - dataTypes = s.dataTypes.slice(); + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if (s.ifModified) { + if (jQuery.lastModified[cacheURL]) { + jqXHR.setRequestHeader("If-Modified-Since", jQuery.lastModified[cacheURL]); + } - // Create converters map with lowercased keys - if (dataTypes[1]) { - for (conv in s.converters) { - converters[conv.toLowerCase()] = s.converters[conv]; + if (jQuery.etag[cacheURL]) { + jqXHR.setRequestHeader("If-None-Match", jQuery.etag[cacheURL]); } } - current = dataTypes.shift(); - - // Convert to each sequential dataType - while (current) { - if (s.responseFields[current]) { - jqXHR[s.responseFields[current]] = response; - } - - // Apply the dataFilter if provided - if (!prev && isSuccess && s.dataFilter) { - response = s.dataFilter(response, s.dataType); - } - - prev = current; - current = dataTypes.shift(); - - if (current) { - // There's only work to do if current dataType is non-auto - if (current === "*") { - current = prev; - } else if (prev !== "*" && prev !== current) { - // Seek a direct converter - conv = converters[prev + " " + current] || converters["* " + current]; // Convert response if prev dataType is non-auto and differs from current - - // If none found, seek a pair - if (!conv) { - for (conv2 in converters) { - // If conv2 outputs current - tmp = conv2.split(" "); - - if (tmp[1] === current) { - // If prev can be converted to accepted input - conv = converters[prev + " " + tmp[0]] || converters["* " + tmp[0]]; - - if (conv) { - // Condense equivalence converters - if (conv === true) { - conv = converters[conv2]; - } else if (converters[conv2] !== true) { - current = tmp[0]; // Otherwise, insert the intermediate dataType - dataTypes.unshift(tmp[1]); - } + // Set the correct header, if data is being sent + if (s.data && s.hasContent && s.contentType !== false || options.contentType) { + jqXHR.setRequestHeader("Content-Type", s.contentType); + } - break; - } - } - } - } + // Set the Accepts header for the server, depending on the dataType + jqXHR.setRequestHeader("Accept", s.dataTypes[0] && s.accepts[s.dataTypes[0]] + ? s.accepts[s.dataTypes[0]] + (s.dataTypes[0] !== "*" ? ", " + allTypes + "; q=0.01" : "") + : s.accepts["*"]); - // Apply converter (if not an equivalence) - if (conv !== true) { - // Unless errors are allowed to bubble, catch and return them - if (conv && s.throws) { - response = conv(response); - } else { - try { - response = conv(response); - } catch(e) { - return { - state: "parsererror", - error: conv ? e : "No conversion from " + prev + " to " + current - }; - } - } - } - } - } + // Check for headers option + for (i in s.headers) { + jqXHR.setRequestHeader(i, s.headers[i]); } - return { state: "success", data: response }; - } - - jQuery.extend({ - // Counter for holding the number of active queries - active: 0, - // Last-Modified header cache for next request - lastModified: {}, - etag: {}, - ajaxSettings: { - url: location.href, - type: "GET", - isLocal: rlocalProtocol.test(location.protocol), - global: true, - processData: true, - async: true, - contentType: "application/x-www-form-urlencoded; charset=UTF-8", - /* - timeout: 0, - data: null, - dataType: null, - username: null, - password: null, - cache: null, - throws: false, - traditional: false, - headers: {}, - */ - accepts: { - "*": allTypes, - text: "text/plain", - html: "text/html", - xml: "application/xml, text/xml", - json: "application/json, text/javascript" - }, - contents: { - xml: /\bxml\b/, - html: /\bhtml/, - json: /\bjson\b/ - }, - responseFields: { - xml: "responseXML", - text: "responseText", - json: "responseJSON" - }, - // Data converters - // Keys separate source (or catchall "*") and destination types with a single space - converters: { - // Convert anything to text - "* text": String, - // Text to html (true = no transformation) - "text html": true, - // Evaluate text as a json expression - "text json": JSON.parse, - // Parse text as xml - "text xml": jQuery.parseXML - }, - // For options that shouldn't be deep extended: - // you can add your own custom options here if - // and when you create one that shouldn't be - // deep extended (see ajaxExtend) - flatOptions: { url: true, context: true } - }, - ajaxSetup(target, settings) { - return settings ? // Building a settings object - ajaxExtend(ajaxExtend(target, jQuery.ajaxSettings), settings) : // Extending ajaxSettings - ajaxExtend(jQuery.ajaxSettings, target); - }, - ajaxPrefilter: addToPrefiltersOrTransports(prefilters), - ajaxTransport: addToPrefiltersOrTransports(transports), - ajax(url, options) { - // If url is an object, simulate pre-1.5 signature - if (typeof url === "object") { - options = url; - url = undefined; - } - - // Force options to be an object - options = options || {}; - - var transport, - // URL without anti-cache param - cacheURL, - // Response headers - responseHeadersString, - responseHeaders, - // timeout handle - timeoutTimer, - // Url cleanup var - urlAnchor, - // Request state (becomes false upon send and true upon completion) - completed, - // To know if global events are to be dispatched - fireGlobals, - // Loop variable - i, - // uncached part of the url - uncached, - // Create the final options object - s = jQuery.ajaxSetup({}, options), - // Callbacks context - callbackContext = s.context || s, - // Context for global events is callbackContext if it is a DOM node or jQuery collection - globalEventContext = s.context && (callbackContext.nodeType || callbackContext.jquery) ? jQuery(callbackContext) : jQuery.event, - // Deferreds - deferred = jQuery.Deferred(), - completeDeferred = jQuery.Callbacks("once memory"), - // Status-dependent callbacks - statusCode = s.statusCode || {}, - // Headers (they are sent all at once) - requestHeaders = {}, - requestHeadersNames = {}, - // Default abort message - strAbort = "canceled", - // Fake xhr - jqXHR = { - readyState: 0, - getResponseHeader(key) { - var match; + // Allow custom headers/mimetypes and early abort + if (s.beforeSend && (s.beforeSend.call(callbackContext, jqXHR, s) === false || completed)) { + // Abort if not done already and return + return jqXHR.abort(); + } - if (completed) { - if (!responseHeaders) { - responseHeaders = {}; + // Aborting is no longer a cancellation + strAbort = "abort"; - while (match = rheaders.exec(responseHeadersString)) { - responseHeaders[match[1].toLowerCase() + " "] = (responseHeaders[match[1].toLowerCase() + " "] || []).concat(match[2]); - } - } + // Install callbacks on deferreds + completeDeferred.add(s.complete); - match = responseHeaders[key.toLowerCase() + " "]; - } + jqXHR.done(s.success); + jqXHR.fail(s.error); - return match == null ? null : match.join(", "); - }, - getAllResponseHeaders() { - return completed ? responseHeadersString : null; - }, - setRequestHeader(name, value) { - if (completed == null) { - name = requestHeadersNames[name.toLowerCase()] = requestHeadersNames[name.toLowerCase()] || name; - requestHeaders[name] = value; - } + // Get transport + transport = inspectPrefiltersOrTransports(transports, s, options, jqXHR); - return this; - }, - overrideMimeType(type) { - if (completed == null) { - s.mimeType = type; - } + // If no transport, we auto-abort + if (!transport) { + done(-1, "No Transport"); + } else { + jqXHR.readyState = 1; - return this; - }, - statusCode(map) { - var code; + // Send global event + if (fireGlobals) { + globalEventContext.trigger("ajaxSend", [jqXHR, s]); + } - if (map) { - if (completed) { - // Execute the appropriate callbacks - jqXHR.always(map[jqXHR.status]); - } else { - // Lazy-add the new callbacks in a way that preserves old ones - for (code in map) { - statusCode[code] = [statusCode[code], map[code]]; - } - } - } + // If request was aborted inside ajaxSend, stop there + if (completed) { + return jqXHR; + } - return this; + // Timeout + if (s.async && s.timeout > 0) { + timeoutTimer = window.setTimeout( + function () { + jqXHR.abort("timeout"); }, - abort(statusText) { - var finalText = statusText || strAbort; - - if (transport) { - transport.abort(finalText); - } - - done(0, finalText); - return this; - } - }; + s.timeout + ); + } - // Attach deferreds - deferred.promise(jqXHR); - // Add protocol if not provided (prefilters might expect it) - // Handle falsy url in the settings object (trac-10093: consistency with old signature) - // We also use the url parameter if available - s.url = ((url || s.url || location.href) + "").replace(rprotocol, location.protocol + "//"); - // Alias method option to type as per ticket trac-12004 - s.type = options.method || options.type || s.method || s.type; - // Extract dataTypes list - s.dataTypes = (s.dataType || "*").toLowerCase().match(rnothtmlwhite) || [""]; - - // A cross-domain request is in order when the origin doesn't match the current origin. - if (s.crossDomain == null) { - urlAnchor = document.createElement("a"); - - // Support: IE <=8 - 11, Edge 12 - 15 - // IE throws exception on accessing the href property if url is malformed, - // e.g. http://example.com:80x/ - try { - urlAnchor.href = s.url; - // Support: IE <=8 - 11 only - // Anchor's host property isn't correctly set when s.url is relative - urlAnchor.href = urlAnchor.href; - s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !== urlAnchor.protocol + "//" + urlAnchor.host; - } catch(e) { - // If there is an error parsing the URL, assume it is crossDomain, - // it can be rejected by the transport if it is invalid - s.crossDomain = true; + try { + completed = false; + transport.send(requestHeaders, done); + } catch(e) { + // Rethrow post-completion exceptions + if (completed) { + throw e; } - } - // Convert data if not already a string - if (s.data && s.processData && typeof s.data !== "string") { - s.data = jQuery.param(s.data, s.traditional); + // Propagate others as results + done(-1, e); } + } - // Apply prefilters - inspectPrefiltersOrTransports(prefilters, s, options, jqXHR); + // Callback for when everything is done + function done(status, nativeStatusText, responses, headers) { + var isSuccess, + success, + error, + response, + modified, + statusText = nativeStatusText; - // If request was aborted inside a prefilter, stop there + // Ignore repeat invocations if (completed) { - return jqXHR; + return; } - // We can fire global events as of now if asked to - // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (trac-15118) - fireGlobals = jQuery.event && s.global; + completed = true; - // Watch for a new set of requests - if (fireGlobals && jQuery.active++ === 0) { - jQuery.event.trigger("ajaxStart"); + // Clear timeout if it exists + if (timeoutTimer) { + window.clearTimeout(timeoutTimer); } - // Uppercase the type - s.type = s.type.toUpperCase(); - // Determine if request has content - s.hasContent = !rnoContent.test(s.type); - // Save the URL in case we're toying with the If-Modified-Since - // and/or If-None-Match header later on - // Remove hash to simplify url manipulation - cacheURL = s.url.replace(rhash, ""); + // Dereference transport for early garbage collection + // (no matter how long the jqXHR object will be used) + transport = undefined; - // More options handling for requests with no content - if (!s.hasContent) { - // Remember the hash so we can put it back - uncached = s.url.slice(cacheURL.length); + // Cache response headers + responseHeadersString = headers || ""; - // If data is available and should be processed, append data to url - if (s.data && (s.processData || typeof s.data === "string")) { - cacheURL += (rquery.test(cacheURL) ? "&" : "?") + s.data; - // trac-9682: remove data so that it's not used in an eventual retry - delete s.data; - } + // Set readyState + jqXHR.readyState = status > 0 ? 4 : 0; - // Add or update anti-cache param if needed - if (s.cache === false) { - cacheURL = cacheURL.replace(rantiCache, "$1"); - uncached = (rquery.test(cacheURL) ? "&" : "?") + "_=" + nonce.guid++ + uncached; - } + // Determine if successful + isSuccess = status >= 200 && status < 300 || status === 304; - // Put hash and anti-cache on the URL that will be requested (gh-1732) - s.url = cacheURL + uncached; - } else if (s.data && s.processData && (s.contentType || "").indexOf("application/x-www-form-urlencoded") === 0) { - s.data = s.data.replace( - r20, // Change '%20' to '+' if this is encoded form body content (gh-2658) - "+" - ); + // Get response data + if (responses) { + response = ajaxHandleResponses(s, jqXHR, responses); } - // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. - if (s.ifModified) { - if (jQuery.lastModified[cacheURL]) { - jqXHR.setRequestHeader("If-Modified-Since", jQuery.lastModified[cacheURL]); - } - - if (jQuery.etag[cacheURL]) { - jqXHR.setRequestHeader("If-None-Match", jQuery.etag[cacheURL]); - } + // Use a noop converter for missing script but not if jsonp + if (!isSuccess && jQuery.inArray("script", s.dataTypes) > -1 && jQuery.inArray("json", s.dataTypes) < 0) { + s.converters["text script"] = function () {}; } - // Set the correct header, if data is being sent - if (s.data && s.hasContent && s.contentType !== false || options.contentType) { - jqXHR.setRequestHeader("Content-Type", s.contentType); - } + // Convert no matter what (that way responseXXX fields are always set) + response = ajaxConvert(s, response, jqXHR, isSuccess); - // Set the Accepts header for the server, depending on the dataType - jqXHR.setRequestHeader("Accept", s.dataTypes[0] && s.accepts[s.dataTypes[0]] ? s.accepts[s.dataTypes[0]] + (s.dataTypes[0] !== "*" ? ", " + allTypes + "; q=0.01" : "") : s.accepts["*"]); + // If successful, handle type chaining + if (isSuccess) { + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if (s.ifModified) { + modified = jqXHR.getResponseHeader("Last-Modified"); - // Check for headers option - for (i in s.headers) { - jqXHR.setRequestHeader(i, s.headers[i]); - } + if (modified) { + jQuery.lastModified[cacheURL] = modified; + } - // Allow custom headers/mimetypes and early abort - if (s.beforeSend && (s.beforeSend.call(callbackContext, jqXHR, s) === false || completed)) { - // Abort if not done already and return - return jqXHR.abort(); - } + modified = jqXHR.getResponseHeader("etag"); - // Aborting is no longer a cancellation - strAbort = "abort"; - // Install callbacks on deferreds - completeDeferred.add(s.complete); - jqXHR.done(s.success); - jqXHR.fail(s.error); - // Get transport - transport = inspectPrefiltersOrTransports(transports, s, options, jqXHR); + if (modified) { + jQuery.etag[cacheURL] = modified; + } + } - // If no transport, we auto-abort - if (!transport) { - done(-1, "No Transport"); - } else { - jqXHR.readyState = 1; + // if no content + if (status === 204 || s.type === "HEAD") { + statusText = "nocontent"; - // Send global event - if (fireGlobals) { - globalEventContext.trigger("ajaxSend", [jqXHR, s]); - } + // if not modified + } else if (status === 304) { + statusText = "notmodified"; - // If request was aborted inside ajaxSend, stop there - if (completed) { - return jqXHR; + // If we have data, let's convert it + } else { + statusText = response.state; + success = response.data; + error = response.error; + isSuccess = !error; } + } else { + // Extract error from statusText and normalize for non-aborts + error = statusText; - // Timeout - if (s.async && s.timeout > 0) { - timeoutTimer = window.setTimeout( - function () { - jqXHR.abort("timeout"); - }, - s.timeout - ); - } + if (status || !statusText) { + statusText = "error"; - try { - completed = false; - transport.send(requestHeaders, done); - } catch(e) { - // Rethrow post-completion exceptions - if (completed) { - throw e; + if (status < 0) { + status = 0; } - - // Propagate others as results - done(-1, e); } } - // Callback for when everything is done - function done( - status, - nativeStatusText, - responses, - headers - ) { - var isSuccess, - success, - error, - response, - modified, - statusText = nativeStatusText; + // Set data for the fake xhr object + jqXHR.status = status; - // Ignore repeat invocations - if (completed) { - return; - } + jqXHR.statusText = (nativeStatusText || statusText) + ""; + + // Success/Error + if (isSuccess) { + deferred.resolveWith(callbackContext, [success, statusText, jqXHR]); + } else { + deferred.rejectWith(callbackContext, [jqXHR, statusText, error]); + } - completed = true; + // Status-dependent callbacks + jqXHR.statusCode(statusCode); - // Clear timeout if it exists - if (timeoutTimer) { - window.clearTimeout(timeoutTimer); - } + statusCode = undefined; - // Dereference transport for early garbage collection - // (no matter how long the jqXHR object will be used) - transport = undefined; - // Cache response headers - responseHeadersString = headers || ""; - // Set readyState - jqXHR.readyState = status > 0 ? 4 : 0; - // Determine if successful - isSuccess = status >= 200 && status < 300 || status === 304; + if (fireGlobals) { + globalEventContext.trigger(isSuccess ? "ajaxSuccess" : "ajaxError", [jqXHR, s, isSuccess ? success : error]); + } - // Get response data - if (responses) { - response = ajaxHandleResponses(s, jqXHR, responses); - } + // Complete + completeDeferred.fireWith(callbackContext, [jqXHR, statusText]); - // Use a noop converter for missing script but not if jsonp - if (!isSuccess && jQuery.inArray("script", s.dataTypes) > -1 && jQuery.inArray("json", s.dataTypes) < 0) { - s.converters["text script"] = function () {}; - } + if (fireGlobals) { + globalEventContext.trigger("ajaxComplete", [jqXHR, s]); - // Convert no matter what (that way responseXXX fields are always set) - response = ajaxConvert(s, response, jqXHR, isSuccess); + // Handle the global AJAX counter + if (!--jQuery.active) { + jQuery.event.trigger("ajaxStop"); + } + } + } - // If successful, handle type chaining - if (isSuccess) { - // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. - if (s.ifModified) { - modified = jqXHR.getResponseHeader("Last-Modified"); + return jqXHR; + }, - if (modified) { - jQuery.lastModified[cacheURL] = modified; - } + getJSON(url, data, callback) { + return jQuery.get(url, data, callback, "json"); + }, - modified = jqXHR.getResponseHeader("etag"); + getScript(url, callback) { + return jQuery.get(url, undefined, callback, "script"); + } + }); - if (modified) { - jQuery.etag[cacheURL] = modified; - } - } + jQuery.each(["get", "post"], function (_i, method) { + jQuery[method] = function (url, data, callback, type) { + // Shift arguments if data argument was omitted + if (isFunction(data)) { + type = type || callback; + callback = data; + data = undefined; + } - // if no content - if (status === 204 || s.type === "HEAD") { - statusText = "nocontent"; - } else if (status === 304) { - statusText = "notmodified"; // if not modified - } else { - statusText = response.state; // If we have data, let's convert it - success = response.data; - error = response.error; - isSuccess = !error; - } - } else { - // Extract error from statusText and normalize for non-aborts - error = statusText; + // The url can be an options object (which then must have .url) + return jQuery.ajax(jQuery.extend({ url, type: method, dataType: type, data, success: callback }, jQuery.isPlainObject(url) && url)); + }; + }); - if (status || !statusText) { - statusText = "error"; + jQuery.ajaxPrefilter(function (s) { + var i; - if (status < 0) { - status = 0; - } - } - } + for (i in s.headers) { + if (i.toLowerCase() === "content-type") { + s.contentType = s.headers[i] || ""; + } + } + }); - // Set data for the fake xhr object - jqXHR.status = status; - jqXHR.statusText = (nativeStatusText || statusText) + ""; + jQuery._evalUrl = function (url, options, doc) { + return jQuery.ajax({ + url, - // Success/Error - if (isSuccess) { - deferred.resolveWith(callbackContext, [success, statusText, jqXHR]); - } else { - deferred.rejectWith(callbackContext, [jqXHR, statusText, error]); - } + // Make this explicit, since user can override this through ajaxSetup (trac-11264) + type: "GET", - // Status-dependent callbacks - jqXHR.statusCode(statusCode); - statusCode = undefined; + dataType: "script", + cache: true, + async: false, + global: false, - if (fireGlobals) { - globalEventContext.trigger(isSuccess ? "ajaxSuccess" : "ajaxError", [jqXHR, s, isSuccess ? success : error]); - } + // Only evaluate the response if it is successful (gh-4126) + // dataFilter is not invoked for failure responses, so using it instead + // of the default converter is kludgy but it works. + converters: { "text script"() {} }, - // Complete - completeDeferred.fireWith(callbackContext, [jqXHR, statusText]); + dataFilter(response) { + jQuery.globalEval(response, options, doc); + } + }); + }; - if (fireGlobals) { - globalEventContext.trigger("ajaxComplete", [jqXHR, s]); + jQuery.fn.extend({ + wrapAll(html) { + var wrap; - // Handle the global AJAX counter - if (!--jQuery.active) { - jQuery.event.trigger("ajaxStop"); - } - } + if (this[0]) { + if (isFunction(html)) { + html = html.call(this[0]); } - return jqXHR; - }, - getJSON(url, data, callback) { - return jQuery.get(url, data, callback, "json"); - }, - getScript(url, callback) { - return jQuery.get(url, undefined, callback, "script"); - } - }); + // The elements to wrap the target around + wrap = jQuery(html, this[0].ownerDocument).eq(0).clone(true); - jQuery.each(["get", "post"], function (_i, method) { - jQuery[method] = function (url, data, callback, type) { - // Shift arguments if data argument was omitted - if (isFunction(data)) { - type = type || callback; - callback = data; - data = undefined; + if (this[0].parentNode) { + wrap.insertBefore(this[0]); } - // The url can be an options object (which then must have .url) - return jQuery.ajax(jQuery.extend( - { - url, - type: method, - dataType: type, - data, - success: callback - }, - jQuery.isPlainObject(url) && url - )); - }; - }); + wrap.map(function () { + var elem = this; - jQuery.ajaxPrefilter(function (s) { - var i; + while (elem.firstElementChild) { + elem = elem.firstElementChild; + } - for (i in s.headers) { - if (i.toLowerCase() === "content-type") { - s.contentType = s.headers[i] || ""; - } + return elem; + }).append(this); } - }); - jQuery._evalUrl = function (url, options, doc) { - return jQuery.ajax({ - url, - // Make this explicit, since user can override this through ajaxSetup (trac-11264) - type: "GET", - dataType: "script", - cache: true, - async: false, - global: false, - // Only evaluate the response if it is successful (gh-4126) - // dataFilter is not invoked for failure responses, so using it instead - // of the default converter is kludgy but it works. - converters: { "text script"() {} }, - dataFilter(response) { - jQuery.globalEval(response, options, doc); + return this; + }, + + wrapInner(html) { + if (isFunction(html)) { + return this.each(function (i) { + jQuery(this).wrapInner(html.call(this, i)); + }); + } + + return this.each(function () { + var self = jQuery(this), + contents = self.contents(); + + if (contents.length) { + contents.wrapAll(html); + } else { + self.append(html); } }); - }; + }, - jQuery.fn.extend({ - wrapAll(html) { - var wrap; + wrap(html) { + var htmlIsFunction = isFunction(html); - if (this[0]) { - if (isFunction(html)) { - html = html.call(this[0]); - } + return this.each(function (i) { + jQuery(this).wrapAll(htmlIsFunction ? html.call(this, i) : html); + }); + }, - // The elements to wrap the target around - wrap = jQuery(html, this[0].ownerDocument).eq(0).clone(true); + unwrap(selector) { + this.parent(selector).not("body").each(function () { + jQuery(this).replaceWith(this.childNodes); + }); - if (this[0].parentNode) { - wrap.insertBefore(this[0]); - } + return this; + } + }); + + jQuery.expr.pseudos.hidden = function (elem) { + return !jQuery.expr.pseudos.visible(elem); + }; + + jQuery.expr.pseudos.visible = function (elem) { + return !!(elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length); + }; + + jQuery.ajaxSettings.xhr = function () { + try { + return new window.XMLHttpRequest(); + } catch(e) {} + }; - wrap.map(function () { - var elem = this; + var xhrSuccessStatus = { + // File protocol always yields status code 0, assume 200 + 0: 200, - while (elem.firstElementChild) { - elem = elem.firstElementChild; + // Support: IE <=9 only + // trac-1450: sometimes IE returns 1223 when it should be 204 + 1223: 204 + }, + xhrSupported = jQuery.ajaxSettings.xhr(); + + support.cors = !!xhrSupported && "withCredentials" in xhrSupported; + support.ajax = xhrSupported = !!xhrSupported; + + jQuery.ajaxTransport(function (options) { + var callback, errorCallback; + + // Cross domain only allowed if supported through XMLHttpRequest + if (support.cors || xhrSupported && !options.crossDomain) { + return { + send(headers, complete) { + var i, xhr = options.xhr(); + + xhr.open(options.type, options.url, options.async, options.username, options.password); + + // Apply custom fields if provided + if (options.xhrFields) { + for (i in options.xhrFields) { + xhr[i] = options.xhrFields[i]; } + } - return elem; - }).append(this); - } + // Override mime type if needed + if (options.mimeType && xhr.overrideMimeType) { + xhr.overrideMimeType(options.mimeType); + } - return this; - }, - wrapInner(html) { - if (isFunction(html)) { - return this.each(function (i) { - jQuery(this).wrapInner(html.call(this, i)); - }); - } + // X-Requested-With header + // For cross-domain requests, seeing as conditions for a preflight are + // akin to a jigsaw puzzle, we simply never set it to be sure. + // (it can always be set on a per-request basis or even using ajaxSetup) + // For same-domain requests, won't change header if already provided. + if (!options.crossDomain && !headers["X-Requested-With"]) { + headers["X-Requested-With"] = "XMLHttpRequest"; + } - return this.each(function () { - var self = jQuery(this), - contents = self.contents(); + // Set headers + for (i in headers) { + xhr.setRequestHeader(i, headers[i]); + } + + // Callback + callback = function (type) { + return function () { + if (callback) { + callback = errorCallback = xhr.onload = xhr.onerror = xhr.onabort = xhr.ontimeout = xhr.onreadystatechange = null; + + if (type === "abort") { + xhr.abort(); + } else if (type === "error") { + // Support: IE <=9 only + // On a manual native abort, IE9 throws + // errors on any property access that is not readyState + if (typeof xhr.status !== "number") { + complete(0, "error"); + } else { + complete( + // File: protocol always yields status 0; see trac-8605, trac-14207 + xhr.status, + xhr.statusText + ); + } + } else { + complete( + xhrSuccessStatus[xhr.status] || xhr.status, + xhr.statusText, + // Support: IE <=9 only + // IE9 has no XHR2 but throws on binary (trac-11426) + // For XHR2 non-text, let the caller handle it (gh-2498) + (xhr.responseType || "text") !== "text" || typeof xhr.responseText !== "string" ? { binary: xhr.response } : { text: xhr.responseText }, + xhr.getAllResponseHeaders() + ); + } + } + }; + }; - if (contents.length) { - contents.wrapAll(html); + // Listen to events + xhr.onload = callback(); + + errorCallback = xhr.onerror = xhr.ontimeout = callback("error"); + + // Support: IE 9 only + // Use onreadystatechange to replace onabort + // to handle uncaught aborts + if (xhr.onabort !== undefined) { + xhr.onabort = errorCallback; } else { - self.append(html); + xhr.onreadystatechange = function () { + // Check readyState before timeout as it changes + if (xhr.readyState === 4) { + // Allow onerror to be called first, + // but that will not handle a native abort + // Also, save errorCallback to a variable + // as xhr.onerror cannot be accessed + window.setTimeout(function () { + if (callback) { + errorCallback(); + } + }); + } + }; } - }); - }, - wrap(html) { - var htmlIsFunction = isFunction(html); - return this.each(function (i) { - jQuery(this).wrapAll(htmlIsFunction ? html.call(this, i) : html); - }); - }, - unwrap(selector) { - this.parent(selector).not("body").each(function () { - jQuery(this).replaceWith(this.childNodes); - }); + // Create the abort callback + callback = callback("abort"); + + try { + // Do send the request (this may raise an exception) + xhr.send(options.hasContent && options.data || null); + } catch(e) { + // trac-14683: Only rethrow if this hasn't been notified as an error yet + if (callback) { + throw e; + } + } + }, + + abort() { + if (callback) { + callback(); + } + } + }; + } + }); - return this; - } - }); + // Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432) + jQuery.ajaxPrefilter(function (s) { + if (s.crossDomain) { + s.contents.script = false; + } + }); - jQuery.expr.pseudos.hidden = function (elem) { - return !jQuery.expr.pseudos.visible(elem); - }; + // Install script dataType + jQuery.ajaxSetup({ + accepts: { + script: "text/javascript, application/javascript, " + "application/ecmascript, application/x-ecmascript" + }, - jQuery.expr.pseudos.visible = function (elem) { - return !!(elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length); - }; + contents: { script: /\b(?:java|ecma)script\b/ }, - jQuery.ajaxSettings.xhr = function () { - try { - return new window.XMLHttpRequest(); - } catch(e) {} - }; + converters: { + "text script"(text) { + jQuery.globalEval(text); - var xhrSuccessStatus = { // File protocol always yields status code 0, assume 200 - 0: 200, // Support: IE <=9 only - // trac-1450: sometimes IE returns 1223 when it should be 204 - 1223: 204 }, - xhrSupported = jQuery.ajaxSettings.xhr(); + return text; + } + } + }); - support.cors = !!xhrSupported && "withCredentials" in xhrSupported; - support.ajax = xhrSupported = !!xhrSupported; + // Handle cache's special case and crossDomain + jQuery.ajaxPrefilter("script", function (s) { + if (s.cache === undefined) { + s.cache = false; + } - jQuery.ajaxTransport(function (options) { - var callback, errorCallback; + if (s.crossDomain) { + s.type = "GET"; + } + }); - // Cross domain only allowed if supported through XMLHttpRequest - if (support.cors || xhrSupported && !options.crossDomain) { - return { - send(headers, complete) { - var i, xhr = options.xhr(); + // Bind script tag hack transport + jQuery.ajaxTransport("script", function (s) { + // This transport only deals with cross domain or forced-by-attrs requests + if (s.crossDomain || s.scriptAttrs) { + var script, callback; - xhr.open(options.type, options.url, options.async, options.username, options.password); + return { + send(_, complete) { + script = jQuery("