diff --git a/.csslintrc b/.csslintrc new file mode 100644 index 00000000000..227cda5158b --- /dev/null +++ b/.csslintrc @@ -0,0 +1,13 @@ +{ + "adjoining-classes": false, + "box-model": false, + "box-sizing": false, + "compatible-vendor-prefixes": false, + "duplicate-background-images": false, + "import": false, + "important": false, + "outline-none": false, + "order-alphabetical": false, + "overqualified-elements": false, + "text-indent": false +} diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000000..fa81b6e2977 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,20 @@ +# This file is for unifying the coding style for different editors and IDEs +# editorconfig.org + +root = true + +[*] +indent_style = tab +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.yml] +indent_style = space +indent_size = 2 + +[external/**] +trim_trailing_whitespace = false +insert_final_newline = varies +end_of_line = varies diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000000..b7ca95b5b77 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,5 @@ +# Auto detect text files and perform LF normalization +* text=auto + +# JS files must always use LF for tools to work +*.js eol=lf diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000000..aa2f7456527 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,13 @@ +version: 2 +updates: + - package-ecosystem: github-actions + directory: "/" + schedule: + interval: monthly + + # Group all dependabot version update PRs into one + groups: + github-actions: + applies-to: version-updates + patterns: + - "*" diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 00000000000..5b2bdead3e8 --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,58 @@ +name: "Code scanning - action" + +on: + pull_request: + push: + branches-ignore: "dependabot/**" + schedule: + - cron: "0 4 * * 6" + +permissions: + contents: read # to fetch code (actions/checkout) + +jobs: + CodeQL-Build: + permissions: + contents: read # to fetch code (actions/checkout) + security-events: write # (github/codeql-action/autobuild) + + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + # We must fetch at least the immediate parents so that if this is + # a pull request then we can checkout the head. + fetch-depth: 2 + + # If this run was triggered by a pull request event, then checkout + # the head of the pull request instead of the merge commit. + - run: git checkout HEAD^2 + if: ${{ github.event_name == 'pull_request' }} + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18 + # Override language selection by uncommenting this and choosing your languages + # with: + # languages: go, javascript, csharp, python, cpp, java + + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18 + + # ℹ️ Command-line programs to run using the OS shell. + # 📚 https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun + + # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines + # and modify them (or add more) to build your code if your project + # uses a compiled language + + #- run: | + # make bootstrap + # make release + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18 diff --git a/.github/workflows/filestash.yml b/.github/workflows/filestash.yml new file mode 100644 index 00000000000..9f0960a4a98 --- /dev/null +++ b/.github/workflows/filestash.yml @@ -0,0 +1,51 @@ +name: Filestash + +on: + push: + branches: + - main + +permissions: + contents: read # to fetch code (actions/checkout) + +jobs: + update: + runs-on: ubuntu-latest + environment: filestash + env: + NODE_VERSION: 22.x + name: Update Filestash + steps: + - name: Checkout + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - name: Use Node.js ${{ env.NODE_VERSION }} + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + with: + node-version: ${{ env.NODE_VERSION }} + + - name: Cache + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 + with: + path: ~/.npm + key: ${{ runner.os }}-node-${{ env.NODE_VERSION }}-npm-lock-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-node-${{ env.NODE_VERSION }}-npm-lock- + + - name: Install dependencies + run: npm install + + - name: Build + run: npm run build + + - name: Set up SSH + run: | + install --directory ~/.ssh --mode 700 + base64 --decode <<< "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_ed25519 + chmod 600 ~/.ssh/id_ed25519 + ssh-keyscan -t ed25519 -H "${{ secrets.FILESTASH_SERVER }}" >> ~/.ssh/known_hosts + + - name: Upload to Filestash + run: | + rsync dist/jquery-ui.js filestash@"${{ secrets.FILESTASH_SERVER }}":ui/jquery-ui-git.js + rsync dist/jquery-ui.css filestash@"${{ secrets.FILESTASH_SERVER }}":ui/jquery-ui-git.css diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml new file mode 100644 index 00000000000..cccd059d28e --- /dev/null +++ b/.github/workflows/node.js.yml @@ -0,0 +1,139 @@ +name: Node + +on: + pull_request: + push: + branches-ignore: "dependabot/**" + # Once a week every Monday + schedule: + - cron: "42 1 * * 1" + +permissions: + contents: read + +env: + NODE_VERSION: 22.x + +jobs: + build-and-test: + runs-on: ubuntu-latest + name: | + ${{ matrix.BROWSER }} | ${{ matrix.CONFIGS.name }} + strategy: + fail-fast: false + matrix: + BROWSER: [chrome, firefox] + CONFIGS: + - config: jtr-git.yml + name: jQuery git + - config: jtr-stable.yml + name: jQuery stable + + steps: + - name: Checkout + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - name: Use Node.js ${{ env.NODE_VERSION }} + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + with: + node-version: ${{ env.NODE_VERSION }} + + - name: Cache + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 + with: + path: ~/.npm + key: ${{ runner.os }}-node-${{ env.NODE_VERSION }}-npm-lock-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-node-${{ env.NODE_VERSION }}-npm-lock- + + - name: Install npm dependencies + run: npm install + + - name: Build + run: npm run build + + # Lint must happen after build as we lint generated files. + - name: Lint + run: npm run lint + + - name: Test + run: | + npm run test:unit -- \ + --headless -b ${{ matrix.BROWSER }} \ + -c ${{ matrix.CONFIGS.config }} + + edge: + runs-on: windows-latest + name: | + edge | ${{ matrix.CONFIGS.name }} + strategy: + fail-fast: false + matrix: + CONFIGS: + - config: jtr-git.yml + name: jQuery git + - config: jtr-stable.yml + name: jQuery stable + steps: + - name: Checkout + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - name: Use Node.js ${{ env.NODE_VERSION }} + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + with: + node-version: ${{ env.NODE_VERSION }} + + - name: Cache + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 + with: + path: ~/.npm + key: ${{ runner.os }}-node-${{ env.NODE_VERSION }}-npm-lock-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-node-${{ env.NODE_VERSION }}-npm-lock- + + - name: Install dependencies + run: npm install + + - name: Build + run: npm run build + + - name: Test + run: npm run test:unit -- -- --headless -b edge -c ${{ matrix.CONFIGS.config }} + + safari: + runs-on: macos-latest + name: | + safari | ${{ matrix.CONFIGS.name }} + strategy: + fail-fast: false + matrix: + CONFIGS: + - config: jtr-git.yml + name: jQuery git + - config: jtr-stable.yml + name: jQuery stable + steps: + - name: Checkout + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - name: Use Node.js ${{ env.NODE_VERSION }} + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + with: + node-version: ${{ env.NODE_VERSION }} + + - name: Cache + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 + with: + path: ~/.npm + key: ${{ runner.os }}-node-${{ env.NODE_VERSION }}-npm-lock-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-node-${{ env.NODE_VERSION }}-npm-lock- + + - name: Install dependencies + run: npm install + + - name: Build + run: npm run build + + - name: Test + run: npm run test:unit -- -b safari -c ${{ matrix.CONFIGS.config }} diff --git a/.gitignore b/.gitignore index e39040f5b4a..154e8fb56e1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,6 @@ -build/dist -docs -.project -*~ -*.diff -*.patch -.DS_Store +dist +bower_components +node_modules +.sizecache.json +package-lock.json +local.log diff --git a/.mailmap b/.mailmap new file mode 100644 index 00000000000..867c841da1d --- /dev/null +++ b/.mailmap @@ -0,0 +1,120 @@ +Aaron Peterson +Adam Baratz +Adam Sontag +Alexander Polomoshnov +Aliaksandr Rahalevich +Andrew Couch +Andrew Newcomb +Andrew Powell +Andrew Powell +Andrey Kapitcyn +Ben Hollis +Benjamin Scott Boyle +Bert ter Heide +Bjørn Johansen +Chairat Sunthornwiphat +Christoph Rönsch +Corey Frang +Courtland Allen +Dan Streetman +Dan Strohl +Danny Trunk +David De Sloovere +David Murdoch +Diego Tres +Dominique Vincent +Doug Blood +Douglas Cerna +Douglas Neiner +Douglas Neiner +Dylan Just +Eddie Monge +Edward A Faulkner +Eric Hynds +Ethan Romba +EungJun Yi +Eyal Kobrigo +Felix Nagel +Filippo Cavallarin +Florian Gutmann +Genie <386@mail.com> +Guntupalli Karunakar +Harri Kilpiö +Heiko Henning +Hiroshi Tomita +Ian Simpson +Igor Milla +Israel Tsadok +Jacek Jędrzejewski +Jamie Gegerson +Jason Oster +Jay Merrifield +Jean-Francois Remy +Jyoti Deka +John Enters +Jonathan Vingiano +Josh Varner +Justin Domnitz +Justin MacCarthy +Jörn Zaefferer +Karl Kirch +Keith Wood +Kevin Dalman +Klaus Hartl +Klaus Hartl +Kris Borchers +Kris Borchers +Krzysztof Rosiński +Lev Kitsis +Maciej Mroziński +Maggie Wachs +Maggie Wachs +Marc Neuwirth +Marcos Sousa +Martin Frost +Mathias Stenbom +Matt Hoskins +Matthew Edward Hutton +Max Schnur +Michael Hollis +Michael Stay +Michael Wu +Michał Gołębiowski-Owczarek +Mike Alsup +Milan Broum +Mohamed Cherif Bouchelaghem +Monika Piotrowicz +Nick Pierpoint +Ondrej Novy +Paul Bakaus +Paul Irish +Pavol Hluchý +Peter Heiberg +Petr Hromadko +Phillip Barnes +Pierre-Henri Ausseil +Raymond Schwartz +Richard Worth +Rick Waldron +Ryan Neufeld +Ryan Olton +Saji Nediyanchath Saji +Scott Jehl +Sebastian Sauer +Sergey Kartashov +Shahyar Ghobadpour +Shane Whittet +Shannon Pekary +Siebrand Mazeland +Simon Sattes +Stojce Slavkovski +Tarafder Ashek-E-Elahi +Thibault Duplessis +Thomas Jaggi +Ting Kuei +Todd Parker +Wesley Walser +Xavi Ramirez +Yermo Lamers +Yuriy Khabarov <13real008@gmail.com> +Ziling Zhao diff --git a/.npmignore b/.npmignore new file mode 100644 index 00000000000..9e6b8c0c8f7 --- /dev/null +++ b/.npmignore @@ -0,0 +1,14 @@ +/.github +/build +/demos +/dist/cdn +/external +/tests +/Gruntfile.js + +.csslintrc +.editorconfig +.eslintrc.json +.eslintignore +.gitattributes +.mailmap diff --git a/.npmrc b/.npmrc new file mode 100644 index 00000000000..cffe8cdef13 --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +save-exact=true diff --git a/AUTHORS.txt b/AUTHORS.txt index b2168655ee0..b855d39997e 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -1,30 +1,384 @@ -jQuery UI Authors (http://jqueryui.com/about) +Authors ordered by first contribution +A list of current team members is available at https://jqueryui.com/about -This software consists of voluntary contributions made by many -individuals. For exact contribution history, see the revision history -and logs, available at http://github.com/jquery/jquery-ui - -Brandon Aaron -Paul Bakaus (paulbakaus.com) -David Bolter -Rich Caloggero -Chi Cheng (cloudream@gmail.com) -Colin Clark (http://colin.atrc.utoronto.ca/) -Michelle D'Souza -Aaron Eisenberger (aaronchi@gmail.com) -Ariel Flesler -Bohdan Ganicky -Scott González -Marc Grabanski (m@marcgrabanski.com) -Klaus Hartl (stilbuero.de) -Scott Jehl -Cody Lindley -Eduardo Lundgren (eduardolundgren@gmail.com) -Todd Parker -John Resig -Patty Toland -Ca-Phun Ung (yelotofu.com) -Keith Wood (kbwood@virginbroadband.com.au) -Maggie Costello Wachs -Richard D. Worth (rdworth.org) -Jörn Zaefferer (bassistance.de) +Paul Bakaus +Richard Worth +Yehuda Katz +Sean Catchpole +John Resig +Tane Piper +Dmitri Gaskin +Klaus Hartl +Stefan Petre +Gilles van den Hoven +Micheil Bryan Smith +Jörn Zaefferer +Marc Grabanski +Keith Wood +Brandon Aaron +Scott González +Eduardo Lundgren +Aaron Eisenberger +Joan Piedra +Bruno Basto +Remy Sharp +Bohdan Ganicky +David Bolter +Chi Cheng +Ca-Phun Ung +Ariel Flesler +Maggie Wachs +Scott Jehl +Todd Parker +Andrew Powell +Brant Burnett +Douglas Neiner +Paul Irish +Ralph Whitbeck +Thibault Duplessis +Dominique Vincent +Jack Hsu +Adam Sontag +Carl Fürstenberg +Kevin Dalman +Alberto Fernández Capel +Jacek Jędrzejewski (https://jacek.jedrzejewski.name) +Ting Kuei +Samuel Cormier-Iijima +Jon Palmer +Ben Hollis +Justin MacCarthy +Eyal Kobrigo +Tiago Freire +Diego Tres +Holger Rüprich +Ziling Zhao +Mike Alsup +Robson Braga Araujo +Pierre-Henri Ausseil +Christopher McCulloh +Andrew Newcomb +Lim Chee Aun +Jorge Barreiro +Daniel Steigerwald +John Firebaugh +John Enters +Andrey Kapitcyn +Dmitry Petrov +Eric Hynds +Chairat Sunthornwiphat +Josh Varner +Stéphane Raimbault +Jay Merrifield +J. Ryan Stinnett +Peter Heiberg +Alex Dovenmuehle +Jamie Gegerson +Raymond Schwartz +Phillip Barnes +Kyle Wilkinson +Khaled AlHourani +Marian Rudzynski +Jean-Francois Remy +Doug Blood +Filippo Cavallarin +Heiko Henning +Aliaksandr Rahalevich +Mario Visic +Xavi Ramirez +Max Schnur +Saji Nediyanchath +Corey Frang +Aaron Peterson +Ivan Peters +Mohamed Cherif Bouchelaghem +Marcos Sousa +Michael DellaNoce +George Marshall +Tobias Brunner +Martin Solli +David Petersen +Dan Heberden +William Kevin Manire +Gilmore Davidson +Michael Wu +Adam Parod +Guillaume Gautreau +Marcel Toele +Dan Streetman +Matt Hoskins +Giovanni Giacobbi +Kyle Florence +Pavol Hluchý +Hans Hillen +Mark Johnson +Trey Hunner +Shane Whittet +Edward A Faulkner +Adam Baratz +Kato Kazuyoshi +Eike Send +Kris Borchers +Eddie Monge +Israel Tsadok +Carson McDonald +Jason Davies +Garrison Locke +David Murdoch +Benjamin Scott Boyle +Jesse Baird +Jonathan Vingiano +Dylan Just +Hiroshi Tomita +Glenn Goodrich +Tarafder Ashek-E-Elahi +Ryan Neufeld +Marc Neuwirth +Philip Graham +Benjamin Sterling +Wesley Walser +Kouhei Sutou +Karl Kirch +Chris Kelly +Jason Oster +Felix Nagel +Alexander Polomoshnov +David Leal +Igor Milla +Dave Methvin +Florian Gutmann +Marwan Al Jubeh +Milan Broum +Sebastian Sauer +Gaëtan Muller +Michel Weimerskirch +William Griffiths +Stojce Slavkovski +David Soms +David De Sloovere +Michael P. Jung +Shannon Pekary +Dan Wellman +Matthew Edward Hutton +James Khoury +Rob Loach +Alberto Monteiro +Alex Rhea +Krzysztof Rosiński +Ryan Olton +Genie <386@mail.com> +Rick Waldron +Ian Simpson +Lev Kitsis +TJ VanToll +Justin Domnitz +Douglas Cerna +Bert ter Heide +Jasvir Nagra +Yuriy Khabarov <13real008@gmail.com> +Harri Kilpiö +Lado Lomidze +Amir E. Aharoni +Simon Sattes +Jo Liss +Guntupalli Karunakar +Shahyar Ghobadpour +Lukasz Lipinski +Timo Tijhof +Jason Moon +Martin Frost +Eneko Illarramendi +EungJun Yi +Courtland Allen +Viktar Varvanovich +Danny Trunk +Pavel Stetina +Michael Stay +Steven Roussey +Michael Hollis +Lee Rowlands +Timmy Willison +Karl Swedberg +Baoju Yuan +Maciej Mroziński +Luis Dalmolin +Mark Aaron Shirley +Martin Hoch +Jiayi Yang +Philipp Benjamin Köppchen +Sindre Sorhus +Bernhard Sirlinger +Jared A. Scheel +Rafael Xavier de Souza +John Chen +Robert Beuligmann +Dale Kocian +Mike Sherov +Andrew Couch +Marc-Andre Lafortune +Nate Eagle +David Souther +Mathias Stenbom +Sergey Kartashov +Avinash R +Ethan Romba +Cory Gackenheimer +Juan Pablo Kaniefsky +Roman Salnikov +Anika Henke +Samuel Bovée +Fabrício Matté +Viktor Kojouharov +Pawel Maruszczyk (http://hrabstwo.net) +Pavel Selitskas +Bjørn Johansen +Matthieu Penant +Dominic Barnes +David Sullivan +Thomas Jaggi +Vahid Sohrabloo +Travis Carden +Bruno M. Custódio +Nathanael Silverman +Christian Wenz +Steve Urmston +Zaven Muradyan +Woody Gilk +Zbigniew Motyka +Suhail Alkowaileet +Toshi MARUYAMA +David Hansen +Brian Grinstead +Christian Klammer +Steven Luscher +Gan Eng Chin +Gabriel Schulhof +Alexander Schmitz +Vilhjálmur Skúlason +Siebrand Mazeland +Mohsen Ekhtiari +Pere Orga +Jasper de Groot +Stephane Deschamps +Jyoti Deka +Andrei Picus +Ondrej Novy +Jacob McCutcheon +Monika Piotrowicz +Imants Horsts +Eric Dahl +Dave Stein +Dylan Barrell +Daniel DeGroff +Michael Wiencek +Thomas Meyer +Ruslan Yakhyaev +Brian J. Dowling +Ben Higgins +Yermo Lamers +Patrick Stapleton +Trisha Crowley +Usman Akeju +Rodrigo Menezes +Jacques Perrault +Frederik Elvhage +Will Holley +Uri Gilad +Richard Gibson +Simen Bekkhus +Chen Eshchar +Bruno Pérel +Mohammed Alshehri +Lisa Seacat DeLuca +Anne-Gaelle Colom +Adam Foster +Luke Page +Daniel Owens +Michael Orchard +Marcus Warren +Nils Heuermann +Marco Ziech +Patricia Juarez +Ben Mosher +Ablay Keldibek +Thomas Applencourt +Jiabao Wu +Eric Lee Carraway +Victor Homyakov +Myeongjin Lee +Liran Sharir +Weston Ruter +Mani Mishra +Hannah Methvin +Leonardo Balter +Benjamin Albert +Michał Gołębiowski-Owczarek +Alyosha Pushak +Fahad Ahmad +Matt Brundage +Francesc Baeta +Piotr Baran +Mukul Hase +Konstantin Dinev +Rand Scullard +Dan Strohl +Maksim Ryzhikov +Amine HADDAD +Amanpreet Singh +Alexey Balchunas +Peter Kehl +Peter Dave Hello +Johannes Schäfer +Ville Skyttä +Ryan Oriecuia +Sergei Ratnikov +milk54 +Evelyn Masso +Robin +Simon Asika +Kevin Cupp +Jeremy Mickelson +Kyle Rosenberg +Petri Partio +pallxk +Luke Brookhart +claudi +Eirik Sletteberg +Albert Johansson +A. Wells +Robert Brignull +Horus68 +Maksymenkov Eugene +OskarNS +Gez Quinn +jigar gala +Florian Wegscheider +Fatér Zsolt +Szabolcs Szabolcsi-Toth +Jérémy Munsch +Hrvoje Novosel +Paul Capron +Micah Miller +sakshi87 <53863764+sakshi87@users.noreply.github.com> +Mikolaj Wolicki +Patrick McKay +c-lambert <58025159+c-lambert@users.noreply.github.com> +Josep Sanz +Ben Mullins +Christian Oliff +dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> +Adam Lidén Hällgren +James Hinderks +Denny Septian Panggabean <97607754+ddevsr@users.noreply.github.com> +Matías Cánepa +Ashish Kurmi <100655670+boahc077@users.noreply.github.com> +DeerBear +Дилян Палаузов +Kenneth DeBacker +Timo Tijhof +Timmy Willison +divdeploy <166095818+divdeploy@users.noreply.github.com> +mark van tilburg +Ralf Koller <1665422+rpkoller@users.noreply.github.com> +Porter Clevidence <116387727+porterclev@users.noreply.github.com> +Daniel García <93217193+Daniel-Garmig@users.noreply.github.com> diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000000..6d6a7e8142a --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,88 @@ +# Contributing to jQuery UI + +Welcome! Thanks for your interest in contributing to jQuery UI. Most of our information on how to contribute to this and all other jQuery projects is over at [contribute.jquery.org](https://contribute.jquery.org). You'll definitely want to take a look at the articles on contributing [code](https://contribute.jquery.org/code). + +You may also want to take a look at our [commit & pull request guide](https://contribute.jquery.org/commits-and-pull-requests/) and [style guides](https://contribute.jquery.org/style-guide/) for instructions on how to maintain your fork and submit your code. Before we can merge any pull request, we'll also need you to sign our [contributor license agreement](https://contribute.jquery.org/cla). + +You can find us on [IRC](https://irc.jquery.org), specifically in #jqueryui-dev should you have any questions. If you've never contributed to open source before, we've put together [a short guide with tips, tricks, and ideas on getting started](https://contribute.jquery.org/open-source/). For other forms of discussion and support, please see the [jQuery UI support center](https://jqueryui.com/support/). + +## Getting Involved + +There are a number of ways to get involved with the development of jQuery UI. Even if you've never contributed code to an Open Source project before, we're always looking for help identifying bugs, writing and reducing test cases and documentation. + +This is the best way to contribute to jQuery UI. Please read through the full guide detailing [How to Report Bugs](https://contribute.jquery.org/bug-reports/). + +## Tips for Getting Started + +### Environment: Minimum Required + +If you are contributing changes you will need a fork of jquery-ui (see [Getting the Source](#environment-getting-the-source)). If you just want the source code you could clone jquery-ui directly: + +```bash +git clone git://github.com/jquery/jquery-ui.git +cd jquery-ui +``` + +The tests can run in any local web server. Ideally you should test your patch in appropriate web browsers and if possible run `npm test` to lint the code and run automated tests (this will happen automatically when you create a pull request). See the [Recommended Setup](#environment-recommended-setup) for setting up Node.js so that the `npm test` command works. + +### Environment: Getting the Source + +* Create a fork of the jQuery UI repo on GitHub at https://github.com/jquery/jquery-ui. This will create a fork of jquery-ui in your Github account. +* You may want to clone jquery-ui under the path to your web server. If so, change to the required directory + +```bash +cd /path/to/your/www/root/ +``` + +* Clone your jQuery UI git repo. + +```bash +git clone git://github.com/[USERNAME]/jquery-ui.git +cd jquery-ui +``` + +*Note: be sure to replace `[USERNAME]` with your GitHub username.* + +* Add the official jQuery repository as a remote. We recommend naming it "upstream". + +```bash +git remote add upstream git://github.com/jquery/jquery-ui.git +``` + +* Get in the habit of pulling in the "upstream" main branch to stay up to date as jQuery UI receives new commits. + +```bash +git pull upstream main +``` + +### Environment: Recommended Setup + +jQuery UI uses Node.js to automate the building and validation of source code. Here is how to set that up: + +* Get [Node.js](https://nodejs.org/) (includes NPM, necessary for the next step) +* Install local Node.js modules + +```bash +npm install +``` + +The tests require a local web server and the samples contain some PHP, so a PHP web server may be useful. + +* Install a web server. Here are some you could use: + * Windows: [WAMP download](https://www.wampserver.com/en/) + * Mac: [MAMP download](https://www.mamp.info/en/mac/) + * Linux: [Setting up LAMP](https://www.linux.com/learn/tutorials/288158-easy-lamp-server-installation) + * [Mongoose (most platforms)](https://mongoose.ws/) + * [http-server](https://www.npmjs.com/package/http-server) + +### Running the Tests + +To lint the JavaScript, HTML, and CSS, as well as run the full test suite in Headless Chrome: + +```bash +npm test +``` + +To run the tests for a specific plugin in your browser, open the appropriate file from the `/tests/unit/` directory, for example: `http://localhost/tests/unit/accordion/accordion.html`. The domain will be dependent on your local server configuration; if there is a port, be sure to include it. + +Ideally you would test in all of our [supported browsers](https://jqueryui.com/browser-support/), but if you don't have all of these browsers available, that's ok. diff --git a/GPL-LICENSE.txt b/GPL-LICENSE.txt deleted file mode 100644 index 11dddd00ef0..00000000000 --- a/GPL-LICENSE.txt +++ /dev/null @@ -1,278 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. diff --git a/Gruntfile.js b/Gruntfile.js new file mode 100644 index 00000000000..bbb71d33e52 --- /dev/null +++ b/Gruntfile.js @@ -0,0 +1,411 @@ +"use strict"; + +module.exports = function( grunt ) { + +const { gzipSync } = require( "node:zlib" ); + +// files +const coreFiles = [ + "widget.js", + "widgets/mouse.js", + "widgets/draggable.js", + "widgets/droppable.js", + "widgets/resizable.js", + "widgets/selectable.js", + "widgets/sortable.js", + "effect.js" +]; + +const uiFiles = coreFiles.map( function( file ) { + return "ui/" + file; +} ).concat( expandFiles( "ui/**/*.js" ).filter( function( file ) { + return coreFiles.indexOf( file.substring( 3 ) ) === -1; +} ) ); + +const allI18nFiles = expandFiles( "ui/i18n/*.js" ); + +const cssFiles = [ + "core", + "accordion", + "autocomplete", + "button", + "checkboxradio", + "controlgroup", + "datepicker", + "dialog", + "draggable", + "menu", + "progressbar", + "resizable", + "selectable", + "selectmenu", + "sortable", + "slider", + "spinner", + "tabs", + "tooltip", + "theme" +].map( function( component ) { + return "themes/base/" + component + ".css"; +} ); + +// minified files +const minify = { + main: { + options: { + banner: createBanner( uiFiles ) + }, + files: { + "dist/jquery-ui.min.js": "dist/jquery-ui.js" + } + }, + i18n: { + options: { + banner: createBanner( allI18nFiles ) + }, + files: { + "dist/i18n/jquery-ui-i18n.min.js": "dist/i18n/jquery-ui-i18n.js" + } + } +}; + +const compareFiles = { + all: [ + "dist/jquery-ui.js", + "dist/jquery-ui.min.js" + ], + options: { + compress: { + gz: function( contents ) { + return gzipSync( contents ).length; + } + }, + cache: "build/.sizecache.json" + } +}; + +const htmllintBad = [ + "demos/tabs/ajax/content*.html", + "demos/tooltip/ajax/content*.html", + "tests/unit/core/core.html", + "tests/unit/tabs/data/test.html" +]; + +function mapMinFile( file ) { + return "dist/" + file.replace( /ui\//, "minified/" ); +} + +function expandFiles( files ) { + return grunt.util._.map( grunt.file.expandMapping( files ), "src" ).map( function( values ) { + return values[ 0 ]; + } ); +} + +uiFiles.concat( allI18nFiles ).forEach( function( file ) { + minify[ file ] = { + options: { + banner: createBanner() + }, + files: {} + }; + minify[ file ].files[ mapMinFile( file ) ] = file; +} ); + +uiFiles.forEach( function( file ) { + compareFiles[ file ] = [ file, mapMinFile( file ) ]; +} ); + +function stripDirectory( file ) { + return file.replace( /.+\/(.+?)>?$/, "$1" ); +} + +function createBanner( files ) { + + // strip folders + const fileNames = files && files.map( stripDirectory ); + return "/*! <%= pkg.title || pkg.name %> - v<%= pkg.version %> - " + + "<%= grunt.template.today('isoDate') %>\n" + + "<%= pkg.homepage ? '* ' + pkg.homepage + '\\n' : '' %>" + + ( files ? "* Includes: " + fileNames.join( ", " ) + "\n" : "" ) + + "* Copyright <%= pkg.author.name %>;" + + " Licensed <%= _.map(pkg.licenses, 'type').join(', ') %> */\n"; +} + +grunt.initConfig( { + pkg: grunt.file.readJSON( "package.json" ), + files: { + dist: "<%= pkg.name %>-<%= pkg.version %>" + }, + compare_size: compareFiles, + concat: { + css: { + options: { + banner: createBanner( cssFiles ), + stripBanners: { + block: true + } + }, + src: cssFiles, + dest: "dist/jquery-ui.css" + } + }, + requirejs: { + js: { + options: { + baseUrl: "./", + paths: { + jquery: "./external/jquery/jquery", + external: "./external/" + }, + preserveLicenseComments: false, + optimize: "none", + findNestedDependencies: true, + skipModuleInsertion: true, + exclude: [ "jquery" ], + include: expandFiles( [ "ui/**/*.js", "!ui/i18n/*" ] ), + out: "dist/jquery-ui.js", + wrap: { + start: createBanner( uiFiles ) + } + } + } + }, + + minify, + htmllint: { + good: { + options: { + ignore: [ + /The text content of element “script” was not in the required format: Expected space, tab, newline, or slash but found “.” instead/, + /This document appears to be written in .*. Consider using “lang=".*"” \(or variant\) instead/ + ] + }, + src: [ + "{demos,tests}/**/*.html", + ...htmllintBad.map( pattern => `!${ pattern }` ) + ] + }, + bad: { + options: { + ignore: [ + /Start tag seen without seeing a doctype first/, + /Element “head” is missing a required instance of child element “title”/, + /Element “object” is missing one or more of the following/, + /The “codebase” attribute on the “object” element is obsolete/, + /Consider adding a “lang” attribute to the “html” start tag/, + /This document appears to be written in .*. Consider (?:adding|using) “lang=".*"” \(or variant\)/ + ] + }, + src: htmllintBad + } + }, + eslint: { + all: [ + "ui/**/*.js", + "!ui/vendor/**/*.js", + "Gruntfile.js", + "dist/jquery-ui.js", + "dist/jquery-ui.min.js", + "build/**/*.js", + "tests/unit/**/*.js", + "tests/lib/**/*.js", + "!tests/lib/vendor/**/*.js", + "demos/**/*.js" + ] + }, + csslint: { + base_theme: { + src: "themes/base/*.css", + options: { + csslintrc: ".csslintrc" + } + } + }, + + bowercopy: { + inlineVendors: { + options: { + clean: true, + destPrefix: "ui/vendor" + }, + files: { + "jquery-color/jquery.color.js": "jquery-color/dist/jquery.color.js", + "jquery-color/LICENSE.txt": "jquery-color/LICENSE.txt" + } + }, + + all: { + options: { + clean: true, + ignore: [ "jquery" ], + destPrefix: "external" + }, + files: { + "qunit/qunit.js": "qunit/qunit/qunit.js", + "qunit/qunit.css": "qunit/qunit/qunit.css", + "qunit/LICENSE.txt": "qunit/LICENSE.txt", + + "requirejs/require.js": "requirejs/require.js", + + "jquery-mousewheel/jquery.mousewheel.js": "jquery-mousewheel/jquery.mousewheel.js", + "jquery-mousewheel/LICENSE.txt": "jquery-mousewheel/LICENSE.txt", + + "jquery-simulate/jquery.simulate.js": "jquery-simulate/jquery.simulate.js", + "jquery-simulate/LICENSE.txt": "jquery-simulate/LICENSE.txt", + + "jquery/jquery.js": "jquery-3.x/dist/jquery.js", + "jquery/LICENSE.txt": "jquery-3.x/LICENSE.txt", + + "jquery-1.12.4/jquery.js": "jquery-1.12.4/dist/jquery.js", + "jquery-1.12.4/LICENSE.txt": "jquery-1.12.4/LICENSE.txt", + + "jquery-2.2.4/jquery.js": "jquery-2.2.4/dist/jquery.js", + "jquery-2.2.4/LICENSE.txt": "jquery-2.2.4/LICENSE.txt", + + "jquery-3.0.0/jquery.js": "jquery-3.0.0/dist/jquery.js", + "jquery-3.0.0/LICENSE.txt": "jquery-3.0.0/LICENSE.txt", + + "jquery-3.1.0/jquery.js": "jquery-3.1.0/dist/jquery.js", + "jquery-3.1.0/LICENSE.txt": "jquery-3.1.0/LICENSE.txt", + + "jquery-3.1.1/jquery.js": "jquery-3.1.1/dist/jquery.js", + "jquery-3.1.1/LICENSE.txt": "jquery-3.1.1/LICENSE.txt", + + "jquery-3.2.0/jquery.js": "jquery-3.2.0/dist/jquery.js", + "jquery-3.2.0/LICENSE.txt": "jquery-3.2.0/LICENSE.txt", + + "jquery-3.2.1/jquery.js": "jquery-3.2.1/dist/jquery.js", + "jquery-3.2.1/LICENSE.txt": "jquery-3.2.1/LICENSE.txt", + + "jquery-3.3.0/jquery.js": "jquery-3.3.0/dist/jquery.js", + "jquery-3.3.0/LICENSE.txt": "jquery-3.3.0/LICENSE.txt", + + "jquery-3.3.1/jquery.js": "jquery-3.3.1/dist/jquery.js", + "jquery-3.3.1/LICENSE.txt": "jquery-3.3.1/LICENSE.txt", + + "jquery-3.4.0/jquery.js": "jquery-3.4.0/dist/jquery.js", + "jquery-3.4.0/LICENSE.txt": "jquery-3.4.0/LICENSE.txt", + + "jquery-3.4.1/jquery.js": "jquery-3.4.1/dist/jquery.js", + "jquery-3.4.1/LICENSE.txt": "jquery-3.4.1/LICENSE.txt", + + "jquery-3.5.0/jquery.js": "jquery-3.5.0/dist/jquery.js", + "jquery-3.5.0/LICENSE.txt": "jquery-3.5.0/LICENSE.txt", + + "jquery-3.5.1/jquery.js": "jquery-3.5.1/dist/jquery.js", + "jquery-3.5.1/LICENSE.txt": "jquery-3.5.1/LICENSE.txt", + + "jquery-3.6.0/jquery.js": "jquery-3.6.0/dist/jquery.js", + "jquery-3.6.0/LICENSE.txt": "jquery-3.6.0/LICENSE.txt", + + "jquery-3.6.1/jquery.js": "jquery-3.6.1/dist/jquery.js", + "jquery-3.6.1/LICENSE.txt": "jquery-3.6.1/LICENSE.txt", + + "jquery-3.6.2/jquery.js": "jquery-3.6.2/dist/jquery.js", + "jquery-3.6.2/LICENSE.txt": "jquery-3.6.2/LICENSE.txt", + + "jquery-3.6.3/jquery.js": "jquery-3.6.3/dist/jquery.js", + "jquery-3.6.3/LICENSE.txt": "jquery-3.6.3/LICENSE.txt", + + "jquery-3.6.4/jquery.js": "jquery-3.6.4/dist/jquery.js", + "jquery-3.6.4/LICENSE.txt": "jquery-3.6.4/LICENSE.txt", + + "jquery-3.7.0/jquery.js": "jquery-3.7.0/dist/jquery.js", + "jquery-3.7.0/LICENSE.txt": "jquery-3.7.0/LICENSE.txt", + + "jquery-3.7.1/jquery.js": "jquery-3.7.1/dist/jquery.js", + "jquery-3.7.1/LICENSE.txt": "jquery-3.7.1/LICENSE.txt", + + "jquery-migrate-1.x/jquery-migrate.js": + "jquery-migrate-1.x/dist/jquery-migrate.js", + "jquery-migrate-1.x/LICENSE.txt": "jquery-migrate-1.x/LICENSE.txt", + + "jquery-migrate-3.x/jquery-migrate.js": + "jquery-migrate-3.x/dist/jquery-migrate.js", + "jquery-migrate-3.x/LICENSE.txt": "jquery-migrate-3.x/LICENSE.txt" + } + } + }, + + authors: { + prior: [ + "Paul Bakaus ", + "Richard Worth ", + "Yehuda Katz ", + "Sean Catchpole ", + "John Resig ", + "Tane Piper ", + "Dmitri Gaskin ", + "Klaus Hartl ", + "Stefan Petre ", + "Gilles van den Hoven ", + "Micheil Bryan Smith ", + "Jörn Zaefferer ", + "Marc Grabanski ", + "Keith Wood ", + "Brandon Aaron ", + "Scott González ", + "Eduardo Lundgren ", + "Aaron Eisenberger ", + "Joan Piedra ", + "Bruno Basto ", + "Remy Sharp ", + "Bohdan Ganicky " + ] + } +} ); + +// grunt plugins +require( "load-grunt-tasks" )( grunt ); + +// local tasks +grunt.loadTasks( "build/tasks" ); + +grunt.registerTask( "update-authors", function() { + const getAuthors = require( "grunt-git-authors" ).getAuthors; + const done = this.async(); + + getAuthors( { + priorAuthors: grunt.config( "authors.prior" ) + }, function( error, authors ) { + if ( error ) { + grunt.log.error( error ); + return done( false ); + } + + authors = authors.map( function( author ) { + if ( author.match( /^Jacek Jędrzejewski { + const task = args.join( ":" ); + grunt.log.writeln( "Old Node.js detected, running the task \"" + task + "\" skipped..." ); +} ); + +// Keep this task list in sync with the testing steps in our GitHub action test workflow file! +grunt.registerTask( "lint", [ + "asciilint", + "eslint", + "csslint", + "htmllint" +] ); +grunt.registerTask( "build", [ "requirejs", "concat", "minify:main" ] ); +grunt.registerTask( "default", [ "build", "lint" ] ); +grunt.registerTask( "sizer", [ "requirejs:js", "minify:main", "compare_size:all" ] ); +grunt.registerTask( "sizer_all", [ "requirejs:js", "minify", "compare_size" ] ); + +}; diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 00000000000..78108290c40 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,43 @@ +Copyright OpenJS Foundation and other contributors, https://openjsf.org/ + +This software consists of voluntary contributions made by many +individuals. For exact contribution history, see the revision history +available at https://github.com/jquery/jquery-ui + +The following license applies to all parts of this software except as +documented below: + +==== + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +==== + +Copyright and related rights for sample code are waived via CC0. Sample +code is defined as all source code contained within the demos directory. + +CC0: http://creativecommons.org/publicdomain/zero/1.0/ + +==== + +All files located in the node_modules and external directories are +externally maintained libraries used by this software which have their +own licenses; we recommend you read them, as their terms may differ from +the terms above. diff --git a/MIT-LICENSE.txt b/MIT-LICENSE.txt deleted file mode 100644 index 2585de262e3..00000000000 --- a/MIT-LICENSE.txt +++ /dev/null @@ -1,25 +0,0 @@ -Copyright (c) 2010 Paul Bakaus, http://jqueryui.com/ - -This software consists of voluntary contributions made by many -individuals (AUTHORS.txt, http://jqueryui.com/about) For exact -contribution history, see the revision history and logs, available -at http://jquery-ui.googlecode.com/svn/ - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md index 5c7d79a1335..18770aa5bf7 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,32 @@ -[jQuery UI](http://jqueryui.com/) - Interactions and Widgets for the web -================================ +# [jQuery UI](https://jqueryui.com/) - Interactions and Widgets for the web -jQuery UI provides interactions like Drag and Drop and widgets like Autocomplete, Tabs and Slider and makes these as easy to use as jQuery itself. +_**Note:** jQuery UI is in maintenance-only mode. Please read [the project status blog post](https://blog.jqueryui.com/2021/10/jquery-maintainers-update-and-transition-jquery-ui-as-part-of-overall-modernization-efforts/) for more information._ -If you want to use jQuery UI, go to [jqueryui.com](http://jqueryui.com) to get started. Or visit the [Using jQuery UI Forum](http://forum.jquery.com/using-jquery-ui) for discussions and questions. +jQuery UI is a curated set of user interface interactions, effects, widgets, and themes built on top of jQuery. Whether you're building highly interactive web applications, or you just need to add a date picker to a form control, jQuery UI is the perfect choice. -If you are interested in helping developing jQuery UI, you are in the right place. -To discuss development with team members and the community, visit the [Developing jQuery UI Forum](http://forum.jquery.com/developing-jquery-ui). +If you want to use jQuery UI, go to [jqueryui.com](https://jqueryui.com) to get started, [jqueryui.com/demos/](https://jqueryui.com/demos/) for demos, [api.jqueryui.com](https://api.jqueryui.com/) for API documentation, or the [Using jQuery UI Forum](https://forum.jquery.com/using-jquery-ui) for discussions and questions. + +If you want to report a bug/issue, please visit [the GitHub issues page](https://github.com/jquery/jquery-ui/issues). Archive of older bug reports is kept for historical reasons in read-only mode at [bugs.jqueryui.com](https://bugs.jqueryui.com). If any of them still matters to you, please open a bug about it on GitHub, linking to the legacy [bugs.jqueryui.com](https://bugs.jqueryui.com) issue for context. + +If you are interested in helping develop jQuery UI, you are in the right place. +To discuss development with team members and the community, visit the [Developing jQuery UI Forum](https://forum.jquery.com/developing-jquery-ui) or [#jqueryui-dev on irc.freenode.net](https://irc.jquery.org/). + + +## For Contributors + +If you want to help and provide a patch for a bugfix or new feature, please take +a few minutes and look at [our Getting Involved guide](https://wiki.jqueryui.com/w/page/35263114/Getting-Involved). +In particular check out the [Coding standards](https://wiki.jqueryui.com/w/page/12137737/Coding-standards) +and [Commit Message Style Guide](https://contribute.jquery.org/commits-and-pull-requests/#commit-guidelines). + +In general, fork the project, create a branch for a specific change and send a +pull request for that branch. Don't mix unrelated changes. You can use the commit +message as the description for the pull request. + +For more information, see the [contributing page](CONTRIBUTING.md). + +## Running the Unit Tests + +Run the unit tests manually with appropriate browsers and any local web server. See our [environment setup](CONTRIBUTING.md#environment-minimum-required) and [information on running tests](CONTRIBUTING.md#running-the-tests). + +You can also run the unit tests `npm run test:unit -- --help`. diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000000..fae31da8522 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,11 @@ +# Security Policy + +## Supported Versions + +The [latest released version](https://github.com/jquery/jquery-ui/releases) of jQuery UI is supported. + +## Reporting a Vulnerability + +Please email security@jquery.com, and we will respond as quickly as possible. + +If the vulnerability is considered valid and accepted, a patch will be made for the latest jQuery UI version. If the vulnerability is deemed invalid, no further action is required. diff --git a/bower.json b/bower.json new file mode 100644 index 00000000000..eb3187e0c38 --- /dev/null +++ b/bower.json @@ -0,0 +1,44 @@ +{ + "name": "jquery-ui", + "ignore": [ + "**/.*", + "build", + "demos", + "external", + "tests" + ], + "license": "MIT", + "dependencies": { + "jquery": ">=1.12.0 <5.0.0" + }, + "devDependencies": { + "jquery-color": "3.0.0", + "jquery-mousewheel": "3.2.2", + "jquery-simulate": "1.1.1", + "qunit": "2.19.4", + "requirejs": "2.1.14", + "jquery-1.12.4": "jquery#1.12.4", + "jquery-3.x": "jquery#3.7.1", + "jquery-2.2.4": "jquery#2.2.4", + "jquery-3.0.0": "jquery#3.0.0", + "jquery-3.1.0": "jquery#3.1.0", + "jquery-3.1.1": "jquery#3.1.1", + "jquery-3.2.0": "jquery#3.2.0", + "jquery-3.2.1": "jquery#3.2.1", + "jquery-3.3.0": "jquery#3.3.0", + "jquery-3.3.1": "jquery#3.3.1", + "jquery-3.4.0": "jquery#3.4.0", + "jquery-3.4.1": "jquery#3.4.1", + "jquery-3.5.0": "jquery#3.5.0", + "jquery-3.5.1": "jquery#3.5.1", + "jquery-3.6.0": "jquery#3.6.0", + "jquery-3.6.1": "jquery#3.6.1", + "jquery-3.6.2": "jquery#3.6.2", + "jquery-3.6.3": "jquery#3.6.3", + "jquery-3.6.4": "jquery#3.6.4", + "jquery-3.7.0": "jquery#3.7.0", + "jquery-3.7.1": "jquery#3.7.1", + "jquery-migrate-1.x": "https://registry.npmjs.org/jquery-migrate/-/jquery-migrate-1.4.1.tgz", + "jquery-migrate-3.x": "https://registry.npmjs.org/jquery-migrate/-/jquery-migrate-3.5.2.tgz" + } +} diff --git a/build/build.xml b/build/build.xml deleted file mode 100644 index 3abaa4fa832..00000000000 --- a/build/build.xml +++ /dev/null @@ -1,352 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ${relativepath} - - - - - - - - - - diff --git a/build/build/ant-contrib-0.6.jar b/build/build/ant-contrib-0.6.jar deleted file mode 100644 index db90b0aae85..00000000000 Binary files a/build/build/ant-contrib-0.6.jar and /dev/null differ diff --git a/build/build/google-compiler-20091218.jar b/build/build/google-compiler-20091218.jar deleted file mode 100644 index da053a7dddb..00000000000 Binary files a/build/build/google-compiler-20091218.jar and /dev/null differ diff --git a/build/build/style.xsl b/build/build/style.xsl deleted file mode 100644 index 32daeed9434..00000000000 --- a/build/build/style.xsl +++ /dev/null @@ -1,211 +0,0 @@ - - - - - - link- - - - - - - - - - - - # - - - - - - - - - - - - - - A jQuery object. - true or false. - A simple Javascript object.. - A string of characters. - A valid numeric. - A string of characters or a number. - The Javascript object representation of a DOM Element. - One or more DOM Elements (a single one or an array). - A Javascript object that contains key/value pairs in the form of properties and values. - An Array of DOM Elements. - An Array of strings. - A reference to a Javascript function. - An XMLHttpRequest object (referencing a HTTP request). - - - - - - - - - A jQuery object. - true or false. - A simple Javascript object.. - A string of characters. - A valid numeric. - A string of characters or a number. - The Javascript object representation of a DOM Element. - One or more DOM Elements (a single one or an array). - A Javascript object that contains key/value pairs in the form of properties and values. - An Array of DOM Elements. - An Array of strings. - A reference to a Javascript function. - An XMLHttpRequest object (referencing a HTTP request). - - - - - - - - - - -
-
-

-

-

Default:

-
-
-

- - -

Code sample:

-

- - - -
-
-
-
- - -
- - - -
- -
-

- - - -

-

- - - -

-
-
- - -
-

- -
-

Property options

-

Show details | Hide details

-
- -
- - - -
- -
-

Event options

-

Show details | Hide details

-
- -
- - - -
-
- - -
-

A brief description of methods and their uses goes here so their use is clearly explained and any caveats can be mentioned up front.

- -
-

Methods

-

Show details | Hide details

-
- -
- -
-
-

( - - , - - )

-

Returns:

-
-
-

-

-

Arguments:

- - - - - - - - - - -
- -

Code sample:

- -
- - - -
-
-
-
- -
-
- - -
- %%THEMING%% -
-
-
- -
diff --git a/build/release-test.js b/build/release-test.js new file mode 100644 index 00000000000..083f1a6c538 --- /dev/null +++ b/build/release-test.js @@ -0,0 +1,49 @@ +"use strict"; + +var shell = require( "shelljs" ); +var Release = { + define: function( props ) { + for ( var key in props ) { + Release[ key ] = props[ key ]; + } + }, + exec: function( _options, errorMessage ) { + var result, + command = _options.command || _options, + options = {}; + + if ( _options.silent ) { + options.silent = true; + } + + errorMessage = errorMessage || "Error executing command: " + command; + + result = shell.exec( command, options ); + if ( result.code !== 0 ) { + Release.abort( errorMessage ); + } + + return result.output; + }, + abort: function() { + console.error.apply( console, arguments ); + process.exit( 1 ); + }, + newVersion: require( "../package" ).version +}; + +var script = require( "./release" ); +script( Release ); + +// Ignores actual version installed, should be good enough for a test +if ( shell.exec( "npm ls --depth 0 | grep download.jqueryui.com" ).code === 1 ) { + shell.exec( "npm install --no-save " + script.dependencies.join( " " ) ); +} + +// If AUTHORS.txt is outdated, this will update it +// Very annoying during an actual release +shell.exec( "grunt update-authors" ); + +Release.generateArtifacts( function() { + console.log( "Done generating artifacts, verify output, should be in dist/cdn" ); +} ); diff --git a/build/release.js b/build/release.js new file mode 100644 index 00000000000..633dd34d12c --- /dev/null +++ b/build/release.js @@ -0,0 +1,159 @@ +"use strict"; + +module.exports = function( Release ) { + +var crypto = require( "crypto" ); +var shell = require( "shelljs" ), + path = require( "path" ), + fs = require( "fs" ); + +function replaceAtVersion() { + console.log( "Replacing @VERSION..." ); + var matches = []; + + function recurse( folder ) { + fs.readdirSync( folder ).forEach( function( fileName ) { + var content, + fullPath = folder + "/" + fileName; + if ( fs.statSync( fullPath ).isDirectory() ) { + recurse( fullPath ); + return; + } + content = fs.readFileSync( fullPath, { + encoding: "utf-8" + } ); + if ( !/@VERSION/.test( content ) ) { + return; + } + matches.push( fullPath ); + fs.writeFileSync( fullPath, content.replace( /@VERSION/g, Release.newVersion ) ); + } ); + } + + [ "ui", "themes" ].forEach( recurse ); + + console.log( "Replaced @VERSION in " + matches.length + " files." ); + + return matches; +} + +function removeExternals( packager ) { + Object.keys( packager.builtFiles ).forEach( function( filepath ) { + if ( /^external\//.test( filepath ) ) { + delete packager.builtFiles[ filepath ]; + } + } ); +} + +function addManifest( packager ) { + var output = packager.builtFiles; + output.MANIFEST = Object.keys( output ).sort( function( a, b ) { + return a.localeCompare( b ); + } ).map( function( filepath ) { + var md5 = crypto.createHash( "md5" ); + md5.update( output[ filepath ] ); + return filepath + " " + md5.digest( "hex" ); + } ).join( "\n" ); +} + +function buildCDNPackage( callback ) { + console.log( "Building CDN package" ); + var JqueryUi = require( "download.jqueryui.com/lib/jquery-ui" ); + var PackageWithoutThemes = require( "download.jqueryui.com/lib/package" ); + var PackageOfThemes = require( "download.jqueryui.com/lib/package-themes" ); + var Packager = require( "node-packager" ); + + // PackageOfThemes doesn't contain JS files, PackageWithoutThemes doesn't contain themes; + // we need both. + function Package() { + + // PackageOfThemes invokes PackageWithoutThemes's constructor in its own so we don't + // need to do it by ourselves; we just need to handle prototypes that way. + PackageOfThemes.apply( this, arguments ); + } + + Object.assign( Package.prototype, PackageWithoutThemes.prototype, PackageOfThemes.prototype ); + + var jqueryUi = new JqueryUi( path.resolve( "." ) ); + var target = fs.createWriteStream( "../" + jqueryUi.pkg.name + "-" + jqueryUi.pkg.version + + "-cdn.zip" ); + var packager = new Packager( jqueryUi.files().cache, Package, { + components: jqueryUi.components().map( function( component ) { + return component.name; + } ), + jqueryUi: jqueryUi, + themeVars: null + } ); + packager.ready + .then( function() { + removeExternals( packager ); + addManifest( packager ); + packager.toZip( target, { + basedir: "" + }, function( error ) { + if ( error ) { + Release.abort( "Failed to zip the CDN package", error ); + } + callback(); + } ); + } ) + .catch( function( error ) { + Release.abort( "Failed to create the CDN package", error ); + } ); +} + +Release.define( { + npmPublish: true, + issueTracker: "github", + changelogShell: function() { + var monthNames = [ "January", "February", "March", "April", "May", "June", "July", + "August", "September", "October", "November", "December" ], + now = new Date(); + return "\n\nReleased on " + monthNames[ now.getMonth() ] + " " + now.getDate() + + ", " + now.getFullYear() + "\n\n"; + }, + generateArtifacts: function( fn ) { + var files = replaceAtVersion(); + + buildCDNPackage( function copyCdnFiles() { + var zipFile = shell.ls( "../jquery*-cdn.zip" )[ 0 ], + tmpFolder = "../tmp-zip-output", + unzipCommand = "unzip -o " + zipFile + " -d " + tmpFolder; + + console.log( "Unzipping for dist/cdn copies" ); + shell.mkdir( "-p", tmpFolder ); + Release.exec( { + command: unzipCommand, + silent: true + }, "Failed to unzip cdn files" ); + + shell.mkdir( "-p", "dist/cdn" ); + shell.cp( tmpFolder + "/jquery-ui*.js", "dist/cdn" ); + shell.cp( "-r", tmpFolder + "/themes", "dist/cdn" ); + + // Copy all the files to be published on the CDN to the dist directory + // as well. + shell.cp( "dist/cdn/jquery-ui.js", "dist" ); + shell.cp( "dist/cdn/jquery-ui.min.js", "dist" ); + shell.cp( "-r", "dist/cdn/themes", "dist" ); + + Release.exec( "git add --force dist/jquery-ui.js", + "Error adding dist/jquery-ui.js." ); + Release.exec( "git add --force dist/jquery-ui.min.js", + "Error adding dist/jquery-ui.min.js." ); + Release.exec( "git add --force dist/themes", + "Error adding dist/themes." ); + + fn( files ); + } ); + } +} ); + +}; + +module.exports.dependencies = [ + "download.jqueryui.com@2.3.12", + "node-packager@0.0.7", + "shelljs@0.8.5" +]; diff --git a/build/tasks/build.js b/build/tasks/build.js new file mode 100644 index 00000000000..bd07364ea36 --- /dev/null +++ b/build/tasks/build.js @@ -0,0 +1,42 @@ +"use strict"; + +module.exports = function( grunt ) { + +grunt.registerTask( "clean", function() { + require( "rimraf" ).rimrafSync( "dist" ); +} ); + +grunt.registerTask( "asciilint", function() { + var valid = true, + files = grunt.file.expand( { filter: "isFile" }, "ui/*.js" ); + files.forEach( function( filename ) { + var i, c, + text = grunt.file.read( filename ); + + // Ensure files use only \n for line endings, not \r\n + if ( /\x0d\x0a/.test( text ) ) { + grunt.log.error( filename + ": Incorrect line endings (\\r\\n)" ); + valid = false; + } + + // Ensure only ASCII chars so script tags don't need a charset attribute + if ( text.length !== Buffer.byteLength( text, "utf8" ) ) { + grunt.log.error( filename + ": Non-ASCII characters detected:" ); + for ( i = 0; i < text.length; i++ ) { + c = text.charCodeAt( i ); + if ( c > 127 ) { + grunt.log.error( "- position " + i + ": " + c ); + grunt.log.error( "-- " + text.substring( i - 20, i + 20 ) ); + break; + } + } + valid = false; + } + } ); + if ( valid ) { + grunt.log.ok( files.length + " files lint free." ); + } + return valid; +} ); + +}; diff --git a/build/tasks/minify.js b/build/tasks/minify.js new file mode 100644 index 00000000000..6d83831ee3c --- /dev/null +++ b/build/tasks/minify.js @@ -0,0 +1,53 @@ +"use strict"; + +const swc = require( "@swc/core" ); + +module.exports = function( grunt ) { + +grunt.registerMultiTask( "minify", async function() { + const done = this.async(); + const options = this.options(); + + for ( const file of this.files ) { + if ( file.src.length === 0 ) { + grunt.log.writeln( + `No source file found, skipping minification to "${ file.dest }".` ); + continue; + } + if ( file.src.length !== 1 ) { + grunt.fail.warn( "Minifying multiple source files into one " + + "destination file not supported" ); + } + + const contents = grunt.file.read( file.src[ 0 ] ); + + const { code } = await swc.minify( + contents, + { + compress: { + ecma: 5, + hoist_funs: false, + loops: false + }, + format: { + ecma: 5, + asciiOnly: true, + comments: false, + preamble: options.banner + }, + inlineSourcesContent: false, + mangle: true, + module: false, + sourceMap: false + } + ); + + grunt.file.write( file.dest, code ); + + grunt.log.writeln( `File ${ file.dest } created.` ); + } + + done(); +} ); + +}; diff --git a/build/themes b/build/themes deleted file mode 100644 index ec9ac1f2b17..00000000000 --- a/build/themes +++ /dev/null @@ -1 +0,0 @@ -download=true&files%5B%5D=ui.core.js&files%5B%5D=ui.widget.js&files%5B%5D=ui.mouse.js&files%5B%5D=ui.position.js&files%5B%5D=ui.draggable.js&files%5B%5D=ui.droppable.js&files%5B%5D=ui.resizable.js&files%5B%5D=ui.selectable.js&files%5B%5D=ui.sortable.js&files%5B%5D=ui.accordion.js&files%5B%5D=ui.autocomplete.js&files%5B%5D=ui.button.js&files%5B%5D=ui.dialog.js&files%5B%5D=ui.slider.js&files%5B%5D=ui.tabs.js&files%5B%5D=ui.datepicker.js&files%5B%5D=ui.progressbar.js&files%5B%5D=effects.core.js&files%5B%5D=effects.blind.js&files%5B%5D=effects.bounce.js&files%5B%5D=effects.clip.js&files%5B%5D=effects.drop.js&files%5B%5D=effects.explode.js&files%5B%5D=effects.fold.js&files%5B%5D=effects.highlight.js&files%5B%5D=effects.pulsate.js&files%5B%5D=effects.scale.js&files%5B%5D=effects.shake.js&files%5B%5D=effects.slide.js&files%5B%5D=effects.transfer.js&theme=%3FffDefault%3DTrebuchet%2BMS%2C%2BTahoma%2C%2BVerdana%2C%2BArial%2C%2Bsans-serif%26fwDefault%3Dbold%26fsDefault%3D1.1em%26cornerRadius%3D4px%26bgColorHeader%3Df6a828%26bgTextureHeader%3D12_gloss_wave.png%26bgImgOpacityHeader%3D35%26borderColorHeader%3De78f08%26fcHeader%3Dffffff%26iconColorHeader%3Dffffff%26bgColorContent%3Deeeeee%26bgTextureContent%3D03_highlight_soft.png%26bgImgOpacityContent%3D100%26borderColorContent%3Ddddddd%26fcContent%3D333333%26iconColorContent%3D222222%26bgColorDefault%3Df6f6f6%26bgTextureDefault%3D02_glass.png%26bgImgOpacityDefault%3D100%26borderColorDefault%3Dcccccc%26fcDefault%3D1c94c4%26iconColorDefault%3Def8c08%26bgColorHover%3Dfdf5ce%26bgTextureHover%3D02_glass.png%26bgImgOpacityHover%3D100%26borderColorHover%3Dfbcb09%26fcHover%3Dc77405%26iconColorHover%3Def8c08%26bgColorActive%3Dffffff%26bgTextureActive%3D02_glass.png%26bgImgOpacityActive%3D65%26borderColorActive%3Dfbd850%26fcActive%3Deb8f00%26iconColorActive%3Def8c08%26bgColorHighlight%3Dffe45c%26bgTextureHighlight%3D03_highlight_soft.png%26bgImgOpacityHighlight%3D75%26borderColorHighlight%3Dfed22f%26fcHighlight%3D363636%26iconColorHighlight%3D228ef1%26bgColorError%3Db81900%26bgTextureError%3D08_diagonals_thick.png%26bgImgOpacityError%3D18%26borderColorError%3Dcd0a0a%26fcError%3Dffffff%26iconColorError%3Dffd27a%26bgColorOverlay%3D666666%26bgTextureOverlay%3D08_diagonals_thick.png%26bgImgOpacityOverlay%3D20%26opacityOverlay%3D50%26bgColorShadow%3D000000%26bgTextureShadow%3D01_flat.png%26bgImgOpacityShadow%3D10%26opacityShadow%3D20%26thicknessShadow%3D5px%26offsetTopShadow%3D-5px%26offsetLeftShadow%3D-5px%26cornerRadiusShadow%3D5px&scope=&t-name=ui-lightness&ui-version=1.8.2,download=true&files%5B%5D=ui.core.js&files%5B%5D=ui.widget.js&files%5B%5D=ui.mouse.js&files%5B%5D=ui.position.js&files%5B%5D=ui.draggable.js&files%5B%5D=ui.droppable.js&files%5B%5D=ui.resizable.js&files%5B%5D=ui.selectable.js&files%5B%5D=ui.sortable.js&files%5B%5D=ui.accordion.js&files%5B%5D=ui.autocomplete.js&files%5B%5D=ui.button.js&files%5B%5D=ui.dialog.js&files%5B%5D=ui.slider.js&files%5B%5D=ui.tabs.js&files%5B%5D=ui.datepicker.js&files%5B%5D=ui.progressbar.js&files%5B%5D=effects.core.js&files%5B%5D=effects.blind.js&files%5B%5D=effects.bounce.js&files%5B%5D=effects.clip.js&files%5B%5D=effects.drop.js&files%5B%5D=effects.explode.js&files%5B%5D=effects.fold.js&files%5B%5D=effects.highlight.js&files%5B%5D=effects.pulsate.js&files%5B%5D=effects.scale.js&files%5B%5D=effects.shake.js&files%5B%5D=effects.slide.js&files%5B%5D=effects.transfer.js&theme=%3FffDefault%3DSegoe%2BUI%252C%2BArial%252C%2Bsans-serif%26fwDefault%3Dbold%26fsDefault%3D1.1em%26cornerRadius%3D6px%26bgColorHeader%3D333333%26bgTextureHeader%3D12_gloss_wave.png%26bgImgOpacityHeader%3D25%26borderColorHeader%3D333333%26fcHeader%3Dffffff%26iconColorHeader%3Dffffff%26bgColorContent%3D000000%26bgTextureContent%3D05_inset_soft.png%26bgImgOpacityContent%3D25%26borderColorContent%3D666666%26fcContent%3Dffffff%26iconColorContent%3Dcccccc%26bgColorDefault%3D555555%26bgTextureDefault%3D02_glass.png%26bgImgOpacityDefault%3D20%26borderColorDefault%3D666666%26fcDefault%3Deeeeee%26iconColorDefault%3Dcccccc%26bgColorHover%3D0078a3%26bgTextureHover%3D02_glass.png%26bgImgOpacityHover%3D40%26borderColorHover%3D59b4d4%26fcHover%3Dffffff%26iconColorHover%3Dffffff%26bgColorActive%3Df58400%26bgTextureActive%3D05_inset_soft.png%26bgImgOpacityActive%3D30%26borderColorActive%3Dffaf0f%26fcActive%3Dffffff%26iconColorActive%3D222222%26bgColorHighlight%3Deeeeee%26bgTextureHighlight%3D03_highlight_soft.png%26bgImgOpacityHighlight%3D80%26borderColorHighlight%3Dcccccc%26fcHighlight%3D2e7db2%26iconColorHighlight%3D4b8e0b%26bgColorError%3Dffc73d%26bgTextureError%3D02_glass.png%26bgImgOpacityError%3D40%26borderColorError%3Dffb73d%26fcError%3D111111%26iconColorError%3Da83300%26bgColorOverlay%3D5c5c5c%26bgTextureOverlay%3D01_flat.png%26bgImgOpacityOverlay%3D50%26opacityOverlay%3D80%26bgColorShadow%3Dcccccc%26bgTextureShadow%3D01_flat.png%26bgImgOpacityShadow%3D30%26opacityShadow%3D60%26thicknessShadow%3D7px%26offsetTopShadow%3D-7px%26offsetLeftShadow%3D-7px%26cornerRadiusShadow%3D8px&scope=&t-name=ui-darkness&ui-version=1.8.2,download=true&files%5B%5D=ui.core.js&files%5B%5D=ui.widget.js&files%5B%5D=ui.mouse.js&files%5B%5D=ui.position.js&files%5B%5D=ui.draggable.js&files%5B%5D=ui.droppable.js&files%5B%5D=ui.resizable.js&files%5B%5D=ui.selectable.js&files%5B%5D=ui.sortable.js&files%5B%5D=ui.accordion.js&files%5B%5D=ui.autocomplete.js&files%5B%5D=ui.button.js&files%5B%5D=ui.dialog.js&files%5B%5D=ui.slider.js&files%5B%5D=ui.tabs.js&files%5B%5D=ui.datepicker.js&files%5B%5D=ui.progressbar.js&files%5B%5D=effects.core.js&files%5B%5D=effects.blind.js&files%5B%5D=effects.bounce.js&files%5B%5D=effects.clip.js&files%5B%5D=effects.drop.js&files%5B%5D=effects.explode.js&files%5B%5D=effects.fold.js&files%5B%5D=effects.highlight.js&files%5B%5D=effects.pulsate.js&files%5B%5D=effects.scale.js&files%5B%5D=effects.shake.js&files%5B%5D=effects.slide.js&files%5B%5D=effects.transfer.js&theme=%3FffDefault%3DVerdana%2CArial%2Csans-serif%26fwDefault%3Dnormal%26fsDefault%3D1.1em%26cornerRadius%3D4px%26bgColorHeader%3Dcccccc%26bgTextureHeader%3D03_highlight_soft.png%26bgImgOpacityHeader%3D75%26borderColorHeader%3Daaaaaa%26fcHeader%3D222222%26iconColorHeader%3D222222%26bgColorContent%3Dffffff%26bgTextureContent%3D01_flat.png%26bgImgOpacityContent%3D75%26borderColorContent%3Daaaaaa%26fcContent%3D222222%26iconColorContent%3D222222%26bgColorDefault%3De6e6e6%26bgTextureDefault%3D02_glass.png%26bgImgOpacityDefault%3D75%26borderColorDefault%3Dd3d3d3%26fcDefault%3D555555%26iconColorDefault%3D888888%26bgColorHover%3Ddadada%26bgTextureHover%3D02_glass.png%26bgImgOpacityHover%3D75%26borderColorHover%3D999999%26fcHover%3D212121%26iconColorHover%3D454545%26bgColorActive%3Dffffff%26bgTextureActive%3D02_glass.png%26bgImgOpacityActive%3D65%26borderColorActive%3Daaaaaa%26fcActive%3D212121%26iconColorActive%3D454545%26bgColorHighlight%3Dfbf9ee%26bgTextureHighlight%3D02_glass.png%26bgImgOpacityHighlight%3D55%26borderColorHighlight%3Dfcefa1%26fcHighlight%3D363636%26iconColorHighlight%3D2e83ff%26bgColorError%3Dfef1ec%26bgTextureError%3D02_glass.png%26bgImgOpacityError%3D95%26borderColorError%3Dcd0a0a%26fcError%3Dcd0a0a%26iconColorError%3Dcd0a0a%26bgColorOverlay%3Daaaaaa%26bgTextureOverlay%3D01_flat.png%26bgImgOpacityOverlay%3D0%26opacityOverlay%3D30%26bgColorShadow%3Daaaaaa%26bgTextureShadow%3D01_flat.png%26bgImgOpacityShadow%3D0%26opacityShadow%3D30%26thicknessShadow%3D8px%26offsetTopShadow%3D-8px%26offsetLeftShadow%3D-8px%26cornerRadiusShadow%3D8px&scope=&t-name=smoothness&ui-version=1.8.2,download=true&files%5B%5D=ui.core.js&files%5B%5D=ui.widget.js&files%5B%5D=ui.mouse.js&files%5B%5D=ui.position.js&files%5B%5D=ui.draggable.js&files%5B%5D=ui.droppable.js&files%5B%5D=ui.resizable.js&files%5B%5D=ui.selectable.js&files%5B%5D=ui.sortable.js&files%5B%5D=ui.accordion.js&files%5B%5D=ui.autocomplete.js&files%5B%5D=ui.button.js&files%5B%5D=ui.dialog.js&files%5B%5D=ui.slider.js&files%5B%5D=ui.tabs.js&files%5B%5D=ui.datepicker.js&files%5B%5D=ui.progressbar.js&files%5B%5D=effects.core.js&files%5B%5D=effects.blind.js&files%5B%5D=effects.bounce.js&files%5B%5D=effects.clip.js&files%5B%5D=effects.drop.js&files%5B%5D=effects.explode.js&files%5B%5D=effects.fold.js&files%5B%5D=effects.highlight.js&files%5B%5D=effects.pulsate.js&files%5B%5D=effects.scale.js&files%5B%5D=effects.shake.js&files%5B%5D=effects.slide.js&files%5B%5D=effects.transfer.js&theme=%3FffDefault%3DVerdana%252CArial%252Csans-serif%26fwDefault%3Dnormal%26fsDefault%3D1.1em%26cornerRadius%3D5px%26bgColorHeader%3D2191c0%26bgTextureHeader%3D12_gloss_wave.png%26bgImgOpacityHeader%3D75%26borderColorHeader%3D4297d7%26fcHeader%3Deaf5f7%26iconColorHeader%3Dd8e7f3%26bgColorContent%3Dfcfdfd%26bgTextureContent%3D06_inset_hard.png%26bgImgOpacityContent%3D100%26borderColorContent%3Da6c9e2%26fcContent%3D222222%26iconColorContent%3D0078ae%26bgColorDefault%3D0078ae%26bgTextureDefault%3D02_glass.png%26bgImgOpacityDefault%3D45%26borderColorDefault%3D77d5f7%26fcDefault%3Dffffff%26iconColorDefault%3De0fdff%26bgColorHover%3D79c9ec%26bgTextureHover%3D02_glass.png%26bgImgOpacityHover%3D75%26borderColorHover%3D448dae%26fcHover%3D026890%26iconColorHover%3D056b93%26bgColorActive%3D6eac2c%26bgTextureActive%3D12_gloss_wave.png%26bgImgOpacityActive%3D50%26borderColorActive%3Dacdd4a%26fcActive%3Dffffff%26iconColorActive%3Df5e175%26bgColorHighlight%3Df8da4e%26bgTextureHighlight%3D02_glass.png%26bgImgOpacityHighlight%3D55%26borderColorHighlight%3Dfcd113%26fcHighlight%3D915608%26iconColorHighlight%3Df7a50d%26bgColorError%3De14f1c%26bgTextureError%3D12_gloss_wave.png%26bgImgOpacityError%3D45%26borderColorError%3Dcd0a0a%26fcError%3Dffffff%26iconColorError%3Dfcd113%26bgColorOverlay%3Daaaaaa%26bgTextureOverlay%3D01_flat.png%26bgImgOpacityOverlay%3D75%26opacityOverlay%3D30%26bgColorShadow%3D999999%26bgTextureShadow%3D01_flat.png%26bgImgOpacityShadow%3D55%26opacityShadow%3D45%26thicknessShadow%3D0px%26offsetTopShadow%3D5px%26offsetLeftShadow%3D5px%26cornerRadiusShadow%3D5px&scope=&t-name=start&ui-version=1.8.2,download=true&files%5B%5D=ui.core.js&files%5B%5D=ui.widget.js&files%5B%5D=ui.mouse.js&files%5B%5D=ui.position.js&files%5B%5D=ui.draggable.js&files%5B%5D=ui.droppable.js&files%5B%5D=ui.resizable.js&files%5B%5D=ui.selectable.js&files%5B%5D=ui.sortable.js&files%5B%5D=ui.accordion.js&files%5B%5D=ui.autocomplete.js&files%5B%5D=ui.button.js&files%5B%5D=ui.dialog.js&files%5B%5D=ui.slider.js&files%5B%5D=ui.tabs.js&files%5B%5D=ui.datepicker.js&files%5B%5D=ui.progressbar.js&files%5B%5D=effects.core.js&files%5B%5D=effects.blind.js&files%5B%5D=effects.bounce.js&files%5B%5D=effects.clip.js&files%5B%5D=effects.drop.js&files%5B%5D=effects.explode.js&files%5B%5D=effects.fold.js&files%5B%5D=effects.highlight.js&files%5B%5D=effects.pulsate.js&files%5B%5D=effects.scale.js&files%5B%5D=effects.shake.js&files%5B%5D=effects.slide.js&files%5B%5D=effects.transfer.js&theme=%3FffDefault%3DLucida%2BGrande%2C%2BLucida%2BSans%2C%2BArial%2C%2Bsans-serif%26fwDefault%3Dbold%26fsDefault%3D1.1em%26cornerRadius%3D5px%26bgColorHeader%3D5c9ccc%26bgTextureHeader%3D12_gloss_wave.png%26bgImgOpacityHeader%3D55%26borderColorHeader%3D4297d7%26fcHeader%3Dffffff%26iconColorHeader%3Dd8e7f3%26bgColorContent%3Dfcfdfd%26bgTextureContent%3D06_inset_hard.png%26bgImgOpacityContent%3D100%26borderColorContent%3Da6c9e2%26fcContent%3D222222%26iconColorContent%3D469bdd%26bgColorDefault%3Ddfeffc%26bgTextureDefault%3D02_glass.png%26bgImgOpacityDefault%3D85%26borderColorDefault%3Dc5dbec%26fcDefault%3D2e6e9e%26iconColorDefault%3D6da8d5%26bgColorHover%3Dd0e5f5%26bgTextureHover%3D02_glass.png%26bgImgOpacityHover%3D75%26borderColorHover%3D79b7e7%26fcHover%3D1d5987%26iconColorHover%3D217bc0%26bgColorActive%3Df5f8f9%26bgTextureActive%3D06_inset_hard.png%26bgImgOpacityActive%3D100%26borderColorActive%3D79b7e7%26fcActive%3De17009%26iconColorActive%3Df9bd01%26bgColorHighlight%3Dfbec88%26bgTextureHighlight%3D01_flat.png%26bgImgOpacityHighlight%3D55%26borderColorHighlight%3Dfad42e%26fcHighlight%3D363636%26iconColorHighlight%3D2e83ff%26bgColorError%3Dfef1ec%26bgTextureError%3D02_glass.png%26bgImgOpacityError%3D95%26borderColorError%3Dcd0a0a%26fcError%3Dcd0a0a%26iconColorError%3Dcd0a0a%26bgColorOverlay%3Daaaaaa%26bgTextureOverlay%3D01_flat.png%26bgImgOpacityOverlay%3D0%26opacityOverlay%3D30%26bgColorShadow%3Daaaaaa%26bgTextureShadow%3D01_flat.png%26bgImgOpacityShadow%3D0%26opacityShadow%3D30%26thicknessShadow%3D8px%26offsetTopShadow%3D-8px%26offsetLeftShadow%3D-8px%26cornerRadiusShadow%3D8px&scope=&t-name=redmond&ui-version=1.8.2,download=true&files%5B%5D=ui.core.js&files%5B%5D=ui.widget.js&files%5B%5D=ui.mouse.js&files%5B%5D=ui.position.js&files%5B%5D=ui.draggable.js&files%5B%5D=ui.droppable.js&files%5B%5D=ui.resizable.js&files%5B%5D=ui.selectable.js&files%5B%5D=ui.sortable.js&files%5B%5D=ui.accordion.js&files%5B%5D=ui.autocomplete.js&files%5B%5D=ui.button.js&files%5B%5D=ui.dialog.js&files%5B%5D=ui.slider.js&files%5B%5D=ui.tabs.js&files%5B%5D=ui.datepicker.js&files%5B%5D=ui.progressbar.js&files%5B%5D=effects.core.js&files%5B%5D=effects.blind.js&files%5B%5D=effects.bounce.js&files%5B%5D=effects.clip.js&files%5B%5D=effects.drop.js&files%5B%5D=effects.explode.js&files%5B%5D=effects.fold.js&files%5B%5D=effects.highlight.js&files%5B%5D=effects.pulsate.js&files%5B%5D=effects.scale.js&files%5B%5D=effects.shake.js&files%5B%5D=effects.slide.js&files%5B%5D=effects.transfer.js&theme=%3FffDefault%3DSegoe%2BUI%252C%2BArial%252C%2Bsans-serif%26fwDefault%3Dbold%26fsDefault%3D1.1em%26cornerRadius%3D8px%26bgColorHeader%3D817865%26bgTextureHeader%3D12_gloss_wave.png%26bgImgOpacityHeader%3D45%26borderColorHeader%3D494437%26fcHeader%3Dffffff%26iconColorHeader%3Dfadc7a%26bgColorContent%3Dfeeebd%26bgTextureContent%3D03_highlight_soft.png%26bgImgOpacityContent%3D100%26borderColorContent%3D8e846b%26fcContent%3D383838%26iconColorContent%3Dd19405%26bgColorDefault%3Dfece2f%26bgTextureDefault%3D12_gloss_wave.png%26bgImgOpacityDefault%3D60%26borderColorDefault%3Dd19405%26fcDefault%3D4c3000%26iconColorDefault%3D3d3d3d%26bgColorHover%3Dffdd57%26bgTextureHover%3D12_gloss_wave.png%26bgImgOpacityHover%3D70%26borderColorHover%3Da45b13%26fcHover%3D381f00%26iconColorHover%3Dbd7b00%26bgColorActive%3Dffffff%26bgTextureActive%3D05_inset_soft.png%26bgImgOpacityActive%3D30%26borderColorActive%3D655e4e%26fcActive%3D0074c7%26iconColorActive%3Deb990f%26bgColorHighlight%3Dfff9e5%26bgTextureHighlight%3D12_gloss_wave.png%26bgImgOpacityHighlight%3D90%26borderColorHighlight%3Deeb420%26fcHighlight%3D1f1f1f%26iconColorHighlight%3Ded9f26%26bgColorError%3Dd34d17%26bgTextureError%3D07_diagonals_medium.png%26bgImgOpacityError%3D20%26borderColorError%3Dffb73d%26fcError%3Dffffff%26iconColorError%3Dffe180%26bgColorOverlay%3D5c5c5c%26bgTextureOverlay%3D01_flat.png%26bgImgOpacityOverlay%3D50%26opacityOverlay%3D80%26bgColorShadow%3Dcccccc%26bgTextureShadow%3D01_flat.png%26bgImgOpacityShadow%3D30%26opacityShadow%3D60%26thicknessShadow%3D7px%26offsetTopShadow%3D-7px%26offsetLeftShadow%3D-7px%26cornerRadiusShadow%3D8px&scope=&t-name=sunny&ui-version=1.8.2,download=true&files%5B%5D=ui.core.js&files%5B%5D=ui.widget.js&files%5B%5D=ui.mouse.js&files%5B%5D=ui.position.js&files%5B%5D=ui.draggable.js&files%5B%5D=ui.droppable.js&files%5B%5D=ui.resizable.js&files%5B%5D=ui.selectable.js&files%5B%5D=ui.sortable.js&files%5B%5D=ui.accordion.js&files%5B%5D=ui.autocomplete.js&files%5B%5D=ui.button.js&files%5B%5D=ui.dialog.js&files%5B%5D=ui.slider.js&files%5B%5D=ui.tabs.js&files%5B%5D=ui.datepicker.js&files%5B%5D=ui.progressbar.js&files%5B%5D=effects.core.js&files%5B%5D=effects.blind.js&files%5B%5D=effects.bounce.js&files%5B%5D=effects.clip.js&files%5B%5D=effects.drop.js&files%5B%5D=effects.explode.js&files%5B%5D=effects.fold.js&files%5B%5D=effects.highlight.js&files%5B%5D=effects.pulsate.js&files%5B%5D=effects.scale.js&files%5B%5D=effects.shake.js&files%5B%5D=effects.slide.js&files%5B%5D=effects.transfer.js&theme=%3FffDefault%3DTrebuchet%2BMS%252C%2BHelvetica%252C%2BArial%252C%2Bsans-serif%26fwDefault%3Dbold%26fsDefault%3D1.1em%26cornerRadius%3D6px%26bgColorHeader%3Ddddddd%26bgTextureHeader%3D02_glass.png%26bgImgOpacityHeader%3D35%26borderColorHeader%3Dbbbbbb%26fcHeader%3D444444%26iconColorHeader%3D999999%26bgColorContent%3Dc9c9c9%26bgTextureContent%3D05_inset_soft.png%26bgImgOpacityContent%3D50%26borderColorContent%3Daaaaaa%26fcContent%3D333333%26iconColorContent%3D999999%26bgColorDefault%3Deeeeee%26bgTextureDefault%3D02_glass.png%26bgImgOpacityDefault%3D60%26borderColorDefault%3Dcccccc%26fcDefault%3D3383bb%26iconColorDefault%3D70b2e1%26bgColorHover%3Df8f8f8%26bgTextureHover%3D02_glass.png%26bgImgOpacityHover%3D100%26borderColorHover%3Dbbbbbb%26fcHover%3D599fcf%26iconColorHover%3D3383bb%26bgColorActive%3D999999%26bgTextureActive%3D06_inset_hard.png%26bgImgOpacityActive%3D75%26borderColorActive%3D999999%26fcActive%3Dffffff%26iconColorActive%3D454545%26bgColorHighlight%3Deeeeee%26bgTextureHighlight%3D01_flat.png%26bgImgOpacityHighlight%3D55%26borderColorHighlight%3Dffffff%26fcHighlight%3D444444%26iconColorHighlight%3D3383bb%26bgColorError%3Dc0402a%26bgTextureError%3D01_flat.png%26bgImgOpacityError%3D55%26borderColorError%3Dc0402a%26fcError%3Dffffff%26iconColorError%3Dfbc856%26bgColorOverlay%3Deeeeee%26bgTextureOverlay%3D01_flat.png%26bgImgOpacityOverlay%3D0%26opacityOverlay%3D80%26bgColorShadow%3Daaaaaa%26bgTextureShadow%3D01_flat.png%26bgImgOpacityShadow%3D0%26opacityShadow%3D60%26thicknessShadow%3D4px%26offsetTopShadow%3D-4px%26offsetLeftShadow%3D-4px%26cornerRadiusShadow%3D0pxdow%253D0px&scope=&t-name=overcast&ui-version=1.8.2,download=true&files%5B%5D=ui.core.js&files%5B%5D=ui.widget.js&files%5B%5D=ui.mouse.js&files%5B%5D=ui.position.js&files%5B%5D=ui.draggable.js&files%5B%5D=ui.droppable.js&files%5B%5D=ui.resizable.js&files%5B%5D=ui.selectable.js&files%5B%5D=ui.sortable.js&files%5B%5D=ui.accordion.js&files%5B%5D=ui.autocomplete.js&files%5B%5D=ui.button.js&files%5B%5D=ui.dialog.js&files%5B%5D=ui.slider.js&files%5B%5D=ui.tabs.js&files%5B%5D=ui.datepicker.js&files%5B%5D=ui.progressbar.js&files%5B%5D=effects.core.js&files%5B%5D=effects.blind.js&files%5B%5D=effects.bounce.js&files%5B%5D=effects.clip.js&files%5B%5D=effects.drop.js&files%5B%5D=effects.explode.js&files%5B%5D=effects.fold.js&files%5B%5D=effects.highlight.js&files%5B%5D=effects.pulsate.js&files%5B%5D=effects.scale.js&files%5B%5D=effects.shake.js&files%5B%5D=effects.slide.js&files%5B%5D=effects.transfer.js&theme=%3FffDefault%3DLucida%2BGrande%252C%2BLucida%2BSans%252C%2BArial%252C%2Bsans-serif%26fwDefault%3Dnormal%26fsDefault%3D1.1em%26cornerRadius%3D10px%26bgColorHeader%3D3a8104%26bgTextureHeader%3D03_highlight_soft.png%26bgImgOpacityHeader%3D33%26borderColorHeader%3D3f7506%26fcHeader%3Dffffff%26iconColorHeader%3Dffffff%26bgColorContent%3D285c00%26bgTextureContent%3D05_inset_soft.png%26bgImgOpacityContent%3D10%26borderColorContent%3D72b42d%26fcContent%3Dffffff%26iconColorContent%3D72b42d%26bgColorDefault%3D4ca20b%26bgTextureDefault%3D03_highlight_soft.png%26bgImgOpacityDefault%3D60%26borderColorDefault%3D45930b%26fcDefault%3Dffffff%26iconColorDefault%3Dffffff%26bgColorHover%3D4eb305%26bgTextureHover%3D03_highlight_soft.png%26bgImgOpacityHover%3D50%26borderColorHover%3D8bd83b%26fcHover%3Dffffff%26iconColorHover%3Dffffff%26bgColorActive%3D285c00%26bgTextureActive%3D04_highlight_hard.png%26bgImgOpacityActive%3D30%26borderColorActive%3D72b42d%26fcActive%3Dffffff%26iconColorActive%3Dffffff%26bgColorHighlight%3Dfbf5d0%26bgTextureHighlight%3D02_glass.png%26bgImgOpacityHighlight%3D55%26borderColorHighlight%3Df9dd34%26fcHighlight%3D363636%26iconColorHighlight%3D4eb305%26bgColorError%3Dffdc2e%26bgTextureError%3D08_diagonals_thick.png%26bgImgOpacityError%3D95%26borderColorError%3Dfad000%26fcError%3D2b2b2b%26iconColorError%3Dcd0a0a%26bgColorOverlay%3D444444%26bgTextureOverlay%3D08_diagonals_thick.png%26bgImgOpacityOverlay%3D15%26opacityOverlay%3D30%26bgColorShadow%3Daaaaaa%26bgTextureShadow%3D07_diagonals_small.png%26bgImgOpacityShadow%3D0%26opacityShadow%3D30%26thicknessShadow%3D0px%26offsetTopShadow%3D4px%26offsetLeftShadow%3D4px%26cornerRadiusShadow%3D4px&scope=&t-name=le-frog&ui-version=1.8.2,download=true&files%5B%5D=ui.core.js&files%5B%5D=ui.widget.js&files%5B%5D=ui.mouse.js&files%5B%5D=ui.position.js&files%5B%5D=ui.draggable.js&files%5B%5D=ui.droppable.js&files%5B%5D=ui.resizable.js&files%5B%5D=ui.selectable.js&files%5B%5D=ui.sortable.js&files%5B%5D=ui.accordion.js&files%5B%5D=ui.autocomplete.js&files%5B%5D=ui.button.js&files%5B%5D=ui.dialog.js&files%5B%5D=ui.slider.js&files%5B%5D=ui.tabs.js&files%5B%5D=ui.datepicker.js&files%5B%5D=ui.progressbar.js&files%5B%5D=effects.core.js&files%5B%5D=effects.blind.js&files%5B%5D=effects.bounce.js&files%5B%5D=effects.clip.js&files%5B%5D=effects.drop.js&files%5B%5D=effects.explode.js&files%5B%5D=effects.fold.js&files%5B%5D=effects.highlight.js&files%5B%5D=effects.pulsate.js&files%5B%5D=effects.scale.js&files%5B%5D=effects.shake.js&files%5B%5D=effects.slide.js&files%5B%5D=effects.transfer.js&theme=%3FffDefault%3DHelvetica%252C%2BArial%252C%2Bsans-serif%26fwDefault%3Dbold%26fsDefault%3D1.1em%26cornerRadius%3D2px%26bgColorHeader%3Ddddddd%26bgTextureHeader%3D03_highlight_soft.png%26bgImgOpacityHeader%3D50%26borderColorHeader%3Ddddddd%26fcHeader%3D444444%26iconColorHeader%3D0073ea%26bgColorContent%3Dffffff%26bgTextureContent%3D01_flat.png%26bgImgOpacityContent%3D75%26borderColorContent%3Ddddddd%26fcContent%3D444444%26iconColorContent%3Dff0084%26bgColorDefault%3Df6f6f6%26bgTextureDefault%3D03_highlight_soft.png%26bgImgOpacityDefault%3D100%26borderColorDefault%3Ddddddd%26fcDefault%3D0073ea%26iconColorDefault%3D666666%26bgColorHover%3D0073ea%26bgTextureHover%3D03_highlight_soft.png%26bgImgOpacityHover%3D25%26borderColorHover%3D0073ea%26fcHover%3Dffffff%26iconColorHover%3Dffffff%26bgColorActive%3Dffffff%26bgTextureActive%3D02_glass.png%26bgImgOpacityActive%3D65%26borderColorActive%3Ddddddd%26fcActive%3Dff0084%26iconColorActive%3D454545%26bgColorHighlight%3Dffffff%26bgTextureHighlight%3D01_flat.png%26bgImgOpacityHighlight%3D55%26borderColorHighlight%3Dcccccc%26fcHighlight%3D444444%26iconColorHighlight%3D0073ea%26bgColorError%3Dffffff%26bgTextureError%3D01_flat.png%26bgImgOpacityError%3D55%26borderColorError%3Dff0084%26fcError%3D222222%26iconColorError%3Dff0084%26bgColorOverlay%3Deeeeee%26bgTextureOverlay%3D01_flat.png%26bgImgOpacityOverlay%3D0%26opacityOverlay%3D80%26bgColorShadow%3Daaaaaa%26bgTextureShadow%3D01_flat.png%26bgImgOpacityShadow%3D0%26opacityShadow%3D60%26thicknessShadow%3D4px%26offsetTopShadow%3D-4px%26offsetLeftShadow%3D-4px%26cornerRadiusShadow%3D0px&scope=&t-name=flick&ui-version=1.8.2,download=true&files%5B%5D=ui.core.js&files%5B%5D=ui.widget.js&files%5B%5D=ui.mouse.js&files%5B%5D=ui.position.js&files%5B%5D=ui.draggable.js&files%5B%5D=ui.droppable.js&files%5B%5D=ui.resizable.js&files%5B%5D=ui.selectable.js&files%5B%5D=ui.sortable.js&files%5B%5D=ui.accordion.js&files%5B%5D=ui.autocomplete.js&files%5B%5D=ui.button.js&files%5B%5D=ui.dialog.js&files%5B%5D=ui.slider.js&files%5B%5D=ui.tabs.js&files%5B%5D=ui.datepicker.js&files%5B%5D=ui.progressbar.js&files%5B%5D=effects.core.js&files%5B%5D=effects.blind.js&files%5B%5D=effects.bounce.js&files%5B%5D=effects.clip.js&files%5B%5D=effects.drop.js&files%5B%5D=effects.explode.js&files%5B%5D=effects.fold.js&files%5B%5D=effects.highlight.js&files%5B%5D=effects.pulsate.js&files%5B%5D=effects.scale.js&files%5B%5D=effects.shake.js&files%5B%5D=effects.slide.js&files%5B%5D=effects.transfer.js&theme=%3FffDefault%3DTrebuchet%2BMS%252C%2BTahoma%252C%2BVerdana%252C%2BArial%252C%2Bsans-serif%26fwDefault%3Dbold%26fsDefault%3D1.1em%26cornerRadius%3D6px%26bgColorHeader%3Dffffff%26bgTextureHeader%3D23_fine_grain.png%26bgImgOpacityHeader%3D15%26borderColorHeader%3Dd4d1bf%26fcHeader%3D453821%26iconColorHeader%3Db83400%26bgColorContent%3Deceadf%26bgTextureContent%3D23_fine_grain.png%26bgImgOpacityContent%3D10%26borderColorContent%3Dd9d6c4%26fcContent%3D1f1f1f%26iconColorContent%3D222222%26bgColorDefault%3Df8f7f6%26bgTextureDefault%3D23_fine_grain.png%26bgImgOpacityDefault%3D10%26borderColorDefault%3Dcbc7bd%26fcDefault%3D654b24%26iconColorDefault%3Db83400%26bgColorHover%3D654b24%26bgTextureHover%3D23_fine_grain.png%26bgImgOpacityHover%3D65%26borderColorHover%3D654b24%26fcHover%3Dffffff%26iconColorHover%3Dffffff%26bgColorActive%3Deceadf%26bgTextureActive%3D23_fine_grain.png%26bgImgOpacityActive%3D15%26borderColorActive%3Dd9d6c4%26fcActive%3D140f06%26iconColorActive%3D8c291d%26bgColorHighlight%3Df7f3de%26bgTextureHighlight%3D23_fine_grain.png%26bgImgOpacityHighlight%3D15%26borderColorHighlight%3Db2a266%26fcHighlight%3D3a3427%26iconColorHighlight%3D3572ac%26bgColorError%3Db83400%26bgTextureError%3D23_fine_grain.png%26bgImgOpacityError%3D68%26borderColorError%3D681818%26fcError%3Dffffff%26iconColorError%3Dfbdb93%26bgColorOverlay%3D6e4f1c%26bgTextureOverlay%3D16_diagonal_maze.png%26bgImgOpacityOverlay%3D20%26opacityOverlay%3D60%26bgColorShadow%3D000000%26bgTextureShadow%3D16_diagonal_maze.png%26bgImgOpacityShadow%3D40%26opacityShadow%3D60%26thicknessShadow%3D5px%26offsetTopShadow%3D0%26offsetLeftShadow%3D-10px%26cornerRadiusShadow%3D18px&scope=&t-name=pepper-grinder&ui-version=1.8.2,download=true&files%5B%5D=ui.core.js&files%5B%5D=ui.widget.js&files%5B%5D=ui.mouse.js&files%5B%5D=ui.position.js&files%5B%5D=ui.draggable.js&files%5B%5D=ui.droppable.js&files%5B%5D=ui.resizable.js&files%5B%5D=ui.selectable.js&files%5B%5D=ui.sortable.js&files%5B%5D=ui.accordion.js&files%5B%5D=ui.autocomplete.js&files%5B%5D=ui.button.js&files%5B%5D=ui.dialog.js&files%5B%5D=ui.slider.js&files%5B%5D=ui.tabs.js&files%5B%5D=ui.datepicker.js&files%5B%5D=ui.progressbar.js&files%5B%5D=effects.core.js&files%5B%5D=effects.blind.js&files%5B%5D=effects.bounce.js&files%5B%5D=effects.clip.js&files%5B%5D=effects.drop.js&files%5B%5D=effects.explode.js&files%5B%5D=effects.fold.js&files%5B%5D=effects.highlight.js&files%5B%5D=effects.pulsate.js&files%5B%5D=effects.scale.js&files%5B%5D=effects.shake.js&files%5B%5D=effects.slide.js&files%5B%5D=effects.transfer.js&theme=%3FffDefault%3DLucida%2BGrande%252C%2BLucida%2BSans%252C%2BArial%252C%2Bsans-serif%26fwDefault%3Dbold%26fsDefault%3D1.1em%26cornerRadius%3D6px%26bgColorHeader%3D30273a%26bgTextureHeader%3D03_highlight_soft.png%26bgImgOpacityHeader%3D25%26borderColorHeader%3D231d2b%26fcHeader%3Dffffff%26iconColorHeader%3Da8a3ae%26bgColorContent%3D3d3644%26bgTextureContent%3D12_gloss_wave.png%26bgImgOpacityContent%3D30%26borderColorContent%3D7e7783%26fcContent%3Dffffff%26iconColorContent%3Dffffff%26bgColorDefault%3Ddcd9de%26bgTextureDefault%3D03_highlight_soft.png%26bgImgOpacityDefault%3D100%26borderColorDefault%3Ddcd9de%26fcDefault%3D665874%26iconColorDefault%3D8d78a5%26bgColorHover%3Deae6ea%26bgTextureHover%3D03_highlight_soft.png%26bgImgOpacityHover%3D100%26borderColorHover%3Dd1c5d8%26fcHover%3D734d99%26iconColorHover%3D734d99%26bgColorActive%3D5f5964%26bgTextureActive%3D03_highlight_soft.png%26bgImgOpacityActive%3D45%26borderColorActive%3D7e7783%26fcActive%3Dffffff%26iconColorActive%3D454545%26bgColorHighlight%3Dfafafa%26bgTextureHighlight%3D01_flat.png%26bgImgOpacityHighlight%3D55%26borderColorHighlight%3Dffdb1f%26fcHighlight%3D333333%26iconColorHighlight%3D8d78a5%26bgColorError%3D994d53%26bgTextureError%3D01_flat.png%26bgImgOpacityError%3D55%26borderColorError%3D994d53%26fcError%3Dffffff%26iconColorError%3Debccce%26bgColorOverlay%3Deeeeee%26bgTextureOverlay%3D01_flat.png%26bgImgOpacityOverlay%3D0%26opacityOverlay%3D80%26bgColorShadow%3Daaaaaa%26bgTextureShadow%3D01_flat.png%26bgImgOpacityShadow%3D0%26opacityShadow%3D60%26thicknessShadow%3D4px%26offsetTopShadow%3D-4px%26offsetLeftShadow%3D-4px%26cornerRadiusShadow%3D0px&scope=&t-name=eggplant&ui-version=1.8.2,download=true&files%5B%5D=ui.core.js&files%5B%5D=ui.widget.js&files%5B%5D=ui.mouse.js&files%5B%5D=ui.position.js&files%5B%5D=ui.draggable.js&files%5B%5D=ui.droppable.js&files%5B%5D=ui.resizable.js&files%5B%5D=ui.selectable.js&files%5B%5D=ui.sortable.js&files%5B%5D=ui.accordion.js&files%5B%5D=ui.autocomplete.js&files%5B%5D=ui.button.js&files%5B%5D=ui.dialog.js&files%5B%5D=ui.slider.js&files%5B%5D=ui.tabs.js&files%5B%5D=ui.datepicker.js&files%5B%5D=ui.progressbar.js&files%5B%5D=effects.core.js&files%5B%5D=effects.blind.js&files%5B%5D=effects.bounce.js&files%5B%5D=effects.clip.js&files%5B%5D=effects.drop.js&files%5B%5D=effects.explode.js&files%5B%5D=effects.fold.js&files%5B%5D=effects.highlight.js&files%5B%5D=effects.pulsate.js&files%5B%5D=effects.scale.js&files%5B%5D=effects.shake.js&files%5B%5D=effects.slide.js&files%5B%5D=effects.transfer.js&theme=%3FffDefault%3DVerdana%252C%2BArial%252C%2Bsans-serif%26fwDefault%3Dnormal%26fsDefault%3D1.1em%26cornerRadius%3D6px%26bgColorHeader%3D444444%26bgTextureHeader%3D03_highlight_soft.png%26bgImgOpacityHeader%3D44%26borderColorHeader%3D333333%26fcHeader%3Dffffff%26iconColorHeader%3Dffffff%26bgColorContent%3D000000%26bgTextureContent%3D14_loop.png%26bgImgOpacityContent%3D25%26borderColorContent%3D555555%26fcContent%3Dffffff%26iconColorContent%3Dcccccc%26bgColorDefault%3D222222%26bgTextureDefault%3D03_highlight_soft.png%26bgImgOpacityDefault%3D35%26borderColorDefault%3D444444%26fcDefault%3Deeeeee%26iconColorDefault%3Dcccccc%26bgColorHover%3D003147%26bgTextureHover%3D03_highlight_soft.png%26bgImgOpacityHover%3D33%26borderColorHover%3D0b93d5%26fcHover%3Dffffff%26iconColorHover%3Dffffff%26bgColorActive%3D0972a5%26bgTextureActive%3D04_highlight_hard.png%26bgImgOpacityActive%3D20%26borderColorActive%3D26b3f7%26fcActive%3Dffffff%26iconColorActive%3D222222%26bgColorHighlight%3Deeeeee%26bgTextureHighlight%3D03_highlight_soft.png%26bgImgOpacityHighlight%3D80%26borderColorHighlight%3Dcccccc%26fcHighlight%3D2e7db2%26iconColorHighlight%3D4b8e0b%26bgColorError%3Dffc73d%26bgTextureError%3D02_glass.png%26bgImgOpacityError%3D40%26borderColorError%3Dffb73d%26fcError%3D111111%26iconColorError%3Da83300%26bgColorOverlay%3D5c5c5c%26bgTextureOverlay%3D01_flat.png%26bgImgOpacityOverlay%3D50%26opacityOverlay%3D80%26bgColorShadow%3Dcccccc%26bgTextureShadow%3D01_flat.png%26bgImgOpacityShadow%3D30%26opacityShadow%3D60%26thicknessShadow%3D7px%26offsetTopShadow%3D-7px%26offsetLeftShadow%3D-7px%26cornerRadiusShadow%3D8px&scope=&t-name=dark-hive&ui-version=1.8.2,download=true&files%5B%5D=ui.core.js&files%5B%5D=ui.widget.js&files%5B%5D=ui.mouse.js&files%5B%5D=ui.position.js&files%5B%5D=ui.draggable.js&files%5B%5D=ui.droppable.js&files%5B%5D=ui.resizable.js&files%5B%5D=ui.selectable.js&files%5B%5D=ui.sortable.js&files%5B%5D=ui.accordion.js&files%5B%5D=ui.autocomplete.js&files%5B%5D=ui.button.js&files%5B%5D=ui.dialog.js&files%5B%5D=ui.slider.js&files%5B%5D=ui.tabs.js&files%5B%5D=ui.datepicker.js&files%5B%5D=ui.progressbar.js&files%5B%5D=effects.core.js&files%5B%5D=effects.blind.js&files%5B%5D=effects.bounce.js&files%5B%5D=effects.clip.js&files%5B%5D=effects.drop.js&files%5B%5D=effects.explode.js&files%5B%5D=effects.fold.js&files%5B%5D=effects.highlight.js&files%5B%5D=effects.pulsate.js&files%5B%5D=effects.scale.js&files%5B%5D=effects.shake.js&files%5B%5D=effects.slide.js&files%5B%5D=effects.transfer.js&theme=%3FffDefault%3DLucida%2BGrande%252C%2BLucida%2BSans%252C%2BArial%252C%2Bsans-serif%26fwDefault%3Dbold%26fsDefault%3D1.1em%26cornerRadius%3D6px%26bgColorHeader%3Ddeedf7%26bgTextureHeader%3D03_highlight_soft.png%26bgImgOpacityHeader%3D100%26borderColorHeader%3Daed0ea%26fcHeader%3D222222%26iconColorHeader%3D72a7cf%26bgColorContent%3Df2f5f7%26bgTextureContent%3D04_highlight_hard.png%26bgImgOpacityContent%3D100%26borderColorContent%3Ddddddd%26fcContent%3D362b36%26iconColorContent%3D72a7cf%26bgColorDefault%3Dd7ebf9%26bgTextureDefault%3D02_glass.png%26bgImgOpacityDefault%3D80%26borderColorDefault%3Daed0ea%26fcDefault%3D2779aa%26iconColorDefault%3D3d80b3%26bgColorHover%3De4f1fb%26bgTextureHover%3D02_glass.png%26bgImgOpacityHover%3D100%26borderColorHover%3D74b2e2%26fcHover%3D0070a3%26iconColorHover%3D2694e8%26bgColorActive%3D3baae3%26bgTextureActive%3D02_glass.png%26bgImgOpacityActive%3D50%26borderColorActive%3D2694e8%26fcActive%3Dffffff%26iconColorActive%3Dffffff%26bgColorHighlight%3Dffef8f%26bgTextureHighlight%3D03_highlight_soft.png%26bgImgOpacityHighlight%3D25%26borderColorHighlight%3Df9dd34%26fcHighlight%3D363636%26iconColorHighlight%3D2e83ff%26bgColorError%3Dcd0a0a%26bgTextureError%3D01_flat.png%26bgImgOpacityError%3D15%26borderColorError%3Dcd0a0a%26fcError%3Dffffff%26iconColorError%3Dffffff%26bgColorOverlay%3Deeeeee%26bgTextureOverlay%3D08_diagonals_thick.png%26bgImgOpacityOverlay%3D90%26opacityOverlay%3D80%26bgColorShadow%3D000000%26bgTextureShadow%3D04_highlight_hard.png%26bgImgOpacityShadow%3D70%26opacityShadow%3D30%26thicknessShadow%3D7px%26offsetTopShadow%3D-7px%26offsetLeftShadow%3D-7px%26cornerRadiusShadow%3D8px&scope=&t-name=cupertino&ui-version=1.8.2,download=true&files%5B%5D=ui.core.js&files%5B%5D=ui.widget.js&files%5B%5D=ui.mouse.js&files%5B%5D=ui.position.js&files%5B%5D=ui.draggable.js&files%5B%5D=ui.droppable.js&files%5B%5D=ui.resizable.js&files%5B%5D=ui.selectable.js&files%5B%5D=ui.sortable.js&files%5B%5D=ui.accordion.js&files%5B%5D=ui.autocomplete.js&files%5B%5D=ui.button.js&files%5B%5D=ui.dialog.js&files%5B%5D=ui.slider.js&files%5B%5D=ui.tabs.js&files%5B%5D=ui.datepicker.js&files%5B%5D=ui.progressbar.js&files%5B%5D=effects.core.js&files%5B%5D=effects.blind.js&files%5B%5D=effects.bounce.js&files%5B%5D=effects.clip.js&files%5B%5D=effects.drop.js&files%5B%5D=effects.explode.js&files%5B%5D=effects.fold.js&files%5B%5D=effects.highlight.js&files%5B%5D=effects.pulsate.js&files%5B%5D=effects.scale.js&files%5B%5D=effects.shake.js&files%5B%5D=effects.slide.js&files%5B%5D=effects.transfer.js&theme=%3FffDefault%3Dsegoe%2Bui%252C%2BArial%252C%2Bsans-serif%26fwDefault%3Dbold%26fsDefault%3D1.1em%26cornerRadius%3D6px%26bgColorHeader%3Dece8da%26bgTextureHeader%3D12_gloss_wave.png%26bgImgOpacityHeader%3D100%26borderColorHeader%3Dd4ccb0%26fcHeader%3D433f38%26iconColorHeader%3D847e71%26bgColorContent%3Df5f3e5%26bgTextureContent%3D04_highlight_hard.png%26bgImgOpacityContent%3D100%26borderColorContent%3Ddfd9c3%26fcContent%3D312e25%26iconColorContent%3D808080%26bgColorDefault%3D459e00%26bgTextureDefault%3D04_highlight_hard.png%26bgImgOpacityDefault%3D15%26borderColorDefault%3D327E04%26fcDefault%3Dffffff%26iconColorDefault%3Deeeeee%26bgColorHover%3D67b021%26bgTextureHover%3D03_highlight_soft.png%26bgImgOpacityHover%3D25%26borderColorHover%3D327E04%26fcHover%3Dffffff%26iconColorHover%3Dffffff%26bgColorActive%3Dfafaf4%26bgTextureActive%3D04_highlight_hard.png%26bgImgOpacityActive%3D100%26borderColorActive%3Dd4ccb0%26fcActive%3D459e00%26iconColorActive%3D8DC262%26bgColorHighlight%3Dfcf0ba%26bgTextureHighlight%3D02_glass.png%26bgImgOpacityHighlight%3D55%26borderColorHighlight%3De8e1b5%26fcHighlight%3D363636%26iconColorHighlight%3D8DC262%26bgColorError%3Dffedad%26bgTextureError%3D03_highlight_soft.png%26bgImgOpacityError%3D95%26borderColorError%3De3a345%26fcError%3Dcd5c0a%26iconColorError%3Dcd0a0a%26bgColorOverlay%3D2b2922%26bgTextureOverlay%3D05_inset_soft.png%26bgImgOpacityOverlay%3D15%26opacityOverlay%3D90%26bgColorShadow%3Dcccccc%26bgTextureShadow%3D04_highlight_hard.png%26bgImgOpacityShadow%3D95%26opacityShadow%3D20%26thicknessShadow%3D12px%26offsetTopShadow%3D-12px%26offsetLeftShadow%3D-12px%26cornerRadiusShadow%3D10px&scope=&t-name=south-street&ui-version=1.8.2,download=true&files%5B%5D=ui.core.js&files%5B%5D=ui.widget.js&files%5B%5D=ui.mouse.js&files%5B%5D=ui.position.js&files%5B%5D=ui.draggable.js&files%5B%5D=ui.droppable.js&files%5B%5D=ui.resizable.js&files%5B%5D=ui.selectable.js&files%5B%5D=ui.sortable.js&files%5B%5D=ui.accordion.js&files%5B%5D=ui.autocomplete.js&files%5B%5D=ui.button.js&files%5B%5D=ui.dialog.js&files%5B%5D=ui.slider.js&files%5B%5D=ui.tabs.js&files%5B%5D=ui.datepicker.js&files%5B%5D=ui.progressbar.js&files%5B%5D=effects.core.js&files%5B%5D=effects.blind.js&files%5B%5D=effects.bounce.js&files%5B%5D=effects.clip.js&files%5B%5D=effects.drop.js&files%5B%5D=effects.explode.js&files%5B%5D=effects.fold.js&files%5B%5D=effects.highlight.js&files%5B%5D=effects.pulsate.js&files%5B%5D=effects.scale.js&files%5B%5D=effects.shake.js&files%5B%5D=effects.slide.js&files%5B%5D=effects.transfer.js&theme=%3FffDefault%3DArial%2Csans-serif%26fwDefault%3Dbold%26fsDefault%3D1.1em%26cornerRadius%3D6px%26bgColorHeader%3Dcc0000%26bgTextureHeader%3D03_highlight_soft.png%26bgImgOpacityHeader%3D15%26borderColorHeader%3De3a1a1%26fcHeader%3Dffffff%26iconColorHeader%3Dffffff%26bgColorContent%3Dffffff%26bgTextureContent%3D01_flat.png%26bgImgOpacityContent%3D75%26borderColorContent%3Deeeeee%26fcContent%3D333333%26iconColorContent%3Dcc0000%26bgColorDefault%3Deeeeee%26bgTextureDefault%3D04_highlight_hard.png%26bgImgOpacityDefault%3D100%26borderColorDefault%3Dd8dcdf%26fcDefault%3D004276%26iconColorDefault%3Dcc0000%26bgColorHover%3Df6f6f6%26bgTextureHover%3D04_highlight_hard.png%26bgImgOpacityHover%3D100%26borderColorHover%3Dcdd5da%26fcHover%3D111111%26iconColorHover%3Dcc0000%26bgColorActive%3Dffffff%26bgTextureActive%3D01_flat.png%26bgImgOpacityActive%3D65%26borderColorActive%3Deeeeee%26fcActive%3Dcc0000%26iconColorActive%3Dcc0000%26bgColorHighlight%3Dfbf8ee%26bgTextureHighlight%3D02_glass.png%26bgImgOpacityHighlight%3D55%26borderColorHighlight%3Dfcd3a1%26fcHighlight%3D444444%26iconColorHighlight%3D004276%26bgColorError%3Df3d8d8%26bgTextureError%3D08_diagonals_thick.png%26bgImgOpacityError%3D75%26borderColorError%3Dcc0000%26fcError%3D2e2e2e%26iconColorError%3Dcc0000%26bgColorOverlay%3Da6a6a6%26bgTextureOverlay%3D09_dots_small.png%26bgImgOpacityOverlay%3D65%26opacityOverlay%3D40%26bgColorShadow%3D333333%26bgTextureShadow%3D01_flat.png%26bgImgOpacityShadow%3D0%26opacityShadow%3D10%26thicknessShadow%3D8px%26offsetTopShadow%3D-8px%26offsetLeftShadow%3D-8px%26cornerRadiusShadow%3D8px&scope=&t-name=blitzer&ui-version=1.8.2,download=true&files%5B%5D=ui.core.js&files%5B%5D=ui.widget.js&files%5B%5D=ui.mouse.js&files%5B%5D=ui.position.js&files%5B%5D=ui.draggable.js&files%5B%5D=ui.droppable.js&files%5B%5D=ui.resizable.js&files%5B%5D=ui.selectable.js&files%5B%5D=ui.sortable.js&files%5B%5D=ui.accordion.js&files%5B%5D=ui.autocomplete.js&files%5B%5D=ui.button.js&files%5B%5D=ui.dialog.js&files%5B%5D=ui.slider.js&files%5B%5D=ui.tabs.js&files%5B%5D=ui.datepicker.js&files%5B%5D=ui.progressbar.js&files%5B%5D=effects.core.js&files%5B%5D=effects.blind.js&files%5B%5D=effects.bounce.js&files%5B%5D=effects.clip.js&files%5B%5D=effects.drop.js&files%5B%5D=effects.explode.js&files%5B%5D=effects.fold.js&files%5B%5D=effects.highlight.js&files%5B%5D=effects.pulsate.js&files%5B%5D=effects.scale.js&files%5B%5D=effects.shake.js&files%5B%5D=effects.slide.js&files%5B%5D=effects.transfer.js&theme=%3Ftr%3DffDefault%3DHelvetica%2CArial%2Csans-serif%26fwDefault%3Dnormal%26fsDefault%3D1.1em%26cornerRadius%3D6px%26bgColorHeader%3Dcb842e%26bgTextureHeader%3D02_glass.png%26bgImgOpacityHeader%3D25%26borderColorHeader%3Dd49768%26fcHeader%3Dffffff%26iconColorHeader%3Dffffff%26bgColorContent%3Df4f0ec%26bgTextureContent%3D05_inset_soft.png%26bgImgOpacityContent%3D100%26borderColorContent%3De0cfc2%26fcContent%3D1e1b1d%26iconColorContent%3Dc47a23%26bgColorDefault%3Dede4d4%26bgTextureDefault%3D02_glass.png%26bgImgOpacityDefault%3D70%26borderColorDefault%3Dcdc3b7%26fcDefault%3D3f3731%26iconColorDefault%3Df08000%26bgColorHover%3Df5f0e5%26bgTextureHover%3D02_glass.png%26bgImgOpacityHover%3D100%26borderColorHover%3Df5ad66%26fcHover%3Da46313%26iconColorHover%3Df08000%26bgColorActive%3Df4f0ec%26bgTextureActive%3D04_highlight_hard.png%26bgImgOpacityActive%3D100%26borderColorActive%3De0cfc2%26fcActive%3Db85700%26iconColorActive%3Df35f07%26bgColorHighlight%3Df5f5b5%26bgTextureHighlight%3D04_highlight_hard.png%26bgImgOpacityHighlight%3D75%26borderColorHighlight%3Dd9bb73%26fcHighlight%3D060200%26iconColorHighlight%3Dcb672b%26bgColorError%3Dfee4bd%26bgTextureError%3D04_highlight_hard.png%26bgImgOpacityError%3D65%26borderColorError%3Df8893f%26fcError%3D592003%26iconColorError%3Dff7519%26bgColorOverlay%3Daaaaaa%26bgTextureOverlay%3D01_flat.png%26bgImgOpacityOverlay%3D75%26opacityOverlay%3D30%26bgColorShadow%3Daaaaaa%26bgTextureShadow%3D01_flat.png%26bgImgOpacityShadow%3D75%26opacityShadow%3D30%26thicknessShadow%3D8px%26offsetTopShadow%3D-8px%26offsetLeftShadow%3D-8px%26cornerRadiusShadow%3D8px&scope=&t-name=humanity&ui-version=1.8.2,download=true&files%5B%5D=ui.core.js&files%5B%5D=ui.widget.js&files%5B%5D=ui.mouse.js&files%5B%5D=ui.position.js&files%5B%5D=ui.draggable.js&files%5B%5D=ui.droppable.js&files%5B%5D=ui.resizable.js&files%5B%5D=ui.selectable.js&files%5B%5D=ui.sortable.js&files%5B%5D=ui.accordion.js&files%5B%5D=ui.autocomplete.js&files%5B%5D=ui.button.js&files%5B%5D=ui.dialog.js&files%5B%5D=ui.slider.js&files%5B%5D=ui.tabs.js&files%5B%5D=ui.datepicker.js&files%5B%5D=ui.progressbar.js&files%5B%5D=effects.core.js&files%5B%5D=effects.blind.js&files%5B%5D=effects.bounce.js&files%5B%5D=effects.clip.js&files%5B%5D=effects.drop.js&files%5B%5D=effects.explode.js&files%5B%5D=effects.fold.js&files%5B%5D=effects.highlight.js&files%5B%5D=effects.pulsate.js&files%5B%5D=effects.scale.js&files%5B%5D=effects.shake.js&files%5B%5D=effects.slide.js&files%5B%5D=effects.transfer.js&theme=%3FffDefault%3DGill%2BSans%2CArial%2Csans-serif%26fwDefault%3Dbold%26fsDefault%3D1.2em%26cornerRadius%3D4px%26bgColorHeader%3D35414f%26bgTextureHeader%3D09_dots_small.png%26bgImgOpacityHeader%3D35%26borderColorHeader%3D2c4359%26fcHeader%3De1e463%26iconColorHeader%3De1e463%26bgColorContent%3Dffffff%26bgTextureContent%3D01_flat.png%26bgImgOpacityContent%3D75%26borderColorContent%3Daaaaaa%26fcContent%3D2c4359%26iconColorContent%3Dc02669%26bgColorDefault%3D93c3cd%26bgTextureDefault%3D07_diagonals_small.png%26bgImgOpacityDefault%3D50%26borderColorDefault%3D93c3cd%26fcDefault%3D333333%26iconColorDefault%3Dffffff%26bgColorHover%3Dccd232%26bgTextureHover%3D07_diagonals_small.png%26bgImgOpacityHover%3D75%26borderColorHover%3D999999%26fcHover%3D212121%26iconColorHover%3D454545%26bgColorActive%3Ddb4865%26bgTextureActive%3D07_diagonals_small.png%26bgImgOpacityActive%3D40%26borderColorActive%3Dff6b7f%26fcActive%3Dffffff%26iconColorActive%3Dffffff%26bgColorHighlight%3Dffff38%26bgTextureHighlight%3D10_dots_medium.png%26bgImgOpacityHighlight%3D80%26borderColorHighlight%3Db4d100%26fcHighlight%3D363636%26iconColorHighlight%3D88a206%26bgColorError%3Dff3853%26bgTextureError%3D07_diagonals_small.png%26bgImgOpacityError%3D50%26borderColorError%3Dff6b7f%26fcError%3Dffffff%26iconColorError%3Dffeb33%26bgColorOverlay%3Df7f7ba%26bgTextureOverlay%3D11_white_lines.png%26bgImgOpacityOverlay%3D85%26opacityOverlay%3D80%26bgColorShadow%3Dba9217%26bgTextureShadow%3D01_flat.png%26bgImgOpacityShadow%3D75%26opacityShadow%3D20%26thicknessShadow%3D10px%26offsetTopShadow%3D8px%26offsetLeftShadow%3D8px%26cornerRadiusShadow%3D5px&scope=&t-name=hot-sneaks&ui-version=1.8.2,download=true&files%5B%5D=ui.core.js&files%5B%5D=ui.widget.js&files%5B%5D=ui.mouse.js&files%5B%5D=ui.position.js&files%5B%5D=ui.draggable.js&files%5B%5D=ui.droppable.js&files%5B%5D=ui.resizable.js&files%5B%5D=ui.selectable.js&files%5B%5D=ui.sortable.js&files%5B%5D=ui.accordion.js&files%5B%5D=ui.autocomplete.js&files%5B%5D=ui.button.js&files%5B%5D=ui.dialog.js&files%5B%5D=ui.slider.js&files%5B%5D=ui.tabs.js&files%5B%5D=ui.datepicker.js&files%5B%5D=ui.progressbar.js&files%5B%5D=effects.core.js&files%5B%5D=effects.blind.js&files%5B%5D=effects.bounce.js&files%5B%5D=effects.clip.js&files%5B%5D=effects.drop.js&files%5B%5D=effects.explode.js&files%5B%5D=effects.fold.js&files%5B%5D=effects.highlight.js&files%5B%5D=effects.pulsate.js&files%5B%5D=effects.scale.js&files%5B%5D=effects.shake.js&files%5B%5D=effects.slide.js&files%5B%5D=effects.transfer.js&theme=%3FffDefault%3Dsegoe%2Bui%2C%2BArial%2C%2Bsans-serif%26fwDefault%3Dbold%26fsDefault%3D1.1em%26cornerRadius%3D3px%26bgColorHeader%3Df9f9f9%26bgTextureHeader%3D03_highlight_soft.png%26bgImgOpacityHeader%3D100%26borderColorHeader%3Dcccccc%26fcHeader%3De69700%26iconColorHeader%3D5fa5e3%26bgColorContent%3Deeeeee%26bgTextureContent%3D06_inset_hard.png%26bgImgOpacityContent%3D100%26borderColorContent%3Daaaaaa%26fcContent%3D222222%26iconColorContent%3D0a82eb%26bgColorDefault%3D1484e6%26bgTextureDefault%3D08_diagonals_thick.png%26bgImgOpacityDefault%3D22%26borderColorDefault%3Dffffff%26fcDefault%3Dffffff%26iconColorDefault%3Dfcdd4a%26bgColorHover%3D2293f7%26bgTextureHover%3D08_diagonals_thick.png%26bgImgOpacityHover%3D26%26borderColorHover%3D2293f7%26fcHover%3Dffffff%26iconColorHover%3Dffffff%26bgColorActive%3De69700%26bgTextureActive%3D08_diagonals_thick.png%26bgImgOpacityActive%3D20%26borderColorActive%3De69700%26fcActive%3Dffffff%26iconColorActive%3Dffffff%26bgColorHighlight%3Dc5ddfc%26bgTextureHighlight%3D07_diagonals_small.png%26bgImgOpacityHighlight%3D25%26borderColorHighlight%3Dffffff%26fcHighlight%3D333333%26iconColorHighlight%3D0b54d5%26bgColorError%3De69700%26bgTextureError%3D08_diagonals_thick.png%26bgImgOpacityError%3D20%26borderColorError%3De69700%26fcError%3Dffffff%26iconColorError%3Dffffff%26bgColorOverlay%3De6b900%26bgTextureOverlay%3D01_flat.png%26bgImgOpacityOverlay%3D0%26opacityOverlay%3D30%26bgColorShadow%3De69700%26bgTextureShadow%3D01_flat.png%26bgImgOpacityShadow%3D0%26opacityShadow%3D20%26thicknessShadow%3D0px%26offsetTopShadow%3D6px%26offsetLeftShadow%3D6px%26cornerRadiusShadow%3D3px&scope=&t-name=excite-bike&ui-version=1.8.2,download=true&files%5B%5D=ui.core.js&files%5B%5D=ui.widget.js&files%5B%5D=ui.mouse.js&files%5B%5D=ui.position.js&files%5B%5D=ui.draggable.js&files%5B%5D=ui.droppable.js&files%5B%5D=ui.resizable.js&files%5B%5D=ui.selectable.js&files%5B%5D=ui.sortable.js&files%5B%5D=ui.accordion.js&files%5B%5D=ui.autocomplete.js&files%5B%5D=ui.button.js&files%5B%5D=ui.dialog.js&files%5B%5D=ui.slider.js&files%5B%5D=ui.tabs.js&files%5B%5D=ui.datepicker.js&files%5B%5D=ui.progressbar.js&files%5B%5D=effects.core.js&files%5B%5D=effects.blind.js&files%5B%5D=effects.bounce.js&files%5B%5D=effects.clip.js&files%5B%5D=effects.drop.js&files%5B%5D=effects.explode.js&files%5B%5D=effects.fold.js&files%5B%5D=effects.highlight.js&files%5B%5D=effects.pulsate.js&files%5B%5D=effects.scale.js&files%5B%5D=effects.shake.js&files%5B%5D=effects.slide.js&files%5B%5D=effects.transfer.js&theme=%3Ftr%26ffDefault%3DHelvetica%2C%2BArial%2C%2Bsans-serif%26fwDefault%3Dnormal%26fsDefault%3D1.1%26fsDefaultUnit%3Dem%26cornerRadius%3D5%26cornerRadiusUnit%3Dpx%26bgColorHeader%3D888888%26bgTextureHeader%3D04_highlight_hard.png%26bgImgOpacityHeader%3D15%26borderColorHeader%3D404040%26fcHeader%3Dffffff%26iconColorHeader%3Dcccccc%26bgColorContent%3D121212%26bgTextureContent%3D12_gloss_wave.png%26bgImgOpacityContent%3D16%26borderColorContent%3D404040%26fcContent%3Deeeeee%26iconColorContent%3Dbbbbbb%26bgColorDefault%3Dadadad%26bgTextureDefault%3D03_highlight_soft.png%26bgImgOpacityDefault%3D35%26borderColorDefault%3Dcccccc%26fcDefault%3D333333%26iconColorDefault%3D666666%26bgColorHover%3Ddddddd%26bgTextureHover%3D03_highlight_soft.png%26bgImgOpacityHover%3D60%26borderColorHover%3Ddddddd%26fcHover%3D000000%26iconColorHover%3Dc98000%26bgColorActive%3D121212%26bgTextureActive%3D05_inset_soft.png%26bgImgOpacityActive%3D15%26borderColorActive%3D000000%26fcActive%3Dffffff%26iconColorActive%3Df29a00%26bgColorHighlight%3D555555%26bgTextureHighlight%3D04_highlight_hard.png%26bgImgOpacityHighlight%3D55%26borderColorHighlight%3D404040%26fcHighlight%3Dcccccc%26iconColorHighlight%3Daaaaaa%26bgColorError%3Dfef1ec%26bgTextureError%3D02_glass.png%26bgImgOpacityError%3D95%26borderColorError%3Dcd0a0a%26fcError%3Dcd0a0a%26iconColorError%3Dcd0a0a&scope=&t-name=vader&ui-version=1.8.2,download=true&files%5B%5D=ui.core.js&files%5B%5D=ui.widget.js&files%5B%5D=ui.mouse.js&files%5B%5D=ui.position.js&files%5B%5D=ui.draggable.js&files%5B%5D=ui.droppable.js&files%5B%5D=ui.resizable.js&files%5B%5D=ui.selectable.js&files%5B%5D=ui.sortable.js&files%5B%5D=ui.accordion.js&files%5B%5D=ui.autocomplete.js&files%5B%5D=ui.button.js&files%5B%5D=ui.dialog.js&files%5B%5D=ui.slider.js&files%5B%5D=ui.tabs.js&files%5B%5D=ui.datepicker.js&files%5B%5D=ui.progressbar.js&files%5B%5D=effects.core.js&files%5B%5D=effects.blind.js&files%5B%5D=effects.bounce.js&files%5B%5D=effects.clip.js&files%5B%5D=effects.drop.js&files%5B%5D=effects.explode.js&files%5B%5D=effects.fold.js&files%5B%5D=effects.highlight.js&files%5B%5D=effects.pulsate.js&files%5B%5D=effects.scale.js&files%5B%5D=effects.shake.js&files%5B%5D=effects.slide.js&files%5B%5D=effects.transfer.js&theme=%3FffDefault%3DArial%2C%2Bsans-serif%26fwDefault%3Dbold%26fsDefault%3D1.3em%26cornerRadius%3D4px%26bgColorHeader%3D0b3e6f%26bgTextureHeader%3D08_diagonals_thick.png%26bgImgOpacityHeader%3D15%26borderColorHeader%3D0b3e6f%26fcHeader%3Df6f6f6%26iconColorHeader%3D98d2fb%26bgColorContent%3D111111%26bgTextureContent%3D12_gloss_wave.png%26bgImgOpacityContent%3D20%26borderColorContent%3D000000%26fcContent%3Dd9d9d9%26iconColorContent%3D9ccdfc%26bgColorDefault%3D333333%26bgTextureDefault%3D09_dots_small.png%26bgImgOpacityDefault%3D20%26borderColorDefault%3D333333%26fcDefault%3Dffffff%26iconColorDefault%3D9ccdfc%26bgColorHover%3D00498f%26bgTextureHover%3D09_dots_small.png%26bgImgOpacityHover%3D40%26borderColorHover%3D222222%26fcHover%3Dffffff%26iconColorHover%3Dffffff%26bgColorActive%3D292929%26bgTextureActive%3D01_flat.png%26bgImgOpacityActive%3D40%26borderColorActive%3D096ac8%26fcActive%3D75abff%26iconColorActive%3D00498f%26bgColorHighlight%3D0b58a2%26bgTextureHighlight%3D10_dots_medium.png%26bgImgOpacityHighlight%3D30%26borderColorHighlight%3D052f57%26fcHighlight%3Dffffff%26iconColorHighlight%3Dffffff%26bgColorError%3Da32d00%26bgTextureError%3D09_dots_small.png%26bgImgOpacityError%3D30%26borderColorError%3Dcd0a0a%26fcError%3Dffffff%26iconColorError%3Dffffff%26bgColorOverlay%3Daaaaaa%26bgTextureOverlay%3D01_flat.png%26bgImgOpacityOverlay%3D0%26opacityOverlay%3D30%26bgColorShadow%3Daaaaaa%26bgTextureShadow%3D01_flat.png%26bgImgOpacityShadow%3D0%26opacityShadow%3D30%26thicknessShadow%3D8px%26offsetTopShadow%3D-8px%26offsetLeftShadow%3D-8px%26cornerRadiusShadow%3D8px&scope=&t-name=dot-luv&ui-version=1.8.2,download=true&files%5B%5D=ui.core.js&files%5B%5D=ui.widget.js&files%5B%5D=ui.mouse.js&files%5B%5D=ui.position.js&files%5B%5D=ui.draggable.js&files%5B%5D=ui.droppable.js&files%5B%5D=ui.resizable.js&files%5B%5D=ui.selectable.js&files%5B%5D=ui.sortable.js&files%5B%5D=ui.accordion.js&files%5B%5D=ui.autocomplete.js&files%5B%5D=ui.button.js&files%5B%5D=ui.dialog.js&files%5B%5D=ui.slider.js&files%5B%5D=ui.tabs.js&files%5B%5D=ui.datepicker.js&files%5B%5D=ui.progressbar.js&files%5B%5D=effects.core.js&files%5B%5D=effects.blind.js&files%5B%5D=effects.bounce.js&files%5B%5D=effects.clip.js&files%5B%5D=effects.drop.js&files%5B%5D=effects.explode.js&files%5B%5D=effects.fold.js&files%5B%5D=effects.highlight.js&files%5B%5D=effects.pulsate.js&files%5B%5D=effects.scale.js&files%5B%5D=effects.shake.js&files%5B%5D=effects.slide.js&files%5B%5D=effects.transfer.js&theme=%3FffDefault%3DSegoe%2BUI%252C%2BHelvetica%252C%2BArial%252C%2Bsans-serif%26fwDefault%3Dbold%26fsDefault%3D1.1em%26cornerRadius%3D4px%26bgColorHeader%3D453326%26bgTextureHeader%3D12_gloss_wave.png%26bgImgOpacityHeader%3D25%26borderColorHeader%3D695649%26fcHeader%3De3ddc9%26iconColorHeader%3De3ddc9%26bgColorContent%3D201913%26bgTextureContent%3D05_inset_soft.png%26bgImgOpacityContent%3D10%26borderColorContent%3D9c947c%26fcContent%3Dffffff%26iconColorContent%3D222222%26bgColorDefault%3D1c160d%26bgTextureDefault%3D12_gloss_wave.png%26bgImgOpacityDefault%3D20%26borderColorDefault%3D695444%26fcDefault%3D9bcc60%26iconColorDefault%3D9bcc60%26bgColorHover%3D44372c%26bgTextureHover%3D12_gloss_wave.png%26bgImgOpacityHover%3D30%26borderColorHover%3D9c947c%26fcHover%3Dbaec7e%26iconColorHover%3Dadd978%26bgColorActive%3D201913%26bgTextureActive%3D03_highlight_soft.png%26bgImgOpacityActive%3D20%26borderColorActive%3D9c947c%26fcActive%3De3ddc9%26iconColorActive%3De3ddc9%26bgColorHighlight%3D619226%26bgTextureHighlight%3D03_highlight_soft.png%26bgImgOpacityHighlight%3D20%26borderColorHighlight%3Dadd978%26fcHighlight%3Dffffff%26iconColorHighlight%3Dffffff%26bgColorError%3D5f391b%26bgTextureError%3D02_glass.png%26bgImgOpacityError%3D15%26borderColorError%3D5f391b%26fcError%3Dffffff%26iconColorError%3Df1fd86%26bgColorOverlay%3Daaaaaa%26bgTextureOverlay%3D01_flat.png%26bgImgOpacityOverlay%3D0%26opacityOverlay%3D30%26bgColorShadow%3Daaaaaa%26bgTextureShadow%3D01_flat.png%26bgImgOpacityShadow%3D0%26opacityShadow%3D30%26thicknessShadow%3D8px%26offsetTopShadow%3D-8px%26offsetLeftShadow%3D-8px%26cornerRadiusShadow%3D8px&scope=&t-name=mint-choc&ui-version=1.8.2,download=true&files%5B%5D=ui.core.js&files%5B%5D=ui.widget.js&files%5B%5D=ui.mouse.js&files%5B%5D=ui.position.js&files%5B%5D=ui.draggable.js&files%5B%5D=ui.droppable.js&files%5B%5D=ui.resizable.js&files%5B%5D=ui.selectable.js&files%5B%5D=ui.sortable.js&files%5B%5D=ui.accordion.js&files%5B%5D=ui.autocomplete.js&files%5B%5D=ui.button.js&files%5B%5D=ui.dialog.js&files%5B%5D=ui.slider.js&files%5B%5D=ui.tabs.js&files%5B%5D=ui.datepicker.js&files%5B%5D=ui.progressbar.js&files%5B%5D=effects.core.js&files%5B%5D=effects.blind.js&files%5B%5D=effects.bounce.js&files%5B%5D=effects.clip.js&files%5B%5D=effects.drop.js&files%5B%5D=effects.explode.js&files%5B%5D=effects.fold.js&files%5B%5D=effects.highlight.js&files%5B%5D=effects.pulsate.js&files%5B%5D=effects.scale.js&files%5B%5D=effects.shake.js&files%5B%5D=effects.slide.js&files%5B%5D=effects.transfer.js&theme=%3FffDefault%3DVerdana%2C%2BArial%2C%2Bsans-serif%26fwDefault%3Dnormal%26fsDefault%3D1.1em%26cornerRadius%3D4px%26bgColorHeader%3D333333%26bgTextureHeader%3D08_diagonals_thick.png%26bgImgOpacityHeader%3D8%26borderColorHeader%3Da3a3a3%26fcHeader%3Deeeeee%26iconColorHeader%3Dbbbbbb%26bgColorContent%3Df9f9f9%26bgTextureContent%3D04_highlight_hard.png%26bgImgOpacityContent%3D100%26borderColorContent%3Dcccccc%26fcContent%3D222222%26iconColorContent%3D222222%26bgColorDefault%3D111111%26bgTextureDefault%3D02_glass.png%26bgImgOpacityDefault%3D40%26borderColorDefault%3D777777%26fcDefault%3De3e3e3%26iconColorDefault%3Dededed%26bgColorHover%3D1c1c1c%26bgTextureHover%3D02_glass.png%26bgImgOpacityHover%3D55%26borderColorHover%3D000000%26fcHover%3Dffffff%26iconColorHover%3Dffffff%26bgColorActive%3Dffffff%26bgTextureActive%3D01_flat.png%26bgImgOpacityActive%3D65%26borderColorActive%3Dcccccc%26fcActive%3D222222%26iconColorActive%3D222222%26bgColorHighlight%3Dffeb80%26bgTextureHighlight%3D06_inset_hard.png%26bgImgOpacityHighlight%3D55%26borderColorHighlight%3Dffde2e%26fcHighlight%3D363636%26iconColorHighlight%3D4ca300%26bgColorError%3Dcd0a0a%26bgTextureError%3D06_inset_hard.png%26bgImgOpacityError%3D45%26borderColorError%3D9e0505%26fcError%3Dffffff%26iconColorError%3Dffcf29%26bgColorOverlay%3Daaaaaa%26bgTextureOverlay%3D04_highlight_hard.png%26bgImgOpacityOverlay%3D40%26opacityOverlay%3D30%26bgColorShadow%3Daaaaaa%26bgTextureShadow%3D03_highlight_soft.png%26bgImgOpacityShadow%3D50%26opacityShadow%3D20%26thicknessShadow%3D8px%26offsetTopShadow%3D-8px%26offsetLeftShadow%3D-8px%26cornerRadiusShadow%3D8px&scope=&t-name=black-tie&ui-version=1.8.2,download=true&files%5B%5D=ui.core.js&files%5B%5D=ui.widget.js&files%5B%5D=ui.mouse.js&files%5B%5D=ui.position.js&files%5B%5D=ui.draggable.js&files%5B%5D=ui.droppable.js&files%5B%5D=ui.resizable.js&files%5B%5D=ui.selectable.js&files%5B%5D=ui.sortable.js&files%5B%5D=ui.accordion.js&files%5B%5D=ui.autocomplete.js&files%5B%5D=ui.button.js&files%5B%5D=ui.dialog.js&files%5B%5D=ui.slider.js&files%5B%5D=ui.tabs.js&files%5B%5D=ui.datepicker.js&files%5B%5D=ui.progressbar.js&files%5B%5D=effects.core.js&files%5B%5D=effects.blind.js&files%5B%5D=effects.bounce.js&files%5B%5D=effects.clip.js&files%5B%5D=effects.drop.js&files%5B%5D=effects.explode.js&files%5B%5D=effects.fold.js&files%5B%5D=effects.highlight.js&files%5B%5D=effects.pulsate.js&files%5B%5D=effects.scale.js&files%5B%5D=effects.shake.js&files%5B%5D=effects.slide.js&files%5B%5D=effects.transfer.js&theme=%3FffDefault%3DSegoe%2BUI%2C%2BHelvetica%2C%2BArial%2C%2Bsans-serif%26fwDefault%3Dbold%26fsDefault%3D1.1em%26cornerRadius%3D6px%26bgColorHeader%3D9fda58%26bgTextureHeader%3D12_gloss_wave.png%26bgImgOpacityHeader%3D85%26borderColorHeader%3D000000%26fcHeader%3D222222%26iconColorHeader%3D1f1f1f%26bgColorContent%3D000000%26bgTextureContent%3D12_gloss_wave.png%26bgImgOpacityContent%3D55%26borderColorContent%3D4a4a4a%26fcContent%3Dffffff%26iconColorContent%3D9fda58%26bgColorDefault%3D0a0a0a%26bgTextureDefault%3D02_glass.png%26bgImgOpacityDefault%3D40%26borderColorDefault%3D1b1613%26fcDefault%3Db8ec79%26iconColorDefault%3Db8ec79%26bgColorHover%3D000000%26bgTextureHover%3D02_glass.png%26bgImgOpacityHover%3D60%26borderColorHover%3D000000%26fcHover%3D96f226%26iconColorHover%3Db8ec79%26bgColorActive%3D4c4c4c%26bgTextureActive%3D01_flat.png%26bgImgOpacityActive%3D0%26borderColorActive%3D696969%26fcActive%3Dffffff%26iconColorActive%3Dffffff%26bgColorHighlight%3Df1fbe5%26bgTextureHighlight%3D02_glass.png%26bgImgOpacityHighlight%3D55%26borderColorHighlight%3D8cce3b%26fcHighlight%3D030303%26iconColorHighlight%3D000000%26bgColorError%3Df6ecd5%26bgTextureError%3D12_gloss_wave.png%26bgImgOpacityError%3D95%26borderColorError%3Df1ac88%26fcError%3D74736d%26iconColorError%3Dcd0a0a%26bgColorOverlay%3D262626%26bgTextureOverlay%3D07_diagonals_small.png%26bgImgOpacityOverlay%3D50%26opacityOverlay%3D30%26bgColorShadow%3D303030%26bgTextureShadow%3D01_flat.png%26bgImgOpacityShadow%3D0%26opacityShadow%3D50%26thicknessShadow%3D6px%26offsetTopShadow%3D-6px%26offsetLeftShadow%3D-6px%26cornerRadiusShadow%3D12px&scope=&t-name=trontastic&ui-version=1.8.2,download=true&files%5B%5D=ui.core.js&files%5B%5D=ui.widget.js&files%5B%5D=ui.mouse.js&files%5B%5D=ui.position.js&files%5B%5D=ui.draggable.js&files%5B%5D=ui.droppable.js&files%5B%5D=ui.resizable.js&files%5B%5D=ui.selectable.js&files%5B%5D=ui.sortable.js&files%5B%5D=ui.accordion.js&files%5B%5D=ui.autocomplete.js&files%5B%5D=ui.button.js&files%5B%5D=ui.dialog.js&files%5B%5D=ui.slider.js&files%5B%5D=ui.tabs.js&files%5B%5D=ui.datepicker.js&files%5B%5D=ui.progressbar.js&files%5B%5D=effects.core.js&files%5B%5D=effects.blind.js&files%5B%5D=effects.bounce.js&files%5B%5D=effects.clip.js&files%5B%5D=effects.drop.js&files%5B%5D=effects.explode.js&files%5B%5D=effects.fold.js&files%5B%5D=effects.highlight.js&files%5B%5D=effects.pulsate.js&files%5B%5D=effects.scale.js&files%5B%5D=effects.shake.js&files%5B%5D=effects.slide.js&files%5B%5D=effects.transfer.js&theme=%3FffDefault%3DGeorgia%252C%2BVerdana%252CArial%252Csans-serif%26fwDefault%3Dbold%26fsDefault%3D1.2em%26cornerRadius%3D5px%26bgColorHeader%3D261803%26bgTextureHeader%3D13_diamond.png%26bgImgOpacityHeader%3D8%26borderColorHeader%3Dbaaa5a%26fcHeader%3Deacd86%26iconColorHeader%3De9cd86%26bgColorContent%3D443113%26bgTextureContent%3D13_diamond.png%26bgImgOpacityContent%3D8%26borderColorContent%3Defec9f%26fcContent%3Defec9f%26iconColorContent%3Defec9f%26bgColorDefault%3D4f4221%26bgTextureDefault%3D13_diamond.png%26bgImgOpacityDefault%3D10%26borderColorDefault%3D362917%26fcDefault%3Df8eec9%26iconColorDefault%3De8e2b5%26bgColorHover%3D675423%26bgTextureHover%3D13_diamond.png%26bgImgOpacityHover%3D25%26borderColorHover%3D362917%26fcHover%3Df8eec9%26iconColorHover%3Df2ec64%26bgColorActive%3D443113%26bgTextureActive%3D13_diamond.png%26bgImgOpacityActive%3D8%26borderColorActive%3Defec9f%26fcActive%3Df9f2bd%26iconColorActive%3Df9f2bd%26bgColorHighlight%3Dd5ac5d%26bgTextureHighlight%3D13_diamond.png%26bgImgOpacityHighlight%3D25%26borderColorHighlight%3D362917%26fcHighlight%3D060200%26iconColorHighlight%3D070603%26bgColorError%3Dfee4bd%26bgTextureError%3D04_highlight_hard.png%26bgImgOpacityError%3D65%26borderColorError%3Dc26629%26fcError%3D803f1e%26iconColorError%3Dff7519%26bgColorOverlay%3D372806%26bgTextureOverlay%3D13_diamond.png%26bgImgOpacityOverlay%3D20%26opacityOverlay%3D80%26bgColorShadow%3Dddd4b0%26bgTextureShadow%3D01_flat.png%26bgImgOpacityShadow%3D75%26opacityShadow%3D30%26thicknessShadow%3D8px%26offsetTopShadow%3D-8px%26offsetLeftShadow%3D-8px%26cornerRadiusShadow%3D12px&scope=&t-name=swanky-purse&ui-version=1.8.2 \ No newline at end of file diff --git a/demos/accordion/collapsible.html b/demos/accordion/collapsible.html index 6618baff273..e4c3e8ea371 100644 --- a/demos/accordion/collapsible.html +++ b/demos/accordion/collapsible.html @@ -1,36 +1,30 @@ - + - + + jQuery UI Accordion - Collapse content - - - - - - - + -
-
-

Section 1

+

Section 1

Mauris mauris ante, blandit et, ultrices a, suscipit eget, quam. Integer ut neque. Vivamus nisi metus, molestie vel, gravida in, condimentum sit amet, nunc. Nam a nibh. Donec suscipit eros. Nam mi. Proin viverra leo ut odio. Curabitur malesuada. Vestibulum a velit eu ante scelerisque vulputate.

-

Section 2

+

Section 2

Sed non urna. Donec et ante. Phasellus eu ligula. Vestibulum sit amet purus. Vivamus hendrerit, dolor at aliquet laoreet, mauris turpis porttitor velit, faucibus interdum tellus libero ac justo. Vivamus non quam. In suscipit faucibus urna.

-

Section 3

+

Section 3

Nam enim risus, molestie et, porta ac, aliquam ac, risus. Quisque lobortis. Phasellus pellentesque purus in massa. Aenean in pede. Phasellus ac libero ac tellus pellentesque semper. Sed ac felis. Sed commodo, magna quis lacinia ornare, quam ante aliquam nisi, eu iaculis leo purus venenatis dui.

    @@ -39,22 +33,14 @@

    Section 3

  • List item three
-

Section 4

+

Section 4

Cras dictum. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Aenean lacinia mauris vel est.

Suspendisse eu nisl. Nullam ut libero. Integer dignissim consequat lectus. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos.

-
- - -
- -

By default, accordions always keep one section open. To allow for all sections to be be collapsible, set the collapsible option to true. Click on the currently open section to collapse its content pane.

- - -
- +

By default, accordions always keep one section open. To allow for all sections to be collapsible, set the collapsible option to true. Click on the currently open section to collapse its content pane.

+ diff --git a/demos/accordion/custom-icons.html b/demos/accordion/custom-icons.html index c81fb31202f..f7a9862a058 100644 --- a/demos/accordion/custom-icons.html +++ b/demos/accordion/custom-icons.html @@ -1,46 +1,41 @@ - + - + + jQuery UI Accordion - Customize icons - - - - - - - - + -
-
-

Section 1

+

Section 1

Mauris mauris ante, blandit et, ultrices a, suscipit eget, quam. Integer ut neque. Vivamus nisi metus, molestie vel, gravida in, condimentum sit amet, nunc. Nam a nibh. Donec suscipit eros. Nam mi. Proin viverra leo ut odio. Curabitur malesuada. Vestibulum a velit eu ante scelerisque vulputate.

-

Section 2

+

Section 2

Sed non urna. Donec et ante. Phasellus eu ligula. Vestibulum sit amet purus. Vivamus hendrerit, dolor at aliquet laoreet, mauris turpis porttitor velit, faucibus interdum tellus libero ac justo. Vivamus non quam. In suscipit faucibus urna.

-

Section 3

+

Section 3

Nam enim risus, molestie et, porta ac, aliquam ac, risus. Quisque lobortis. Phasellus pellentesque purus in massa. Aenean in pede. Phasellus ac libero ac tellus pellentesque semper. Sed ac felis. Sed commodo, magna quis lacinia ornare, quam ante aliquam nisi, eu iaculis leo purus venenatis dui.

    @@ -49,7 +44,7 @@

    Section 3

  • List item three
-

Section 4

+

Section 4

Cras dictum. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Aenean lacinia mauris vel est.

Suspendisse eu nisl. Nullam ut libero. Integer dignissim consequat lectus. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos.

@@ -57,15 +52,8 @@

Section 4

-
- - -
- -

Customize the header icons with the icons option, which accepts classes for the header's default and selected (open) state. Use any class from the UI CSS framework, or create custom classes with background images.

- -
- +

Customize the header icons with the icons option, which accepts classes for the header's default and active (open) state. Use any class from the UI CSS framework, or create custom classes with background images.

+
diff --git a/demos/accordion/default.html b/demos/accordion/default.html index 2eb93dd7aa0..7ed676760ae 100644 --- a/demos/accordion/default.html +++ b/demos/accordion/default.html @@ -1,26 +1,20 @@ - + - + + jQuery UI Accordion - Default functionality - - - - - - - + -
-
-

Section 1

+

Section 1

Mauris mauris ante, blandit et, ultrices a, suscipit eget, quam. Integer @@ -29,7 +23,7 @@

Section 1

odio. Curabitur malesuada. Vestibulum a velit eu ante scelerisque vulputate.

-

Section 2

+

Section 2

Sed non urna. Donec et ante. Phasellus eu ligula. Vestibulum sit amet @@ -38,7 +32,7 @@

Section 2

suscipit faucibus urna.

-

Section 3

+

Section 3

Nam enim risus, molestie et, porta ac, aliquam ac, risus. Quisque lobortis. @@ -52,7 +46,7 @@

Section 3

  • List item three
  • -

    Section 4

    +

    Section 4

    Cras dictum. Pellentesque habitant morbi tristique senectus et netus @@ -68,8 +62,6 @@

    Section 4

    -
    -

    Click headers to expand/collapse content that is broken into logical sections, much like tabs. @@ -79,7 +71,6 @@

    Section 4

    The underlying HTML markup is a series of headers (H3 tags) and content divs so the content is usable without JavaScript.

    -
    - + diff --git a/demos/accordion/fillspace.html b/demos/accordion/fillspace.html index 77507821c1f..9bafeaac5fd 100644 --- a/demos/accordion/fillspace.html +++ b/demos/accordion/fillspace.html @@ -1,79 +1,65 @@ - + - + + jQuery UI Accordion - Fill space - - - - - - - - - + -
    -

    Resize the outer container:

    - -
    -
    -

    Section 1

    -
    -

    Mauris mauris ante, blandit et, ultrices a, suscipit eget, quam. Integer ut neque. Vivamus nisi metus, molestie vel, gravida in, condimentum sit amet, nunc. Nam a nibh. Donec suscipit eros. Nam mi. Proin viverra leo ut odio. Curabitur malesuada. Vestibulum a velit eu ante scelerisque vulputate.

    -
    -

    Section 2

    -
    -

    Sed non urna. Donec et ante. Phasellus eu ligula. Vestibulum sit amet purus. Vivamus hendrerit, dolor at aliquet laoreet, mauris turpis porttitor velit, faucibus interdum tellus libero ac justo. Vivamus non quam. In suscipit faucibus urna.

    -
    -

    Section 3

    -
    -

    Nam enim risus, molestie et, porta ac, aliquam ac, risus. Quisque lobortis. Phasellus pellentesque purus in massa. Aenean in pede. Phasellus ac libero ac tellus pellentesque semper. Sed ac felis. Sed commodo, magna quis lacinia ornare, quam ante aliquam nisi, eu iaculis leo purus venenatis dui.

    -
      -
    • List item one
    • -
    • List item two
    • -
    • List item three
    • -
    -
    -

    Section 4

    -
    -

    Cras dictum. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Aenean lacinia mauris vel est.

    Suspendisse eu nisl. Nullam ut libero. Integer dignissim consequat lectus. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos.

    +
    +
    +

    Section 1

    +
    +

    Mauris mauris ante, blandit et, ultrices a, suscipit eget, quam. Integer ut neque. Vivamus nisi metus, molestie vel, gravida in, condimentum sit amet, nunc. Nam a nibh. Donec suscipit eros. Nam mi. Proin viverra leo ut odio. Curabitur malesuada. Vestibulum a velit eu ante scelerisque vulputate.

    +
    +

    Section 2

    +
    +

    Sed non urna. Donec et ante. Phasellus eu ligula. Vestibulum sit amet purus. Vivamus hendrerit, dolor at aliquet laoreet, mauris turpis porttitor velit, faucibus interdum tellus libero ac justo. Vivamus non quam. In suscipit faucibus urna.

    +
    +

    Section 3

    +
    +

    Nam enim risus, molestie et, porta ac, aliquam ac, risus. Quisque lobortis. Phasellus pellentesque purus in massa. Aenean in pede. Phasellus ac libero ac tellus pellentesque semper. Sed ac felis. Sed commodo, magna quis lacinia ornare, quam ante aliquam nisi, eu iaculis leo purus venenatis dui.

    +
      +
    • List item one
    • +
    • List item two
    • +
    • List item three
    • +
    +
    +

    Section 4

    +
    +

    Cras dictum. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Aenean lacinia mauris vel est.

    Suspendisse eu nisl. Nullam ut libero. Integer dignissim consequat lectus. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos.

    +
    - -
    - -
    I'm another panel
    - -
    - - -
    - -

    Because the accordion is comprised of block-level elements, by default its width fills the available horizontal space. To fill the vertical space allocated by its container, set the boolean fillSpace option to true, and the script will automatically set the dimensions of the accordion to the height of its parent container. The accordion will also resize with its container if the container is resizable.

    - -
    - - +

    Because the accordion is comprised of block-level elements, by default its width fills the available horizontal space. To fill the vertical space allocated by its container, set the heightStyle option to "fill", and the script will automatically set the dimensions of the accordion to the height of its parent container.

    +
    diff --git a/demos/accordion/index.html b/demos/accordion/index.html index de3751128d5..4f364a299ab 100644 --- a/demos/accordion/index.html +++ b/demos/accordion/index.html @@ -1,22 +1,20 @@ - + - + + jQuery UI Accordion Demos - - + + + diff --git a/demos/accordion/mouseover.html b/demos/accordion/mouseover.html deleted file mode 100644 index 374fc7536fb..00000000000 --- a/demos/accordion/mouseover.html +++ /dev/null @@ -1,59 +0,0 @@ - - - - - jQuery UI Accordion - Open on mouseover - - - - - - - - - - -
    - -
    -

    Section 1

    -
    -

    Mauris mauris ante, blandit et, ultrices a, suscipit eget, quam. Integer ut neque. Vivamus nisi metus, molestie vel, gravida in, condimentum sit amet, nunc. Nam a nibh. Donec suscipit eros. Nam mi. Proin viverra leo ut odio. Curabitur malesuada. Vestibulum a velit eu ante scelerisque vulputate.

    -
    -

    Section 2

    -
    -

    Sed non urna. Donec et ante. Phasellus eu ligula. Vestibulum sit amet purus. Vivamus hendrerit, dolor at aliquet laoreet, mauris turpis porttitor velit, faucibus interdum tellus libero ac justo. Vivamus non quam. In suscipit faucibus urna.

    -
    -

    Section 3

    -
    -

    Nam enim risus, molestie et, porta ac, aliquam ac, risus. Quisque lobortis. Phasellus pellentesque purus in massa. Aenean in pede. Phasellus ac libero ac tellus pellentesque semper. Sed ac felis. Sed commodo, magna quis lacinia ornare, quam ante aliquam nisi, eu iaculis leo purus venenatis dui.

    -
      -
    • List item one
    • -
    • List item two
    • -
    • List item three
    • -
    -
    -

    Section 4

    -
    -

    Cras dictum. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Aenean lacinia mauris vel est.

    Suspendisse eu nisl. Nullam ut libero. Integer dignissim consequat lectus. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos.

    -
    -
    - -
    - - - -
    - -

    Toggle sections open/closed on mouseover with the event option. The default value for event is "click."

    - -
    - - - diff --git a/demos/accordion/no-auto-height.html b/demos/accordion/no-auto-height.html index 5cd89c61ca1..b12598553c8 100644 --- a/demos/accordion/no-auto-height.html +++ b/demos/accordion/no-auto-height.html @@ -1,37 +1,30 @@ - + - - jQuery UI Accordion - No Auto Height - - - - - - - + -
    -
    -

    Section 1

    +

    Section 1

    Mauris mauris ante, blandit et, ultrices a, susceros. Nam mi. Proin viverra leo ut odio. Curabitur malesuada. Vestibulum a velit eu ante scelerisque vulputate.

    -

    Section 2

    +

    Section 2

    Sed non urna. Donec et ante. Phasellus eu ligula. Vestibulum sit amet purus. Vivamus hendrerit, dolor at aliquet laoreet, mauris turpis porttitor velit, faucibus interdum tellus libero ac justo. Vivamus non quam. In suscipit faucibus urna.

    -

    Section 3

    +

    Section 3

    Nam enim risus, molestie et, porta ac, aliquam ac, risus. Quisque lobortis. Phasellus pellentesque purus in massa. Aenean in pede. Phasellus ac libero ac tellus pellentesque semper. Sed ac felis. Sed commodo, magna quis lacinia ornare, quam ante aliquam nisi, eu iaculis leo purus venenatis dui.

      @@ -43,21 +36,11 @@

      Section 3

    • List item
    • List item
    - Link to other content
    -
    - - -
    - -

    Setting autoHeight: false allows to accordion panels to keep their native height.

    - -

    In addition, the navigation option is enabled, opening the panel based on the current location, eg. no-auto-height.html#panel2 would open the second panel on page load. It also finds anchors within the content, so #othercontent will open the third section, as it contains a link with that href.

    - -
    - +

    Setting heightStyle: "content" allows the accordion panels to keep their native height.

    +
    diff --git a/demos/accordion/sortable.html b/demos/accordion/sortable.html index 80487290f09..dfd06c5116a 100644 --- a/demos/accordion/sortable.html +++ b/demos/accordion/sortable.html @@ -1,57 +1,48 @@ - + - + + jQuery UI Accordion - Sortable - - - - - - - - - + -
    -
    -
    -

    Section 1

    +
    +

    Section 1

    Mauris mauris ante, blandit et, ultrices a, suscipit eget, quam. Integer ut neque. Vivamus nisi metus, molestie vel, gravida in, condimentum sit amet, nunc. Nam a nibh. Donec suscipit eros. Nam mi. Proin viverra leo ut odio. Curabitur malesuada. Vestibulum a velit eu ante scelerisque vulputate.

    -
    -

    Section 2

    +
    +

    Section 2

    Sed non urna. Donec et ante. Phasellus eu ligula. Vestibulum sit amet purus. Vivamus hendrerit, dolor at aliquet laoreet, mauris turpis porttitor velit, faucibus interdum tellus libero ac justo. Vivamus non quam. In suscipit faucibus urna.

    -
    -

    Section 3

    +
    +

    Section 3

    Nam enim risus, molestie et, porta ac, aliquam ac, risus. Quisque lobortis. Phasellus pellentesque purus in massa. Aenean in pede. Phasellus ac libero ac tellus pellentesque semper. Sed ac felis. Sed commodo, magna quis lacinia ornare, quam ante aliquam nisi, eu iaculis leo purus venenatis dui.

    -
    -

    Section 4

    +
    +

    Section 4

    Cras dictum. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Aenean lacinia mauris vel est.

    Suspendisse eu nisl. Nullam ut libero. Integer dignissim consequat lectus. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos.

    -
    - - -
    -

    Drag the header to re-order panels.

    - -
    - +
    diff --git a/demos/addClass/default.html b/demos/addClass/default.html deleted file mode 100644 index 1bb33b362f6..00000000000 --- a/demos/addClass/default.html +++ /dev/null @@ -1,52 +0,0 @@ - - - - - jQuery UI Effects - addClass Demo - - - - - - - - - -
    - -
    -
    - Etiam libero neque, luctus a, eleifend nec, semper at, lorem. Sed pede. -
    -
    - -Run Effect - -
    - -
    - -

    This demo adds a class which animates: text-indent, letter-spacing, width, height, padding, margin, and font-size.

    - -
    - - - diff --git a/demos/addClass/index.html b/demos/addClass/index.html deleted file mode 100644 index 0e9af371fea..00000000000 --- a/demos/addClass/index.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - - jQuery UI Effects Demos - - - - -
    -

    Examples

    - -
    - - - diff --git a/demos/animate/default.html b/demos/animate/default.html deleted file mode 100644 index 21afff719d6..00000000000 --- a/demos/animate/default.html +++ /dev/null @@ -1,53 +0,0 @@ - - - - - jQuery UI Effects - Animate Demo - - - - - - - - - -
    - -
    -
    -

    Animate

    -

    - Etiam libero neque, luctus a, eleifend nec, semper at, lorem. Sed pede. Nulla lorem metus, adipiscing ut, luctus sed, hendrerit vitae, mi. -

    -
    -
    - -Toggle Effect - -
    - -
    - -

    Click the button above to preview the effect.

    - -
    - - - diff --git a/demos/animate/index.html b/demos/animate/index.html deleted file mode 100644 index 0e9af371fea..00000000000 --- a/demos/animate/index.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - - jQuery UI Effects Demos - - - - -
    -

    Examples

    - -
    - - - diff --git a/demos/autocomplete/categories.html b/demos/autocomplete/categories.html index bb59bf31e89..1046988a966 100644 --- a/demos/autocomplete/categories.html +++ b/demos/autocomplete/categories.html @@ -1,40 +1,42 @@ - + - - jQuery UI Autocomplete Custom Data Demo - - - - - - - - - - + -
    - - -
    + +
    -

    - A categorized search result. Try typing "a" or "n". -

    -
    - +

    A categorized search result. Try typing "a" or "n".

    +
    diff --git a/demos/autocomplete/combobox.html b/demos/autocomplete/combobox.html index 3001f7d1785..afe30134906 100644 --- a/demos/autocomplete/combobox.html +++ b/demos/autocomplete/combobox.html @@ -1,128 +1,200 @@ - + - - jQuery UI Autocomplete Combobox Demo - - - - - - - - - - + - -
    -
    -
    -

    -A custom widget built by composition of Autocomplete and Button. You can either type something into the field to get filtered suggestions based on your input, or use the button to get the full list of selections. -

    -

    -The input is read from an existing select-element for progressive enhancement, passed to Autocomplete with a customized source-option. -

    -
    - +

    A custom widget built by composition of Autocomplete and Button. You can either type something into the field to get filtered suggestions based on your input, or use the button to get the full list of selections.

    +

    The input is read from an existing select-element for progressive enhancement, passed to Autocomplete with a customized source-option.

    +

    This is not a supported or even complete widget. Its purely for demoing what autocomplete can do with a bit of customization. For a detailed explanation of how the widget works, check out this Learning jQuery article.

    +
    diff --git a/demos/autocomplete/custom-data.html b/demos/autocomplete/custom-data.html index 139b41d9988..149d7cbc50b 100644 --- a/demos/autocomplete/custom-data.html +++ b/demos/autocomplete/custom-data.html @@ -1,16 +1,12 @@ - + - - jQuery UI Autocomplete Custom Data Demo - - - - - - - - - + -
    -
    Select a project (type "j" for a start):
    - - - -

    -
    +
    Select a project (type "j" for a start):
    + + + +

    -

    -You can use your own custom data formats and displays by simply overriding the default focus and select actions. -

    -

    -Try typing "j" to get a list of projects or just press the down arrow. -

    -
    - +

    You can use your own custom data formats and displays by simply overriding the default focus and select actions.

    +

    Try typing "j" to get a list of projects or just press the down arrow.

    +
    diff --git a/demos/autocomplete/default.html b/demos/autocomplete/default.html index d78b0576cd6..21fd8a2683c 100644 --- a/demos/autocomplete/default.html +++ b/demos/autocomplete/default.html @@ -1,43 +1,52 @@ - + - - jQuery UI Autocomplete Default Demo - - - - - - - - + - -
    - +
    -
    -
    -

    -The Autocomplete widgets provides suggestions while you type into the field. Here the suggestions are tags for programming languages, give "ja" (for Java or JavaScript) a try. -

    -

    -The datasource is a simple JavaScript array, provided to the widget using the source-option. -

    -
    - +

    The Autocomplete widgets provides suggestions while you type into the field. Here the suggestions are tags for programming languages, give "ja" (for Java or JavaScript) a try.

    +

    The datasource is a simple JavaScript array, provided to the widget using the source-option.

    + diff --git a/demos/autocomplete/folding.html b/demos/autocomplete/folding.html index d5bc71e9df7..b5833e429f1 100644 --- a/demos/autocomplete/folding.html +++ b/demos/autocomplete/folding.html @@ -1,25 +1,21 @@ - + - - jQuery UI Autocomplete Accent Folding Demo - - - - - - - - + -
    -
    - +
    -
    -
    -

    -The autocomplete field uses a custom source option which will match results that have accented characters even when the text field doesn't contain accented characters. However if the you type in accented characters in the text field it is smart enough not to show results that aren't accented. -

    -

    -Try typing "Jo" to see "John" and "Jörn", then type "Jö" to see only "Jörn". -

    -
    - +

    The autocomplete field uses a custom source option which will match results that have accented characters even when the text field doesn't contain accented characters. However if the you type in accented characters in the text field it is smart enough not to show results that aren't accented.

    +

    Try typing "Jo" to see "John" and "Jörn", then type "Jö" to see only "Jörn".

    + diff --git a/demos/autocomplete/images/jquery_32x32.png b/demos/autocomplete/images/jquery_32x32.png new file mode 100644 index 00000000000..6f356f3abcd Binary files /dev/null and b/demos/autocomplete/images/jquery_32x32.png differ diff --git a/demos/autocomplete/images/jqueryui_32x32.png b/demos/autocomplete/images/jqueryui_32x32.png new file mode 100644 index 00000000000..8dd0cf7cc62 Binary files /dev/null and b/demos/autocomplete/images/jqueryui_32x32.png differ diff --git a/demos/autocomplete/images/sizzlejs_32x32.png b/demos/autocomplete/images/sizzlejs_32x32.png new file mode 100644 index 00000000000..f5d8e2a0447 Binary files /dev/null and b/demos/autocomplete/images/sizzlejs_32x32.png differ diff --git a/demos/autocomplete/images/transparent_1x1.png b/demos/autocomplete/images/transparent_1x1.png new file mode 100644 index 00000000000..ac576dd6ed1 Binary files /dev/null and b/demos/autocomplete/images/transparent_1x1.png differ diff --git a/demos/autocomplete/images/ui-anim_basic_16x16.gif b/demos/autocomplete/images/ui-anim_basic_16x16.gif new file mode 100644 index 00000000000..084ecb879b9 Binary files /dev/null and b/demos/autocomplete/images/ui-anim_basic_16x16.gif differ diff --git a/demos/autocomplete/index.html b/demos/autocomplete/index.html index ba96d994e00..03f80c8fa79 100644 --- a/demos/autocomplete/index.html +++ b/demos/autocomplete/index.html @@ -1,25 +1,26 @@ - + - + + jQuery UI Autocomplete Demos - - + + + diff --git a/demos/autocomplete/maxheight.html b/demos/autocomplete/maxheight.html new file mode 100644 index 00000000000..b8c59819d63 --- /dev/null +++ b/demos/autocomplete/maxheight.html @@ -0,0 +1,59 @@ + + + + + + jQuery UI Autocomplete - Scrollable results + + + + + + + + +
    + + +
    + +
    +

    When displaying a long list of options, you can simply set the max-height for the autocomplete menu to prevent the menu from growing too large. Try typing "a" or "s" above to get a long list of results that you can scroll through.

    +
    + + diff --git a/demos/autocomplete/multiple-remote.html b/demos/autocomplete/multiple-remote.html index 2046db61452..89e32499bd6 100644 --- a/demos/autocomplete/multiple-remote.html +++ b/demos/autocomplete/multiple-remote.html @@ -1,82 +1,75 @@ - + - - jQuery UI Autocomplete multiple demo - - - - - - - - + + -
    -
    - +
    -
    -
    -

    -Usage: Enter at least two characters to get bird name suggestions. Select a value to continue adding more names. -

    -

    -This is an example showing how to use the source-option along with some events to enable autocompleting multiple values into a single field. -

    -
    - +

    Usage: Enter at least two characters to get bird name suggestions. Select a value to continue adding more names.

    +

    This is an example showing how to use the source-option along with some events to enable autocompleting multiple values into a single field.

    + diff --git a/demos/autocomplete/multiple.html b/demos/autocomplete/multiple.html index d8cb7e403af..829af15cef4 100644 --- a/demos/autocomplete/multiple.html +++ b/demos/autocomplete/multiple.html @@ -1,76 +1,87 @@ - + - - jQuery UI Autocomplete multiple demo - - - - - - - - + -
    -
    - +
    -
    -
    -

    -Usage: Type something, eg. "j" to see suggestions for tagging with programming languages. Select a value, then continue typing to add more. -

    -

    -This is an example showing how to use the source-option along with some events to enable autocompleting multiple values into a single field. -

    -
    - +

    Usage: Type something, eg. "j" to see suggestions for tagging with programming languages. Select a value, then continue typing to add more.

    +

    This is an example showing how to use the source-option along with some events to enable autocompleting multiple values into a single field.

    + diff --git a/demos/autocomplete/remote-jsonp.html b/demos/autocomplete/remote-jsonp.html index ab8a600a807..9962f895dd0 100644 --- a/demos/autocomplete/remote-jsonp.html +++ b/demos/autocomplete/remote-jsonp.html @@ -1,69 +1,49 @@ - + - - jQuery UI Autocomplete Remote JSONP datasource demo - - - - - - - - + - + -
    -
    - - - Powered by geonames.org + +
    @@ -71,16 +51,9 @@
    -
    -
    -

    -The Autocomplete widgets provides suggestions while you type into the field. Here the suggestions are cities, displayed when at least two characters are entered into the field. -

    -

    -In this case, the datasource is the geonames.org webservice. While only the city name itself ends up in the input after selecting an element, more info is displayed in the suggestions to help find the right entry. That data is also available in callbacks, as illustrated by the Result area below the input. -

    -
    - +

    The Autocomplete widgets provides suggestions while you type into the field. Here the suggestions are bird names, displayed when at least two characters are entered into the field.

    +

    The datasource is a server-side script which returns JSONP data, specified via a function which uses jQuery.ajax() for the source option.

    + diff --git a/demos/autocomplete/remote-with-cache.html b/demos/autocomplete/remote-with-cache.html index b7f68817510..610e74f11f0 100644 --- a/demos/autocomplete/remote-with-cache.html +++ b/demos/autocomplete/remote-with-cache.html @@ -1,59 +1,47 @@ - + - - jQuery UI Autocomplete Remote with caching demo - - - - - - - - + + -
    -
    - +
    -
    -
    -

    -The Autocomplete widgets provides suggestions while you type into the field. Here the suggestions are bird names, displayed when at least two characters are entered into the field. -

    -

    -Similar to the remote datasource demo, though this adds some local caching to improve performance. The cache here saves just one query, and could be extended to cache multiple values, one for each term. -

    -
    - +

    The Autocomplete widgets provides suggestions while you type into the field. Here the suggestions are bird names, displayed when at least two characters are entered into the field.

    +

    Similar to the remote datasource demo, though this adds some local caching to improve performance. The cache here saves just one query, and could be extended to cache multiple values, one for each term.

    + diff --git a/demos/autocomplete/remote.html b/demos/autocomplete/remote.html index 9414102e68c..c9e366aec3f 100644 --- a/demos/autocomplete/remote.html +++ b/demos/autocomplete/remote.html @@ -1,39 +1,38 @@ - + - - jQuery UI Autocomplete Remote datasource demo - - - - - - - - + + -
    -
    - +
    @@ -41,16 +40,9 @@
    -
    -
    -

    -The Autocomplete widgets provides suggestions while you type into the field. Here the suggestions are bird names, displayed when at least two characters are entered into the field. -

    -

    -The datasource is a server-side script which returns JSON data, specified via a simple URL for the source-option. In addition, the minLength-option is set to 2 to avoid queries that would return too many results and the select-event is used to display some feedback. -

    -
    - +

    The Autocomplete widgets provides suggestions while you type into the field. Here the suggestions are bird names, displayed when at least two characters are entered into the field.

    +

    The datasource is a server-side script which returns JSON data, specified via a simple URL for the source-option. In addition, the minLength-option is set to 2 to avoid queries that would return too many results and the select-event is used to display some feedback.

    + diff --git a/demos/autocomplete/search.php b/demos/autocomplete/search.php deleted file mode 100644 index 01206489a13..00000000000 --- a/demos/autocomplete/search.php +++ /dev/null @@ -1,640 +0,0 @@ -Bittern"=>"Botaurus stellaris", -"Little Grebe"=>"Tachybaptus ruficollis", -"Black-necked Grebe"=>"Podiceps nigricollis", -"Little Bittern"=>"Ixobrychus minutus", -"Black-crowned Night Heron"=>"Nycticorax nycticorax", -"Purple Heron"=>"Ardea purpurea", -"White Stork"=>"Ciconia ciconia", -"Spoonbill"=>"Platalea leucorodia", -"Red-crested Pochard"=>"Netta rufina", -"Common Eider"=>"Somateria mollissima", -"Red Kite"=>"Milvus milvus", -"Hen Harrier"=>"Circus cyaneus", -"Montagu`s Harrier"=>"Circus pygargus", -"Black Grouse"=>"Tetrao tetrix", -"Grey Partridge"=>"Perdix perdix", -"Spotted Crake"=>"Porzana porzana", -"Corncrake"=>"Crex crex", -"Common Crane"=>"Grus grus", -"Avocet"=>"Recurvirostra avosetta", -"Stone Curlew"=>"Burhinus oedicnemus", -"Common Ringed Plover"=>"Charadrius hiaticula", -"Kentish Plover"=>"Charadrius alexandrinus", -"Ruff"=>"Philomachus pugnax", -"Common Snipe"=>"Gallinago gallinago", -"Black-tailed Godwit"=>"Limosa limosa", -"Common Redshank"=>"Tringa totanus", -"Sandwich Tern"=>"Sterna sandvicensis", -"Common Tern"=>"Sterna hirundo", -"Arctic Tern"=>"Sterna paradisaea", -"Little Tern"=>"Sternula albifrons", -"Black Tern"=>"Chlidonias niger", -"Barn Owl"=>"Tyto alba", -"Little Owl"=>"Athene noctua", -"Short-eared Owl"=>"Asio flammeus", -"European Nightjar"=>"Caprimulgus europaeus", -"Common Kingfisher"=>"Alcedo atthis", -"Eurasian Hoopoe"=>"Upupa epops", -"Eurasian Wryneck"=>"Jynx torquilla", -"European Green Woodpecker"=>"Picus viridis", -"Crested Lark"=>"Galerida cristata", -"White-headed Duck"=>"Oxyura leucocephala", -"Pale-bellied Brent Goose"=>"Branta hrota", -"Tawny Pipit"=>"Anthus campestris", -"Whinchat"=>"Saxicola rubetra", -"European Stonechat"=>"Saxicola rubicola", -"Northern Wheatear"=>"Oenanthe oenanthe", -"Savi`s Warbler"=>"Locustella luscinioides", -"Sedge Warbler"=>"Acrocephalus schoenobaenus", -"Great Reed Warbler"=>"Acrocephalus arundinaceus", -"Bearded Reedling"=>"Panurus biarmicus", -"Red-backed Shrike"=>"Lanius collurio", -"Great Grey Shrike"=>"Lanius excubitor", -"Woodchat Shrike"=>"Lanius senator", -"Common Raven"=>"Corvus corax", -"Yellowhammer"=>"Emberiza citrinella", -"Ortolan Bunting"=>"Emberiza hortulana", -"Corn Bunting"=>"Emberiza calandra", -"Great Cormorant"=>"Phalacrocorax carbo", -"Hawfinch"=>"Coccothraustes coccothraustes", -"Common Shelduck"=>"Tadorna tadorna", -"Bluethroat"=>"Luscinia svecica", -"Grey Heron"=>"Ardea cinerea", -"Barn Swallow"=>"Hirundo rustica", -"Hooded Crow"=>"Corvus cornix", -"Dunlin"=>"Calidris alpina", -"Eurasian Pied Flycatcher"=>"Ficedula hypoleuca", -"Eurasian Nuthatch"=>"Sitta europaea", -"Short-toed Tree Creeper"=>"Certhia brachydactyla", -"Wood Lark"=>"Lullula arborea", -"Tree Pipit"=>"Anthus trivialis", -"Eurasian Hobby"=>"Falco subbuteo", -"Marsh Warbler"=>"Acrocephalus palustris", -"Wood Sandpiper"=>"Tringa glareola", -"Tawny Owl"=>"Strix aluco", -"Lesser Whitethroat"=>"Sylvia curruca", -"Barnacle Goose"=>"Branta leucopsis", -"Common Goldeneye"=>"Bucephala clangula", -"Western Marsh Harrier"=>"Circus aeruginosus", -"Common Buzzard"=>"Buteo buteo", -"Sanderling"=>"Calidris alba", -"Little Gull"=>"Larus minutus", -"Eurasian Magpie"=>"Pica pica", -"Willow Warbler"=>"Phylloscopus trochilus", -"Wood Warbler"=>"Phylloscopus sibilatrix", -"Great Crested Grebe"=>"Podiceps cristatus", -"Eurasian Jay"=>"Garrulus glandarius", -"Common Redstart"=>"Phoenicurus phoenicurus", -"Blue-headed Wagtail"=>"Motacilla flava", -"Common Swift"=>"Apus apus", -"Marsh Tit"=>"Poecile palustris", -"Goldcrest"=>"Regulus regulus", -"European Golden Plover"=>"Pluvialis apricaria", -"Eurasian Bullfinch"=>"Pyrrhula pyrrhula", -"Common Whitethroat"=>"Sylvia communis", -"Meadow Pipit"=>"Anthus pratensis", -"Greylag Goose"=>"Anser anser", -"Spotted Flycatcher"=>"Muscicapa striata", -"European Greenfinch"=>"Carduelis chloris", -"Common Greenshank"=>"Tringa nebularia", -"Great Spotted Woodpecker"=>"Dendrocopos major", -"Greater Canada Goose"=>"Branta canadensis", -"Mistle Thrush"=>"Turdus viscivorus", -"Great Black-backed Gull"=>"Larus marinus", -"Goosander"=>"Mergus merganser", -"Great Egret"=>"Casmerodius albus", -"Northern Goshawk"=>"Accipiter gentilis", -"Dunnock"=>"Prunella modularis", -"Stock Dove"=>"Columba oenas", -"Common Wood Pigeon"=>"Columba palumbus", -"Eurasian Woodcock"=>"Scolopax rusticola", -"House Sparrow"=>"Passer domesticus", -"Common House Martin"=>"Delichon urbicum", -"Red Knot"=>"Calidris canutus", -"Western Jackdaw"=>"Corvus monedula", -"Brambling"=>"Fringilla montifringilla", -"Northern Lapwing"=>"Vanellus vanellus", -"European Reed Warbler"=>"Acrocephalus scirpaceus", -"Lesser Black-backed Gull"=>"Larus fuscus", -"Little Egret"=>"Egretta garzetta", -"Little Stint"=>"Calidris minuta", -"Common Linnet"=>"Carduelis cannabina", -"Mute Swan"=>"Cygnus olor", -"Common Cuckoo"=>"Cuculus canorus", -"Black-headed Gull"=>"Larus ridibundus", -"Greater White-fronted Goose"=>"Anser albifrons", -"Great Tit"=>"Parus major", -"Redwing"=>"Turdus iliacus", -"Gadwall"=>"Anas strepera", -"Fieldfare"=>"Turdus pilaris", -"Tufted Duck"=>"Aythya fuligula", -"Crested Tit"=>"Lophophanes cristatus", -"Willow Tit"=>"Poecile montanus", -"Eurasian Coot"=>"Fulica atra", -"Common Blackbird"=>"Turdus merula", -"Smew"=>"Mergus albellus", -"Common Sandpiper"=>"Actitis hypoleucos", -"Sand Martin"=>"Riparia riparia", -"Purple Sandpiper"=>"Calidris maritima", -"Northern Pintail"=>"Anas acuta", -"Blue Tit"=>"Cyanistes caeruleus", -"European Goldfinch"=>"Carduelis carduelis", -"Eurasian Whimbrel"=>"Numenius phaeopus", -"Common Reed Bunting"=>"Emberiza schoeniclus", -"Eurasian Tree Sparrow"=>"Passer montanus", -"Rook"=>"Corvus frugilegus", -"European Robin"=>"Erithacus rubecula", -"Bar-tailed Godwit"=>"Limosa lapponica", -"Dark-bellied Brent Goose"=>"Branta bernicla", -"Eurasian Oystercatcher"=>"Haematopus ostralegus", -"Eurasian Siskin"=>"Carduelis spinus", -"Northern Shoveler"=>"Anas clypeata", -"Eurasian Wigeon"=>"Anas penelope", -"Eurasian Sparrow Hawk"=>"Accipiter nisus", -"Icterine Warbler"=>"Hippolais icterina", -"Common Starling"=>"Sturnus vulgaris", -"Long-tailed Tit"=>"Aegithalos caudatus", -"Ruddy Turnstone"=>"Arenaria interpres", -"Mew Gull"=>"Larus canus", -"Common Pochard"=>"Aythya ferina", -"Common Chiffchaff"=>"Phylloscopus collybita", -"Greater Scaup"=>"Aythya marila", -"Common Kestrel"=>"Falco tinnunculus", -"Garden Warbler"=>"Sylvia borin", -"Eurasian Collared Dove"=>"Streptopelia decaocto", -"Eurasian Skylark"=>"Alauda arvensis", -"Common Chaffinch"=>"Fringilla coelebs", -"Common Moorhen"=>"Gallinula chloropus", -"Water Pipit"=>"Anthus spinoletta", -"Mallard"=>"Anas platyrhynchos", -"Winter Wren"=>"Troglodytes troglodytes", -"Common Teal"=>"Anas crecca", -"Green Sandpiper"=>"Tringa ochropus", -"White Wagtail"=>"Motacilla alba", -"Eurasian Curlew"=>"Numenius arquata", -"Song Thrush"=>"Turdus philomelos", -"European Herring Gull"=>"Larus argentatus", -"Grey Plover"=>"Pluvialis squatarola", -"Carrion Crow"=>"Corvus corone", -"Coal Tit"=>"Periparus ater", -"Spotted Redshank"=>"Tringa erythropus", -"Blackcap"=>"Sylvia atricapilla", -"Egyptian Vulture"=>"Neophron percnopterus", -"Razorbill"=>"Alca torda", -"Alpine Swift"=>"Apus melba", -"Long-legged Buzzard"=>"Buteo rufinus", -"Audouin`s Gull"=>"Larus audouinii", -"Balearic Shearwater"=>"Puffinus mauretanicus", -"Upland Sandpiper"=>"Bartramia longicauda", -"Greater Spotted Eagle"=>"Aquila clanga", -"Ring Ouzel"=>"Turdus torquatus", -"Yellow-browed Warbler"=>"Phylloscopus inornatus", -"Blue Rock Thrush"=>"Monticola solitarius", -"Buff-breasted Sandpiper"=>"Tryngites subruficollis", -"Jack Snipe"=>"Lymnocryptes minimus", -"White-rumped Sandpiper"=>"Calidris fuscicollis", -"Ruddy Shelduck"=>"Tadorna ferruginea", -"Cetti's Warbler"=>"Cettia cetti", -"Citrine Wagtail"=>"Motacilla citreola", -"Roseate Tern"=>"Sterna dougallii", -"Black-legged Kittiwake"=>"Rissa tridactyla", -"Pygmy Cormorant"=>"Phalacrocorax pygmeus", -"Booted Eagle"=>"Aquila pennata", -"Lesser White-fronted Goose"=>"Anser erythropus", -"Little Bunting"=>"Emberiza pusilla", -"Eleonora's Falcon"=>"Falco eleonorae", -"European Serin"=>"Serinus serinus", -"Twite"=>"Carduelis flavirostris", -"Yellow-legged Gull"=>"Larus michahellis", -"Gyr Falcon"=>"Falco rusticolus", -"Greenish Warbler"=>"Phylloscopus trochiloides", -"Red-necked Phalarope"=>"Phalaropus lobatus", -"Mealy Redpoll"=>"Carduelis flammea", -"Glaucous Gull"=>"Larus hyperboreus", -"Great Skua"=>"Stercorarius skua", -"Great Bustard"=>"Otis tarda", -"Velvet Scoter"=>"Melanitta fusca", -"Pine Grosbeak"=>"Pinicola enucleator", -"House Crow"=>"Corvus splendens", -"Hume`s Leaf Warbler"=>"Phylloscopus humei", -"Great Northern Loon"=>"Gavia immer", -"Long-tailed Duck"=>"Clangula hyemalis", -"Lapland Longspur"=>"Calcarius lapponicus", -"Northern Gannet"=>"Morus bassanus", -"Eastern Imperial Eagle"=>"Aquila heliaca", -"Little Auk"=>"Alle alle", -"Lesser Spotted Woodpecker"=>"Dendrocopos minor", -"Iceland Gull"=>"Larus glaucoides", -"Parasitic Jaeger"=>"Stercorarius parasiticus", -"Bewick`s Swan"=>"Cygnus bewickii", -"Little Bustard"=>"Tetrax tetrax", -"Little Crake"=>"Porzana parva", -"Baillon`s Crake"=>"Porzana pusilla", -"Long-tailed Jaeger"=>"Stercorarius longicaudus", -"King Eider"=>"Somateria spectabilis", -"Greater Short-toed Lark"=>"Calandrella brachydactyla", -"Houbara Bustard"=>"Chlamydotis undulata", -"Curlew Sandpiper"=>"Calidris ferruginea", -"Common Crossbill"=>"Loxia curvirostra", -"European Shag"=>"Phalacrocorax aristotelis", -"Horned Grebe"=>"Podiceps auritus", -"Common Quail"=>"Coturnix coturnix", -"Bearded Vulture"=>"Gypaetus barbatus", -"Lanner Falcon"=>"Falco biarmicus", -"Middle Spotted Woodpecker"=>"Dendrocopos medius", -"Pomarine Jaeger"=>"Stercorarius pomarinus", -"Red-breasted Merganser"=>"Mergus serrator", -"Eurasian Black Vulture"=>"Aegypius monachus", -"Eurasian Dotterel"=>"Charadrius morinellus", -"Common Nightingale"=>"Luscinia megarhynchos", -"Northern willow warbler"=>"Phylloscopus trochilus acredula", -"Manx Shearwater"=>"Puffinus puffinus", -"Northern Fulmar"=>"Fulmarus glacialis", -"Eurasian Eagle Owl"=>"Bubo bubo", -"Orphean Warbler"=>"Sylvia hortensis", -"Melodious Warbler"=>"Hippolais polyglotta", -"Pallas's Leaf Warbler"=>"Phylloscopus proregulus", -"Atlantic Puffin"=>"Fratercula arctica", -"Black-throated Loon"=>"Gavia arctica", -"Bohemian Waxwing"=>"Bombycilla garrulus", -"Marsh Sandpiper"=>"Tringa stagnatilis", -"Great Snipe"=>"Gallinago media", -"Squacco Heron"=>"Ardeola ralloides", -"Long-eared Owl"=>"Asio otus", -"Caspian Tern"=>"Hydroprogne caspia", -"Red-breasted Goose"=>"Branta ruficollis", -"Red-throated Loon"=>"Gavia stellata", -"Common Rosefinch"=>"Carpodacus erythrinus", -"Red-footed Falcon"=>"Falco vespertinus", -"Ross's Goose"=>"Anser rossii", -"Red Phalarope"=>"Phalaropus fulicarius", -"Pied Wagtail"=>"Motacilla yarrellii", -"Rose-coloured Starling"=>"Sturnus roseus", -"Rough-legged Buzzard"=>"Buteo lagopus", -"Saker Falcon"=>"Falco cherrug", -"European Roller"=>"Coracias garrulus", -"Short-toed Eagle"=>"Circaetus gallicus", -"Peregrine Falcon"=>"Falco peregrinus", -"Merlin"=>"Falco columbarius", -"Snow Goose"=>"Anser caerulescens", -"Snowy Owl"=>"Bubo scandiacus", -"Snow Bunting"=>"Plectrophenax nivalis", -"Common Grasshopper Warbler"=>"Locustella naevia", -"Golden Eagle"=>"Aquila chrysaetos", -"Black-winged Stilt"=>"Himantopus himantopus", -"Steppe Eagle"=>"Aquila nipalensis", -"Pallid Harrier"=>"Circus macrourus", -"European Storm-petrel"=>"Hydrobates pelagicus", -"Horned Lark"=>"Eremophila alpestris", -"Eurasian Treecreeper"=>"Certhia familiaris", -"Taiga Bean Goose"=>"Anser fabalis", -"Temminck`s Stint"=>"Calidris temminckii", -"Terek Sandpiper"=>"Xenus cinereus", -"Tundra Bean Goose"=>"Anser serrirostris", -"European Turtle Dove"=>"Streptopelia turtur", -"Leach`s Storm-petrel"=>"Oceanodroma leucorhoa", -"Eurasian Griffon Vulture"=>"Gyps fulvus", -"Paddyfield Warbler"=>"Acrocephalus agricola", -"Osprey"=>"Pandion haliaetus", -"Firecrest"=>"Regulus ignicapilla", -"Water Rail"=>"Rallus aquaticus", -"European Honey Buzzard"=>"Pernis apivorus", -"Eurasian Golden Oriole"=>"Oriolus oriolus", -"Whooper Swan"=>"Cygnus cygnus", -"Two-barred Crossbill"=>"Loxia leucoptera", -"White-tailed Eagle"=>"Haliaeetus albicilla", -"Atlantic Murre"=>"Uria aalge", -"Garganey"=>"Anas querquedula", -"Black Redstart"=>"Phoenicurus ochruros", -"Common Scoter"=>"Melanitta nigra", -"Rock Pipit"=>"Anthus petrosus", -"Lesser Spotted Eagle"=>"Aquila pomarina", -"Cattle Egret"=>"Bubulcus ibis", -"White-winged Black Tern"=>"Chlidonias leucopterus", -"Black Stork"=>"Ciconia nigra", -"Mediterranean Gull"=>"Larus melanocephalus", -"Black Kite"=>"Milvus migrans", -"Yellow Wagtail"=>"Motacilla flavissima", -"Red-necked Grebe"=>"Podiceps grisegena", -"Gull-billed Tern"=>"Gelochelidon nilotica", -"Pectoral Sandpiper"=>"Calidris melanotos", -"Barred Warbler"=>"Sylvia nisoria", -"Red-throated Pipit"=>"Anthus cervinus", -"Grey Wagtail"=>"Motacilla cinerea", -"Richard`s Pipit"=>"Anthus richardi", -"Black Woodpecker"=>"Dryocopus martius", -"Little Ringed Plover"=>"Charadrius dubius", -"Whiskered Tern"=>"Chlidonias hybrida", -"Lesser Redpoll"=>"Carduelis cabaret", -"Pallas' Bunting"=>"Emberiza pallasi", -"Ferruginous Duck"=>"Aythya nyroca", -"Whistling Swan"=>"Cygnus columbianus", -"Black Brant"=>"Branta nigricans", -"Marbled Teal"=>"Marmaronetta angustirostris", -"Canvasback"=>"Aythya valisineria", -"Redhead"=>"Aythya americana", -"Lesser Scaup"=>"Aythya affinis", -"Steller`s Eider"=>"Polysticta stelleri", -"Spectacled Eider"=>"Somateria fischeri", -"Harlequin Duck"=>"Histronicus histrionicus", -"Black Scoter"=>"Melanitta americana", -"Surf Scoter"=>"Melanitta perspicillata", -"Barrow`s Goldeneye"=>"Bucephala islandica", -"Falcated Duck"=>"Anas falcata", -"American Wigeon"=>"Anas americana", -"Blue-winged Teal"=>"Anas discors", -"American Black Duck"=>"Anas rubripes", -"Baikal Teal"=>"Anas formosa", -"Green-Winged Teal"=>"Anas carolinensis", -"Hazel Grouse"=>"Bonasa bonasia", -"Rock Partridge"=>"Alectoris graeca", -"Red-legged Partridge"=>"Alectoris rufa", -"Yellow-billed Loon"=>"Gavia adamsii", -"Cory`s Shearwater"=>"Calonectris borealis", -"Madeiran Storm-Petrel"=>"Oceanodroma castro", -"Great White Pelican"=>"Pelecanus onocrotalus", -"Dalmatian Pelican"=>"Pelecanus crispus", -"American Bittern"=>"Botaurus lentiginosus", -"Glossy Ibis"=>"Plegadis falcinellus", -"Spanish Imperial Eagle"=>"Aquila adalberti", -"Lesser Kestrel"=>"Falco naumanni", -"Houbara Bustard"=>"Chlamydotis undulata", -"Crab-Plover"=>"Dromas ardeola", -"Cream-coloured Courser"=>"Cursorius cursor", -"Collared Pratincole"=>"Glareola pratincola", -"Black-winged Pratincole"=>"Glareola nordmanni", -"Killdeer"=>"Charadrius vociferus", -"Lesser Sand Plover"=>"Charadrius mongolus", -"Greater Sand Plover"=>"Charadrius leschenaultii", -"Caspian Plover"=>"Charadrius asiaticus", -"American Golden Plover"=>"Pluvialis dominica", -"Pacific Golden Plover"=>"Pluvialis fulva", -"Sharp-tailed Sandpiper"=>"Calidris acuminata", -"Broad-billed Sandpiper"=>"Limicola falcinellus", -"Spoon-Billed Sandpiper"=>"Eurynorhynchus pygmaeus", -"Short-Billed Dowitcher"=>"Limnodromus griseus", -"Long-billed Dowitcher"=>"Limnodromus scolopaceus", -"Hudsonian Godwit"=>"Limosa haemastica", -"Little Curlew"=>"Numenius minutus", -"Lesser Yellowlegs"=>"Tringa flavipes", -"Wilson`s Phalarope"=>"Phalaropus tricolor", -"Pallas`s Gull"=>"Larus ichthyaetus", -"Laughing Gull"=>"Larus atricilla", -"Franklin`s Gull"=>"Larus pipixcan", -"Bonaparte`s Gull"=>"Larus philadelphia", -"Ring-billed Gull"=>"Larus delawarensis", -"American Herring Gull"=>"Larus smithsonianus", -"Caspian Gull"=>"Larus cachinnans", -"Ivory Gull"=>"Pagophila eburnea", -"Royal Tern"=>"Sterna maxima", -"Brünnich`s Murre"=>"Uria lomvia", -"Crested Auklet"=>"Aethia cristatella", -"Parakeet Auklet"=>"Cyclorrhynchus psittacula", -"Tufted Puffin"=>"Lunda cirrhata", -"Laughing Dove"=>"Streptopelia senegalensis", -"Great Spotted Cuckoo"=>"Clamator glandarius", -"Great Grey Owl"=>"Strix nebulosa", -"Tengmalm`s Owl"=>"Aegolius funereus", -"Red-Necked Nightjar"=>"Caprimulgus ruficollis", -"Chimney Swift"=>"Chaetura pelagica", -"Green Bea-Eater"=>"Merops orientalis", -"Grey-headed Woodpecker"=>"Picus canus", -"Lesser Short-Toed Lark"=>"Calandrella rufescens", -"Eurasian Crag Martin"=>"Hirundo rupestris", -"Red-rumped Swallow"=>"Cecropis daurica", -"Blyth`s Pipit"=>"Anthus godlewskii", -"Pechora Pipit"=>"Anthus gustavi", -"Grey-headed Wagtail"=>"Motacilla thunbergi", -"Yellow-Headed Wagtail"=>"Motacilla lutea", -"White-throated Dipper"=>"Cinclus cinclus", -"Rufous-Tailed Scrub Robin"=>"Cercotrichas galactotes", -"Thrush Nightingale"=>"Luscinia luscinia", -"White-throated Robin"=>"Irania gutturalis", -"Caspian Stonechat"=>"Saxicola maura variegata", -"Western Black-eared Wheatear"=>"Oenanthe hispanica", -"Rufous-tailed Rock Thrush"=>"Monticola saxatilis", -"Red-throated Thrush/Black-throated"=>"Turdus ruficollis", -"American Robin"=>"Turdus migratorius", -"Zitting Cisticola"=>"Cisticola juncidis", -"Lanceolated Warbler"=>"Locustella lanceolata", -"River Warbler"=>"Locustella fluviatilis", -"Blyth`s Reed Warbler"=>"Acrocephalus dumetorum", -"Caspian Reed Warbler"=>"Acrocephalus fuscus", -"Aquatic Warbler"=>"Acrocephalus paludicola", -"Booted Warbler"=>"Acrocephalus caligatus", -"Marmora's Warbler"=>"Sylvia sarda", -"Dartford Warbler"=>"Sylvia undata", -"Subalpine Warbler"=>"Sylvia cantillans", -"Ménétries's Warbler"=>"Sylvia mystacea", -"Rüppel's Warbler"=>"Sylvia rueppelli", -"Asian Desert Warbler"=>"Sylvia nana", -"Western Orphean Warbler"=>"Sylvia hortensis hortensis", -"Arctic Warbler"=>"Phylloscopus borealis", -"Radde`s Warbler"=>"Phylloscopus schwarzi", -"Western Bonelli`s Warbler"=>"Phylloscopus bonelli", -"Red-breasted Flycatcher"=>"Ficedula parva", -"Eurasian Penduline Tit"=>"Remiz pendulinus", -"Daurian Shrike"=>"Lanius isabellinus", -"Long-Tailed Shrike"=>"Lanius schach", -"Lesser Grey Shrike"=>"Lanius minor", -"Southern Grey Shrike"=>"Lanius meridionalis", -"Masked Shrike"=>"Lanius nubicus", -"Spotted Nutcracker"=>"Nucifraga caryocatactes", -"Daurian Jackdaw"=>"Corvus dauuricus", -"Purple-Backed Starling"=>"Sturnus sturninus", -"Red-Fronted Serin"=>"Serinus pusillus", -"Arctic Redpoll"=>"Carduelis hornemanni", -"Scottish Crossbill"=>"Loxia scotica", -"Parrot Crossbill"=>"Loxia pytyopsittacus", -"Black-faced Bunting"=>"Emberiza spodocephala", -"Pink-footed Goose"=>"Anser brachyrhynchus", -"Black-winged Kite"=>"Elanus caeruleus", -"European Bee-eater"=>"Merops apiaster", -"Sabine`s Gull"=>"Larus sabini", -"Sooty Shearwater"=>"Puffinus griseus", -"Lesser Canada Goose"=>"Branta hutchinsii", -"Ring-necked Duck"=>"Aythya collaris", -"Greater Flamingo"=>"Phoenicopterus roseus", -"Iberian Chiffchaff"=>"Phylloscopus ibericus", -"Ashy-headed Wagtail"=>"Motacilla cinereocapilla", -"Stilt Sandpiper"=>"Calidris himantopus", -"Siberian Stonechat"=>"Saxicola maurus", -"Greater Yellowlegs"=>"Tringa melanoleuca", -"Forster`s Tern"=>"Sterna forsteri", -"Dusky Warbler"=>"Phylloscopus fuscatus", -"Cirl Bunting"=>"Emberiza cirlus", -"Olive-backed Pipit"=>"Anthus hodgsoni", -"Sociable Lapwing"=>"Vanellus gregarius", -"Spotted Sandpiper"=>"Actitis macularius", -"Baird`s Sandpiper"=>"Calidris bairdii", -"Rustic Bunting"=>"Emberiza rustica", -"Yellow-browed Bunting"=>"Emberiza chrysophrys", -"Great Shearwater"=>"Puffinus gravis", -"Bonelli`s Eagle"=>"Aquila fasciata", -"Calandra Lark"=>"Melanocorypha calandra", -"Sardinian Warbler"=>"Sylvia melanocephala", -"Ross's Gull"=>"Larus roseus", -"Yellow-Breasted Bunting"=>"Emberiza aureola", -"Pine Bunting"=>"Emberiza leucocephalos", -"Black Guillemot"=>"Cepphus grylle", -"Pied-billed Grebe"=>"Podilymbus podiceps", -"Soft-plumaged Petrel"=>"Pterodroma mollis", -"Bulwer's Petrel"=>"Bulweria bulwerii", -"White-Faced Storm-Petrel"=>"Pelagodroma marina", -"Pallas’s Fish Eagle"=>"Haliaeetus leucoryphus", -"Sandhill Crane"=>"Grus canadensis", -"Macqueen’s Bustard"=>"Chlamydotis macqueenii", -"White-tailed Lapwing"=>"Vanellus leucurus", -"Great Knot"=>"Calidris tenuirostris", -"Semipalmated Sandpiper"=>"Calidris pusilla", -"Red-necked Stint"=>"Calidris ruficollis", -"Slender-billed Curlew"=>"Numenius tenuirostris", -"Bridled Tern"=>"Onychoprion anaethetus", -"Pallas’s Sandgrouse"=>"Syrrhaptes paradoxus", -"European Scops Owl"=>"Otus scops", -"Northern Hawk Owl"=>"Surnia ulula", -"White-Throated Needletail"=>"Hirundapus caudacutus", -"Belted Kingfisher"=>"Ceryle alcyon", -"Blue-cheeked Bee-eater"=>"Merops persicus", -"Black-headed Wagtail"=>"Motacilla feldegg", -"Northern Mockingbird"=>"Mimus polyglottos", -"Alpine Accentor"=>"Prunella collaris", -"Red-flanked Bluetail"=>"Tarsiger cyanurus", -"Isabelline Wheatear"=>"Oenanthe isabellina", -"Pied Wheatear"=>"Oenanthe pleschanka", -"Eastern Black-eared Wheatear"=>"Oenanthe melanoleuca", -"Desert Wheatear"=>"Oenanthe deserti", -"White`s Thrush"=>"Zoothera aurea", -"Siberian Thrush"=>"Zoothera sibirica", -"Eyebrowed Thrush"=>"Turdus obscurus", -"Dusky Thrush"=>"Turdus eunomus", -"Black-throated Thrush"=>"Turdus atrogularis", -"Pallas`s Grasshopper Warbler"=>"Locustella certhiola", -"Spectacled Warbler"=>"Sylvia conspicillata", -"Two-barred Warbler"=>"Phylloscopus plumbeitarsus", -"Eastern Bonelli’s Warbler"=>"Phylloscopus orientalis", -"Collared Flycatcher"=>"Ficedula albicollis", -"Wallcreeper"=>"Tichodroma muraria", -"Turkestan Shrike"=>"Lanius phoenicuroides", -"Steppe Grey Shrike"=>"Lanius pallidirostris", -"Spanish Sparrow"=>"Passer hispaniolensis", -"Red-eyed Vireo"=>"Vireo olivaceus", -"Myrtle Warbler"=>"Dendroica coronata", -"White-crowned Sparrow"=>"Zonotrichia leucophrys", -"White-throated Sparrow"=>"Zonotrichia albicollis", -"Cretzschmar`s Bunting"=>"Emberiza caesia", -"Chestnut Bunting"=>"Emberiza rutila", -"Red-headed Bunting"=>"Emberiza bruniceps", -"Black-headed Bunting"=>"Emberiza melanocephala", -"Indigo Bunting"=>"Passerina cyanea", -"Balearic Woodchat Shrike"=>"Lanius senator badius", -"Demoiselle Crane"=>"Grus virgo", -"Chough"=>"Pyrrhocorax pyrrhocorax", -"Red-Billed Chough"=>"Pyrrhocorax graculus", -"Elegant Tern"=>"Sterna elegans", -"Chukar"=>"Alectoris chukar", -"Yellow-Billed Cuckoo"=>"Coccyzus americanus", -"American Sandwich Tern"=>"Sterna sandvicensis acuflavida", -"Olive-Tree Warbler"=>"Hippolais olivetorum", -"Eastern Olivaceous Warbler"=>"Acrocephalus pallidus", -"Indian Cormorant"=>"Phalacrocorax fuscicollis", -"Spur-Winged Lapwing"=>"Vanellus spinosus", -"Yelkouan Shearwater"=>"Puffinus yelkouan", -"Trumpeter Finch"=>"Bucanetes githagineus", -"Red Grouse"=>"Lagopus scoticus", -"Rock Ptarmigan"=>"Lagopus mutus", -"Long-Tailed Cormorant"=>"Phalacrocorax africanus", -"Double-crested Cormorant"=>"Phalacrocorax auritus", -"Magnificent Frigatebird"=>"Fregata magnificens", -"Naumann's Thrush"=>"Turdus naumanni", -"Oriental Pratincole"=>"Glareola maldivarum", -"Bufflehead"=>"Bucephala albeola", -"Snowfinch"=>"Montifrigilla nivalis", -"Ural owl"=>"Strix uralensis", -"Spanish Wagtail"=>"Motacilla iberiae", -"Song Sparrow"=>"Melospiza melodia", -"Rock Bunting"=>"Emberiza cia", -"Siberian Rubythroat"=>"Luscinia calliope", -"Pallid Swift"=>"Apus pallidus", -"Eurasian Pygmy Owl"=>"Glaucidium passerinum", -"Madeira Little Shearwater"=>"Puffinus baroli", -"House Finch"=>"Carpodacus mexicanus", -"Green Heron"=>"Butorides virescens", -"Solitary Sandpiper"=>"Tringa solitaria", -"Heuglin's Gull"=>"Larus heuglini" -); - -function array_to_json( $array ){ - - if( !is_array( $array ) ){ - return false; - } - - $associative = count( array_diff( array_keys($array), array_keys( array_keys( $array )) )); - if( $associative ){ - - $construct = array(); - foreach( $array as $key => $value ){ - - // We first copy each key/value pair into a staging array, - // formatting each key and value properly as we go. - - // Format the key: - if( is_numeric($key) ){ - $key = "key_$key"; - } - $key = "\"".addslashes($key)."\""; - - // Format the value: - if( is_array( $value )){ - $value = array_to_json( $value ); - } else if( !is_numeric( $value ) || is_string( $value ) ){ - $value = "\"".addslashes($value)."\""; - } - - // Add to staging array: - $construct[] = "$key: $value"; - } - - // Then we collapse the staging array into the JSON form: - $result = "{ " . implode( ", ", $construct ) . " }"; - - } else { // If the array is a vector (not associative): - - $construct = array(); - foreach( $array as $value ){ - - // Format the value: - if( is_array( $value )){ - $value = array_to_json( $value ); - } else if( !is_numeric( $value ) || is_string( $value ) ){ - $value = "'".addslashes($value)."'"; - } - - // Add to staging array: - $construct[] = $value; - } - - // Then we collapse the staging array into the JSON form: - $result = "[ " . implode( ", ", $construct ) . " ]"; - } - - return $result; -} - -$result = array(); -foreach ($items as $key=>$value) { - if (strpos(strtolower($key), $q) !== false) { - array_push($result, array("id"=>$value, "label"=>$key, "value" => strip_tags($key))); - } - if (count($result) > 11) - break; -} -echo array_to_json($result); - -?> \ No newline at end of file diff --git a/demos/autocomplete/xml.html b/demos/autocomplete/xml.html index 3a5dadab91e..47e70793d7e 100644 --- a/demos/autocomplete/xml.html +++ b/demos/autocomplete/xml.html @@ -1,69 +1,63 @@ - + - - jQuery UI Autocomplete Remote datasource demo - - - - - - - - + -
    -
    - +
    -
    +
    Result:
    -
    -
    -

    -This demo shows how to retrieve some XML data, parse it using jQuery's methods, then provide it to the autocomplete as the datasource. -

    -

    -This should also serve as a reference on how to parse a remote XML datasource - the parsing would just happen for each request within the source-callback. -

    -
    - +

    This demo shows how to retrieve some XML data, parse it using jQuery's methods, then provide it to the autocomplete as the datasource.

    +

    This should also serve as a reference on how to parse a remote XML datasource - the parsing would just happen for each request within the source-callback.

    +
    diff --git a/demos/bootstrap.js b/demos/bootstrap.js new file mode 100644 index 00000000000..ba1cde2e91d --- /dev/null +++ b/demos/bootstrap.js @@ -0,0 +1,111 @@ +/* globals window, document */ +( function() { +"use strict"; + +var script = document.currentScript; + +// Read the modules +var modules = script.getAttribute( "data-modules" ); +var composite = script.getAttribute( "data-composite" ) || false; +var pathParts = window.location.pathname.split( "/" ); +var effectsAll = [ + "effects/effect-blind", + "effects/effect-bounce", + "effects/effect-clip", + "effects/effect-drop", + "effects/effect-explode", + "effects/effect-fade", + "effects/effect-fold", + "effects/effect-highlight", + "effects/effect-puff", + "effects/effect-pulsate", + "effects/effect-scale", + "effects/effect-shake", + "effects/effect-size", + "effects/effect-slide", + "effects/effect-transfer" +]; +var widgets = [ + "accordion", + "autocomplete", + "button", + "checkboxradio", + "controlgroup", + "datepicker", + "dialog", + "draggable", + "droppable", + "menu", + "mouse", + "progressbar", + "resizable", + "selectable", + "selectmenu", + "slider", + "sortable", + "spinner", + "tabs", + "tooltip" +]; + +function getPath( module ) { + for ( var i = 0; i < widgets.length; i++ ) { + if ( widgets[ i ] === module ) { + return "widgets/" + module; + } + } + for ( var j = 0; j < effectsAll.length; j++ ) { + if ( module !== "effect" ) { + if ( effectsAll[ j ] === module ) { + return module; + } + if ( effectsAll[ j ].indexOf( module ) !== -1 ) { + return "effects/" + module; + } + } + } + return module; +} +function fixPaths( modules ) { + for ( var i = 0; i < modules.length; i++ ) { + modules[ i ] = getPath( modules[ i ] ); + } + return modules; +} + +// Hide the page while things are loading to prevent a FOUC +document.documentElement.className = "demo-loading"; + +require.config( { + baseUrl: window.location.pathname.indexOf( "demos/" ) !== -1 ? "../../ui" : "../../../ui", + paths: { + jquery: "../external/jquery/jquery", + external: "../external/" + }, + shim: { + "external/globalize/globalize.culture.de-DE": [ "external/globalize/globalize" ], + "external/globalize/globalize.culture.ja-JP": [ "external/globalize/globalize" ] + } +} ); + +// Replace effects all shortcut modules with all the effects modules +if ( modules && modules.indexOf( "effects-all" ) !== -1 ) { + modules = modules.replace( /effects-all/, effectsAll.join( " " ) ); +} + +modules = modules ? modules.replace( /^\s+|\s+$/g, "" ).split( /\s+/ ) : []; +if ( !composite ) { + modules.push( pathParts[ pathParts.length - 2 ] ); +} +modules = fixPaths( modules ); + +require( modules, function() { + var newScript = document.createElement( "script" ); + + document.documentElement.className = ""; + + newScript.text = "( function() { " + script.innerHTML + " } )();"; + document.body.appendChild( newScript ).parentNode.removeChild( newScript ); +} ); + +} )(); diff --git a/demos/button/checkbox.html b/demos/button/checkbox.html deleted file mode 100644 index b6192ee28ec..00000000000 --- a/demos/button/checkbox.html +++ /dev/null @@ -1,49 +0,0 @@ - - - - - jQuery UI Button - Checkboxes demo - - - - - - - - - - - -
    - - - -
    - - - -
    - -
    - - - -
    - -

    A checkbox is styled as a toggle button with the button widget. The label element associated with the checkbox is used for the button text.

    - -

    This demo also demonstrates three checkboxes styled as a button set by calling .buttonset() on a common container.

    - -
    - - - - - diff --git a/demos/button/default.html b/demos/button/default.html index 700c64bcc8d..7ac6a325d05 100644 --- a/demos/button/default.html +++ b/demos/button/default.html @@ -1,46 +1,38 @@ - + - - jQuery UI Button - Default demo - - - - - - - + - +
    +

    Widget Buttons

    + -
    + - - - - An anchor +
    +

    CSS Buttons

    + -
    - + +An anchor
    -

    Examples of the markup that can be used for buttons: A button element, an input of type submit and an anchor.

    - -
    - - - +

    Buttons can be styled via the button widget or by adding the classes yourself. This avoids the JavaScript overhead if you don't need any of the methods provided by the button widget.

    + diff --git a/demos/button/icons.html b/demos/button/icons.html index 2dc11c5d8e5..f3d4a385211 100644 --- a/demos/button/icons.html +++ b/demos/button/icons.html @@ -1,63 +1,65 @@ - + - - jQuery UI Button - Icons demo - - - - - - - + - - -
    - +
    +

    Widget

    + - - - -
    - - - + + + +
    +
    +

    CSS

    + + + + + + +
    - -

    Some buttons with various combinations of text and icons, here specified via metadata.

    - -
    - - - +

    Some buttons with various combinations of text and icons.

    + diff --git a/demos/button/index.html b/demos/button/index.html index c2b37200d79..55eacffd811 100644 --- a/demos/button/index.html +++ b/demos/button/index.html @@ -1,23 +1,16 @@ - + - + + jQuery UI Button Demos - - + diff --git a/demos/button/radio.html b/demos/button/radio.html deleted file mode 100644 index 3e5dc2379a9..00000000000 --- a/demos/button/radio.html +++ /dev/null @@ -1,46 +0,0 @@ - - - - - jQuery UI Button - Radio Buttons demo - - - - - - - - - - - -
    - -
    -
    - - - -
    -
    - -
    - - - -
    - -

    A set of three radio buttons transformed into a button set.

    - -
    - - - - - diff --git a/demos/button/splitbutton.html b/demos/button/splitbutton.html deleted file mode 100644 index 7e4d660386e..00000000000 --- a/demos/button/splitbutton.html +++ /dev/null @@ -1,60 +0,0 @@ - - - - - jQuery UI Button - Default demo - - - - - - - - - - - -
    - -
    - - -
    - -
    - - - -
    - -

    An example of a split button built with two buttons: A plan button with just text, one with only a primary icon -and no text. Both are grouped together in a set.

    - -
    - - - - - diff --git a/demos/button/toolbar.html b/demos/button/toolbar.html deleted file mode 100644 index 5573872a763..00000000000 --- a/demos/button/toolbar.html +++ /dev/null @@ -1,124 +0,0 @@ - - - - - jQuery UI Button - Toolbar demo - - - - - - - - - - - -
    - - - - - - - - - - - - - - - - - - -
    - - - -
    - -

    - A mediaplayer toolbar. Take a look at the underlying markup: A few button elements, - an input of type checkbox for the Shuffle button, and three inputs of type radio for the Repeat options. -

    - -
    - - - - - diff --git a/demos/checkboxradio/default.html b/demos/checkboxradio/default.html new file mode 100644 index 00000000000..064967c1219 --- /dev/null +++ b/demos/checkboxradio/default.html @@ -0,0 +1,63 @@ + + + + + jQuery UI Checkboxradio - Default functionality + + + + + + +
    +

    Checkbox and radio button widgets

    + +

    Radio Group

    +
    + Select a Location: + + + + + + +
    + +

    Checkbox

    +
    + Hotel Ratings: + + + + + + + + +
    + +

    Checkbox nested in label

    +
    + Bed Type: + + + + +
    +
    + +
    +

    Examples of the markup that can be used with checkboxes and radio buttons.

    +
    + + diff --git a/demos/checkboxradio/images/jquery-mobile.png b/demos/checkboxradio/images/jquery-mobile.png new file mode 100644 index 00000000000..006230c13d7 Binary files /dev/null and b/demos/checkboxradio/images/jquery-mobile.png differ diff --git a/demos/checkboxradio/images/jquery-ui.png b/demos/checkboxradio/images/jquery-ui.png new file mode 100644 index 00000000000..69f65c96bc2 Binary files /dev/null and b/demos/checkboxradio/images/jquery-ui.png differ diff --git a/demos/checkboxradio/images/jquery.png b/demos/checkboxradio/images/jquery.png new file mode 100644 index 00000000000..034051570fa Binary files /dev/null and b/demos/checkboxradio/images/jquery.png differ diff --git a/demos/checkboxradio/images/qunit.png b/demos/checkboxradio/images/qunit.png new file mode 100644 index 00000000000..1a0eb6ab9af Binary files /dev/null and b/demos/checkboxradio/images/qunit.png differ diff --git a/demos/checkboxradio/images/sizzle.png b/demos/checkboxradio/images/sizzle.png new file mode 100644 index 00000000000..41a0dac1d6e Binary files /dev/null and b/demos/checkboxradio/images/sizzle.png differ diff --git a/demos/checkboxradio/index.html b/demos/checkboxradio/index.html new file mode 100644 index 00000000000..08e598dbc82 --- /dev/null +++ b/demos/checkboxradio/index.html @@ -0,0 +1,18 @@ + + + + + + jQuery UI Checkboxradio Demos + + + + + + + diff --git a/demos/checkboxradio/no-icons.html b/demos/checkboxradio/no-icons.html new file mode 100644 index 00000000000..bcff28dcd2f --- /dev/null +++ b/demos/checkboxradio/no-icons.html @@ -0,0 +1,65 @@ + + + + + jQuery UI Checkboxradio - No Icons + + + + + + +
    +

    Checkbox and radio button widgets

    + +

    Radio Group

    +
    + Select a Location: + + + + + + +
    + +

    Checkbox

    +
    + Hotel Ratings: + + + + + + + + +
    + +

    Checkbox nested in label

    +
    + Bed Type: + + + + +
    +
    + +
    +

    Examples of the markup that can be used with checkboxes and radio buttons, here showing both without icons.

    +
    + + diff --git a/demos/checkboxradio/product-selector.html b/demos/checkboxradio/product-selector.html new file mode 100644 index 00000000000..c78c516572b --- /dev/null +++ b/demos/checkboxradio/product-selector.html @@ -0,0 +1,138 @@ + + + + + jQuery UI Checkboxradio - Product Selector + + + + + + + +
    +
    +

    1.) Select a brand

    +
    + + + + + + + + + + +
    +
    +
    +

    2.) Select a shape

    +
    + + + + + + + + +
    +
    +
    +

    3.) Customize

    +
    + + + + + + + + +
    +
    +
    +
    + +
    +

    Using two sets of radio buttons, as horizontal controlgroups, and one group of checkboxes, as a vertical controlgroup, to implement a product selector.

    +
    + + diff --git a/demos/checkboxradio/radiogroup.html b/demos/checkboxradio/radiogroup.html new file mode 100644 index 00000000000..a8f808c11c3 --- /dev/null +++ b/demos/checkboxradio/radiogroup.html @@ -0,0 +1,33 @@ + + + + + jQuery UI Checkboxradio - Radio Group + + + + + + +
    + +

    Radio Group

    +
    + Select a Location: + + + + + + +
    +
    + +
    +

    Example markup using the controlgroup widget to create a radio group.

    +
    + + diff --git a/demos/controlgroup/default.html b/demos/controlgroup/default.html new file mode 100644 index 00000000000..71418302ac0 --- /dev/null +++ b/demos/controlgroup/default.html @@ -0,0 +1,86 @@ + + + + + jQuery UI Controlgroup - Default Functionality + + + + + + + +
    +

    Controlgroup

    +
    + Rental Car +
    + + + + + + + + + + +
    +
    +
    +
    + Rental Car +
    + + + + + + + + + + +
    +
    +
    +
    +

    A controlgroup featuring various form controls. The first features a horizontal toolbar like orientation, the second is in a space saving vertical orientation for usages like mobile devices and panels.

    +
    + + diff --git a/demos/controlgroup/index.html b/demos/controlgroup/index.html new file mode 100644 index 00000000000..5aa4f5fd6a0 --- /dev/null +++ b/demos/controlgroup/index.html @@ -0,0 +1,17 @@ + + + + + + jQuery UI Controlgroup Demos + + + + + + + diff --git a/demos/controlgroup/splitbutton.html b/demos/controlgroup/splitbutton.html new file mode 100644 index 00000000000..ea3a95e02fd --- /dev/null +++ b/demos/controlgroup/splitbutton.html @@ -0,0 +1,48 @@ + + + + + jQuery UI Controlgroup - Split Button + + + + + + + +
    +

    Split button

    +
    + + +
    +
    +

    Output:

    +
      +
      +
      +

      A controlgroup creating a split button, by combining a button and a selectmenu. We adjust the classes option on the selectmenu to show only the icon

      +
      + + diff --git a/demos/controlgroup/toolbar.html b/demos/controlgroup/toolbar.html new file mode 100644 index 00000000000..81093cbbed3 --- /dev/null +++ b/demos/controlgroup/toolbar.html @@ -0,0 +1,277 @@ + + + + + jQuery UI Controlgroup - Toolbar + + + + + + + +
      +
      + + + + + + + + + + + + +
      +
      +	The Rime of the Ancient Mariner (text of 1834)
      +	BY SAMUEL TAYLOR COLERIDGE
      +	Argument
      +
      +	How a Ship having passed the Line was driven by storms to the cold Country towards the South Pole;
      +	and how from thence she made her course to the tropical Latitude of the Great Pacific Ocean; and
      +	of the strange things that befell; and in what manner the Ancyent Marinere came back to his own
      +	Country.
      +
      +	PART I
      +	It is an ancient Mariner,
      +	And he stoppeth one of three.
      +	'By thy long grey beard and glittering eye,
      +	Now wherefore stopp'st thou me?
      +
      +	The Bridegroom's doors are opened wide,
      +	And I am next of kin;
      +	The guests are met, the feast is set:
      +	May'st hear the merry din.'
      +
      +	He holds him with his skinny hand,
      +	'There was a ship,' quoth he.
      +	'Hold off! unhand me, grey-beard loon!'
      +	Eftsoons his hand dropt he.
      +
      +	He holds him with his glittering eye—
      +	The Wedding-Guest stood still,
      +	And listens like a three years' child:
      +	The Mariner hath his will.
      +
      +	The Wedding-Guest sat on a stone:
      +	He cannot choose but hear;
      +	And thus spake on that ancient man,
      +	The bright-eyed Mariner.
      +
      +	'The ship was cheered, the harbour cleared,
      +	Merrily did we drop
      +	Below the kirk, below the hill,
      +	Below the lighthouse top.
      +
      +	The Sun came up upon the left,
      +	Out of the sea came he!
      +	And he shone bright, and on the right
      +	Went down into the sea.
      +
      +	Higher and higher every day,
      +	Till over the mast at noon—'
      +	The Wedding-Guest here beat his breast,
      +	For he heard the loud bassoon.
      +
      +	The bride hath paced into the hall,
      +	Red as a rose is she;
      +	Nodding their heads before her goes
      +	The merry minstrelsy.
      +
      +	The Wedding-Guest he beat his breast,
      +	Yet he cannot choose but hear;
      +	And thus spake on that ancient man,
      +	The bright-eyed Mariner.
      +
      +	And now the STORM-BLAST came, and he
      +	Was tyrannous and strong:
      +	He struck with his o'ertaking wings,
      +	And chased us south along.
      +
      +	With sloping masts and dipping prow,
      +	As who pursued with yell and blow
      +	Still treads the shadow of his foe,
      +	And forward bends his head,
      +	The ship drove fast, loud roared the blast,
      +	And southward aye we fled.
      +
      +	And now there came both mist and snow,
      +	And it grew wondrous cold:
      +	And ice, mast-high, came floating by,
      +	As green as emerald.
      +
      +	And through the drifts the snowy clifts
      +	Did send a dismal sheen:
      +	Nor shapes of men nor beasts we ken—
      +	The ice was all between.
      +
      +	The ice was here, the ice was there,
      +	The ice was all around:
      +	It cracked and growled, and roared and howled,
      +	Like noises in a swound!
      +
      +	At length did cross an Albatross,
      +	Thorough the fog it came;
      +	As if it had been a Christian soul,
      +	We hailed it in God's name.
      +
      +	It ate the food it ne'er had eat,
      +	And round and round it flew.
      +	The ice did split with a thunder-fit;
      +	The helmsman steered us through!
      +
      +	And a good south wind sprung up behind;
      +	The Albatross did follow,
      +	And every day, for food or play,
      +	Came to the mariner's hollo!
      +
      +	In mist or cloud, on mast or shroud,
      +	It perched for vespers nine;
      +	Whiles all the night, through fog-smoke white,
      +	Glimmered the white Moon-shine.'
      +
      +	'God save thee, ancient Mariner!
      +	From the fiends, that plague thee thus!—
      +	Why look'st thou so?'—With my cross-bow
      +	I shot the ALBATROSS.
      +	
      +
      +
      +

      A sample editor toolbar

      +

      Highlight text and edit it using the buttons and dropdowns in the toolbar.

      +

      Remember: This is only a demo and shouldn't be used for anything in production. Use a proper editor like ProseMirror instead. +

      + + diff --git a/demos/datepicker/alt-field.html b/demos/datepicker/alt-field.html index d51bf06346c..be00e0d7372 100644 --- a/demos/datepicker/alt-field.html +++ b/demos/datepicker/alt-field.html @@ -1,33 +1,25 @@ - + - + + jQuery UI Datepicker - Populate alternate field - - - - - - - + -
      - -

      Date:  

      - -
      +

      Date:  

      -

      Populate an alternate field with its own date format whenever a date is selected using the altField and altFormat options. This feature could be used to present a human-friendly date for user selection, while passing a more computer-friendly date through for further processing.

      - -
      - + diff --git a/demos/datepicker/animation.html b/demos/datepicker/animation.html index 27f20ffb8b5..9f20632e3ad 100644 --- a/demos/datepicker/animation.html +++ b/demos/datepicker/animation.html @@ -1,56 +1,40 @@ - + - + + jQuery UI Datepicker - Animations - - - - - - - - - - - - - - + -
      +

      Date:

      -

      Date:

      - -

      Animations:
      +

      Animations:

      -
      -
      -

      Use different animations when opening or closing the datepicker. Choose an animation from the dropdown, then click on the input to see its effect. You can use one of the three standard animations or any of the UI Effects.

      - -
      - + diff --git a/demos/datepicker/buttonbar.html b/demos/datepicker/buttonbar.html index 6cd4dbedc75..5b48179b49e 100644 --- a/demos/datepicker/buttonbar.html +++ b/demos/datepicker/buttonbar.html @@ -1,35 +1,24 @@ - + - + + jQuery UI Datepicker - Display button bar - - - - - - - + -
      -

      Date:

      -
      -
      -

      Display a button for selecting Today's date and a Done button for closing the calendar with the boolean showButtonPanel option. Each button is enabled by default when the bar is displayed, but can be turned off with additional options. Button text is customizable.

      - -
      - + diff --git a/demos/datepicker/date-formats.html b/demos/datepicker/date-formats.html index 435ef7096bb..1736fabd99b 100644 --- a/demos/datepicker/date-formats.html +++ b/demos/datepicker/date-formats.html @@ -1,28 +1,24 @@ - + - + + jQuery UI Datepicker - Format date - - - - - - - + -
      +

      Date:

      -

      Date:

      - -

      Format options:
      +

      Format options:

      -
      -
      -

      Display date feedback in a variety of ways. Choose a date format from the dropdown, then click on the input and select a date to see it in that format.

      - -
      - + diff --git a/demos/datepicker/date-range.html b/demos/datepicker/date-range.html new file mode 100644 index 00000000000..e3cc202456c --- /dev/null +++ b/demos/datepicker/date-range.html @@ -0,0 +1,53 @@ + + + + + + jQuery UI Datepicker - Select a Date Range + + + + + + + + + + + + +
      +

      Select the date range to search for.

      +
      + + diff --git a/demos/datepicker/default.html b/demos/datepicker/default.html index 4ab50e1746e..c5d668bdae1 100644 --- a/demos/datepicker/default.html +++ b/demos/datepicker/default.html @@ -1,33 +1,22 @@ - + - + + jQuery UI Datepicker - Default functionality - - - - - - - + -
      -

      Date:

      -
      -
      -

      The datepicker is tied to a standard form input field. Focus on the input (click, or use the tab key) to open an interactive calendar in a small overlay. Choose a date, click elsewhere on the page (blur the input), or hit the Esc key to close. If a date is chosen, feedback is shown as the input's value.

      - -
      - + diff --git a/demos/datepicker/dropdown-month-year.html b/demos/datepicker/dropdown-month-year.html index c31d8ba8524..ab3da5d0af3 100644 --- a/demos/datepicker/dropdown-month-year.html +++ b/demos/datepicker/dropdown-month-year.html @@ -1,36 +1,25 @@ - + - + + jQuery UI Datepicker - Display month & year menus - - - - - - - + -
      -

      Date:

      -
      -
      -

      Show month and year dropdowns in place of the static month/year header to facilitate navigation through large timeframes. Add the boolean changeMonth and changeYear options.

      - -
      - + diff --git a/demos/datepicker/event-search.html b/demos/datepicker/event-search.html deleted file mode 100644 index c87ae17a469..00000000000 --- a/demos/datepicker/event-search.html +++ /dev/null @@ -1,46 +0,0 @@ - - - - - jQuery UI Datepicker - Display multiple months - - - - - - - - - - -
      - - - - - - -
      - -
      - -

      Select the date range to search for.

      - -
      - - - diff --git a/demos/datepicker/icon-trigger.html b/demos/datepicker/icon-trigger.html index 6da3a7792d5..71d0621d46b 100644 --- a/demos/datepicker/icon-trigger.html +++ b/demos/datepicker/icon-trigger.html @@ -1,37 +1,27 @@ - + - + + jQuery UI Datepicker - Icon trigger - - - - - - - + -
      -

      Date:

      -
      -
      -

      Click the icon next to the input field to show the datepicker. Set the datepicker to open on focus (default behavior), on icon click, or both.

      - -
      - + diff --git a/demos/datepicker/images/calendar.gif b/demos/datepicker/images/calendar.gif index d0abaa7c0b8..52f2863c907 100644 Binary files a/demos/datepicker/images/calendar.gif and b/demos/datepicker/images/calendar.gif differ diff --git a/demos/datepicker/index.html b/demos/datepicker/index.html index 5749ae757b6..d9c8dfc10da 100644 --- a/demos/datepicker/index.html +++ b/demos/datepicker/index.html @@ -1,31 +1,28 @@ - + - + + jQuery UI Datepicker Demos - - + diff --git a/demos/datepicker/inline.html b/demos/datepicker/inline.html index bf21fc92784..9e802672612 100644 --- a/demos/datepicker/inline.html +++ b/demos/datepicker/inline.html @@ -1,33 +1,22 @@ - + - + + jQuery UI Datepicker - Display inline - - - - - - - + -
      - Date:
      -
      -
      -

      Display the datepicker embedded in the page instead of in an overlay. Simply call .datepicker() on a div instead of an input.

      - -
      - + diff --git a/demos/datepicker/localization.html b/demos/datepicker/localization.html index 079ae05378f..5e9a6cfaf53 100644 --- a/demos/datepicker/localization.html +++ b/demos/datepicker/localization.html @@ -1,143 +1,33 @@ - + - + + jQuery UI Datepicker - Localize calendar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + -
      - -

      Date:   +

      Date:  

      -
      -
      -

      Localize the datepicker calendar language and format (English / Western formatting is the default). The datepicker includes built-in support for languages that read right-to-left, such as Arabic and Hebrew.

      - -
      - + diff --git a/demos/datepicker/min-max.html b/demos/datepicker/min-max.html index 7573e6926ee..13b1b569e0c 100644 --- a/demos/datepicker/min-max.html +++ b/demos/datepicker/min-max.html @@ -1,33 +1,22 @@ - + - + + jQuery UI Datepicker - Restrict date range - - - - - - - + -
      -

      Date:

      -
      -
      -

      Restrict the range of selectable dates with the minDate and maxDate options. Set the beginning and end dates as actual dates (new Date(2009, 1 - 1, 26)), as a numeric offset from today (-20), or as a string of periods and units ('+1M +10D'). For the last, use 'D' for days, 'W' for weeks, 'M' for months, or 'Y' for years.

      - -
      - + diff --git a/demos/datepicker/multiple-calendars.html b/demos/datepicker/multiple-calendars.html index 8051ca524a1..033b648a279 100644 --- a/demos/datepicker/multiple-calendars.html +++ b/demos/datepicker/multiple-calendars.html @@ -1,36 +1,25 @@ - + - + + jQuery UI Datepicker - Display multiple months - - - - - - - + -
      -

      Date:

      -
      -
      -

      Set the numberOfMonths option to an integer of 2 or more to show multiple months in a single datepicker.

      - -
      - + diff --git a/demos/datepicker/other-months.html b/demos/datepicker/other-months.html index 1c0b65559cd..ff86006445c 100644 --- a/demos/datepicker/other-months.html +++ b/demos/datepicker/other-months.html @@ -1,34 +1,26 @@ - + - + + jQuery UI Datepicker - Dates in other months - - - - - - - + -
      -

      Date:

      -
      -
      -

      The datepicker can show dates that come from other than the main month being displayed. These other dates can also be made selectable.

      - -
      - + diff --git a/demos/datepicker/show-week.html b/demos/datepicker/show-week.html index f6015a2af37..022d0271c9f 100644 --- a/demos/datepicker/show-week.html +++ b/demos/datepicker/show-week.html @@ -1,36 +1,28 @@ - + - + + jQuery UI Datepicker - Show week of the year - - - - - - - + -
      -

      Date:

      -
      -
      -

      The datepicker can show the week of the year. The default calculation follows the ISO 8601 definition: the week starts on Monday, the first week of the year contains the first Thursday of the year. This means that some days from one year may be placed into weeks 'belonging' to another year.

      - -
      - + diff --git a/demos/demos.css b/demos/demos.css index 2d2ce1fc82c..0b5b5ee49c4 100644 --- a/demos/demos.css +++ b/demos/demos.css @@ -1,334 +1,20 @@ body { - font-size: 62.5%; + font-family: Arial, Helvetica, sans-serif; } -table { - font-size: 1em; -} - -/* Site - -------------------------------- */ - -body { - font-family: "Trebuchet MS", "Helvetica", "Arial", "Verdana", "sans-serif"; -} - -/* Layout - -------------------------------- */ - -.layout-grid { - width: 960px; -} - -.layout-grid td { - vertical-align: top; -} - -.layout-grid td.left-nav { - width: 140px; -} - -.layout-grid td.normal { - border-left: 1px solid #eee; - padding: 20px 24px; - font-family: "Trebuchet MS", "Helvetica", "Arial", "Verdana", "sans-serif"; -} - -.layout-grid td.demos { - background: url('/images/demos_bg.jpg') no-repeat; - height: 337px; - overflow: hidden; -} - -/* Normal - -------------------------------- */ - -.normal h3, -.normal h4 { - margin: 0; - font-weight: normal; -} - -.normal h3 { - padding: 0 0 9px; - font-size: 1.8em; +.demo-loading { + visibility: hidden; } -.normal h4 { - padding-bottom: 21px; - border-bottom: 1px dashed #999; - font-size: 1.2em; - font-weight: bold; -} - -.normal p { - font-size: 1.2em; -} - -/* Demos */ - -.demos-nav, .demos-nav dt, .demos-nav dd, .demos-nav ul, .demos-nav li { - margin: 0; - padding: 0 -} - -.demos-nav { - float: left; - width: 170px; - font-size: 1.3em; -} - -.demos-nav dt, -.demos-nav h4 { - margin: 0; - padding: 0; - font: normal 1.1em "Trebuchet MS", "Helvetica", "Arial", "Verdana", "sans-serif"; - color: #e87b10; -} - -.demos-nav dt, -.demos-nav h4 { - margin-top: 1.5em; - margin-bottom: 0; - padding-left: 8px; - padding-bottom:5px; - line-height: 1.2em; - border-bottom: 1px solid #F4F4F4; -} - -.demos-nav dd a, -.demos-nav li a { - border-bottom: 1px solid #F4F4F4; - display:block; - padding: 4px 3px 4px 8px; - font-size: 90%; - text-decoration: none; - color: #555 ; - margin:2px 0; - height:13px; -} - -.demos-nav dd a:hover, -.demos-nav dd a:focus, -.demos-nav dd a:hover, -.demos-nav dd a:focus { - background: #f3f3f3; - color:#000; - -moz-border-radius: 5px; -webkit-border-radius: 5px; -} - .demos-nav dd a.selected { - background: #555; - color:#ffffff; - -moz-border-radius: 5px; -webkit-border-radius: 5px; +table { + font-size: 1em; } - -/* new styles for demo pages, added by Filament 12.29.08 -eventually we should convert the font sizes to ems -- using px for now to minimize style conflicts -*/ - -.normal h3.demo-header { font-size:32px; padding:0 0 5px; border-bottom:1px solid #eee; text-transform: capitalize; } -.normal h4.demo-subheader { font-size:10px; text-transform: uppercase; color:#999; padding:8px 0 3px; border:0; margin:0; } -.normal a:link, -.normal a:visited { color:#1b75bb; text-decoration:none; } -.normal a:hover, -.normal a:active { color:#0b559b; } - -#demo-config { padding:20px 0 0; } - -#demo-frame { float:left; width:540px; height:380px; border:1px solid #ddd; overflow: auto; position: relative; } -#demo-frame h3, #demo-frame h4 { padding: 0; font-weight: bold; font-size: 1em; } - -#demo-config-menu { float:right; width:180px; } -#demo-config-menu h4 { font-size:13px; color:#666; font-weight:normal; border:0; padding-left:18px; } - -#demo-config-menu ul { list-style: none; padding: 0; margin: 0; } - -#demo-config-menu li { font-size:12px; padding:0 0 0 10px; margin:3px 0; zoom: 1; } - -#demo-config-menu li a:link, -#demo-config-menu li a:visited { display:block; padding:1px 8px 4px; border-bottom:1px dotted #b3b3b3; } -* html #demo-config-menu li a:link, -* html #demo-config-menu li a:visited { padding:1px 8px 2px; } -#demo-config-menu li a:hover, -#demo-config-menu li a:active { background-color:#f6f6f6; } - -#demo-config-menu li.demo-config-on { background: url(images/demo-config-on-tile.gif) repeat-x left center; } - -#demo-config-menu li.demo-config-on a:link, -#demo-config-menu li.demo-config-on a:visited, -#demo-config-menu li.demo-config-on a:hover, -#demo-config-menu li.demo-config-on a:active { background: url(images/demo-config-on.gif) no-repeat left; padding-left:18px; color:#fff; border:0; margin-left:-10px; margin-top: 0px; margin-bottom: 0px; } - -#demo-source, #demo-notes { +.demo-description { clear: both; - padding: 20px 0 0; - font-size: 1.3em; -} - -#demo-notes { width:520px; color:#333; font-size: 1em; } -#demo-notes p code, .demo-description p code { padding: 0; font-weight: bold; } -#demo-source pre, #demo-source code { padding: 0; } -code, pre { padding:8px 0 8px 20px ; font-size: 1.2em; line-height:130%; } - -#demo-source a:link, -#demo-source a:visited, -#demo-source a:hover, -#demo-source a:active { font-size:12px; padding-left:13px; background-position: left center; background-repeat: no-repeat; } - -#demo-source a.source-open:link, -#demo-source a.source-open:visited, -#demo-source a.source-open:hover, -#demo-source a.source-open:active { background-image: url(images/demo-spindown-open.gif); } - -#demo-source a.source-closed:link, -#demo-source a.source-closed:visited, -#demo-source a.source-closed:hover, -#demo-source a.source-closed:active { background-image: url(images/demo-spindown-closed.gif); } - -div.demo { - padding:12px; - font-family: "Trebuchet MS", "Arial", "Helvetica", "Verdana", "sans-serif"; -} - -div.demo h3.docs { clear:left; font-size:12px; font-weight:normal; padding:0 0 1em; margin:0; } - -div.demo-description { - clear:both; - padding:12px; - font-family: "Trebuchet MS", "Arial", "Helvetica", "Verdana", "sans-serif"; - font-size: 1.3em; - line-height: 1.4em; + padding: 12px; } .ui-draggable, .ui-droppable { - background-position: top left; + background-position: top; } - -.left-nav .demos-nav { - padding-right: 10px; -} - -#demo-link { font-size:11px; padding-top: 6px; clear: both; overflow: hidden; } -#demo-link a span.ui-icon { float:left; margin-right:3px; } - -/* Component containers -----------------------------------*/ -#widget-docs .ui-widget { font-family: Trebuchet MS,Verdana,Arial,sans-serif; font-size: 1em; } -#widget-docs .ui-widget input, #widget-docs .ui-widget select, #widget-docs .ui-widget textarea, #widget-docs .ui-widget button { font-family: Trebuchet MS,Verdana,Arial,sans-serif; font-size: 1em; } -#widget-docs .ui-widget-header { border: 1px solid #ffffff; background: #464646 url(images/464646_40x100_textures_01_flat_100.png) 50% 50% repeat-x; color: #ffffff; font-weight: bold; } -#widget-docs .ui-widget-header a { color: #ffffff; } -#widget-docs .ui-widget-content { border: 1px solid #ffffff; background: #ffffff url(images/ffffff_40x100_textures_01_flat_75.png) 50% 50% repeat-x; color: #222222; } -#widget-docs .ui-widget-content a { color: #222222; } - -/* Interaction states -----------------------------------*/ -#widget-docs .ui-state-default, #widget-docs .ui-widget-content #widget-docs .ui-state-default { border: 1px solid #666666; background: #555555 url(images/555555_40x100_textures_03_highlight_soft_75.png) 50% 50% repeat-x; font-weight: normal; color: #ffffff; outline: none; } -#widget-docs .ui-state-default a { color: #ffffff; text-decoration: none; outline: none; } -#widget-docs .ui-state-hover, #widget-docs .ui-widget-content #widget-docs .ui-state-hover, #widget-docs .ui-state-focus, #widget-docs .ui-widget-content #widget-docs .ui-state-focus { border: 1px solid #666666; background: #444444 url(images/444444_40x100_textures_03_highlight_soft_60.png) 50% 50% repeat-x; font-weight: normal; color: #ffffff; outline: none; } -#widget-docs .ui-state-hover a { color: #ffffff; text-decoration: none; outline: none; } -#widget-docs .ui-state-active, #widget-docs .ui-widget-content #widget-docs .ui-state-active { border: 1px solid #666666; background: #ffffff url(images/ffffff_40x100_textures_01_flat_65.png) 50% 50% repeat-x; font-weight: normal; color: #F6921E; outline: none; } -#widget-docs .ui-state-active a { color: #F6921E; outline: none; text-decoration: none; } - -/* Interaction Cues -----------------------------------*/ -#widget-docs .ui-state-highlight, #widget-docs .ui-widget-content #widget-docs .ui-state-highlight {border: 1px solid #fcefa1; background: #fbf9ee url(images/fbf9ee_40x100_textures_02_glass_55.png) 50% 50% repeat-x; color: #363636; } -#widget-docs .ui-state-error, #widget-docs .ui-widget-content #widget-docs .ui-state-error {border: 1px solid #cd0a0a; background: #fef1ec url(images/fef1ec_40x100_textures_05_inset_soft_95.png) 50% bottom repeat-x; color: #cd0a0a; } -#widget-docs .ui-state-error-text, #widget-docs .ui-widget-content #widget-docs .ui-state-error-text { color: #cd0a0a; } -#widget-docs .ui-state-disabled, #widget-docs .ui-widget-content #widget-docs .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; } -#widget-docs .ui-priority-primary, #widget-docs .ui-widget-content #widget-docs .ui-priority-primary { font-weight: bold; } -#widget-docs .ui-priority-secondary, #widget-docs .ui-widget-content #widget-docs .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; } - -/* Icons -----------------------------------*/ - -/* states and images */ -#demo-frame-wrapper .ui-icon, #widget-docs .ui-icon { width: 16px; height: 16px; background-image: url(images/222222_256x240_icons_icons.png); } -#widget-docs .ui-widget-content .ui-icon {background-image: url(images/222222_256x240_icons_icons.png); } -#widget-docs .ui-widget-header .ui-icon {background-image: url(images/222222_256x240_icons_icons.png); } -#widget-docs .ui-state-default .ui-icon { background-image: url(images/888888_256x240_icons_icons.png); } -#widget-docs .ui-state-hover .ui-icon, #widget-docs .ui-state-focus .ui-icon {background-image: url(images/454545_256x240_icons_icons.png); } -#widget-docs .ui-state-active .ui-icon {background-image: url(images/454545_256x240_icons_icons.png); } -#widget-docs .ui-state-highlight .ui-icon {background-image: url(images/2e83ff_256x240_icons_icons.png); } -#widget-docs .ui-state-error .ui-icon, #widget-docs .ui-state-error-text .ui-icon {background-image: url(images/cd0a0a_256x240_icons_icons.png); } - - -/* Misc visuals -----------------------------------*/ - -/* Corner radius */ -#widget-docs .ui-corner-tl { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; } -#widget-docs .ui-corner-tr { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; } -#widget-docs .ui-corner-bl { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; } -#widget-docs .ui-corner-br { -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; } -#widget-docs .ui-corner-top { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; } -#widget-docs .ui-corner-bottom { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; } -#widget-docs .ui-corner-right { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; } -#widget-docs .ui-corner-left { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; } -#widget-docs .ui-corner-all { -moz-border-radius: 4px; -webkit-border-radius: 4px; } - -/* Overlays */ -#widget-docs .ui-widget-overlay { background: #aaaaaa url(images/aaaaaa_40x100_textures_01_flat_0.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); } -#widget-docs .ui-widget-shadow { margin: -8px 0 0 -8px; padding: 8px; background: #aaaaaa url(images/aaaaaa_40x100_textures_01_flat_0.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); -moz-border-radius: 8px; -webkit-border-radius: 8px; } - -/* -----------------------------------*/ - -#widget-docs { margin:20px 0 0; border: none; } - -#widget-docs h2, #widget-docs h3, #widget-docs h4, #widget-docs p, #widget-docs ul, #widget-docs code { margin:0; padding:0; } -#widget-docs code { display:block; color:#444; font-size:.9em; margin:0 0 1em; } -#widget-docs code strong { color:#000; } -#widget-docs p { margin:0 3em 1.2em 0; } -#widget-docs p.intro { font-size:13px; color:#666; line-height:1.3; } -#widget-docs ul { list-style-type: none; } - -#widget-docs h2 { font-size:16px; margin:1.2em 0 .5em; } -#widget-docs h3 { font-size:14px; color:#e6820E; margin:1.5em 0 .5em; } -.normal #widget-docs h4 { font-size:12px; color:#000; border:0; margin:0 0 .5em; } - -#docs-overview-main { width:400px; } -#docs-overview-sidebar { float:right; width:200px; } -#docs-overview-sidebar a span { color:#666; } -#widget-docs #docs-overview-main p { margin-right:0; } -#widget-docs #docs-overview-sidebar h4 { padding-left:0; } - -.docs-list-header { float:left; width:100%; margin:10px 0 0; border-bottom:1px solid #eee; } -#widget-docs .docs-list-header h2 { float:left; margin:0; } -#widget-docs .docs-list-header p { float:right; margin:5px 0; font-size:11px; } - -.docs-list { float:left; width:100%; padding:0 0 10px; } -.docs-list .param-header { float:left; clear:left; width:100%; padding:8px 0; border-top:1px solid #eee; } -#widget-docs .param-header h3, #widget-docs .param-header p { margin:0; float:left; } -#widget-docs .param-header h3 { width:50%; } -#widget-docs .param-header h3 span { background: url(images/demo-spindown-closed.gif) no-repeat left; padding-left:13px; } -#widget-docs .param-open .param-header h3 span { background: url(images/demo-spindown-open.gif) no-repeat left; } -#widget-docs .param-header p { width:24%; } -#widget-docs .param-header p.param-type span { background: url(images/icon-docs-info.gif) no-repeat left; cursor:pointer; border-bottom:1px dashed #ccc; padding-left:15px; } - -.param-details { padding-left:13px; } -.param-args { margin:0 0 1.5em; border-top:1px dotted #ccc;} -.param-args td { padding:3px 30px 3px 5px; border-bottom:1px dotted #ccc; } - - -/* overrides for ui-tab styles */ -#widget-docs ul.ui-tabs-nav { padding:0 0 0 8px; } -#widget-docs .ui-tabs-nav li { margin:5px 5px 0 0; } - -#widget-docs .ui-tabs-nav li a:link, -#widget-docs .ui-tabs-nav li a:visited, -#widget-docs .ui-tabs-nav li a:hover, -#widget-docs .ui-tabs-nav li a:active { font-size:14px; padding:4px 1.2em 3px; color:#fff; } - -#widget-docs .ui-tabs-nav li.ui-tabs-selected a:link, -#widget-docs .ui-tabs-nav li.ui-tabs-selected a:visited, -#widget-docs .ui-tabs-nav li.ui-tabs-selected a:hover, -#widget-docs .ui-tabs-nav li.ui-tabs-selected a:active { color:#e6820E; } - -#widget-docs .ui-tabs-panel { padding:20px 9px; font-size:12px; line-height:1.4; color:#000; } - -#widget-docs .ui-widget-content a:link, -#widget-docs .ui-widget-content a:visited { color:#1b75bb; text-decoration:none; } -#widget-docs .ui-widget-content a:hover, -#widget-docs .ui-widget-content a:active { color:#0b559b; } - diff --git a/demos/dialog/animated.html b/demos/dialog/animated.html index 26f298acc80..5804610c7e5 100644 --- a/demos/dialog/animated.html +++ b/demos/dialog/animated.html @@ -1,56 +1,40 @@ - + - + + jQuery UI Dialog - Animation - - - - - - - - - - - - - - - + -
      -

      This is an animated dialog which is useful for displaying information. The dialog window can be moved, resized and closed with the 'x' icon.

      -
      -
      -

      Dialogs may be animated by specifying an effect for the show and/or hide properties. You must include the individual effects file for any effects you would like to use.

      - -
      - + diff --git a/demos/dialog/default.html b/demos/dialog/default.html index a0d4481c7a7..65b22a51d34 100644 --- a/demos/dialog/default.html +++ b/demos/dialog/default.html @@ -1,54 +1,24 @@ - + - + + jQuery UI Dialog - Default functionality - - - - - - - - - - - - + -
      -

      This is the default dialog which is useful for displaying information. The dialog window can be moved, resized and closed with the 'x' icon.

      - -
      -

      Sed vel diam id libero rutrum convallis. Donec aliquet leo vel magna. Phasellus rhoncus faucibus ante. Etiam bibendum, enim faucibus aliquet rhoncus, arcu felis ultricies neque, sit amet auctor elit eros a lectus.

      -
      -
      - checkbox
      - radio
      -

      -
      -
      -
      - -
      -
      -

      The basic dialog window is an overlay positioned within the viewport and is protected from page content (like select elements) shining through with an iframe. It has a title bar and a content area, and can be moved, resized and closed with the 'x' icon by default.

      - -
      - + diff --git a/demos/dialog/index.html b/demos/dialog/index.html index 45d4a9f43ec..5ba8452d57c 100644 --- a/demos/dialog/index.html +++ b/demos/dialog/index.html @@ -1,23 +1,19 @@ - + - + + jQuery UI Dialog Demos - - + diff --git a/demos/dialog/modal-confirmation.html b/demos/dialog/modal-confirmation.html index 4affb5964e9..fad6bc396a2 100644 --- a/demos/dialog/modal-confirmation.html +++ b/demos/dialog/modal-confirmation.html @@ -1,69 +1,39 @@ - + - + + jQuery UI Dialog - Modal confirmation - - - - - - - - - - - - + -
      -
      -

      These items will be permanently deleted and cannot be recovered. Are you sure?

      +

      These items will be permanently deleted and cannot be recovered. Are you sure?

      - -
      -

      Sed vel diam id libero rutrum convallis. Donec aliquet leo vel magna. Phasellus rhoncus faucibus ante. Etiam bibendum, enim faucibus aliquet rhoncus, arcu felis ultricies neque, sit amet auctor elit eros a lectus.

      -
      -
      - checkbox
      - radio
      -

      -
      -
      -
      - -
      +

      Sed vel diam id libero rutrum convallis. Donec aliquet leo vel magna. Phasellus rhoncus faucibus ante. Etiam bibendum, enim faucibus aliquet rhoncus, arcu felis ultricies neque, sit amet auctor elit eros a lectus.

      -

      Confirm an action that may be destructive or important. Set the modal option to true, and specify primary and secondary user actions with the buttons option.

      - -
      - + diff --git a/demos/dialog/modal-form.html b/demos/dialog/modal-form.html index 592b4ab3cd9..98d8ba4becc 100644 --- a/demos/dialog/modal-form.html +++ b/demos/dialog/modal-form.html @@ -1,23 +1,12 @@ - + - + + jQuery UI Dialog - Modal form - - - - - - - - - - - - - - - + -
      -

      All form fields are required.

      -
      - - - - - - -
      +
      + + + + + + + + + +
      - -

      Existing Users:

      - - +

      Existing Users:

      @@ -165,13 +151,8 @@

      Existing Users:

      - -
      -

      Use a modal dialog to require that the user enter data during a multi-step process. Embed form markup in the content area, set the modal option to true, and specify primary and secondary user actions with the buttons option.

      - -
      - + diff --git a/demos/dialog/modal-message.html b/demos/dialog/modal-message.html index a0ab01b21ac..9015bb140dd 100644 --- a/demos/dialog/modal-message.html +++ b/demos/dialog/modal-message.html @@ -1,40 +1,25 @@ - + - + + jQuery UI Dialog - Modal message - - - - - - - - - - - - - + -
      -

      @@ -45,27 +30,10 @@

      - -
      -

      Sed vel diam id libero rutrum convallis. Donec aliquet leo vel magna. Phasellus rhoncus faucibus ante. Etiam bibendum, enim faucibus aliquet rhoncus, arcu felis ultricies neque, sit amet auctor elit eros a lectus.

      -
      -
      - checkbox
      - radio
      -

      -
      - -
      - -
      +

      Sed vel diam id libero rutrum convallis. Donec aliquet leo vel magna. Phasellus rhoncus faucibus ante. Etiam bibendum, enim faucibus aliquet rhoncus, arcu felis ultricies neque, sit amet auctor elit eros a lectus.

      -

      Use a modal dialog to explicitly acknowledge information or an action before continuing their work. Set the modal option to true, and specify a primary action (Ok) with the buttons option.

      - -
      - + diff --git a/demos/dialog/modal.html b/demos/dialog/modal.html deleted file mode 100644 index 2846d57d516..00000000000 --- a/demos/dialog/modal.html +++ /dev/null @@ -1,61 +0,0 @@ - - - - - jQuery UI Dialog - Basic modal - - - - - - - - - - - - - - - - -
      - -
      -

      Adding the modal overlay screen makes the dialog look more prominent because it dims out the page content.

      -
      - - -
      -

      Sed vel diam id libero rutrum convallis. Donec aliquet leo vel magna. Phasellus rhoncus faucibus ante. Etiam bibendum, enim faucibus aliquet rhoncus, arcu felis ultricies neque, sit amet auctor elit eros a lectus.

      -
      -
      - checkbox
      - radio
      -

      -
      - -
      - -
      - -
      - -

      A modal dialog prevents the user from interacting with the rest of the page until it is closed.

      - -
      - - - diff --git a/demos/draggable/constrain-movement.html b/demos/draggable/constrain-movement.html index 3bb9075e40e..5b5c9cd9e17 100644 --- a/demos/draggable/constrain-movement.html +++ b/demos/draggable/constrain-movement.html @@ -1,39 +1,32 @@ - + - + + jQuery UI Draggable - Constrain movement - - - - - - - - - + -
      -

      Constrain movement along an axis:

      - +

      Constrain movement along an axis:

      +

      I can be dragged only vertically

      @@ -42,29 +35,19 @@

      Constrain movement along an axis:

      I can be dragged only horizontally

      -

      Or to within another DOM element:

      +

      Or to within another DOM element:

      -
      -

      I'm contained within the box

      -
      +
      +

      I'm contained within the box

      +
      -
      -

      I'm contained within the box's parent

      -
      - -
      -

      I'm contained within my parent

      -
      +
      +

      I'm contained within my parent

      +
      - -
      - -

      -Constrain the movement of each draggable by defining the boundaries of the draggable area. Set the axis option to limit the draggable's path to the x- or y-axis, or use the containment option to specify a parent DOM element or a jQuery selector, like 'document.' -

      - -
      +

      Constrain the movement of each draggable by defining the boundaries of the draggable area. Set the axis option to limit the draggable's path to the x- or y-axis, or use the containment option to specify a parent DOM element or a jQuery selector, like 'document.'

      + diff --git a/demos/draggable/cursor-style.html b/demos/draggable/cursor-style.html index 3263029b03b..822e0e19bba 100644 --- a/demos/draggable/cursor-style.html +++ b/demos/draggable/cursor-style.html @@ -1,29 +1,23 @@ - + - + + jQuery UI Draggable - Cursor style - - - - - - - - - + -
      - +

      I will always stick to the center (relative to the mouse)

      @@ -36,14 +30,8 @@

      My cursor position is only controlled for the 'bottom' value

      - -
      - -

      -Position the cursor while dragging the object. By default the cursor appears in the center of the dragged object; use the cursorAt option to specify another location relative to the draggable (specify a pixel value from the top, right, bottom, and/or left). Customize the cursor's appearance by supplying the cursor option with a valid CSS cursor value: default, move, pointer, crosshair, etc. -

      - -
      +

      Position the cursor while dragging the object. By default the cursor appears in the center of the dragged object; use the cursorAt option to specify another location relative to the draggable (specify a pixel value from the top, right, bottom, and/or left). Customize the cursor's appearance by supplying the cursor option with a valid CSS cursor value: default, move, pointer, crosshair, etc.

      + diff --git a/demos/draggable/default.html b/demos/draggable/default.html index b50c54ab1df..513246ec81d 100644 --- a/demos/draggable/default.html +++ b/demos/draggable/default.html @@ -1,41 +1,27 @@ - + - + + jQuery UI Draggable - Default functionality - - - - - - - - - + -
      -

      Drag me around

      -
      -
      - -

      -Enable draggable functionality on any DOM element. Move the draggable object by clicking on it with the mouse and dragging it anywhere within the viewport. -

      - -
      - +

      Enable draggable functionality on any DOM element. Move the draggable object by clicking on it with the mouse and dragging it anywhere within the viewport.

      + diff --git a/demos/draggable/delay-start.html b/demos/draggable/delay-start.html deleted file mode 100644 index c997e28e26b..00000000000 --- a/demos/draggable/delay-start.html +++ /dev/null @@ -1,45 +0,0 @@ - - - - - jQuery UI Draggable - Delay start - - - - - - - - - - - -
      - -
      -

      Only if you drag me by 20 pixels, the dragging will start

      -
      - -
      -

      Regardless of the distance, you have to drag and wait for 1000ms before dragging starts

      -
      - -
      - -
      - -

      -Delay the start of dragging for a number of milliseconds with the delay option; prevent dragging until the cursor is held down and dragged a specifed number of pixels with the distance option. -

      - -
      - - diff --git a/demos/draggable/events.html b/demos/draggable/events.html index 194598ffb21..9b7656571a9 100644 --- a/demos/draggable/events.html +++ b/demos/draggable/events.html @@ -1,57 +1,52 @@ - + - + + jQuery UI Draggable - Events - - - - - - - - - + -
      -

      Drag me to trigger the chain of events.

      @@ -63,15 +58,8 @@
      -
      -
      - -

      -Layer functionality onto the draggable using the start, drag, and stop events. Start is fired at the start of the drag; drag during the drag; and stop when dragging stops. -

      - -
      - +

      Layer functionality onto the draggable using the start, drag, and stop events. Start is fired at the start of the drag; drag during the drag; and stop when dragging stops.

      + diff --git a/demos/draggable/handle.html b/demos/draggable/handle.html index 16bd8a8d761..76a2b5314ae 100644 --- a/demos/draggable/handle.html +++ b/demos/draggable/handle.html @@ -1,30 +1,24 @@ - + - + + jQuery UI Draggable - Handles - - - - - - - - - + -
      - +

      I can be dragged only by this handle

      @@ -34,15 +28,9 @@

      …but you can't drag me by this handle.

      - - - -
      -

      Allow dragging only when the cursor is over a specific part of the draggable. Use the handle option to specify the jQuery selector of an element (or group of elements) used to drag the object.

      Or prevent dragging when the cursor is over a specific element (or group of elements) within the draggable. Use the cancel option to specify a jQuery selector over which to "cancel" draggable functionality.

      - -
      + diff --git a/demos/draggable/index.html b/demos/draggable/index.html index 65b900c911d..ceffb9b72d4 100644 --- a/demos/draggable/index.html +++ b/demos/draggable/index.html @@ -1,28 +1,24 @@ - + - + + jQuery UI Draggable Demos - - + diff --git a/demos/draggable/revert.html b/demos/draggable/revert.html index 77b79599cf8..1ae97c970eb 100644 --- a/demos/draggable/revert.html +++ b/demos/draggable/revert.html @@ -1,28 +1,22 @@ - + - + + jQuery UI Draggable - Revert position - - - - - - - - - + -
      - +

      Revert the original

      @@ -31,14 +25,8 @@

      Revert the helper

      - -
      - -

      -Return the draggable (or it's helper) to its original location when dragging stops with the boolean revert option. -

      - -
      +

      Return the draggable (or it's helper) to its original location when dragging stops with the boolean revert option.

      + diff --git a/demos/draggable/scroll.html b/demos/draggable/scroll.html index c7033b34eb1..727b226b80a 100644 --- a/demos/draggable/scroll.html +++ b/demos/draggable/scroll.html @@ -1,29 +1,23 @@ - + - + + jQuery UI Draggable - Auto-scroll - - - - - - - - - + -
      - +

      Scroll set to true, default settings

      @@ -38,14 +32,8 @@
      -
      -
      - -

      -Automatically scroll the document when the draggable is moved beyond the viewport. Set the scroll option to true to enable auto-scrolling, and fine-tune when scrolling is triggered and its speed with the scrollSensitivity and scrollSpeed options. -

      - -
      +

      Automatically scroll the document when the draggable is moved beyond the viewport. Set the scroll option to true to enable auto-scrolling, and fine-tune when scrolling is triggered and its speed with the scrollSensitivity and scrollSpeed options.

      + diff --git a/demos/draggable/snap-to.html b/demos/draggable/snap-to.html index a9ad84642d4..a08cdd10a4d 100644 --- a/demos/draggable/snap-to.html +++ b/demos/draggable/snap-to.html @@ -1,38 +1,32 @@ - + - + + jQuery UI Draggable - Snap to element or grid - - - - - - - - - + -
      - +

      I'm a snap target

      -
      +

      Default (snap: true), snaps to all other draggable elements

      @@ -54,17 +48,9 @@

      I snap to a 80 x 80 grid

      -
      -
      -

      Snap the draggable to the inner or outer boundaries of a DOM element. Use the snap, snapMode (inner, outer, both), and snapTolerance (distance in pixels the draggable must be from the element when snapping is invoked) options.

      -

      Or snap the draggable to a grid. Set the dimensions of grid cells (height and width in pixels) with the grid option.

      - -
      - - - + diff --git a/demos/draggable/sortable.html b/demos/draggable/sortable.html index a87ddc0ef91..96c2c4f9b40 100644 --- a/demos/draggable/sortable.html +++ b/demos/draggable/sortable.html @@ -1,37 +1,30 @@ - + - + + jQuery UI Draggable + Sortable - - - - - - - - - - + -
      - +
      • Drag me down
      @@ -44,14 +37,8 @@
    • Item 5
    • -
      -
      - -

      -Draggables are built to interact seamlessly with sortables. -

      - -
      +

      Draggables are built to interact seamlessly with sortables.

      + diff --git a/demos/draggable/visual-feedback.html b/demos/draggable/visual-feedback.html index 4644472f08d..403a37158a3 100644 --- a/demos/draggable/visual-feedback.html +++ b/demos/draggable/visual-feedback.html @@ -1,38 +1,32 @@ - + - + + jQuery UI Draggable - Visual feedback - - - - - - - - - + -

      With helpers:

      @@ -63,14 +57,9 @@

      Stacked:

      - -
      -

      Provide feedback to users as they drag an object in the form of a helper. The helper option accepts the values 'original' (the draggable object moves with the cursor), 'clone' (a duplicate of the draggable moves with the cursor), or a function that returns a DOM element (that element is shown near the cursor during drag). Control the helper's transparency with the opacity option.

      -

      To clarify which draggable is in play, bring the draggable in motion to front. Use the zIndex option to set a higher z-index for the helper, if in play, or use the stack option to ensure that the last item dragged will appear on top of others in the same group on drag stop.

      - -
      + diff --git a/demos/droppable/accepted-elements.html b/demos/droppable/accepted-elements.html index 0ba0207e394..16f224b7d3b 100644 --- a/demos/droppable/accepted-elements.html +++ b/demos/droppable/accepted-elements.html @@ -1,40 +1,35 @@ - + - - jQuery UI Droppable - Accept Demo - - - - - - - - - - + -
      - +

      I'm draggable but can't be dropped

      @@ -47,12 +42,8 @@

      accept: '#draggable'

      - -
      -

      Specify using the accept option which element (or group of elements) is accepted by the target droppable.

      - -
      + diff --git a/demos/droppable/default.html b/demos/droppable/default.html index 4134dc942df..4d76ab4006b 100644 --- a/demos/droppable/default.html +++ b/demos/droppable/default.html @@ -1,35 +1,30 @@ - + - - jQuery UI Droppable - Default Demo - - - - - - - - - - + -
      - +

      Drag me to my target

      @@ -38,12 +33,8 @@

      Drop here

      - -
      -

      Enable any DOM element to be droppable, a target for draggable elements.

      - -
      + diff --git a/demos/droppable/images/high_tatras.jpg b/demos/droppable/images/high_tatras.jpg index e2365c29ede..5723680df54 100644 Binary files a/demos/droppable/images/high_tatras.jpg and b/demos/droppable/images/high_tatras.jpg differ diff --git a/demos/droppable/images/high_tatras2.jpg b/demos/droppable/images/high_tatras2.jpg index 909024a575d..1acad3afb07 100644 Binary files a/demos/droppable/images/high_tatras2.jpg and b/demos/droppable/images/high_tatras2.jpg differ diff --git a/demos/droppable/images/high_tatras3.jpg b/demos/droppable/images/high_tatras3.jpg index 05a43956f9a..e158b1ae064 100644 Binary files a/demos/droppable/images/high_tatras3.jpg and b/demos/droppable/images/high_tatras3.jpg differ diff --git a/demos/droppable/images/high_tatras4.jpg b/demos/droppable/images/high_tatras4.jpg index ed753d1e369..da4124d88f6 100644 Binary files a/demos/droppable/images/high_tatras4.jpg and b/demos/droppable/images/high_tatras4.jpg differ diff --git a/demos/droppable/index.html b/demos/droppable/index.html index e0c4e6ae274..c3317f6c4a5 100644 --- a/demos/droppable/index.html +++ b/demos/droppable/index.html @@ -1,24 +1,20 @@ - + - + + jQuery UI Droppable Demos - - + diff --git a/demos/droppable/photo-manager.html b/demos/droppable/photo-manager.html index a611c0c5051..ba3eedfb306 100644 --- a/demos/droppable/photo-manager.html +++ b/demos/droppable/photo-manager.html @@ -1,167 +1,178 @@ - + - + + jQuery UI Droppable - Simple photo manager - - - - - - - - - - - - + -
      - - - -
      -

      Trash Trash

      -
      - -
      - -
      - -

      You can delete an image either by dragging it to the Trash or by clicking the trash icon.

      -

      You can "recycle" an image by dragging it back to the gallery or by clicking the recycle icon.

      -

      You can view larger image by clicking the zoom icon. jQuery UI dialog widget is used for the modal window.

      - -
      + +
      + + + +
      +

      Trash Trash

      +
      + +
      + +
      +

      You can delete an image either by dragging it to the Trash or by clicking the trash icon.

      +

      You can "recycle" an image by dragging it back to the gallery or by clicking the recycle icon.

      +

      You can view larger image by clicking the zoom icon. jQuery UI dialog widget is used for the modal window.

      +
      diff --git a/demos/droppable/propagation.html b/demos/droppable/propagation.html index e6cf3c212ff..a70c2f07696 100644 --- a/demos/droppable/propagation.html +++ b/demos/droppable/propagation.html @@ -1,50 +1,51 @@ - + - + + jQuery UI Droppable - Prevent propagation - - - - - - - - - - + -
      - +

      Drag me to my target

      @@ -63,12 +64,8 @@
      - -
      -

      When working with nested droppables — for example, you may have an editable directory structure displayed as a tree, with folder and document nodes — the greedy option set to true prevents event propagation when a draggable is dropped on a child node (droppable).

      - -
      + diff --git a/demos/droppable/revert.html b/demos/droppable/revert.html index 1f36c71787b..5beacab992e 100644 --- a/demos/droppable/revert.html +++ b/demos/droppable/revert.html @@ -1,40 +1,36 @@ - + - + + jQuery UI Droppable - Revert draggable position - - - - - - - - - - + -
      - +

      I revert when I'm dropped

      @@ -47,12 +43,8 @@

      Drop me here

      - -
      -

      Return the draggable (or it's helper) to its original location when dragging stops with the boolean revert option set on the draggable.

      - -
      + diff --git a/demos/droppable/shopping-cart.html b/demos/droppable/shopping-cart.html deleted file mode 100644 index de8ce4fe38f..00000000000 --- a/demos/droppable/shopping-cart.html +++ /dev/null @@ -1,101 +0,0 @@ - - - - - jQuery UI Droppable - Shopping Cart Demo - - - - - - - - - - - - - - -
      - -
      -

      Products

      -
      -

      T-Shirts

      -
      -
        -
      • Lolcat Shirt
      • -
      • Cheezeburger Shirt
      • -
      • Buckit Shirt
      • -
      -
      -

      Bags

      -
      -
        -
      • Zebra Striped
      • -
      • Black Leather
      • -
      • Alligator Leather
      • -
      -
      -

      Gadgets

      -
      -
        -
      • iPhone
      • -
      • iPod
      • -
      • iPad
      • -
      -
      -
      -
      - -
      -

      Shopping Cart

      -
      -
        -
      1. Add your items here
      2. -
      -
      -
      - -
      - -
      - -

      Demonstrate how to use an accordion to structure products into a catalog and make use drag and drop for adding -them to a shopping cart, where they are sortable.

      - -
      - - diff --git a/demos/droppable/visual-feedback.html b/demos/droppable/visual-feedback.html index 1bb6c603807..a6eb9db58c3 100644 --- a/demos/droppable/visual-feedback.html +++ b/demos/droppable/visual-feedback.html @@ -1,47 +1,50 @@ - + - + + jQuery UI Droppable - Visual feedback - - - - - - - - - - + -
      -

      Feedback on hover:

      - +

      Feedback on hover:

      +

      Drag me to my target

      @@ -50,7 +53,7 @@

      Feedback on hover:

      Drop here

      -

      Feedback on activating draggable:

      +

      Feedback on activating draggable:

      Drag me to my target

      @@ -60,14 +63,8 @@

      Feedback on activating draggable:

      Drop here

      - - - -
      - -

      Change the droppable's appearance on hover, or when the droppable is active (an acceptable draggable is dropped on it). Use the hoverClass or activeClass options to specify respective classes.

      - -
      +

      Change the droppable's appearance on hover, or when the droppable is active (an acceptable draggable is dropped on it). Set the values of the ui-droppable-hover or ui-droppable-active properties on the classes option to specify the respective classes.

      + diff --git a/demos/effect/addClass.html b/demos/effect/addClass.html new file mode 100644 index 00000000000..45b6f5f4cc2 --- /dev/null +++ b/demos/effect/addClass.html @@ -0,0 +1,42 @@ + + + + + + jQuery UI Effects - addClass demo + + + + + + + + +
      +
      + Etiam libero neque, luctus a, eleifend nec, semper at, lorem. Sed pede. +
      +
      + + + +
      +

      This demo adds a class which animates: text-indent, letter-spacing, width, height, padding, margin, and font-size.

      +
      + + diff --git a/demos/effect/animate.html b/demos/effect/animate.html new file mode 100644 index 00000000000..2ff34399c88 --- /dev/null +++ b/demos/effect/animate.html @@ -0,0 +1,53 @@ + + + + + + jQuery UI Effects - Animate demo + + + + + + + + +
      +
      +

      Animate

      +

      + Etiam libero neque, luctus a, eleifend nec, semper at, lorem. Sed pede. Nulla lorem metus, adipiscing ut, luctus sed, hendrerit vitae, mi. +

      +
      +
      + + + +
      +

      Click the button above to preview the effect.

      +
      + + diff --git a/demos/effect/default.html b/demos/effect/default.html index f2988c5c39f..289d5df7ff0 100644 --- a/demos/effect/default.html +++ b/demos/effect/default.html @@ -1,70 +1,53 @@ - + - - jQuery UI Effects - Effect Demo - - - - - - - - - - - - - - - - - - - + -
      -

      Effect

      @@ -89,19 +72,12 @@

      Effect

      - -Run Effect - - -
      +
      -

      Click the button above to show the effect.

      - -
      - +
      diff --git a/demos/effect/easing.html b/demos/effect/easing.html index 12d18fe7013..3014f762034 100644 --- a/demos/effect/easing.html +++ b/demos/effect/easing.html @@ -1,101 +1,104 @@ - + - - jQuery UI Effects - Effect Demo - - - - - - + -
      - -
      - -
      - -
      +
      - -

      All easings provided by jQuery UI are drawn above, using a HTML canvas element. Click a diagram to see the easing in action.

      - -
      - +

      All easings provided by jQuery UI are drawn above, using an HTML canvas element. Click a diagram to see the easing in action.

      +
      - diff --git a/demos/effect/hide.html b/demos/effect/hide.html new file mode 100644 index 00000000000..cbfb47d619e --- /dev/null +++ b/demos/effect/hide.html @@ -0,0 +1,82 @@ + + + + + + jQuery UI Effects - Hide Demo + + + + + + + + +
      +
      +

      Hide

      +

      + Etiam libero neque, luctus a, eleifend nec, semper at, lorem. Sed pede. Nulla lorem metus, adipiscing ut, luctus sed, hendrerit vitae, mi. +

      +
      +
      + + + + + +
      +

      Click the button above to preview the effect.

      +
      + + diff --git a/demos/effect/index.html b/demos/effect/index.html index cecceb6cd39..92d29860987 100644 --- a/demos/effect/index.html +++ b/demos/effect/index.html @@ -1,24 +1,24 @@ - + - - jQuery UI Effect Demos - + + + jQuery UI Effects Demos -
      -

      Examples

      - -
      + diff --git a/demos/effect/removeClass.html b/demos/effect/removeClass.html new file mode 100644 index 00000000000..1b2c9bd29eb --- /dev/null +++ b/demos/effect/removeClass.html @@ -0,0 +1,42 @@ + + + + + + jQuery UI Effects - removeClass Demo + + + + + + + + +
      +
      + Etiam libero neque, luctus a, eleifend nec, semper at, lorem. Sed pede. +
      +
      + + + +
      +

      Click the button above to preview the effect.

      +
      + + diff --git a/demos/effect/show.html b/demos/effect/show.html new file mode 100644 index 00000000000..8a980711c3b --- /dev/null +++ b/demos/effect/show.html @@ -0,0 +1,84 @@ + + + + + + jQuery UI Effects - Show Demo + + + + + + + + +
      +
      +

      Show

      +

      + Etiam libero neque, luctus a, eleifend nec, semper at, lorem. Sed pede. Nulla lorem metus, adipiscing ut, luctus sed, hendrerit vitae, mi. +

      +
      +
      + + + + + +
      +

      Click the button above to preview the effect.

      +
      + + diff --git a/demos/effect/switchClass.html b/demos/effect/switchClass.html new file mode 100644 index 00000000000..ad52854d1bf --- /dev/null +++ b/demos/effect/switchClass.html @@ -0,0 +1,37 @@ + + + + + + jQuery UI Effects - switchClass Demo + + + + + + + + +
      +
      + Etiam libero neque, luctus a, eleifend nec, semper at, lorem. Sed pede. +
      +
      + + +
      +

      Click the button above to preview the effect.

      +
      + + diff --git a/demos/effect/toggle.html b/demos/effect/toggle.html new file mode 100644 index 00000000000..bf94e82e04d --- /dev/null +++ b/demos/effect/toggle.html @@ -0,0 +1,90 @@ + + + + + + jQuery UI Effects - Toggle Demo + + + + + + + + +
      +
      +

      Toggle

      +

      + Etiam libero neque, luctus a, eleifend nec, semper at, lorem. Sed pede. Nulla lorem metus, adipiscing ut, luctus sed, hendrerit vitae, mi. +

      +
      +
      + + + + + +
      +

      Click the button above to preview the effect.

      +
      + + diff --git a/demos/effect/toggleClass.html b/demos/effect/toggleClass.html new file mode 100644 index 00000000000..80ed7f29fad --- /dev/null +++ b/demos/effect/toggleClass.html @@ -0,0 +1,36 @@ + + + + + + jQuery UI Effects - toggleClass Demo + + + + + + + + +
      +
      + Etiam libero neque, luctus a, eleifend nec, semper at, lorem. Sed pede. +
      +
      + + + +
      +

      Click the button above to preview the effect.

      +
      + + diff --git a/demos/hide/default.html b/demos/hide/default.html deleted file mode 100644 index 678092d9a23..00000000000 --- a/demos/hide/default.html +++ /dev/null @@ -1,102 +0,0 @@ - - - - - jQuery UI Effects - Hide Demo - - - - - - - - - - - - - - - - - - - - -
      - -
      -
      -

      Hide

      -

      - Etiam libero neque, luctus a, eleifend nec, semper at, lorem. Sed pede. Nulla lorem metus, adipiscing ut, luctus sed, hendrerit vitae, mi. -

      -
      -
      - - - -Run Effect - - -
      - -
      - -

      Click the button above to preview the effect.

      - -
      - - - diff --git a/demos/hide/index.html b/demos/hide/index.html deleted file mode 100644 index 0e9af371fea..00000000000 --- a/demos/hide/index.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - - jQuery UI Effects Demos - - - - -
      -

      Examples

      - -
      - - - diff --git a/demos/images/calendar.gif b/demos/images/calendar.gif index d0abaa7c0b8..52f2863c907 100644 Binary files a/demos/images/calendar.gif and b/demos/images/calendar.gif differ diff --git a/demos/images/demo-config-on-tile.gif b/demos/images/demo-config-on-tile.gif index 359da95a77a..a96b5bf33ad 100644 Binary files a/demos/images/demo-config-on-tile.gif and b/demos/images/demo-config-on-tile.gif differ diff --git a/demos/images/demo-config-on.gif b/demos/images/demo-config-on.gif index 9fcec1ac1b1..e3b6d7c0f72 100644 Binary files a/demos/images/demo-config-on.gif and b/demos/images/demo-config-on.gif differ diff --git a/demos/images/demo-spindown-closed.gif b/demos/images/demo-spindown-closed.gif index b247824e904..ad4bd3781b5 100644 Binary files a/demos/images/demo-spindown-closed.gif and b/demos/images/demo-spindown-closed.gif differ diff --git a/demos/images/icon-docs-info.gif b/demos/images/icon-docs-info.gif index 6b0464e0111..ea6d2bece71 100644 Binary files a/demos/images/icon-docs-info.gif and b/demos/images/icon-docs-info.gif differ diff --git a/demos/images/jquery_32x32.png b/demos/images/jquery_32x32.png deleted file mode 100644 index 1cd42c9fe92..00000000000 Binary files a/demos/images/jquery_32x32.png and /dev/null differ diff --git a/demos/images/jqueryui_32x32.png b/demos/images/jqueryui_32x32.png deleted file mode 100644 index 23ca0f8b93f..00000000000 Binary files a/demos/images/jqueryui_32x32.png and /dev/null differ diff --git a/demos/images/pbar-ani.gif b/demos/images/pbar-ani.gif index 0dfd45b885a..c22469afd8a 100644 Binary files a/demos/images/pbar-ani.gif and b/demos/images/pbar-ani.gif differ diff --git a/demos/images/sizzlejs_32x32.png b/demos/images/sizzlejs_32x32.png deleted file mode 100644 index 8d7ae1e0bc6..00000000000 Binary files a/demos/images/sizzlejs_32x32.png and /dev/null differ diff --git a/demos/images/transparent_1x1.png b/demos/images/transparent_1x1.png deleted file mode 100644 index 209a4386453..00000000000 Binary files a/demos/images/transparent_1x1.png and /dev/null differ diff --git a/demos/index.html b/demos/index.html index db3e2bf836f..89375dde704 100644 --- a/demos/index.html +++ b/demos/index.html @@ -1,313 +1,36 @@ - + - - + + jQuery UI Demos - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      - - - - -
      -
      -
      Interactions
      -
      Draggable
      -
      Droppable
      -
      Resizable
      -
      Selectable
      -
      Sortable
      -
      Widgets
      -
      Accordion
      -
      Autocomplete
      -
      Button
      -
      Datepicker
      -
      Dialog
      -
      Progressbar
      -
      Slider
      -
      Tabs
      -
      Effects
      -
      Color Animation
      -
      Toggle Class
      -
      Add Class
      -
      Remove Class
      -
      Switch Class
      -
      Effect
      -
      Toggle
      -
      Hide
      -
      Show
      -
      Utilities
      -
      Position
      -
      About jQuery UI
      -
      Getting Started
      -
      Upgrade Guide
      -
      Changelog
      -
      Roadmap
      -
      Subversion Access
      -
      UI Developer Guidelines
      -
      Theming
      -
      Theming jQuery UI
      -
      jQuery UI CSS Framework
      -
      ThemeRoller application
      -
      Theme Switcher Widget
      - -
      -
      - -
      - -

      Instructions

      -

      - These demos showcase some common uses of each jQuery UI plugin. Simply copy and paste code from the demos to get started. Have fun playing with them. -

      - -
      + -
      diff --git a/demos/menu/categories.html b/demos/menu/categories.html new file mode 100644 index 00000000000..e359292f339 --- /dev/null +++ b/demos/menu/categories.html @@ -0,0 +1,37 @@ + + + + + + jQuery UI Menu - Categories + + + + + + + + + + +
      +

      By using the items option, you can configure which elements are converted into selectable menu items. Here this technique is used to create category headers.

      +
      + + diff --git a/demos/menu/default.html b/demos/menu/default.html new file mode 100644 index 00000000000..9b91b1dc760 --- /dev/null +++ b/demos/menu/default.html @@ -0,0 +1,56 @@ + + + + + + jQuery UI Menu - Default functionality + + + + + + + + + + +
      +

      A menu with the default configuration, disabled items and nested menus. A list is transformed, adding theming, mouse and keyboard navigation support. Try to tab to the menu then use the cursor keys to navigate.

      +
      + + diff --git a/demos/menu/icons.html b/demos/menu/icons.html new file mode 100644 index 00000000000..5f30b9d992f --- /dev/null +++ b/demos/menu/icons.html @@ -0,0 +1,58 @@ + + + + + + jQuery UI Menu - Icons + + + + + + + + + + +
      +

      A menu with the default configuration, showing how to use a menu with icons.

      +
      + + diff --git a/demos/menu/index.html b/demos/menu/index.html new file mode 100644 index 00000000000..431926d357f --- /dev/null +++ b/demos/menu/index.html @@ -0,0 +1,17 @@ + + + + + + jQuery UI Menu Demos + + + + + + + diff --git a/demos/position/cycler.html b/demos/position/cycler.html index fa0571e338f..49616b3806a 100644 --- a/demos/position/cycler.html +++ b/demos/position/cycler.html @@ -1,125 +1,102 @@ - + - - jQuery UI Position - Default functionality - - - - - - - - - - + - -
      - - - - +
      + earth + flight + rocket
      - -

      A prototype for the Photoviewer using Position to place images at the center, left and right and cycle them. -
      Use the links at the top to cycle, or click on the images on the left and right. -
      Note how the images are repositioned when resizing the window. -
      Warning: Doesn't currently work inside the demo viewer; open in a new window instead!

      - -
      - +

      A photoviewer prototype using Position to place images at the center, left and right and cycle them. +
      Use the links at the top to cycle, or click on the images on the left and right. +
      Note how the images are repositioned when resizing the window. +

      diff --git a/demos/position/default.html b/demos/position/default.html index d26959b965d..4f6b807b834 100644 --- a/demos/position/default.html +++ b/demos/position/default.html @@ -1,31 +1,22 @@ - + - + + jQuery UI Position - Default functionality - - - - - - - - - - + - -
      -

      This is the position parent element.

      -
      +

      to position

      -
      +

      to position 2

      @@ -107,10 +86,10 @@ - +
      @@ -123,37 +102,30 @@
      -
      - offset: - -
      collision:
      -
      -
      -

      Use the form controls to configure the positioning, or drag the positioned element to modify its offset. -
      Drag around the parent element to see collision detection in action.

      - -
      - +
      Drag around the parent element to see collision detection in action.

      +
      diff --git a/demos/position/images/earth.jpg b/demos/position/images/earth.jpg index 87ea48803d4..e5477f75461 100644 Binary files a/demos/position/images/earth.jpg and b/demos/position/images/earth.jpg differ diff --git a/demos/position/images/flight.jpg b/demos/position/images/flight.jpg index 9721986c07a..362bd1a2239 100644 Binary files a/demos/position/images/flight.jpg and b/demos/position/images/flight.jpg differ diff --git a/demos/position/images/rocket.jpg b/demos/position/images/rocket.jpg index d3bff6123ae..9c0495c61dc 100644 Binary files a/demos/position/images/rocket.jpg and b/demos/position/images/rocket.jpg differ diff --git a/demos/position/index.html b/demos/position/index.html index 54a6d54c63c..8e515c4fe18 100644 --- a/demos/position/index.html +++ b/demos/position/index.html @@ -1,19 +1,16 @@ - + - + + jQuery UI Position Demo - - + diff --git a/demos/progressbar/animated.html b/demos/progressbar/animated.html deleted file mode 100644 index e094f64a381..00000000000 --- a/demos/progressbar/animated.html +++ /dev/null @@ -1,44 +0,0 @@ - - - - - jQuery UI Progressbar - Animated - - - - - - - - - - - -
      - -
      - -
      - -
      - -

      -This progressbar has an animated fill by setting the -background-image -on the -.ui-progressbar-value -element, using css. -

      - -
      - - - diff --git a/demos/progressbar/default.html b/demos/progressbar/default.html index 86c7c9c54e0..2625b00b123 100644 --- a/demos/progressbar/default.html +++ b/demos/progressbar/default.html @@ -1,39 +1,24 @@ - + - + + jQuery UI Progressbar - Default functionality - - - - - - - + -
      - -
      - -
      - - +
      -

      Default determinate progress bar.

      - -
      - - - +
      diff --git a/demos/progressbar/download.html b/demos/progressbar/download.html new file mode 100644 index 00000000000..0528fc63bbe --- /dev/null +++ b/demos/progressbar/download.html @@ -0,0 +1,106 @@ + + + + + + jQuery UI Progressbar - Download Dialog + + + + + + + + +
      +
      Starting download...
      +
      +
      + + +
      +

      Download dialog progressbar demo.

      +
      + + diff --git a/demos/progressbar/images/pbar-ani.gif b/demos/progressbar/images/pbar-ani.gif index 0dfd45b885a..c22469afd8a 100644 Binary files a/demos/progressbar/images/pbar-ani.gif and b/demos/progressbar/images/pbar-ani.gif differ diff --git a/demos/progressbar/indeterminate.html b/demos/progressbar/indeterminate.html new file mode 100644 index 00000000000..816808f82d7 --- /dev/null +++ b/demos/progressbar/indeterminate.html @@ -0,0 +1,49 @@ + + + + + + jQuery UI Progressbar - Indeterminate Value + + + + + + + + +
      + + + + +
      +

      Indeterminate progress bar and switching between determinate and indeterminate styles.

      +
      + + diff --git a/demos/progressbar/index.html b/demos/progressbar/index.html index cf8ee9fe370..1a9e9c9216b 100644 --- a/demos/progressbar/index.html +++ b/demos/progressbar/index.html @@ -1,20 +1,18 @@ - + - + + jQuery UI Progressbar Demos - - + diff --git a/demos/progressbar/label.html b/demos/progressbar/label.html new file mode 100644 index 00000000000..9ff0a7596e9 --- /dev/null +++ b/demos/progressbar/label.html @@ -0,0 +1,57 @@ + + + + + + jQuery UI Progressbar - Custom Label + + + + + + + + +
      Loading...
      + +
      +

      Custom updated label demo.

      +
      + + diff --git a/demos/progressbar/resize.html b/demos/progressbar/resize.html deleted file mode 100644 index fb99ab8ee6d..00000000000 --- a/demos/progressbar/resize.html +++ /dev/null @@ -1,39 +0,0 @@ - - - - - jQuery UI Progressbar - Resizable - - - - - - - - - - - -
      - -
      -
      -
      - -
      - -
      - -

      The progress bar's widths are specified in percentages for flexible sizing so it will resize to fit its container. Try resizing the height and width of this bar to see how it maintains the correct proportions. (This is not necessarily a real-world example, but it's a good illustration of how flexibly all the plugins are coded.)

      - -
      - - - diff --git a/demos/removeClass/default.html b/demos/removeClass/default.html deleted file mode 100644 index 15a5a57562b..00000000000 --- a/demos/removeClass/default.html +++ /dev/null @@ -1,52 +0,0 @@ - - - - - jQuery UI Effects - removeClass Demo - - - - - - - - - -
      - -
      -
      - Etiam libero neque, luctus a, eleifend nec, semper at, lorem. Sed pede. -
      -
      - -Run Effect - -
      - -
      - -

      Click the button above to preview the effect.

      - -
      - - - diff --git a/demos/removeClass/index.html b/demos/removeClass/index.html deleted file mode 100644 index 0e9af371fea..00000000000 --- a/demos/removeClass/index.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - - jQuery UI Effects Demos - - - - -
      -

      Examples

      - -
      - - - diff --git a/demos/resizable/animate.html b/demos/resizable/animate.html index 36739e3dd37..012777ad731 100644 --- a/demos/resizable/animate.html +++ b/demos/resizable/animate.html @@ -1,41 +1,31 @@ - + - + + jQuery UI Resizable - Animate - - - - - - - - - + -
      - +

      Animate

      -
      -
      -

      Animate the resize action using the animate option (boolean). When this option is set to true, drag the outline to the desired location; the element animates to that size on drag stop.

      - -
      + diff --git a/demos/resizable/aspect-ratio.html b/demos/resizable/aspect-ratio.html index ae236ec59ee..6fe961db4c1 100644 --- a/demos/resizable/aspect-ratio.html +++ b/demos/resizable/aspect-ratio.html @@ -1,40 +1,30 @@ - + - + + jQuery UI Resizable - Preserve aspect ratio - - - - - - - - - + -
      - +

      Preserve aspect ratio

      -
      -
      -

      Maintain the existing aspect ratio or set a new one to constrain the proportions on resize. Set the aspectRatio option to true, and optionally pass in a new ratio (i.e., 4/3)

      - -
      + diff --git a/demos/resizable/constrain-area.html b/demos/resizable/constrain-area.html index 2fdbbd95743..b2660192ea6 100644 --- a/demos/resizable/constrain-area.html +++ b/demos/resizable/constrain-area.html @@ -1,32 +1,26 @@ - + - + + jQuery UI Resizable - Constrain resize area - - - - - - - - - + -
      - +

      Containment

      @@ -34,12 +28,8 @@

      Resizable

      -
      -
      -

      Define the boundaries of the resizable area. Use the containment option to specify a parent DOM element or a jQuery selector, like 'document.'

      - -
      + diff --git a/demos/resizable/default.html b/demos/resizable/default.html index a8dfd251c38..ef82efd2382 100644 --- a/demos/resizable/default.html +++ b/demos/resizable/default.html @@ -1,38 +1,28 @@ - + - + + jQuery UI Resizable - Default functionality - - - - - - - - - + -
      - +

      Resizable

      -
      -
      -

      Enable any DOM element to be resizable. With the cursor grab the right or bottom border and drag to the desired width or height.

      - -
      + diff --git a/demos/resizable/delay-start.html b/demos/resizable/delay-start.html deleted file mode 100644 index 16e0242304d..00000000000 --- a/demos/resizable/delay-start.html +++ /dev/null @@ -1,52 +0,0 @@ - - - - - jQuery UI Resizable - Delay start - - - - - - - - - - - -
      - -

      Time delay (ms):

      -
      -

      Time

      -
      - -

      Distance delay (px):

      -
      -

      Distance

      -
      - - - -
      - -
      - -

      Delay the start of resizng for a number of milliseconds with the delay option; prevent resizing until the cursor is held down and dragged a specifed number of pixels with the distance option.

      - -
      - - diff --git a/demos/resizable/helper.html b/demos/resizable/helper.html index 49e8114ab60..f68da91b726 100644 --- a/demos/resizable/helper.html +++ b/demos/resizable/helper.html @@ -1,41 +1,31 @@ - + - + + jQuery UI Resizable - Helper - - - - - - - - - + -
      - +

      Helper

      -
      -
      -

      Display only an outline of the element while resizing by setting the helper option to a CSS class.

      - -
      + diff --git a/demos/resizable/index.html b/demos/resizable/index.html index 93198d03c99..568c9cb57e4 100644 --- a/demos/resizable/index.html +++ b/demos/resizable/index.html @@ -1,28 +1,24 @@ - + - + + jQuery UI Resizable Demos - - + diff --git a/demos/resizable/max-min.html b/demos/resizable/max-min.html index a1c9f6f867b..69b4b57cb70 100644 --- a/demos/resizable/max-min.html +++ b/demos/resizable/max-min.html @@ -1,43 +1,33 @@ - + - + + jQuery UI Resizable - Maximum / minimum size - - - - - - - - - + -
      - +

      Resize larger / smaller

      -
      -
      -

      Limit the resizable element to a maximum or minimum height or width using the maxHeight, maxWidth, minHeight, and minWidth options.

      - -
      + diff --git a/demos/resizable/snap-to-grid.html b/demos/resizable/snap-to-grid.html index 91ebbcd6f27..172ed724ffc 100644 --- a/demos/resizable/snap-to-grid.html +++ b/demos/resizable/snap-to-grid.html @@ -1,40 +1,30 @@ - + - + + jQuery UI Resizable - Snap to grid - - - - - - - - - + -
      - +

      Grid

      -
      -
      -

      Snap the resizable element to a grid. Set the dimensions of grid cells (height and width in pixels) with the grid option.

      - -
      + diff --git a/demos/resizable/synchronous-resize.html b/demos/resizable/synchronous-resize.html index 3b3b3724130..7086c878c7b 100644 --- a/demos/resizable/synchronous-resize.html +++ b/demos/resizable/synchronous-resize.html @@ -1,33 +1,27 @@ - + - + + jQuery UI Resizable - Synchronous resize - - - - - - - - - + -
      - +

      Resize

      @@ -36,12 +30,8 @@

      Resize

      will also resize

      - -
      -

      Resize multiple elements simultaneously by clicking and dragging the sides of one. Pass a shared selector into the alsoResize option.

      - -
      + diff --git a/demos/resizable/textarea.html b/demos/resizable/textarea.html index 2e6e42f9e85..e752654ef0e 100644 --- a/demos/resizable/textarea.html +++ b/demos/resizable/textarea.html @@ -1,39 +1,29 @@ - + - + + jQuery UI Resizable - Textarea - - - - - - - - - + -
      - - -
      +
      - -

      Display only an outline of the element while resizing by setting the helper option to a CSS class.

      - -
      +

      Resizable can be applied to a textarea. This allows the user to make the textarea bigger to type longer prose.

      + diff --git a/demos/resizable/visual-feedback.html b/demos/resizable/visual-feedback.html index 44178423ca1..750d4858d03 100644 --- a/demos/resizable/visual-feedback.html +++ b/demos/resizable/visual-feedback.html @@ -1,41 +1,31 @@ - + - + + jQuery UI Resizable - Visual feedback - - - - - - - - - + -
      - +

      Ghost

      -
      -
      -

      Instead of showing the actual element during resize, set the ghost option to true to show a semi-transparent part of the element.

      - -
      + diff --git a/demos/search.js b/demos/search.js new file mode 100644 index 00000000000..d3a1d8c2322 --- /dev/null +++ b/demos/search.js @@ -0,0 +1,629 @@ +( function( factory ) { + "use strict"; + + if ( typeof define === "function" && define.amd ) { + + // Fetch jQuery as an AMD dependency + require( [ "jquery" ], factory ); + } else { + + // Use the jQuery browser global + factory( jQuery ); + } +} )( function( $ ) { + "use strict"; + + var database = { + "Great Bittern": "Botaurus stellaris", + "Little Grebe": "Tachybaptus ruficollis", + "Black-necked Grebe": "Podiceps nigricollis", + "Little Bittern": "Ixobrychus minutus", + "Black-crowned Night Heron": "Nycticorax nycticorax", + "Purple Heron": "Ardea purpurea", + "White Stork": "Ciconia ciconia", + "Spoonbill": "Platalea leucorodia", + "Red-crested Pochard": "Netta rufina", + "Common Eider": "Somateria mollissima", + "Red Kite": "Milvus milvus", + "Hen Harrier": "Circus cyaneus", + "Montagu`s Harrier": "Circus pygargus", + "Black Grouse": "Tetrao tetrix", + "Grey Partridge": "Perdix perdix", + "Spotted Crake": "Porzana porzana", + "Corncrake": "Crex crex", + "Common Crane": "Grus grus", + "Avocet": "Recurvirostra avosetta", + "Stone Curlew": "Burhinus oedicnemus", + "Common Ringed Plover": "Charadrius hiaticula", + "Kentish Plover": "Charadrius alexandrinus", + "Ruff": "Philomachus pugnax", + "Common Snipe": "Gallinago gallinago", + "Black-tailed Godwit": "Limosa limosa", + "Common Redshank": "Tringa totanus", + "Sandwich Tern": "Sterna sandvicensis", + "Common Tern": "Sterna hirundo", + "Arctic Tern": "Sterna paradisaea", + "Little Tern": "Sternula albifrons", + "Black Tern": "Chlidonias niger", + "Barn Owl": "Tyto alba", + "Little Owl": "Athene noctua", + "Short-eared Owl": "Asio flammeus", + "European Nightjar": "Caprimulgus europaeus", + "Common Kingfisher": "Alcedo atthis", + "Eurasian Hoopoe": "Upupa epops", + "Eurasian Wryneck": "Jynx torquilla", + "European Green Woodpecker": "Picus viridis", + "Crested Lark": "Galerida cristata", + "White-headed Duck": "Oxyura leucocephala", + "Pale-bellied Brent Goose": "Branta hrota", + "Tawny Pipit": "Anthus campestris", + "Whinchat": "Saxicola rubetra", + "European Stonechat": "Saxicola rubicola", + "Northern Wheatear": "Oenanthe oenanthe", + "Savi`s Warbler": "Locustella luscinioides", + "Sedge Warbler": "Acrocephalus schoenobaenus", + "Great Reed Warbler": "Acrocephalus arundinaceus", + "Bearded Reedling": "Panurus biarmicus", + "Red-backed Shrike": "Lanius collurio", + "Great Grey Shrike": "Lanius excubitor", + "Woodchat Shrike": "Lanius senator", + "Common Raven": "Corvus corax", + "Yellowhammer": "Emberiza citrinella", + "Ortolan Bunting": "Emberiza hortulana", + "Corn Bunting": "Emberiza calandra", + "Great Cormorant": "Phalacrocorax carbo", + "Hawfinch": "Coccothraustes coccothraustes", + "Common Shelduck": "Tadorna tadorna", + "Bluethroat": "Luscinia svecica", + "Grey Heron": "Ardea cinerea", + "Barn Swallow": "Hirundo rustica", + "Hooded Crow": "Corvus cornix", + "Dunlin": "Calidris alpina", + "Eurasian Pied Flycatcher": "Ficedula hypoleuca", + "Eurasian Nuthatch": "Sitta europaea", + "Short-toed Tree Creeper": "Certhia brachydactyla", + "Wood Lark": "Lullula arborea", + "Tree Pipit": "Anthus trivialis", + "Eurasian Hobby": "Falco subbuteo", + "Marsh Warbler": "Acrocephalus palustris", + "Wood Sandpiper": "Tringa glareola", + "Tawny Owl": "Strix aluco", + "Lesser Whitethroat": "Sylvia curruca", + "Barnacle Goose": "Branta leucopsis", + "Common Goldeneye": "Bucephala clangula", + "Western Marsh Harrier": "Circus aeruginosus", + "Common Buzzard": "Buteo buteo", + "Sanderling": "Calidris alba", + "Little Gull": "Larus minutus", + "Eurasian Magpie": "Pica pica", + "Willow Warbler": "Phylloscopus trochilus", + "Wood Warbler": "Phylloscopus sibilatrix", + "Great Crested Grebe": "Podiceps cristatus", + "Eurasian Jay": "Garrulus glandarius", + "Common Redstart": "Phoenicurus phoenicurus", + "Blue-headed Wagtail": "Motacilla flava", + "Common Swift": "Apus apus", + "Marsh Tit": "Poecile palustris", + "Goldcrest": "Regulus regulus", + "European Golden Plover": "Pluvialis apricaria", + "Eurasian Bullfinch": "Pyrrhula pyrrhula", + "Common Whitethroat": "Sylvia communis", + "Meadow Pipit": "Anthus pratensis", + "Greylag Goose": "Anser anser", + "Spotted Flycatcher": "Muscicapa striata", + "European Greenfinch": "Carduelis chloris", + "Common Greenshank": "Tringa nebularia", + "Great Spotted Woodpecker": "Dendrocopos major", + "Greater Canada Goose": "Branta canadensis", + "Mistle Thrush": "Turdus viscivorus", + "Great Black-backed Gull": "Larus marinus", + "Goosander": "Mergus merganser", + "Great Egret": "Casmerodius albus", + "Northern Goshawk": "Accipiter gentilis", + "Dunnock": "Prunella modularis", + "Stock Dove": "Columba oenas", + "Common Wood Pigeon": "Columba palumbus", + "Eurasian Woodcock": "Scolopax rusticola", + "House Sparrow": "Passer domesticus", + "Common House Martin": "Delichon urbicum", + "Red Knot": "Calidris canutus", + "Western Jackdaw": "Corvus monedula", + "Brambling": "Fringilla montifringilla", + "Northern Lapwing": "Vanellus vanellus", + "European Reed Warbler": "Acrocephalus scirpaceus", + "Lesser Black-backed Gull": "Larus fuscus", + "Little Egret": "Egretta garzetta", + "Little Stint": "Calidris minuta", + "Common Linnet": "Carduelis cannabina", + "Mute Swan": "Cygnus olor", + "Common Cuckoo": "Cuculus canorus", + "Black-headed Gull": "Larus ridibundus", + "Greater White-fronted Goose": "Anser albifrons", + "Great Tit": "Parus major", + "Redwing": "Turdus iliacus", + "Gadwall": "Anas strepera", + "Fieldfare": "Turdus pilaris", + "Tufted Duck": "Aythya fuligula", + "Crested Tit": "Lophophanes cristatus", + "Willow Tit": "Poecile montanus", + "Eurasian Coot": "Fulica atra", + "Common Blackbird": "Turdus merula", + "Smew": "Mergus albellus", + "Common Sandpiper": "Actitis hypoleucos", + "Sand Martin": "Riparia riparia", + "Purple Sandpiper": "Calidris maritima", + "Northern Pintail": "Anas acuta", + "Blue Tit": "Cyanistes caeruleus", + "European Goldfinch": "Carduelis carduelis", + "Eurasian Whimbrel": "Numenius phaeopus", + "Common Reed Bunting": "Emberiza schoeniclus", + "Eurasian Tree Sparrow": "Passer montanus", + "Rook": "Corvus frugilegus", + "European Robin": "Erithacus rubecula", + "Bar-tailed Godwit": "Limosa lapponica", + "Dark-bellied Brent Goose": "Branta bernicla", + "Eurasian Oystercatcher": "Haematopus ostralegus", + "Eurasian Siskin": "Carduelis spinus", + "Northern Shoveler": "Anas clypeata", + "Eurasian Wigeon": "Anas penelope", + "Eurasian Sparrow Hawk": "Accipiter nisus", + "Icterine Warbler": "Hippolais icterina", + "Common Starling": "Sturnus vulgaris", + "Long-tailed Tit": "Aegithalos caudatus", + "Ruddy Turnstone": "Arenaria interpres", + "Mew Gull": "Larus canus", + "Common Pochard": "Aythya ferina", + "Common Chiffchaff": "Phylloscopus collybita", + "Greater Scaup": "Aythya marila", + "Common Kestrel": "Falco tinnunculus", + "Garden Warbler": "Sylvia borin", + "Eurasian Collared Dove": "Streptopelia decaocto", + "Eurasian Skylark": "Alauda arvensis", + "Common Chaffinch": "Fringilla coelebs", + "Common Moorhen": "Gallinula chloropus", + "Water Pipit": "Anthus spinoletta", + "Mallard": "Anas platyrhynchos", + "Winter Wren": "Troglodytes troglodytes", + "Common Teal": "Anas crecca", + "Green Sandpiper": "Tringa ochropus", + "White Wagtail": "Motacilla alba", + "Eurasian Curlew": "Numenius arquata", + "Song Thrush": "Turdus philomelos", + "European Herring Gull": "Larus argentatus", + "Grey Plover": "Pluvialis squatarola", + "Carrion Crow": "Corvus corone", + "Coal Tit": "Periparus ater", + "Spotted Redshank": "Tringa erythropus", + "Blackcap": "Sylvia atricapilla", + "Egyptian Vulture": "Neophron percnopterus", + "Razorbill": "Alca torda", + "Alpine Swift": "Apus melba", + "Long-legged Buzzard": "Buteo rufinus", + "Audouin`s Gull": "Larus audouinii", + "Balearic Shearwater": "Puffinus mauretanicus", + "Upland Sandpiper": "Bartramia longicauda", + "Greater Spotted Eagle": "Aquila clanga", + "Ring Ouzel": "Turdus torquatus", + "Yellow-browed Warbler": "Phylloscopus inornatus", + "Blue Rock Thrush": "Monticola solitarius", + "Buff-breasted Sandpiper": "Tryngites subruficollis", + "Jack Snipe": "Lymnocryptes minimus", + "White-rumped Sandpiper": "Calidris fuscicollis", + "Ruddy Shelduck": "Tadorna ferruginea", + "Cetti's Warbler": "Cettia cetti", + "Citrine Wagtail": "Motacilla citreola", + "Roseate Tern": "Sterna dougallii", + "Black-legged Kittiwake": "Rissa tridactyla", + "Pygmy Cormorant": "Phalacrocorax pygmeus", + "Booted Eagle": "Aquila pennata", + "Lesser White-fronted Goose": "Anser erythropus", + "Little Bunting": "Emberiza pusilla", + "Eleonora's Falcon": "Falco eleonorae", + "European Serin": "Serinus serinus", + "Twite": "Carduelis flavirostris", + "Yellow-legged Gull": "Larus michahellis", + "Gyr Falcon": "Falco rusticolus", + "Greenish Warbler": "Phylloscopus trochiloides", + "Red-necked Phalarope": "Phalaropus lobatus", + "Mealy Redpoll": "Carduelis flammea", + "Glaucous Gull": "Larus hyperboreus", + "Great Skua": "Stercorarius skua", + "Great Bustard": "Otis tarda", + "Velvet Scoter": "Melanitta fusca", + "Pine Grosbeak": "Pinicola enucleator", + "House Crow": "Corvus splendens", + "Hume`s Leaf Warbler": "Phylloscopus humei", + "Great Northern Loon": "Gavia immer", + "Long-tailed Duck": "Clangula hyemalis", + "Lapland Longspur": "Calcarius lapponicus", + "Northern Gannet": "Morus bassanus", + "Eastern Imperial Eagle": "Aquila heliaca", + "Little Auk": "Alle alle", + "Lesser Spotted Woodpecker": "Dendrocopos minor", + "Iceland Gull": "Larus glaucoides", + "Parasitic Jaeger": "Stercorarius parasiticus", + "Bewick`s Swan": "Cygnus bewickii", + "Little Bustard": "Tetrax tetrax", + "Little Crake": "Porzana parva", + "Baillon`s Crake": "Porzana pusilla", + "Long-tailed Jaeger": "Stercorarius longicaudus", + "King Eider": "Somateria spectabilis", + "Greater Short-toed Lark": "Calandrella brachydactyla", + "Houbara Bustard": "Chlamydotis undulata", + "Curlew Sandpiper": "Calidris ferruginea", + "Common Crossbill": "Loxia curvirostra", + "European Shag": "Phalacrocorax aristotelis", + "Horned Grebe": "Podiceps auritus", + "Common Quail": "Coturnix coturnix", + "Bearded Vulture": "Gypaetus barbatus", + "Lanner Falcon": "Falco biarmicus", + "Middle Spotted Woodpecker": "Dendrocopos medius", + "Pomarine Jaeger": "Stercorarius pomarinus", + "Red-breasted Merganser": "Mergus serrator", + "Eurasian Black Vulture": "Aegypius monachus", + "Eurasian Dotterel": "Charadrius morinellus", + "Common Nightingale": "Luscinia megarhynchos", + "Northern willow warbler": "Phylloscopus trochilus acredula", + "Manx Shearwater": "Puffinus puffinus", + "Northern Fulmar": "Fulmarus glacialis", + "Eurasian Eagle Owl": "Bubo bubo", + "Orphean Warbler": "Sylvia hortensis", + "Melodious Warbler": "Hippolais polyglotta", + "Pallas's Leaf Warbler": "Phylloscopus proregulus", + "Atlantic Puffin": "Fratercula arctica", + "Black-throated Loon": "Gavia arctica", + "Bohemian Waxwing": "Bombycilla garrulus", + "Marsh Sandpiper": "Tringa stagnatilis", + "Great Snipe": "Gallinago media", + "Squacco Heron": "Ardeola ralloides", + "Long-eared Owl": "Asio otus", + "Caspian Tern": "Hydroprogne caspia", + "Red-breasted Goose": "Branta ruficollis", + "Red-throated Loon": "Gavia stellata", + "Common Rosefinch": "Carpodacus erythrinus", + "Red-footed Falcon": "Falco vespertinus", + "Ross's Goose": "Anser rossii", + "Red Phalarope": "Phalaropus fulicarius", + "Pied Wagtail": "Motacilla yarrellii", + "Rose-coloured Starling": "Sturnus roseus", + "Rough-legged Buzzard": "Buteo lagopus", + "Saker Falcon": "Falco cherrug", + "European Roller": "Coracias garrulus", + "Short-toed Eagle": "Circaetus gallicus", + "Peregrine Falcon": "Falco peregrinus", + "Merlin": "Falco columbarius", + "Snow Goose": "Anser caerulescens", + "Snowy Owl": "Bubo scandiacus", + "Snow Bunting": "Plectrophenax nivalis", + "Common Grasshopper Warbler": "Locustella naevia", + "Golden Eagle": "Aquila chrysaetos", + "Black-winged Stilt": "Himantopus himantopus", + "Steppe Eagle": "Aquila nipalensis", + "Pallid Harrier": "Circus macrourus", + "European Storm-petrel": "Hydrobates pelagicus", + "Horned Lark": "Eremophila alpestris", + "Eurasian Treecreeper": "Certhia familiaris", + "Taiga Bean Goose": "Anser fabalis", + "Temminck`s Stint": "Calidris temminckii", + "Terek Sandpiper": "Xenus cinereus", + "Tundra Bean Goose": "Anser serrirostris", + "European Turtle Dove": "Streptopelia turtur", + "Leach`s Storm-petrel": "Oceanodroma leucorhoa", + "Eurasian Griffon Vulture": "Gyps fulvus", + "Paddyfield Warbler": "Acrocephalus agricola", + "Osprey": "Pandion haliaetus", + "Firecrest": "Regulus ignicapilla", + "Water Rail": "Rallus aquaticus", + "European Honey Buzzard": "Pernis apivorus", + "Eurasian Golden Oriole": "Oriolus oriolus", + "Whooper Swan": "Cygnus cygnus", + "Two-barred Crossbill": "Loxia leucoptera", + "White-tailed Eagle": "Haliaeetus albicilla", + "Atlantic Murre": "Uria aalge", + "Garganey": "Anas querquedula", + "Black Redstart": "Phoenicurus ochruros", + "Common Scoter": "Melanitta nigra", + "Rock Pipit": "Anthus petrosus", + "Lesser Spotted Eagle": "Aquila pomarina", + "Cattle Egret": "Bubulcus ibis", + "White-winged Black Tern": "Chlidonias leucopterus", + "Black Stork": "Ciconia nigra", + "Mediterranean Gull": "Larus melanocephalus", + "Black Kite": "Milvus migrans", + "Yellow Wagtail": "Motacilla flavissima", + "Red-necked Grebe": "Podiceps grisegena", + "Gull-billed Tern": "Gelochelidon nilotica", + "Pectoral Sandpiper": "Calidris melanotos", + "Barred Warbler": "Sylvia nisoria", + "Red-throated Pipit": "Anthus cervinus", + "Grey Wagtail": "Motacilla cinerea", + "Richard`s Pipit": "Anthus richardi", + "Black Woodpecker": "Dryocopus martius", + "Little Ringed Plover": "Charadrius dubius", + "Whiskered Tern": "Chlidonias hybrida", + "Lesser Redpoll": "Carduelis cabaret", + "Pallas' Bunting": "Emberiza pallasi", + "Ferruginous Duck": "Aythya nyroca", + "Whistling Swan": "Cygnus columbianus", + "Black Brant": "Branta nigricans", + "Marbled Teal": "Marmaronetta angustirostris", + "Canvasback": "Aythya valisineria", + "Redhead": "Aythya americana", + "Lesser Scaup": "Aythya affinis", + "Steller`s Eider": "Polysticta stelleri", + "Spectacled Eider": "Somateria fischeri", + "Harlequin Duck": "Histronicus histrionicus", + "Black Scoter": "Melanitta americana", + "Surf Scoter": "Melanitta perspicillata", + "Barrow`s Goldeneye": "Bucephala islandica", + "Falcated Duck": "Anas falcata", + "American Wigeon": "Anas americana", + "Blue-winged Teal": "Anas discors", + "American Black Duck": "Anas rubripes", + "Baikal Teal": "Anas formosa", + "Green-Winged Teal": "Anas carolinensis", + "Hazel Grouse": "Bonasa bonasia", + "Rock Partridge": "Alectoris graeca", + "Red-legged Partridge": "Alectoris rufa", + "Yellow-billed Loon": "Gavia adamsii", + "Cory`s Shearwater": "Calonectris borealis", + "Madeiran Storm-Petrel": "Oceanodroma castro", + "Great White Pelican": "Pelecanus onocrotalus", + "Dalmatian Pelican": "Pelecanus crispus", + "American Bittern": "Botaurus lentiginosus", + "Glossy Ibis": "Plegadis falcinellus", + "Spanish Imperial Eagle": "Aquila adalberti", + "Lesser Kestrel": "Falco naumanni", + "Crab-Plover": "Dromas ardeola", + "Cream-coloured Courser": "Cursorius cursor", + "Collared Pratincole": "Glareola pratincola", + "Black-winged Pratincole": "Glareola nordmanni", + "Killdeer": "Charadrius vociferus", + "Lesser Sand Plover": "Charadrius mongolus", + "Greater Sand Plover": "Charadrius leschenaultii", + "Caspian Plover": "Charadrius asiaticus", + "American Golden Plover": "Pluvialis dominica", + "Pacific Golden Plover": "Pluvialis fulva", + "Sharp-tailed Sandpiper": "Calidris acuminata", + "Broad-billed Sandpiper": "Limicola falcinellus", + "Spoon-Billed Sandpiper": "Eurynorhynchus pygmaeus", + "Short-Billed Dowitcher": "Limnodromus griseus", + "Long-billed Dowitcher": "Limnodromus scolopaceus", + "Hudsonian Godwit": "Limosa haemastica", + "Little Curlew": "Numenius minutus", + "Lesser Yellowlegs": "Tringa flavipes", + "Wilson`s Phalarope": "Phalaropus tricolor", + "Pallas`s Gull": "Larus ichthyaetus", + "Laughing Gull": "Larus atricilla", + "Franklin`s Gull": "Larus pipixcan", + "Bonaparte`s Gull": "Larus philadelphia", + "Ring-billed Gull": "Larus delawarensis", + "American Herring Gull": "Larus smithsonianus", + "Caspian Gull": "Larus cachinnans", + "Ivory Gull": "Pagophila eburnea", + "Royal Tern": "Sterna maxima", + "Brünnich`s Murre": "Uria lomvia", + "Crested Auklet": "Aethia cristatella", + "Parakeet Auklet": "Cyclorrhynchus psittacula", + "Tufted Puffin": "Lunda cirrhata", + "Laughing Dove": "Streptopelia senegalensis", + "Great Spotted Cuckoo": "Clamator glandarius", + "Great Grey Owl": "Strix nebulosa", + "Tengmalm`s Owl": "Aegolius funereus", + "Red-Necked Nightjar": "Caprimulgus ruficollis", + "Chimney Swift": "Chaetura pelagica", + "Green Bea-Eater": "Merops orientalis", + "Grey-headed Woodpecker": "Picus canus", + "Lesser Short-Toed Lark": "Calandrella rufescens", + "Eurasian Crag Martin": "Hirundo rupestris", + "Red-rumped Swallow": "Cecropis daurica", + "Blyth`s Pipit": "Anthus godlewskii", + "Pechora Pipit": "Anthus gustavi", + "Grey-headed Wagtail": "Motacilla thunbergi", + "Yellow-Headed Wagtail": "Motacilla lutea", + "White-throated Dipper": "Cinclus cinclus", + "Rufous-Tailed Scrub Robin": "Cercotrichas galactotes", + "Thrush Nightingale": "Luscinia luscinia", + "White-throated Robin": "Irania gutturalis", + "Caspian Stonechat": "Saxicola maura variegata", + "Western Black-eared Wheatear": "Oenanthe hispanica", + "Rufous-tailed Rock Thrush": "Monticola saxatilis", + "Red-throated Thrush/Black-throated": "Turdus ruficollis", + "American Robin": "Turdus migratorius", + "Zitting Cisticola": "Cisticola juncidis", + "Lanceolated Warbler": "Locustella lanceolata", + "River Warbler": "Locustella fluviatilis", + "Blyth`s Reed Warbler": "Acrocephalus dumetorum", + "Caspian Reed Warbler": "Acrocephalus fuscus", + "Aquatic Warbler": "Acrocephalus paludicola", + "Booted Warbler": "Acrocephalus caligatus", + "Marmora's Warbler": "Sylvia sarda", + "Dartford Warbler": "Sylvia undata", + "Subalpine Warbler": "Sylvia cantillans", + "Ménétries's Warbler": "Sylvia mystacea", + "Rüppel's Warbler": "Sylvia rueppelli", + "Asian Desert Warbler": "Sylvia nana", + "Western Orphean Warbler": "Sylvia hortensis hortensis", + "Arctic Warbler": "Phylloscopus borealis", + "Radde`s Warbler": "Phylloscopus schwarzi", + "Western Bonelli`s Warbler": "Phylloscopus bonelli", + "Red-breasted Flycatcher": "Ficedula parva", + "Eurasian Penduline Tit": "Remiz pendulinus", + "Daurian Shrike": "Lanius isabellinus", + "Long-Tailed Shrike": "Lanius schach", + "Lesser Grey Shrike": "Lanius minor", + "Southern Grey Shrike": "Lanius meridionalis", + "Masked Shrike": "Lanius nubicus", + "Spotted Nutcracker": "Nucifraga caryocatactes", + "Daurian Jackdaw": "Corvus dauuricus", + "Purple-Backed Starling": "Sturnus sturninus", + "Red-Fronted Serin": "Serinus pusillus", + "Arctic Redpoll": "Carduelis hornemanni", + "Scottish Crossbill": "Loxia scotica", + "Parrot Crossbill": "Loxia pytyopsittacus", + "Black-faced Bunting": "Emberiza spodocephala", + "Pink-footed Goose": "Anser brachyrhynchus", + "Black-winged Kite": "Elanus caeruleus", + "European Bee-eater": "Merops apiaster", + "Sabine`s Gull": "Larus sabini", + "Sooty Shearwater": "Puffinus griseus", + "Lesser Canada Goose": "Branta hutchinsii", + "Ring-necked Duck": "Aythya collaris", + "Greater Flamingo": "Phoenicopterus roseus", + "Iberian Chiffchaff": "Phylloscopus ibericus", + "Ashy-headed Wagtail": "Motacilla cinereocapilla", + "Stilt Sandpiper": "Calidris himantopus", + "Siberian Stonechat": "Saxicola maurus", + "Greater Yellowlegs": "Tringa melanoleuca", + "Forster`s Tern": "Sterna forsteri", + "Dusky Warbler": "Phylloscopus fuscatus", + "Cirl Bunting": "Emberiza cirlus", + "Olive-backed Pipit": "Anthus hodgsoni", + "Sociable Lapwing": "Vanellus gregarius", + "Spotted Sandpiper": "Actitis macularius", + "Baird`s Sandpiper": "Calidris bairdii", + "Rustic Bunting": "Emberiza rustica", + "Yellow-browed Bunting": "Emberiza chrysophrys", + "Great Shearwater": "Puffinus gravis", + "Bonelli`s Eagle": "Aquila fasciata", + "Calandra Lark": "Melanocorypha calandra", + "Sardinian Warbler": "Sylvia melanocephala", + "Ross's Gull": "Larus roseus", + "Yellow-Breasted Bunting": "Emberiza aureola", + "Pine Bunting": "Emberiza leucocephalos", + "Black Guillemot": "Cepphus grylle", + "Pied-billed Grebe": "Podilymbus podiceps", + "Soft-plumaged Petrel": "Pterodroma mollis", + "Bulwer's Petrel": "Bulweria bulwerii", + "White-Faced Storm-Petrel": "Pelagodroma marina", + "Pallas’s Fish Eagle": "Haliaeetus leucoryphus", + "Sandhill Crane": "Grus canadensis", + "Macqueen’s Bustard": "Chlamydotis macqueenii", + "White-tailed Lapwing": "Vanellus leucurus", + "Great Knot": "Calidris tenuirostris", + "Semipalmated Sandpiper": "Calidris pusilla", + "Red-necked Stint": "Calidris ruficollis", + "Slender-billed Curlew": "Numenius tenuirostris", + "Bridled Tern": "Onychoprion anaethetus", + "Pallas’s Sandgrouse": "Syrrhaptes paradoxus", + "European Scops Owl": "Otus scops", + "Northern Hawk Owl": "Surnia ulula", + "White-Throated Needletail": "Hirundapus caudacutus", + "Belted Kingfisher": "Ceryle alcyon", + "Blue-cheeked Bee-eater": "Merops persicus", + "Black-headed Wagtail": "Motacilla feldegg", + "Northern Mockingbird": "Mimus polyglottos", + "Alpine Accentor": "Prunella collaris", + "Red-flanked Bluetail": "Tarsiger cyanurus", + "Isabelline Wheatear": "Oenanthe isabellina", + "Pied Wheatear": "Oenanthe pleschanka", + "Eastern Black-eared Wheatear": "Oenanthe melanoleuca", + "Desert Wheatear": "Oenanthe deserti", + "White`s Thrush": "Zoothera aurea", + "Siberian Thrush": "Zoothera sibirica", + "Eyebrowed Thrush": "Turdus obscurus", + "Dusky Thrush": "Turdus eunomus", + "Black-throated Thrush": "Turdus atrogularis", + "Pallas`s Grasshopper Warbler": "Locustella certhiola", + "Spectacled Warbler": "Sylvia conspicillata", + "Two-barred Warbler": "Phylloscopus plumbeitarsus", + "Eastern Bonelli’s Warbler": "Phylloscopus orientalis", + "Collared Flycatcher": "Ficedula albicollis", + "Wallcreeper": "Tichodroma muraria", + "Turkestan Shrike": "Lanius phoenicuroides", + "Steppe Grey Shrike": "Lanius pallidirostris", + "Spanish Sparrow": "Passer hispaniolensis", + "Red-eyed Vireo": "Vireo olivaceus", + "Myrtle Warbler": "Dendroica coronata", + "White-crowned Sparrow": "Zonotrichia leucophrys", + "White-throated Sparrow": "Zonotrichia albicollis", + "Cretzschmar`s Bunting": "Emberiza caesia", + "Chestnut Bunting": "Emberiza rutila", + "Red-headed Bunting": "Emberiza bruniceps", + "Black-headed Bunting": "Emberiza melanocephala", + "Indigo Bunting": "Passerina cyanea", + "Balearic Woodchat Shrike": "Lanius senator badius", + "Demoiselle Crane": "Grus virgo", + "Chough": "Pyrrhocorax pyrrhocorax", + "Red-Billed Chough": "Pyrrhocorax graculus", + "Elegant Tern": "Sterna elegans", + "Chukar": "Alectoris chukar", + "Yellow-Billed Cuckoo": "Coccyzus americanus", + "American Sandwich Tern": "Sterna sandvicensis acuflavida", + "Olive-Tree Warbler": "Hippolais olivetorum", + "Eastern Olivaceous Warbler": "Acrocephalus pallidus", + "Indian Cormorant": "Phalacrocorax fuscicollis", + "Spur-Winged Lapwing": "Vanellus spinosus", + "Yelkouan Shearwater": "Puffinus yelkouan", + "Trumpeter Finch": "Bucanetes githagineus", + "Red Grouse": "Lagopus scoticus", + "Rock Ptarmigan": "Lagopus mutus", + "Long-Tailed Cormorant": "Phalacrocorax africanus", + "Double-crested Cormorant": "Phalacrocorax auritus", + "Magnificent Frigatebird": "Fregata magnificens", + "Naumann's Thrush": "Turdus naumanni", + "Oriental Pratincole": "Glareola maldivarum", + "Bufflehead": "Bucephala albeola", + "Snowfinch": "Montifrigilla nivalis", + "Ural owl": "Strix uralensis", + "Spanish Wagtail": "Motacilla iberiae", + "Song Sparrow": "Melospiza melodia", + "Rock Bunting": "Emberiza cia", + "Siberian Rubythroat": "Luscinia calliope", + "Pallid Swift": "Apus pallidus", + "Eurasian Pygmy Owl": "Glaucidium passerinum", + "Madeira Little Shearwater": "Puffinus baroli", + "House Finch": "Carpodacus mexicanus", + "Green Heron": "Butorides virescens", + "Solitary Sandpiper": "Tringa solitaria", + "Heuglin's Gull": "Larus heuglini" + }; + function searchResponse( term ) { + term = term.toLowerCase(); + var result = []; + for ( var key in database ) { + if ( key.toLowerCase().indexOf( term ) !== -1 ) { + result.push( { + id: database[ key ], + label: key, + value: key + } ); + if ( result.length > 11 ) { + break; + } + } + } + return result; + } + $.ajaxTransport( "json", function( options, originalOptions ) { + if ( options.url.indexOf( "search.json" ) === -1 ) { + return; + } + return { + abort: function() {}, + send: function( headers, completeCallback ) { + console.log( "Mocked AJAX response for " + options.url ); + var result = searchResponse( originalOptions.data.term || "" ); + setTimeout( function() { + completeCallback( 200, "OK", { text: JSON.stringify( result ) }, [] ); + }, 2000 ); + } + }; + } ); + $.ajaxTransport( "script", function( options, originalOptions ) { + if ( options.url.indexOf( "search.json" ) === -1 ) { + return; + } + return { + abort: function() {}, + send: function( headers, completeCallback ) { + console.log( "Mocked AJAX response for " + options.url ); + var result = searchResponse( originalOptions.data.term || "" ); + var script = options.jsonpCallback + "(" + JSON.stringify( result ) + ")"; + setTimeout( function() { + completeCallback( 200, "OK", { text: script }, [] ); + }, 2000 ); + } + }; + } ); +} ); diff --git a/demos/selectable/default.html b/demos/selectable/default.html index f7d6d869332..2113f33edb6 100644 --- a/demos/selectable/default.html +++ b/demos/selectable/default.html @@ -1,31 +1,25 @@ - + - + + jQuery UI Selectable - Default functionality - - - - - - - - - - + -
      1. Item 1
      2. @@ -37,12 +31,8 @@
      3. Item 7
      -
      -
      -

      Enable a DOM element (or group of elements) to be selectable. Draw a box with your cursor to select items. Hold down the Ctrl key to make multiple non-adjacent selections.

      - -
      + diff --git a/demos/selectable/display-grid.html b/demos/selectable/display-grid.html index 654a68d5b3a..c4acc429f2b 100644 --- a/demos/selectable/display-grid.html +++ b/demos/selectable/display-grid.html @@ -1,31 +1,25 @@ - + - + + jQuery UI Selectable - Display as grid - - - - - - - - - - + -
      1. 1
      2. @@ -42,12 +36,8 @@
      3. 12
      -
      -
      -

      To arrange selectable items as a grid, give them identical dimensions and float them using CSS.

      - -
      + diff --git a/demos/selectable/index.html b/demos/selectable/index.html index 19ef9b1faa5..1933fdf9a77 100644 --- a/demos/selectable/index.html +++ b/demos/selectable/index.html @@ -1,20 +1,17 @@ - + - + + jQuery UI Selectable Demos - - + diff --git a/demos/selectable/serialize.html b/demos/selectable/serialize.html index 9744944a554..42370311325 100644 --- a/demos/selectable/serialize.html +++ b/demos/selectable/serialize.html @@ -1,42 +1,36 @@ - + - + + jQuery UI Selectable - Serialize - - - - - - - - - - + -

      -You've selected: none. +You've selected: none.

        @@ -48,12 +42,8 @@
      1. Item 6
      -
      -
      -

      Write a function that fires on the stop event to collect the index values of selected items. Present values as feedback, or pass as a data string.

      - -
      + diff --git a/demos/selectmenu/custom_render.html b/demos/selectmenu/custom_render.html new file mode 100644 index 00000000000..2afc727df83 --- /dev/null +++ b/demos/selectmenu/custom_render.html @@ -0,0 +1,129 @@ + + + + + + jQuery UI Selectmenu - Custom Rendering + + + + + + + + +
      + +
      +

      Selectmenu with framework icons

      +
      + + +
      + +

      Selectmenu with custom icon images

      +
      + + +
      + +

      Selectmenu with custom avatar 16x16 images as CSS background

      +
      + + +
      +
      + +
      + +
      +

      The whole rendering process is extendable to make custom styling as easy as possible.

      +
      + + diff --git a/demos/selectmenu/default.html b/demos/selectmenu/default.html new file mode 100644 index 00000000000..e8bb1a6a74f --- /dev/null +++ b/demos/selectmenu/default.html @@ -0,0 +1,106 @@ + + + + + + jQuery UI Selectmenu - Default functionality + + + + + + + + +
      + +
      + +
      + + + + + + + + + + + +
      + +
      + +
      + +
      +

      The Selectmenu widgets provides a styleable select element replacement. It will act as a proxy back to the original select element, controlling its state for form submission or serialization

      +

      The datasource is a native select element. Supports optgroups.

      +
      + + diff --git a/demos/selectmenu/images/24-podcast-square.png b/demos/selectmenu/images/24-podcast-square.png new file mode 100644 index 00000000000..f49fe096522 Binary files /dev/null and b/demos/selectmenu/images/24-podcast-square.png differ diff --git a/demos/selectmenu/images/24-rss-square.png b/demos/selectmenu/images/24-rss-square.png new file mode 100644 index 00000000000..4905eab8984 Binary files /dev/null and b/demos/selectmenu/images/24-rss-square.png differ diff --git a/demos/selectmenu/images/24-video-square.png b/demos/selectmenu/images/24-video-square.png new file mode 100644 index 00000000000..64348a1bf58 Binary files /dev/null and b/demos/selectmenu/images/24-video-square.png differ diff --git a/demos/selectmenu/index.html b/demos/selectmenu/index.html new file mode 100644 index 00000000000..4b83f727f9d --- /dev/null +++ b/demos/selectmenu/index.html @@ -0,0 +1,17 @@ + + + + + + jQuery UI Selectmenu Demos + + + + + + + diff --git a/demos/selectmenu/product-selection.html b/demos/selectmenu/product-selection.html new file mode 100644 index 00000000000..a6f1a2203ff --- /dev/null +++ b/demos/selectmenu/product-selection.html @@ -0,0 +1,83 @@ + + + + + + jQuery UI Selectmenu - Product Selection + + + + + + + + +
      + +
      + +
      + +
      + + + + + +
      + +
      + +
      + +
      +

      This Selectmenu Widget demo changes color and radius of a CSS circle. This demo is using the provided callback events.

      +
      + + diff --git a/demos/show/default.html b/demos/show/default.html deleted file mode 100644 index 65cb288e5c5..00000000000 --- a/demos/show/default.html +++ /dev/null @@ -1,103 +0,0 @@ - - - - - jQuery UI Effects - Show Demo - - - - - - - - - - - - - - - - - - - - -
      - -
      -
      -

      Show

      -

      - Etiam libero neque, luctus a, eleifend nec, semper at, lorem. Sed pede. Nulla lorem metus, adipiscing ut, luctus sed, hendrerit vitae, mi. -

      -
      -
      - - - -Run Effect - - -
      - -
      - -

      Click the button above to preview the effect.

      - -
      - - - diff --git a/demos/show/index.html b/demos/show/index.html deleted file mode 100644 index 0e9af371fea..00000000000 --- a/demos/show/index.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - - jQuery UI Effects Demos - - - - -
      -

      Examples

      - -
      - - - diff --git a/demos/slider/colorpicker.html b/demos/slider/colorpicker.html index 121249e22cd..66b6474b295 100644 --- a/demos/slider/colorpicker.html +++ b/demos/slider/colorpicker.html @@ -1,16 +1,12 @@ - + - + + jQuery UI Slider - Colorpicker - - - - - - - - - + -
      -

      - -Simple Colorpicker + + Simple Colorpicker

      @@ -83,13 +76,8 @@
      -
      - -
      - +

      Combine three sliders to create a simple RGB colorpicker.

      - -
      - +
      diff --git a/demos/slider/custom-handle.html b/demos/slider/custom-handle.html new file mode 100644 index 00000000000..11192f3189e --- /dev/null +++ b/demos/slider/custom-handle.html @@ -0,0 +1,42 @@ + + + + + + jQuery UI Slider - Custom handle + + + + + + + + +
      +
      +
      + +
      +

      The basic slider is horizontal and has a single handle that can be moved with the mouse or by using the arrow keys.

      +
      + + diff --git a/demos/slider/default.html b/demos/slider/default.html index d63086b4d05..62789ac48c9 100644 --- a/demos/slider/default.html +++ b/demos/slider/default.html @@ -1,37 +1,22 @@ - + - + + jQuery UI Slider - Default functionality - - - - - - - - - + -
      -
      -
      -
      -

      The basic slider is horizontal and has a single handle that can be moved with the mouse or by using the arrow keys.

      - -
      - + diff --git a/demos/slider/hotelrooms.html b/demos/slider/hotelrooms.html index 02f8b772ff9..1eb50470eb4 100644 --- a/demos/slider/hotelrooms.html +++ b/demos/slider/hotelrooms.html @@ -1,40 +1,30 @@ - + - - jQuery UI Slider - Range with fixed minimum - - - - - - - - - + -
      -
      -
      -
      -

      How to bind a slider to an existing select element. The select stays visible to display the change. When the select is changed, the slider is updated, too.

      - -
      - + diff --git a/demos/slider/index.html b/demos/slider/index.html index ec9a2f4f3f1..f853a79aa18 100644 --- a/demos/slider/index.html +++ b/demos/slider/index.html @@ -1,29 +1,25 @@ - + - + + jQuery UI Slider Demos - - + diff --git a/demos/slider/multiple-vertical.html b/demos/slider/multiple-vertical.html index 62d0b163443..71f7076133c 100644 --- a/demos/slider/multiple-vertical.html +++ b/demos/slider/multiple-vertical.html @@ -1,58 +1,50 @@ - + - + + jQuery UI Slider - Multiple sliders - - - - - - - - - + - - -
      +

      - -Master volume + + Master volume

      - -Graphic EQ + + Graphic EQ

      @@ -65,13 +57,8 @@ 70
      -
      - -
      - +

      Combine horizontal and vertical sliders, each with their own options, to create the UI for a music player.

      - -
      - +
      diff --git a/demos/slider/range-vertical.html b/demos/slider/range-vertical.html index 70fbb47b396..0d75b8ae90c 100644 --- a/demos/slider/range-vertical.html +++ b/demos/slider/range-vertical.html @@ -1,50 +1,36 @@ - + - + + jQuery UI Slider - Vertical range slider - - - - - - - - - + -
      -

      - - + +

      -
      -
      -

      Change the orientation of the range slider to vertical. Assign a height value via .height() or by setting the height through CSS, and set the orientation option to "vertical."

      - -
      - + diff --git a/demos/slider/range.html b/demos/slider/range.html index be4e19af48b..162ff064b96 100644 --- a/demos/slider/range.html +++ b/demos/slider/range.html @@ -1,51 +1,37 @@ - + - + + jQuery UI Slider - Range slider - - - - - - - - - + -
      -

      - - + +

      -
      -
      -

      Set the range option to true to capture a range of values with two drag handles. The space between the handles is filled with a different background color to indicate those values are selected.

      - -
      - + diff --git a/demos/slider/rangemax.html b/demos/slider/rangemax.html index b4f4e1e08db..1c7793b161f 100644 --- a/demos/slider/rangemax.html +++ b/demos/slider/rangemax.html @@ -1,50 +1,35 @@ - + - + + jQuery UI Slider - Range with fixed maximum - - - - - - - - - + -
      -

      -Minimum number of bedrooms: - + +

      -
      -
      -

      Fix the maximum value of the range slider so that the user can only select a minimum. Set the range option to "max."

      - -
      - + diff --git a/demos/slider/rangemin.html b/demos/slider/rangemin.html index 4f146824a87..e864a220e7e 100644 --- a/demos/slider/rangemin.html +++ b/demos/slider/rangemin.html @@ -1,51 +1,36 @@ - + - + + jQuery UI Slider - Range with fixed minimum - - - - - - - - - + -
      -

      - - + +

      -
      -
      -

      Fix the minimum value of the range slider so that the user can only select a maximum. Set the range option to "min."

      - -
      - + diff --git a/demos/slider/side-scroll.html b/demos/slider/side-scroll.html deleted file mode 100644 index fe5599bee4c..00000000000 --- a/demos/slider/side-scroll.html +++ /dev/null @@ -1,138 +0,0 @@ - - - - - jQuery UI Slider - Slider scrollbar - - - - - - - - - - - - -
      - -
      -
      -
      1
      -
      2
      -
      3
      -
      4
      -
      5
      -
      6
      -
      7
      -
      8
      -
      9
      -
      10
      -
      11
      -
      12
      -
      13
      -
      14
      -
      15
      -
      16
      -
      17
      -
      18
      -
      19
      -
      20
      -
      -
      -
      -
      -
      - - - -
      - - - -
      - -

      Use a slider to manipulate the positioning of content on the page. In this case, it acts as a scrollbar with the potential to capture values if needed.

      - -
      - - - diff --git a/demos/slider/slider-vertical.html b/demos/slider/slider-vertical.html index b6b4027b10b..1b32619a07c 100644 --- a/demos/slider/slider-vertical.html +++ b/demos/slider/slider-vertical.html @@ -1,52 +1,37 @@ - + - + + jQuery UI Slider - Vertical slider - - - - - - - - - + -
      -

      - - + +

      -
      -
      -

      Change the orientation of the slider to vertical. Assign a height value via .height() or by setting the height through CSS, and set the orientation option to "vertical."

      - -
      - + diff --git a/demos/slider/steps.html b/demos/slider/steps.html index 66c84b0c3b6..cc76eb26ac1 100644 --- a/demos/slider/steps.html +++ b/demos/slider/steps.html @@ -1,51 +1,36 @@ - + - + + jQuery UI Slider - Snap to increments - - - - - - - - - + -
      -

      - - + +

      -
      -
      -

      Increment slider values with the step option set to an integer, commonly a dividend of the slider's maximum value. The default increment is 1.

      - -
      - + diff --git a/demos/slider/tabs.html b/demos/slider/tabs.html deleted file mode 100644 index 40916c46a81..00000000000 --- a/demos/slider/tabs.html +++ /dev/null @@ -1,67 +0,0 @@ - - - - - jQuery UI Slider - Snap to increments - - - - - - - - - - - - - -
      - -
      - -
      - -
      -

      Proin elit arcu, rutrum commodo, vehicula tempus, commodo a, risus. Curabitur nec arcu. Donec sollicitudin mi sit amet mauris. Nam elementum quam ullamcorper ante. Etiam aliquet massa et lorem. Mauris dapibus lacus auctor risus. Aenean tempor ullamcorper leo. Vivamus sed magna quis ligula eleifend adipiscing. Duis orci. Aliquam sodales tortor vitae ipsum. Aliquam nulla. Duis aliquam molestie erat. Ut et mauris vel pede varius sollicitudin. Sed ut dolor nec orci tincidunt interdum. Phasellus ipsum. Nunc tristique tempus lectus.

      -
      -
      -

      Morbi tincidunt, dui sit amet facilisis feugiat, odio metus gravida ante, ut pharetra massa metus id nunc. Duis scelerisque molestie turpis. Sed fringilla, massa eget luctus malesuada, metus eros molestie lectus, ut tempus eros massa ut dolor. Aenean aliquet fringilla sem. Suspendisse sed ligula in ligula suscipit aliquam. Praesent in eros vestibulum mi adipiscing adipiscing. Morbi facilisis. Curabitur ornare consequat nunc. Aenean vel metus. Ut posuere viverra nulla. Aliquam erat volutpat. Pellentesque convallis. Maecenas feugiat, tellus pellentesque pretium posuere, felis lorem euismod felis, eu ornare leo nisi vel felis. Mauris consectetur tortor et purus.

      -
      -
      -

      Mauris eleifend est et turpis. Duis id erat. Suspendisse potenti. Aliquam vulputate, pede vel vehicula accumsan, mi neque rutrum erat, eu congue orci lorem eget lorem. Vestibulum non ante. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Fusce sodales. Quisque eu urna vel enim commodo pellentesque. Praesent eu risus hendrerit ligula tempus pretium. Curabitur lorem enim, pretium nec, feugiat nec, luctus a, lacus.

      -

      Duis cursus. Maecenas ligula eros, blandit nec, pharetra at, semper at, magna. Nullam ac lacus. Nulla facilisi. Praesent viverra justo vitae neque. Praesent blandit adipiscing velit. Suspendisse potenti. Donec mattis, pede vel pharetra blandit, magna ligula faucibus eros, id euismod lacus dolor eget odio. Nam scelerisque. Donec non libero sed nulla mattis commodo. Ut sagittis. Donec nisi lectus, feugiat porttitor, tempor ac, tempor vitae, pede. Aenean vehicula velit eu tellus interdum rutrum. Maecenas commodo. Pellentesque nec elit. Fusce in lacus. Vivamus a libero vitae lectus hendrerit hendrerit.

      -
      -
      - -
      - -
      - -

      Control tabs with a slider.

      - -
      - - - diff --git a/demos/sortable/connect-lists-through-tabs.html b/demos/sortable/connect-lists-through-tabs.html deleted file mode 100644 index d432afe9c0b..00000000000 --- a/demos/sortable/connect-lists-through-tabs.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - jQuery UI Sortable - Connect lists with Tabs - - - - - - - - - - - - - -
      - -
      - -
      -
        -
      • Item 1
      • -
      • Item 2
      • -
      • Item 3
      • -
      • Item 4
      • -
      • Item 5
      • -
      -
      -
      -
        -
      • Item 1
      • -
      • Item 2
      • -
      • Item 3
      • -
      • Item 4
      • -
      • Item 5
      • -
      -
      -
      - -
      - -
      - -

      - Sort items from one list into another and vice versa, by dropping the list item on the appropriate tab above. -

      - -
      - - - diff --git a/demos/sortable/connect-lists.html b/demos/sortable/connect-lists.html index b08678d6121..fcf5dcd0125 100644 --- a/demos/sortable/connect-lists.html +++ b/demos/sortable/connect-lists.html @@ -1,29 +1,37 @@ - + - + + jQuery UI Sortable - Connect lists - - - - - - - - - + -
      • Item 1
      • @@ -41,18 +49,13 @@
      • Item 5
      -
      -
      -

      Sort items from one list into another and vice versa, by passing a selector into the connectWith option. The simplest way to do this is to group all related lists with a CSS class, and then pass that class into the sortable function (i.e., connectWith: '.myclass').

      - -
      - + diff --git a/demos/sortable/default.html b/demos/sortable/default.html index ab81a8bc03b..b3ce9860d0f 100644 --- a/demos/sortable/default.html +++ b/demos/sortable/default.html @@ -1,29 +1,22 @@ - + - + + jQuery UI Sortable - Default functionality - - - - - - - - - + -
      • Item 1
      • @@ -35,17 +28,12 @@
      • Item 7
      -
      -
      -

      Enable a group of DOM elements to be sortable. Click on and drag an element to a new spot within the list, and the other items will adjust to fit. By default, sortable items share draggable properties.

      - -
      - + diff --git a/demos/sortable/delay-start.html b/demos/sortable/delay-start.html deleted file mode 100644 index 7afb6be373d..00000000000 --- a/demos/sortable/delay-start.html +++ /dev/null @@ -1,67 +0,0 @@ - - - - - jQuery UI Sortable - Delay start - - - - - - - - - - - -
      - -

      Time delay of 300ms:

      - -
        -
      • Item 1
      • -
      • Item 2
      • -
      • Item 3
      • -
      • Item 4
      • -
      - -

      Distance delay of 15px:

      - -
        -
      • Item 1
      • -
      • Item 2
      • -
      • Item 3
      • -
      • Item 4
      • -
      - -
      - -
      - -

      - Prevent accidental sorting either by delay (time) or distance. Set a number of - milliseconds the element needs to be dragged before sorting starts - with the delay option. Set a distance in pixels the element - needs to be dragged before sorting starts with the distance - option. -

      - -
      - - - diff --git a/demos/sortable/display-grid.html b/demos/sortable/display-grid.html index e90a38c2596..76f2d7b6816 100644 --- a/demos/sortable/display-grid.html +++ b/demos/sortable/display-grid.html @@ -1,28 +1,22 @@ - + - + + jQuery UI Sortable - Display as grid - - - - - - - - - + -
      • 1
      • @@ -39,16 +33,11 @@
      • 12
      -
      -
      -

      To arrange sortable items as a grid, give them identical dimensions and float them using CSS.

      - -
      - + diff --git a/demos/sortable/empty-lists.html b/demos/sortable/empty-lists.html index b68ad59834a..a6bc4a7f142 100644 --- a/demos/sortable/empty-lists.html +++ b/demos/sortable/empty-lists.html @@ -1,36 +1,30 @@ - + - + + jQuery UI Sortable - Handle empty lists - - - - - - - - - + -
      • Can be dropped..
      • @@ -51,19 +45,14 @@
        -
        - -
      +
      -

      Prevent all items in a list from being dropped into a separate, empty list using the dropOnEmpty option set to false. By default, sortable items can be dropped on empty lists.

      - -
      - + diff --git a/demos/sortable/index.html b/demos/sortable/index.html index 9fa93801ff8..022da81d2b6 100644 --- a/demos/sortable/index.html +++ b/demos/sortable/index.html @@ -1,26 +1,21 @@ - + - + + jQuery UI Sortable Demos - - + diff --git a/demos/sortable/items.html b/demos/sortable/items.html index 3f1cbb6c3d7..a13410d0a40 100644 --- a/demos/sortable/items.html +++ b/demos/sortable/items.html @@ -1,35 +1,29 @@ - + - + + jQuery UI Sortable - Include / exclude items - - - - - - - - - + -

      Specify which items are sortable:

      @@ -49,23 +43,17 @@

      Cancel sorting (but keep as drop targets):

    • Item 4
    • -
      -
      -

      Specify which items are eligible to sort by passing a jQuery selector into the items option. Items excluded from this option are not sortable, nor are they valid targets for sortable items.

      -

      To only prevent sorting on certain items, pass a jQuery selector into the cancel option. Cancelled items remain valid sort targets for others.

      - -
      - + diff --git a/demos/sortable/placeholder.html b/demos/sortable/placeholder.html index d9c7e838cff..50d83c2a995 100644 --- a/demos/sortable/placeholder.html +++ b/demos/sortable/placeholder.html @@ -1,32 +1,26 @@ - + - + + jQuery UI Sortable - Drop placeholder - - - - - - - - - + -
      • Item 1
      • @@ -38,10 +32,7 @@
      • Item 7
      -
      -
      -

      When dragging a sortable item to a new location, other items will make room for the that item by shifting to allow white space between them. Pass a @@ -49,8 +40,6 @@ be visible. Use the boolean forcePlaceholderSize option to set dimensions on the placeholder.

      - -
      - + diff --git a/demos/sortable/portlets.html b/demos/sortable/portlets.html index fefef3d9f00..2eab237cd2f 100644 --- a/demos/sortable/portlets.html +++ b/demos/sortable/portlets.html @@ -1,48 +1,67 @@ - + - + + jQuery UI Sortable - Portlets - - - - - - - - - + -
      @@ -50,7 +69,7 @@
      Feeds
      Lorem ipsum dolor sit amet, consectetuer adipiscing elit
      - +
      News
      Lorem ipsum dolor sit amet, consectetuer adipiscing elit
      @@ -73,7 +92,7 @@
      Links
      Lorem ipsum dolor sit amet, consectetuer adipiscing elit
      - +
      Images
      Lorem ipsum dolor sit amet, consectetuer adipiscing elit
      @@ -81,16 +100,11 @@
      -
      -
      -

      Enable portlets (styled divs) as sortables and use the connectWith option to allow sorting between columns.

      - -
      - + diff --git a/demos/spinner/currency.html b/demos/spinner/currency.html new file mode 100644 index 00000000000..fa3744ba51c --- /dev/null +++ b/demos/spinner/currency.html @@ -0,0 +1,44 @@ + + + + + + jQuery UI Spinner - Currency + + + + + + + +

      + + +

      + +

      + + +

      + +
      +

      Example of a donation form, with currency selection and amount spinner.

      +
      + + diff --git a/demos/spinner/decimal.html b/demos/spinner/decimal.html new file mode 100644 index 00000000000..af86bbbe796 --- /dev/null +++ b/demos/spinner/decimal.html @@ -0,0 +1,47 @@ + + + + + + jQuery UI Spinner - Decimal + + + + + + + +

      + + +

      +

      + + +

      + +
      +

      + Example of a decimal spinner. Step is set to 0.01. +
      The code handling the culture change reads the current spinner value, + then changes the culture, then sets the value again, resulting in an updated + formatting, based on the new culture. +

      +
      + + diff --git a/demos/spinner/default.html b/demos/spinner/default.html new file mode 100644 index 00000000000..2011b84ba85 --- /dev/null +++ b/demos/spinner/default.html @@ -0,0 +1,58 @@ + + + + + + jQuery UI Spinner - Default functionality + + + + + + + +

      + + +

      + +

      + + +

      + +

      + + +

      + +
      +

      Default spinner.

      +
      + + diff --git a/demos/spinner/index.html b/demos/spinner/index.html new file mode 100644 index 00000000000..e61d0ddcaad --- /dev/null +++ b/demos/spinner/index.html @@ -0,0 +1,20 @@ + + + + + + jQuery UI Spinner Demos + + + + + + + diff --git a/demos/spinner/latlong.html b/demos/spinner/latlong.html new file mode 100644 index 00000000000..cdaf65f3c62 --- /dev/null +++ b/demos/spinner/latlong.html @@ -0,0 +1,51 @@ + + + + + + jQuery UI Spinner - Map + + + + + + + + + + + +
      + + + +
      + +
      +

      Google Maps integration, using spinners to change latitude and longitude.

      +
      + + diff --git a/demos/spinner/overflow.html b/demos/spinner/overflow.html new file mode 100644 index 00000000000..76e10783691 --- /dev/null +++ b/demos/spinner/overflow.html @@ -0,0 +1,38 @@ + + + + + + jQuery UI Spinner - Overflow + + + + + + + +

      + + +

      + +
      +

      +Overflowing spinner restricted to a range of -10 to 10. +For anything above 10, it'll overflow to -10, and the other way round. +

      +
      + + diff --git a/demos/spinner/time.html b/demos/spinner/time.html new file mode 100644 index 00000000000..c7ceb7116c9 --- /dev/null +++ b/demos/spinner/time.html @@ -0,0 +1,66 @@ + + + + + + jQuery UI Spinner - Time + + + + + + + +

      + + +

      +

      + + +

      + +
      +

      + A custom widget extending spinner. Use the Globalization plugin to parse and output + a timestamp, with custom step and page options. Cursor up/down spins minutes, page up/down + spins hours. +

      +
      + + diff --git a/demos/switchClass/default.html b/demos/switchClass/default.html deleted file mode 100644 index bfb0c9c8b56..00000000000 --- a/demos/switchClass/default.html +++ /dev/null @@ -1,48 +0,0 @@ - - - - - jQuery UI Effects - switchClass Demo - - - - - - - - - -
      - - -
      -
      - Etiam libero neque, luctus a, eleifend nec, semper at, lorem. Sed pede. -
      -
      -Run Effect - -
      - -
      - -

      Click the button above to preview the effect.

      - -
      - - - diff --git a/demos/switchClass/index.html b/demos/switchClass/index.html deleted file mode 100644 index 0e9af371fea..00000000000 --- a/demos/switchClass/index.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - - jQuery UI Effects Demos - - - - -
      -

      Examples

      - -
      - - - diff --git a/demos/tabs/ajax.html b/demos/tabs/ajax.html index efbdf590a40..598724cd617 100644 --- a/demos/tabs/ajax.html +++ b/demos/tabs/ajax.html @@ -1,51 +1,59 @@ - + - + + jQuery UI Tabs - Content via Ajax - - - - - - - + -
      -

      Proin elit arcu, rutrum commodo, vehicula tempus, commodo a, risus. Curabitur nec arcu. Donec sollicitudin mi sit amet mauris. Nam elementum quam ullamcorper ante. Etiam aliquet massa et lorem. Mauris dapibus lacus auctor risus. Aenean tempor ullamcorper leo. Vivamus sed magna quis ligula eleifend adipiscing. Duis orci. Aliquam sodales tortor vitae ipsum. Aliquam nulla. Duis aliquam molestie erat. Ut et mauris vel pede varius sollicitudin. Sed ut dolor nec orci tincidunt interdum. Phasellus ipsum. Nunc tristique tempus lectus.

      -
      -
      - -

      Fetch external content via Ajax for the tabs by setting an href value in the tab links. While the Ajax request is waiting for a response, the tab label changes to say "Loading...", then returns to the normal label once loaded.

      - -

      Tabs 3 and 4 demonstrate slow-loading and broken AJAX tabs, and how to handle serverside errors in those cases. Note: These two require a webserver to interpret PHP. They won't work from the filesystem.

      -
      - +

      Fetch external content via Ajax for the tabs by setting an href value in the tab links.

      +

      Tabs 3 and 4 demonstrate handling of pages that are slow-loading or have server-side HTTP status errors.

      + diff --git a/demos/tabs/ajax/content1.html b/demos/tabs/ajax/content1.html index 759bf134ec9..472bdfb366b 100644 --- a/demos/tabs/ajax/content1.html +++ b/demos/tabs/ajax/content1.html @@ -1,4 +1,4 @@ -

      This content was loaded via ajax. +

      This content was loaded via ajax.

      Proin elit arcu, rutrum commodo, vehicula tempus, commodo a, risus. Curabitur nec arcu. Donec sollicitudin mi sit amet mauris. Nam elementum quam ullamcorper ante. Etiam aliquet massa et lorem. Mauris dapibus lacus auctor risus. Aenean tempor ullamcorper leo. Vivamus sed magna quis ligula eleifend adipiscing. Duis orci. Aliquam sodales tortor vitae ipsum. Aliquam nulla. Duis aliquam molestie erat. Ut et mauris vel pede varius sollicitudin. Sed ut dolor nec orci tincidunt interdum. Phasellus ipsum. Nunc tristique tempus lectus.

      Mauris vitae ante. Curabitur augue. Nulla purus nibh, lobortis ut, feugiat at, aliquam id, purus. Sed venenatis, lorem venenatis volutpat commodo, purus quam lacinia justo, mattis interdum pede pede a odio. Fusce nibh. Morbi nisl mauris, dapibus in, tristique eget, accumsan et, pede. Donec mauris risus, pulvinar ut, faucibus eu, mollis in, nunc. In augue massa, commodo a, cursus vehicula, varius eu, dui. Suspendisse sodales suscipit lorem. Morbi malesuada, eros quis condimentum dignissim, lectus nibh tristique urna, non bibendum diam massa vel risus. Morbi suscipit. Proin egestas, eros at scelerisque scelerisque, dolor lacus fringilla lacus, ut ullamcorper mi magna at quam. Aliquam sed elit. Aliquam turpis purus, congue quis, iaculis id, ullamcorper sit amet, justo. Maecenas sed mauris. Proin magna justo, interdum in, tincidunt eu, viverra eu, turpis. Suspendisse mollis. In magna. Phasellus pellentesque, urna pellentesque convallis pellentesque, augue sem blandit pede, at rhoncus libero nisl a odio.

      Sed vitae nibh non magna semper tempor. Duis dolor. Nam congue laoreet arcu. Fusce lobortis enim quis ligula. Maecenas commodo odio id mi. Maecenas scelerisque tellus eu odio. Etiam dolor purus, lacinia a, imperdiet in, aliquam et, eros. In pellentesque. Nullam ac massa. Integer et turpis. Ut quam augue, congue non, imperdiet id, eleifend ac, nisi. Etiam ac arcu. Cras iaculis accumsan erat. Nullam vulputate sapien nec nisi pretium rhoncus. Aliquam a nibh. Vivamus est ante, fermentum a, tincidunt ut, imperdiet nec, velit. Aenean non tortor. Sed nec mauris eget tellus condimentum rutrum.

      \ No newline at end of file diff --git a/demos/tabs/ajax/content2.html b/demos/tabs/ajax/content2.html index 95c25dae07d..18b03e40baa 100644 --- a/demos/tabs/ajax/content2.html +++ b/demos/tabs/ajax/content2.html @@ -1,4 +1,4 @@ -

      This other content was loaded via ajax. +

      This other content was loaded via ajax.

      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean nec turpis justo, et facilisis ligula. In congue interdum odio, a scelerisque eros posuere ac. Aenean massa tellus, dictum sit amet laoreet ut, aliquam in orci. Duis eu aliquam ligula. Nullam vel placerat ligula. Fusce venenatis viverra dictum. Phasellus dui dolor, imperdiet in sodales at, mattis sed libero. Morbi ac ipsum ligula. Quisque suscipit dui vel diam pretium nec cursus lacus malesuada. Donec sollicitudin, eros eget dignissim mollis, risus leo feugiat tellus, vel posuere nisl ipsum eu erat. Quisque posuere lacinia imperdiet. Quisque nunc leo, elementum quis ultricies et, vehicula sit amet turpis. Nullam sed nunc nec nibh condimentum mattis. Quisque sed ligula sit amet nisi ultricies bibendum eget id nisi.

      Proin ut erat vel nunc tincidunt commodo. Curabitur feugiat, nisi et vehicula viverra, nisl orci eleifend arcu, sed blandit lectus nisl quis nisi. In hac habitasse platea dictumst. In hac habitasse platea dictumst. Aenean rutrum gravida velit ac imperdiet. Integer vitae arcu risus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Proin tincidunt orci at leo egestas porta. Vivamus ac augue et enim bibendum hendrerit ut id urna. Donec sollicitudin pulvinar turpis vitae scelerisque. Etiam tempor porttitor est sed blandit. Phasellus varius consequat leo eget tincidunt. Aliquam ac dui lectus. In et consectetur orci. Duis posuere nulla ac turpis faucibus vestibulum. Sed ut velit et dolor rhoncus dapibus. Sed sit amet pellentesque est.

      Nam in volutpat orci. Morbi sit amet orci in erat egestas dignissim. Etiam mi sapien, tempus sed iaculis a, adipiscing quis tellus. Suspendisse potenti. Nam malesuada tristique vestibulum. In tempor tellus dignissim neque consectetur eu vestibulum nisl pellentesque. Phasellus ultrices cursus velit, id aliquam nisl fringilla quis. Cras varius elit sed urna ultrices congue. Sed ornare odio sed velit pellentesque id varius nisl sodales. Sed auctor ligula egestas mi pharetra ut consectetur erat pharetra.

      \ No newline at end of file diff --git a/demos/tabs/ajax/content3-slow.html b/demos/tabs/ajax/content3-slow.html new file mode 100644 index 00000000000..6dd4f32507c --- /dev/null +++ b/demos/tabs/ajax/content3-slow.html @@ -0,0 +1,4 @@ +

      This content was loaded via ajax, though it took a second.

      +

      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean nec turpis justo, et facilisis ligula. In congue interdum odio, a scelerisque eros posuere ac. Aenean massa tellus, dictum sit amet laoreet ut, aliquam in orci. Duis eu aliquam ligula. Nullam vel placerat ligula. Fusce venenatis viverra dictum. Phasellus dui dolor, imperdiet in sodales at, mattis sed libero. Morbi ac ipsum ligula. Quisque suscipit dui vel diam pretium nec cursus lacus malesuada. Donec sollicitudin, eros eget dignissim mollis, risus leo feugiat tellus, vel posuere nisl ipsum eu erat. Quisque posuere lacinia imperdiet. Quisque nunc leo, elementum quis ultricies et, vehicula sit amet turpis. Nullam sed nunc nec nibh condimentum mattis. Quisque sed ligula sit amet nisi ultricies bibendum eget id nisi.

      +

      Proin ut erat vel nunc tincidunt commodo. Curabitur feugiat, nisi et vehicula viverra, nisl orci eleifend arcu, sed blandit lectus nisl quis nisi. In hac habitasse platea dictumst. In hac habitasse platea dictumst. Aenean rutrum gravida velit ac imperdiet. Integer vitae arcu risus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Proin tincidunt orci at leo egestas porta. Vivamus ac augue et enim bibendum hendrerit ut id urna. Donec sollicitudin pulvinar turpis vitae scelerisque. Etiam tempor porttitor est sed blandit. Phasellus varius consequat leo eget tincidunt. Aliquam ac dui lectus. In et consectetur orci. Duis posuere nulla ac turpis faucibus vestibulum. Sed ut velit et dolor rhoncus dapibus. Sed sit amet pellentesque est.

      +

      Nam in volutpat orci. Morbi sit amet orci in erat egestas dignissim. Etiam mi sapien, tempus sed iaculis a, adipiscing quis tellus. Suspendisse potenti. Nam malesuada tristique vestibulum. In tempor tellus dignissim neque consectetur eu vestibulum nisl pellentesque. Phasellus ultrices cursus velit, id aliquam nisl fringilla quis. Cras varius elit sed urna ultrices congue. Sed ornare odio sed velit pellentesque id varius nisl sodales. Sed auctor ligula egestas mi pharetra ut consectetur erat pharetra.

      \ No newline at end of file diff --git a/demos/tabs/ajax/content3-slow.php b/demos/tabs/ajax/content3-slow.php deleted file mode 100644 index 9e50dc3acb2..00000000000 --- a/demos/tabs/ajax/content3-slow.php +++ /dev/null @@ -1,7 +0,0 @@ - -

      This content was loaded via ajax, though it took a second. -

      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean nec turpis justo, et facilisis ligula. In congue interdum odio, a scelerisque eros posuere ac. Aenean massa tellus, dictum sit amet laoreet ut, aliquam in orci. Duis eu aliquam ligula. Nullam vel placerat ligula. Fusce venenatis viverra dictum. Phasellus dui dolor, imperdiet in sodales at, mattis sed libero. Morbi ac ipsum ligula. Quisque suscipit dui vel diam pretium nec cursus lacus malesuada. Donec sollicitudin, eros eget dignissim mollis, risus leo feugiat tellus, vel posuere nisl ipsum eu erat. Quisque posuere lacinia imperdiet. Quisque nunc leo, elementum quis ultricies et, vehicula sit amet turpis. Nullam sed nunc nec nibh condimentum mattis. Quisque sed ligula sit amet nisi ultricies bibendum eget id nisi.

      -

      Proin ut erat vel nunc tincidunt commodo. Curabitur feugiat, nisi et vehicula viverra, nisl orci eleifend arcu, sed blandit lectus nisl quis nisi. In hac habitasse platea dictumst. In hac habitasse platea dictumst. Aenean rutrum gravida velit ac imperdiet. Integer vitae arcu risus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Proin tincidunt orci at leo egestas porta. Vivamus ac augue et enim bibendum hendrerit ut id urna. Donec sollicitudin pulvinar turpis vitae scelerisque. Etiam tempor porttitor est sed blandit. Phasellus varius consequat leo eget tincidunt. Aliquam ac dui lectus. In et consectetur orci. Duis posuere nulla ac turpis faucibus vestibulum. Sed ut velit et dolor rhoncus dapibus. Sed sit amet pellentesque est.

      -

      Nam in volutpat orci. Morbi sit amet orci in erat egestas dignissim. Etiam mi sapien, tempus sed iaculis a, adipiscing quis tellus. Suspendisse potenti. Nam malesuada tristique vestibulum. In tempor tellus dignissim neque consectetur eu vestibulum nisl pellentesque. Phasellus ultrices cursus velit, id aliquam nisl fringilla quis. Cras varius elit sed urna ultrices congue. Sed ornare odio sed velit pellentesque id varius nisl sodales. Sed auctor ligula egestas mi pharetra ut consectetur erat pharetra.

      \ No newline at end of file diff --git a/demos/tabs/ajax/content4-broken.php b/demos/tabs/ajax/content4-broken.php deleted file mode 100644 index 55ea2fe9f84..00000000000 --- a/demos/tabs/ajax/content4-broken.php +++ /dev/null @@ -1,3 +0,0 @@ - \ No newline at end of file diff --git a/demos/tabs/bottom.html b/demos/tabs/bottom.html deleted file mode 100644 index c4ab313298e..00000000000 --- a/demos/tabs/bottom.html +++ /dev/null @@ -1,60 +0,0 @@ - - - - - jQuery UI Tabs - Tabs at bottom - - - - - - - - - - - -
      - -
      - -
      -

      Proin elit arcu, rutrum commodo, vehicula tempus, commodo a, risus. Curabitur nec arcu. Donec sollicitudin mi sit amet mauris. Nam elementum quam ullamcorper ante. Etiam aliquet massa et lorem. Mauris dapibus lacus auctor risus. Aenean tempor ullamcorper leo. Vivamus sed magna quis ligula eleifend adipiscing. Duis orci. Aliquam sodales tortor vitae ipsum. Aliquam nulla. Duis aliquam molestie erat. Ut et mauris vel pede varius sollicitudin. Sed ut dolor nec orci tincidunt interdum. Phasellus ipsum. Nunc tristique tempus lectus.

      -
      -
      -

      Morbi tincidunt, dui sit amet facilisis feugiat, odio metus gravida ante, ut pharetra massa metus id nunc. Duis scelerisque molestie turpis. Sed fringilla, massa eget luctus malesuada, metus eros molestie lectus, ut tempus eros massa ut dolor. Aenean aliquet fringilla sem. Suspendisse sed ligula in ligula suscipit aliquam. Praesent in eros vestibulum mi adipiscing adipiscing. Morbi facilisis. Curabitur ornare consequat nunc. Aenean vel metus. Ut posuere viverra nulla. Aliquam erat volutpat. Pellentesque convallis. Maecenas feugiat, tellus pellentesque pretium posuere, felis lorem euismod felis, eu ornare leo nisi vel felis. Mauris consectetur tortor et purus.

      -
      -
      -

      Mauris eleifend est et turpis. Duis id erat. Suspendisse potenti. Aliquam vulputate, pede vel vehicula accumsan, mi neque rutrum erat, eu congue orci lorem eget lorem. Vestibulum non ante. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Fusce sodales. Quisque eu urna vel enim commodo pellentesque. Praesent eu risus hendrerit ligula tempus pretium. Curabitur lorem enim, pretium nec, feugiat nec, luctus a, lacus.

      -

      Duis cursus. Maecenas ligula eros, blandit nec, pharetra at, semper at, magna. Nullam ac lacus. Nulla facilisi. Praesent viverra justo vitae neque. Praesent blandit adipiscing velit. Suspendisse potenti. Donec mattis, pede vel pharetra blandit, magna ligula faucibus eros, id euismod lacus dolor eget odio. Nam scelerisque. Donec non libero sed nulla mattis commodo. Ut sagittis. Donec nisi lectus, feugiat porttitor, tempor ac, tempor vitae, pede. Aenean vehicula velit eu tellus interdum rutrum. Maecenas commodo. Pellentesque nec elit. Fusce in lacus. Vivamus a libero vitae lectus hendrerit hendrerit.

      -
      -
      - -
      - -
      - -

      With some additional CSS (for positioning) and JS (to put the right classes on elements) the tabs can be placed below their content.

      - -
      - - - diff --git a/demos/tabs/collapsible.html b/demos/tabs/collapsible.html index 7a638e29565..7fcd15bdbf0 100644 --- a/demos/tabs/collapsible.html +++ b/demos/tabs/collapsible.html @@ -1,26 +1,20 @@ - + - + + jQuery UI Tabs - Collapse content - - - - - - - + -
      -
      - -
      -

      Click the selected tab to toggle its content closed/open. To enable this functionality, set the collapsible option to true.

      -
      collapsible: true
       
      - -
      - + diff --git a/demos/tabs/cookie.html b/demos/tabs/cookie.html deleted file mode 100644 index 638ee37f299..00000000000 --- a/demos/tabs/cookie.html +++ /dev/null @@ -1,57 +0,0 @@ - - - - - jQuery UI Tabs - Default functionality - - - - - - - - - - - -
      - -
      - -
      -

      Proin elit arcu, rutrum commodo, vehicula tempus, commodo a, risus. Curabitur nec arcu. Donec sollicitudin mi sit amet mauris. Nam elementum quam ullamcorper ante. Etiam aliquet massa et lorem. Mauris dapibus lacus auctor risus. Aenean tempor ullamcorper leo. Vivamus sed magna quis ligula eleifend adipiscing. Duis orci. Aliquam sodales tortor vitae ipsum. Aliquam nulla. Duis aliquam molestie erat. Ut et mauris vel pede varius sollicitudin. Sed ut dolor nec orci tincidunt interdum. Phasellus ipsum. Nunc tristique tempus lectus.

      -
      -
      -

      Morbi tincidunt, dui sit amet facilisis feugiat, odio metus gravida ante, ut pharetra massa metus id nunc. Duis scelerisque molestie turpis. Sed fringilla, massa eget luctus malesuada, metus eros molestie lectus, ut tempus eros massa ut dolor. Aenean aliquet fringilla sem. Suspendisse sed ligula in ligula suscipit aliquam. Praesent in eros vestibulum mi adipiscing adipiscing. Morbi facilisis. Curabitur ornare consequat nunc. Aenean vel metus. Ut posuere viverra nulla. Aliquam erat volutpat. Pellentesque convallis. Maecenas feugiat, tellus pellentesque pretium posuere, felis lorem euismod felis, eu ornare leo nisi vel felis. Mauris consectetur tortor et purus.

      -
      -
      -

      Mauris eleifend est et turpis. Duis id erat. Suspendisse potenti. Aliquam vulputate, pede vel vehicula accumsan, mi neque rutrum erat, eu congue orci lorem eget lorem. Vestibulum non ante. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Fusce sodales. Quisque eu urna vel enim commodo pellentesque. Praesent eu risus hendrerit ligula tempus pretium. Curabitur lorem enim, pretium nec, feugiat nec, luctus a, lacus.

      -

      Duis cursus. Maecenas ligula eros, blandit nec, pharetra at, semper at, magna. Nullam ac lacus. Nulla facilisi. Praesent viverra justo vitae neque. Praesent blandit adipiscing velit. Suspendisse potenti. Donec mattis, pede vel pharetra blandit, magna ligula faucibus eros, id euismod lacus dolor eget odio. Nam scelerisque. Donec non libero sed nulla mattis commodo. Ut sagittis. Donec nisi lectus, feugiat porttitor, tempor ac, tempor vitae, pede. Aenean vehicula velit eu tellus interdum rutrum. Maecenas commodo. Pellentesque nec elit. Fusce in lacus. Vivamus a libero vitae lectus hendrerit hendrerit.

      -
      -
      - -
      - -
      - -

      Looks the same as the default demo, but uses cookie to store the selected tab, and restore it when the page (re)loads. - -The cookie is stored for a day, so tabs will be restored even after closing the browser. Use cookie: {} for using cookies with default options.

      - -
      - - - diff --git a/demos/tabs/default.html b/demos/tabs/default.html index 7b01cc8b46c..4c2b0fad304 100644 --- a/demos/tabs/default.html +++ b/demos/tabs/default.html @@ -1,24 +1,18 @@ - + - + + jQuery UI Tabs - Default functionality - - - - - - - + -
      -
      - -
      -

      Click tabs to swap between content that is broken into logical sections.

      - -
      - + diff --git a/demos/tabs/index.html b/demos/tabs/index.html index 8fc417a4ffa..11d0b46b360 100644 --- a/demos/tabs/index.html +++ b/demos/tabs/index.html @@ -1,25 +1,20 @@ - + - + + jQuery UI Tabs Demos - - + diff --git a/demos/tabs/manipulation.html b/demos/tabs/manipulation.html index ec143d52aef..a9f40b771f5 100644 --- a/demos/tabs/manipulation.html +++ b/demos/tabs/manipulation.html @@ -1,120 +1,115 @@ - + - + + jQuery UI Tabs - Simple manipulation - - - - - - - - - - + -
      - -
      -
      -
      - - - - -
      -
      -
      +
      +
      +
      + + + + +
      +
      +
      - + -
      - -
      -

      Proin elit arcu, rutrum commodo, vehicula tempus, commodo a, risus. Curabitur nec arcu. Donec sollicitudin mi sit amet mauris. Nam elementum quam ullamcorper ante. Etiam aliquet massa et lorem. Mauris dapibus lacus auctor risus. Aenean tempor ullamcorper leo. Vivamus sed magna quis ligula eleifend adipiscing. Duis orci. Aliquam sodales tortor vitae ipsum. Aliquam nulla. Duis aliquam molestie erat. Ut et mauris vel pede varius sollicitudin. Sed ut dolor nec orci tincidunt interdum. Phasellus ipsum. Nunc tristique tempus lectus.

      -
      +
      + +
      +

      Proin elit arcu, rutrum commodo, vehicula tempus, commodo a, risus. Curabitur nec arcu. Donec sollicitudin mi sit amet mauris. Nam elementum quam ullamcorper ante. Etiam aliquet massa et lorem. Mauris dapibus lacus auctor risus. Aenean tempor ullamcorper leo. Vivamus sed magna quis ligula eleifend adipiscing. Duis orci. Aliquam sodales tortor vitae ipsum. Aliquam nulla. Duis aliquam molestie erat. Ut et mauris vel pede varius sollicitudin. Sed ut dolor nec orci tincidunt interdum. Phasellus ipsum. Nunc tristique tempus lectus.

      - -
      +
      -

      Simple tabs adding and removing.

      -
      - +

      Simple tabs adding and removing.

      +
      diff --git a/demos/tabs/mouseover.html b/demos/tabs/mouseover.html index 30233d61e4d..edd0943c88f 100644 --- a/demos/tabs/mouseover.html +++ b/demos/tabs/mouseover.html @@ -1,26 +1,20 @@ - + - + + jQuery UI Tabs - Open on mouseover - - - - - - - + -
      -
      - -
      -

      Toggle sections open/closed on mouseover with the event option. The default value for event is "click."

      - -
      event: 'mouseover'
      -
      - -
      - + diff --git a/demos/tabs/sortable.html b/demos/tabs/sortable.html index e57f41309f8..81ae22a2546 100644 --- a/demos/tabs/sortable.html +++ b/demos/tabs/sortable.html @@ -1,26 +1,35 @@ - + - + + jQuery UI Tabs - Sortable - - - - - - - - - + -
      -
      - -
      - -

      -Drag the tabs above to re-order them. -

      - -

      -Making tabs sortable is as simple as calling - -.sortable() - -on the - -.ui-tabs-nav - -element. -

      - -
      - +

      Drag the tabs above to re-order them.

      +

      Making tabs sortable is as simple as calling .sortable() on the .ui-tabs-nav element.

      + diff --git a/demos/tabs/vertical.html b/demos/tabs/vertical.html index e13cd8290fa..8b6aa45a5ec 100644 --- a/demos/tabs/vertical.html +++ b/demos/tabs/vertical.html @@ -1,36 +1,27 @@ - + - + + jQuery UI Tabs - Vertical Tabs functionality - - - - - - - + - -
      -
      - -
      -

      Click tabs to swap between content that is broken into logical sections.

      - -
      - + diff --git a/demos/toggle/default.html b/demos/toggle/default.html deleted file mode 100644 index d34fb22cd08..00000000000 --- a/demos/toggle/default.html +++ /dev/null @@ -1,92 +0,0 @@ - - - - - jQuery UI Effects - Toggle Demo - - - - - - - - - - - - - - - - - - - - -
      - -
      -
      -

      Toggle

      -

      - Etiam libero neque, luctus a, eleifend nec, semper at, lorem. Sed pede. Nulla lorem metus, adipiscing ut, luctus sed, hendrerit vitae, mi. -

      -
      -
      - - - -Run Effect -
      - -
      - -

      Click the button above to preview the effect.

      - -
      - - - diff --git a/demos/toggle/index.html b/demos/toggle/index.html deleted file mode 100644 index 0e9af371fea..00000000000 --- a/demos/toggle/index.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - - jQuery UI Effects Demos - - - - -
      -

      Examples

      - -
      - - - diff --git a/demos/toggleClass/default.html b/demos/toggleClass/default.html deleted file mode 100644 index b679c96b775..00000000000 --- a/demos/toggleClass/default.html +++ /dev/null @@ -1,46 +0,0 @@ - - - - - jQuery UI Effects - toggleClass Demo - - - - - - - - - -
      - -
      -
      - Etiam libero neque, luctus a, eleifend nec, semper at, lorem. Sed pede. -
      -
      - -Run Effect - -
      - -
      - -

      Click the button above to preview the effect.

      - -
      - - - diff --git a/demos/toggleClass/index.html b/demos/toggleClass/index.html deleted file mode 100644 index 0e9af371fea..00000000000 --- a/demos/toggleClass/index.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - - jQuery UI Effects Demos - - - - -
      -

      Examples

      - -
      - - - diff --git a/demos/tooltip/ajax/content1.html b/demos/tooltip/ajax/content1.html new file mode 100644 index 00000000000..a1401b26da5 --- /dev/null +++ b/demos/tooltip/ajax/content1.html @@ -0,0 +1 @@ +

      This content was loaded via ajax.

      \ No newline at end of file diff --git a/demos/tooltip/ajax/content2.html b/demos/tooltip/ajax/content2.html new file mode 100644 index 00000000000..f4132d731bf --- /dev/null +++ b/demos/tooltip/ajax/content2.html @@ -0,0 +1 @@ +

      This other content was loaded via ajax.

      \ No newline at end of file diff --git a/demos/tooltip/custom-animation.html b/demos/tooltip/custom-animation.html new file mode 100644 index 00000000000..df31be87f43 --- /dev/null +++ b/demos/tooltip/custom-animation.html @@ -0,0 +1,47 @@ + + + + + + jQuery UI Tooltip - Custom animation demo + + + + + + + +

      There are various ways to customize the animation of a tooltip.

      +

      You can use the show and +hide options.

      +

      You can also use the open event.

      + +
      +

      This demo shows how to customize animations using the show and hide options, +as well as the open event.

      +
      + + diff --git a/demos/tooltip/custom-content.html b/demos/tooltip/custom-content.html new file mode 100644 index 00000000000..8a40aae1f34 --- /dev/null +++ b/demos/tooltip/custom-content.html @@ -0,0 +1,78 @@ + + + + + + jQuery UI Tooltip - Custom content + + + + + + + + +
      +
      +

      St. Stephen's Cathedral

      +

      Vienna, Austria

      +
      + + St. Stephen's Cathedral + +
      + +
      +
      +

      Tower Bridge

      +

      London, England

      +
      + + Tower Bridge + +
      + +

      All images are part of Wikimedia Commons +and are licensed under CC BY-SA 3.0 by the copyright holder.

      + +
      +

      Shows how to combine different event delegated tooltips into a single instance, by customizing the items and content options.

      +

      For interactive content, such as scrollable maps, use a dialog.

      +
      + + diff --git a/demos/tooltip/custom-style.html b/demos/tooltip/custom-style.html new file mode 100644 index 00000000000..8ab8dcc9d2f --- /dev/null +++ b/demos/tooltip/custom-style.html @@ -0,0 +1,86 @@ + + + + + + jQuery UI Tooltip - Custom Styling + + + + + + + + +

      Tooltips can be attached to any element. When you hover +the element with your mouse, the title attribute is displayed in a little box next to the element, just like a native tooltip.

      +

      But as it's not a native tooltip, it can be styled. Any themes built with +ThemeRoller +will also style tooltips accordingly.

      +

      Tooltips are also useful for form elements, to show some additional information in the context of each field.

      +

      +

      Hover the field to see the tooltip.

      + +
      +

      Hover the links above or use the tab key to cycle the focus on each element.

      +
      + + diff --git a/demos/tooltip/default.html b/demos/tooltip/default.html new file mode 100644 index 00000000000..bd846a85a60 --- /dev/null +++ b/demos/tooltip/default.html @@ -0,0 +1,35 @@ + + + + + + jQuery UI Tooltip - Default functionality + + + + + + + + +

      Tooltips can be attached to any element. When you hover +the element with your mouse, the title attribute is displayed in a little box next to the element, just like a native tooltip.

      +

      But as it's not a native tooltip, it can be styled. Any themes built with +ThemeRoller +will also style tooltips accordingly.

      +

      Tooltips are also useful for form elements, to show some additional information in the context of each field.

      +

      +

      Hover the field to see the tooltip.

      + +
      +

      Hover the links above or use the tab key to cycle the focus on each element.

      +
      + + diff --git a/demos/tooltip/forms.html b/demos/tooltip/forms.html new file mode 100644 index 00000000000..7221d38abf3 --- /dev/null +++ b/demos/tooltip/forms.html @@ -0,0 +1,65 @@ + + + + + + jQuery UI Tooltip - Forms + + + + + + + + +
      +
      +
      + + +
      +
      + + +
      +
      + + +
      +
      +
      + +
      +

      Use the button below to display the help texts, or just focus or mouseover the indivdual inputs.

      +

      A fixed width is defined in CSS to make the tooltips look consistent when displayed all at once.

      +
      + + diff --git a/demos/tooltip/images/st-stephens.jpg b/demos/tooltip/images/st-stephens.jpg new file mode 100644 index 00000000000..30fc36d6741 Binary files /dev/null and b/demos/tooltip/images/st-stephens.jpg differ diff --git a/demos/tooltip/images/tower-bridge.jpg b/demos/tooltip/images/tower-bridge.jpg new file mode 100644 index 00000000000..d1e14d6d28d Binary files /dev/null and b/demos/tooltip/images/tower-bridge.jpg differ diff --git a/demos/tooltip/index.html b/demos/tooltip/index.html new file mode 100644 index 00000000000..2ff0fc10c13 --- /dev/null +++ b/demos/tooltip/index.html @@ -0,0 +1,21 @@ + + + + + + jQuery UI Tooltip Demos + + + + + + + diff --git a/demos/tooltip/tracking.html b/demos/tooltip/tracking.html new file mode 100644 index 00000000000..635c5303437 --- /dev/null +++ b/demos/tooltip/tracking.html @@ -0,0 +1,37 @@ + + + + + + jQuery UI Tooltip - Track the mouse + + + + + + + + +

      Tooltips can be attached to any element. When you hover +the element with your mouse, the title attribute is displayed in a little box next to the element, just like a native tooltip.

      +

      But as it's not a native tooltip, it can be styled. Any themes built with +ThemeRoller +will also style tooltips accordingly.

      +

      Tooltips are also useful for form elements, to show some additional information in the context of each field.

      +

      +

      Hover the field to see the tooltip.

      + +
      +

      Here the tooltips are positioned relative to the mouse, and follow the mouse while it moves above the element, using the track option.

      +
      + + diff --git a/demos/tooltip/video-player.html b/demos/tooltip/video-player.html new file mode 100644 index 00000000000..c7601b7478f --- /dev/null +++ b/demos/tooltip/video-player.html @@ -0,0 +1,140 @@ + + + + + + jQuery UI Tooltip - Video Player demo + + + + + + + + +
      Here Be Video (HTML5?)
      +
      + + + + +
      + + +
        +
      • Favorites
      • +
      • Funnees
      • +
      • +
      • New playlist...
      • +
      +
      + + +
      + +
      +

      A fake video player with like/share/stats button, each with a custom-styled tooltip.

      +
      + + diff --git a/demos/widget/default.html b/demos/widget/default.html new file mode 100644 index 00000000000..bf380929fd4 --- /dev/null +++ b/demos/widget/default.html @@ -0,0 +1,172 @@ + + + + + + jQuery UI Widget - Default functionality + + + + + + + + +
      +
      color me
      +
      color me
      +
      color me
      + + +
      + +
      +

      This demo shows a simple custom widget built using the widget factory (jquery.ui.widget.js).

      +

      The three boxes are initialized in different ways. Clicking them changes their background color. View source to see how it works, its heavily commented

      +

      To learn more about the widget factory, visit learn.jquery.com.

      +
      + + diff --git a/demos/widget/index.html b/demos/widget/index.html new file mode 100644 index 00000000000..e75390ba0f1 --- /dev/null +++ b/demos/widget/index.html @@ -0,0 +1,15 @@ + + + + + + jQuery UI Widget Demo + + + + + + + diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 00000000000..4fb03f6b3e1 --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,162 @@ +import jqueryConfig from "eslint-config-jquery"; +import globals from "globals"; + +export default [ + { + ignores: [ + "dist/**/*", + "!dist/jquery-ui.js", + "!dist/jquery-ui.min.js", + "external/**/*", + "tests/lib/vendor/**/*", + "ui/vendor/**/*" + ] + }, + + { + ignores: [ "dist/**/*" ], + rules: { + ...jqueryConfig.rules, + "no-unused-vars": [ + "error", + { + argsIgnorePattern: "^_", + caughtErrorsIgnorePattern: "^_" + } + ] + } + }, + + { + files: [ "Gruntfile.js" ], + languageOptions: { + ecmaVersion: "latest", + sourceType: "commonjs", + globals: { + ...globals.node + } + }, + rules: { + strict: [ "error", "global" ] + } + }, + + { + files: [ "eslint.config.mjs" ], + languageOptions: { + ecmaVersion: "latest", + sourceType: "module", + globals: { + ...globals.node + } + }, + rules: { + strict: [ "error", "global" ] + } + }, + + // Source, demos + { + files: [ "ui/**/*.js", "demos/**/*.js" ], + languageOptions: { + ecmaVersion: 5, + sourceType: "script", + globals: { + ...globals.browser, + ...globals.jquery, + define: false, + Globalize: false + } + }, + rules: { + strict: [ "error", "function" ], + + // The following rule is relaxed due to too many violations: + "no-unused-vars": [ + "error", + { + args: "after-used", + argsIgnorePattern: "^_", + caughtErrorsIgnorePattern: "^_" + } + ], + + // Too many violations: + camelcase: "off", + "no-nested-ternary": "off" + } + }, + { + files: [ "ui/i18n/**/*.js" ], + rules: { + + // We want to keep all the strings in separate single lines + "max-len": "off" + } + }, + + // Dist files + // For dist files, we don't include any jQuery rules on purpose. + // We just want to make sure the files are correct ES5. + { + files: [ "dist/jquery-ui.js", "dist/jquery-ui.min.js" ], + languageOptions: { + ecmaVersion: 5, + sourceType: "script" + }, + linterOptions: { + reportUnusedDisableDirectives: "off" + } + }, + + // Build + { + files: [ "build/**/*.js" ], + languageOptions: { + ecmaVersion: "latest", + sourceType: "commonjs", + globals: { + ...globals.node + } + }, + rules: { + "no-implicit-globals": "error", + strict: [ "error", "global" ] + } + }, + + // Demos + { + files: [ "demos/**/*.js" ], + languageOptions: { + globals: { + require: true + } + } + }, + + // Tests + { + files: [ "tests/**/*.js" ], + languageOptions: { + ecmaVersion: 5, + sourceType: "script", + globals: { + ...globals.browser, + ...globals.jquery, + define: false, + Globalize: false, + QUnit: false, + require: true, + requirejs: true + } + }, + "rules": { + + // Too many violations: + "max-len": "off", + "no-unused-vars": "off", + strict: "off" // ideally, `[ "error", "function" ]` + } + } +]; diff --git a/external/globalize/LICENSE b/external/globalize/LICENSE new file mode 100644 index 00000000000..9c8b022405c --- /dev/null +++ b/external/globalize/LICENSE @@ -0,0 +1,21 @@ +Copyright Software Freedom Conservancy, Inc. +http://jquery.org/license + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/external/globalize/globalize.culture.de-DE.js b/external/globalize/globalize.culture.de-DE.js new file mode 100644 index 00000000000..5466bd75e3b --- /dev/null +++ b/external/globalize/globalize.culture.de-DE.js @@ -0,0 +1,81 @@ +/* + * Globalize Culture de-DE + * + * http://github.com/jquery/globalize + * + * Copyright Software Freedom Conservancy, Inc. + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * This file was generated by the Globalize Culture Generator + * Translation: bugs found in this file need to be fixed in the generator + */ + +(function( window, undefined ) { + +var Globalize; + +if ( typeof require !== "undefined" + && typeof exports !== "undefined" + && typeof module !== "undefined" ) { + // Assume CommonJS + Globalize = require( "globalize" ); +} else { + // Global variable + Globalize = window.Globalize; +} + +Globalize.addCultureInfo( "de-DE", "default", { + name: "de-DE", + englishName: "German (Germany)", + nativeName: "Deutsch (Deutschland)", + language: "de", + numberFormat: { + ",": ".", + ".": ",", + NaN: "n. def.", + negativeInfinity: "-unendlich", + positiveInfinity: "+unendlich", + percent: { + pattern: ["-n%","n%"], + ",": ".", + ".": "," + }, + currency: { + pattern: ["-n $","n $"], + ",": ".", + ".": ",", + symbol: "€" + } + }, + calendars: { + standard: { + "/": ".", + firstDay: 1, + days: { + names: ["Sonntag","Montag","Dienstag","Mittwoch","Donnerstag","Freitag","Samstag"], + namesAbbr: ["So","Mo","Di","Mi","Do","Fr","Sa"], + namesShort: ["So","Mo","Di","Mi","Do","Fr","Sa"] + }, + months: { + names: ["Januar","Februar","März","April","Mai","Juni","Juli","August","September","Oktober","November","Dezember",""], + namesAbbr: ["Jan","Feb","Mrz","Apr","Mai","Jun","Jul","Aug","Sep","Okt","Nov","Dez",""] + }, + AM: null, + PM: null, + eras: [{"name":"n. Chr.","start":null,"offset":0}], + patterns: { + d: "dd.MM.yyyy", + D: "dddd, d. MMMM yyyy", + t: "HH:mm", + T: "HH:mm:ss", + f: "dddd, d. MMMM yyyy HH:mm", + F: "dddd, d. MMMM yyyy HH:mm:ss", + M: "dd MMMM", + Y: "MMMM yyyy" + } + } + } +}); + +}( this )); diff --git a/external/globalize/globalize.culture.ja-JP.js b/external/globalize/globalize.culture.ja-JP.js new file mode 100644 index 00000000000..a9469d709f4 --- /dev/null +++ b/external/globalize/globalize.culture.ja-JP.js @@ -0,0 +1,100 @@ +/* + * Globalize Culture ja-JP + * + * http://github.com/jquery/globalize + * + * Copyright Software Freedom Conservancy, Inc. + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * This file was generated by the Globalize Culture Generator + * Translation: bugs found in this file need to be fixed in the generator + */ + +(function( window, undefined ) { + +var Globalize; + +if ( typeof require !== "undefined" + && typeof exports !== "undefined" + && typeof module !== "undefined" ) { + // Assume CommonJS + Globalize = require( "globalize" ); +} else { + // Global variable + Globalize = window.Globalize; +} + +Globalize.addCultureInfo( "ja-JP", "default", { + name: "ja-JP", + englishName: "Japanese (Japan)", + nativeName: "日本語 (日本)", + language: "ja", + numberFormat: { + NaN: "NaN (非数値)", + negativeInfinity: "-∞", + positiveInfinity: "+∞", + percent: { + pattern: ["-n%","n%"] + }, + currency: { + pattern: ["-$n","$n"], + decimals: 0, + symbol: "¥" + } + }, + calendars: { + standard: { + days: { + names: ["日曜日","月曜日","火曜日","水曜日","木曜日","金曜日","土曜日"], + namesAbbr: ["日","月","火","水","木","金","土"], + namesShort: ["日","月","火","水","木","金","土"] + }, + months: { + names: ["1月","2月","3月","4月","5月","6月","7月","8月","9月","10月","11月","12月",""], + namesAbbr: ["1","2","3","4","5","6","7","8","9","10","11","12",""] + }, + AM: ["午前","午前","午前"], + PM: ["午後","午後","午後"], + eras: [{"name":"西暦","start":null,"offset":0}], + patterns: { + d: "yyyy/MM/dd", + D: "yyyy'年'M'月'd'日'", + t: "H:mm", + T: "H:mm:ss", + f: "yyyy'年'M'月'd'日' H:mm", + F: "yyyy'年'M'月'd'日' H:mm:ss", + M: "M'月'd'日'", + Y: "yyyy'年'M'月'" + } + }, + Japanese: { + name: "Japanese", + days: { + names: ["日曜日","月曜日","火曜日","水曜日","木曜日","金曜日","土曜日"], + namesAbbr: ["日","月","火","水","木","金","土"], + namesShort: ["日","月","火","水","木","金","土"] + }, + months: { + names: ["1月","2月","3月","4月","5月","6月","7月","8月","9月","10月","11月","12月",""], + namesAbbr: ["1","2","3","4","5","6","7","8","9","10","11","12",""] + }, + AM: ["午前","午前","午前"], + PM: ["午後","午後","午後"], + eras: [{"name":"平成","start":null,"offset":1867},{"name":"昭和","start":-1812153600000,"offset":1911},{"name":"大正","start":-1357603200000,"offset":1925},{"name":"明治","start":60022080000,"offset":1988}], + twoDigitYearMax: 99, + patterns: { + d: "gg y/M/d", + D: "gg y'年'M'月'd'日'", + t: "H:mm", + T: "H:mm:ss", + f: "gg y'年'M'月'd'日' H:mm", + F: "gg y'年'M'月'd'日' H:mm:ss", + M: "M'月'd'日'", + Y: "gg y'年'M'月'" + } + } + } +}); + +}( this )); diff --git a/external/globalize/globalize.js b/external/globalize/globalize.js new file mode 100644 index 00000000000..a38a32625d3 --- /dev/null +++ b/external/globalize/globalize.js @@ -0,0 +1,1585 @@ +/*! + * Globalize + * + * http://github.com/jquery/globalize + * + * Copyright Software Freedom Conservancy, Inc. + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + */ + +(function( window, undefined ) { + +var Globalize, + // private variables + regexHex, + regexInfinity, + regexParseFloat, + regexTrim, + // private JavaScript utility functions + arrayIndexOf, + endsWith, + extend, + isArray, + isFunction, + isObject, + startsWith, + trim, + truncate, + zeroPad, + // private Globalization utility functions + appendPreOrPostMatch, + expandFormat, + formatDate, + formatNumber, + getTokenRegExp, + getEra, + getEraYear, + parseExact, + parseNegativePattern; + +// Global variable (Globalize) or CommonJS module (globalize) +Globalize = function( cultureSelector ) { + return new Globalize.prototype.init( cultureSelector ); +}; + +if ( typeof require !== "undefined" && + typeof exports !== "undefined" && + typeof module !== "undefined" ) { + // Assume CommonJS + module.exports = Globalize; +} else { + // Export as global variable + window.Globalize = Globalize; +} + +Globalize.cultures = {}; + +Globalize.prototype = { + constructor: Globalize, + init: function( cultureSelector ) { + this.cultures = Globalize.cultures; + this.cultureSelector = cultureSelector; + + return this; + } +}; +Globalize.prototype.init.prototype = Globalize.prototype; + +// 1. When defining a culture, all fields are required except the ones stated as optional. +// 2. Each culture should have a ".calendars" object with at least one calendar named "standard" +// which serves as the default calendar in use by that culture. +// 3. Each culture should have a ".calendar" object which is the current calendar being used, +// it may be dynamically changed at any time to one of the calendars in ".calendars". +Globalize.cultures[ "default" ] = { + // A unique name for the culture in the form - + name: "en", + // the name of the culture in the english language + englishName: "English", + // the name of the culture in its own language + nativeName: "English", + // whether the culture uses right-to-left text + isRTL: false, + // "language" is used for so-called "specific" cultures. + // For example, the culture "es-CL" means "Spanish, in Chili". + // It represents the Spanish-speaking culture as it is in Chili, + // which might have different formatting rules or even translations + // than Spanish in Spain. A "neutral" culture is one that is not + // specific to a region. For example, the culture "es" is the generic + // Spanish culture, which may be a more generalized version of the language + // that may or may not be what a specific culture expects. + // For a specific culture like "es-CL", the "language" field refers to the + // neutral, generic culture information for the language it is using. + // This is not always a simple matter of the string before the dash. + // For example, the "zh-Hans" culture is netural (Simplified Chinese). + // And the "zh-SG" culture is Simplified Chinese in Singapore, whose lanugage + // field is "zh-CHS", not "zh". + // This field should be used to navigate from a specific culture to it's + // more general, neutral culture. If a culture is already as general as it + // can get, the language may refer to itself. + language: "en", + // numberFormat defines general number formatting rules, like the digits in + // each grouping, the group separator, and how negative numbers are displayed. + numberFormat: { + // [negativePattern] + // Note, numberFormat.pattern has no "positivePattern" unlike percent and currency, + // but is still defined as an array for consistency with them. + // negativePattern: one of "(n)|-n|- n|n-|n -" + pattern: [ "-n" ], + // number of decimal places normally shown + decimals: 2, + // string that separates number groups, as in 1,000,000 + ",": ",", + // string that separates a number from the fractional portion, as in 1.99 + ".": ".", + // array of numbers indicating the size of each number group. + // TODO: more detailed description and example + groupSizes: [ 3 ], + // symbol used for positive numbers + "+": "+", + // symbol used for negative numbers + "-": "-", + // symbol used for NaN (Not-A-Number) + "NaN": "NaN", + // symbol used for Negative Infinity + negativeInfinity: "-Infinity", + // symbol used for Positive Infinity + positiveInfinity: "Infinity", + percent: { + // [negativePattern, positivePattern] + // negativePattern: one of "-n %|-n%|-%n|%-n|%n-|n-%|n%-|-% n|n %-|% n-|% -n|n- %" + // positivePattern: one of "n %|n%|%n|% n" + pattern: [ "-n %", "n %" ], + // number of decimal places normally shown + decimals: 2, + // array of numbers indicating the size of each number group. + // TODO: more detailed description and example + groupSizes: [ 3 ], + // string that separates number groups, as in 1,000,000 + ",": ",", + // string that separates a number from the fractional portion, as in 1.99 + ".": ".", + // symbol used to represent a percentage + symbol: "%" + }, + currency: { + // [negativePattern, positivePattern] + // negativePattern: one of "($n)|-$n|$-n|$n-|(n$)|-n$|n-$|n$-|-n $|-$ n|n $-|$ n-|$ -n|n- $|($ n)|(n $)" + // positivePattern: one of "$n|n$|$ n|n $" + pattern: [ "($n)", "$n" ], + // number of decimal places normally shown + decimals: 2, + // array of numbers indicating the size of each number group. + // TODO: more detailed description and example + groupSizes: [ 3 ], + // string that separates number groups, as in 1,000,000 + ",": ",", + // string that separates a number from the fractional portion, as in 1.99 + ".": ".", + // symbol used to represent currency + symbol: "$" + } + }, + // calendars defines all the possible calendars used by this culture. + // There should be at least one defined with name "standard", and is the default + // calendar used by the culture. + // A calendar contains information about how dates are formatted, information about + // the calendar's eras, a standard set of the date formats, + // translations for day and month names, and if the calendar is not based on the Gregorian + // calendar, conversion functions to and from the Gregorian calendar. + calendars: { + standard: { + // name that identifies the type of calendar this is + name: "Gregorian_USEnglish", + // separator of parts of a date (e.g. "/" in 11/05/1955) + "/": "/", + // separator of parts of a time (e.g. ":" in 05:44 PM) + ":": ":", + // the first day of the week (0 = Sunday, 1 = Monday, etc) + firstDay: 0, + days: { + // full day names + names: [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ], + // abbreviated day names + namesAbbr: [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ], + // shortest day names + namesShort: [ "Su", "Mo", "Tu", "We", "Th", "Fr", "Sa" ] + }, + months: { + // full month names (13 months for lunar calendards -- 13th month should be "" if not lunar) + names: [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", "" ], + // abbreviated month names + namesAbbr: [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "" ] + }, + // AM and PM designators in one of these forms: + // The usual view, and the upper and lower case versions + // [ standard, lowercase, uppercase ] + // The culture does not use AM or PM (likely all standard date formats use 24 hour time) + // null + AM: [ "AM", "am", "AM" ], + PM: [ "PM", "pm", "PM" ], + eras: [ + // eras in reverse chronological order. + // name: the name of the era in this culture (e.g. A.D., C.E.) + // start: when the era starts in ticks (gregorian, gmt), null if it is the earliest supported era. + // offset: offset in years from gregorian calendar + { + "name": "A.D.", + "start": null, + "offset": 0 + } + ], + // when a two digit year is given, it will never be parsed as a four digit + // year greater than this year (in the appropriate era for the culture) + // Set it as a full year (e.g. 2029) or use an offset format starting from + // the current year: "+19" would correspond to 2029 if the current year 2010. + twoDigitYearMax: 2029, + // set of predefined date and time patterns used by the culture + // these represent the format someone in this culture would expect + // to see given the portions of the date that are shown. + patterns: { + // short date pattern + d: "M/d/yyyy", + // long date pattern + D: "dddd, MMMM dd, yyyy", + // short time pattern + t: "h:mm tt", + // long time pattern + T: "h:mm:ss tt", + // long date, short time pattern + f: "dddd, MMMM dd, yyyy h:mm tt", + // long date, long time pattern + F: "dddd, MMMM dd, yyyy h:mm:ss tt", + // month/day pattern + M: "MMMM dd", + // month/year pattern + Y: "yyyy MMMM", + // S is a sortable format that does not vary by culture + S: "yyyy\u0027-\u0027MM\u0027-\u0027dd\u0027T\u0027HH\u0027:\u0027mm\u0027:\u0027ss" + } + // optional fields for each calendar: + /* + monthsGenitive: + Same as months but used when the day preceeds the month. + Omit if the culture has no genitive distinction in month names. + For an explaination of genitive months, see http://blogs.msdn.com/michkap/archive/2004/12/25/332259.aspx + convert: + Allows for the support of non-gregorian based calendars. This convert object is used to + to convert a date to and from a gregorian calendar date to handle parsing and formatting. + The two functions: + fromGregorian( date ) + Given the date as a parameter, return an array with parts [ year, month, day ] + corresponding to the non-gregorian based year, month, and day for the calendar. + toGregorian( year, month, day ) + Given the non-gregorian year, month, and day, return a new Date() object + set to the corresponding date in the gregorian calendar. + */ + } + }, + // For localized strings + messages: {} +}; + +Globalize.cultures[ "default" ].calendar = Globalize.cultures[ "default" ].calendars.standard; + +Globalize.cultures.en = Globalize.cultures[ "default" ]; + +Globalize.cultureSelector = "en"; + +// +// private variables +// + +regexHex = /^0x[a-f0-9]+$/i; +regexInfinity = /^[+\-]?infinity$/i; +regexParseFloat = /^[+\-]?\d*\.?\d*(e[+\-]?\d+)?$/; +regexTrim = /^\s+|\s+$/g; + +// +// private JavaScript utility functions +// + +arrayIndexOf = function( array, item ) { + if ( array.indexOf ) { + return array.indexOf( item ); + } + for ( var i = 0, length = array.length; i < length; i++ ) { + if ( array[i] === item ) { + return i; + } + } + return -1; +}; + +endsWith = function( value, pattern ) { + return value.substr( value.length - pattern.length ) === pattern; +}; + +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; + target = arguments[1] || {}; + // skip the boolean and the target + i = 2; + } + + // 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 ) { + src = target[ name ]; + copy = options[ name ]; + + // Prevent never-ending loop + if ( target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( isObject(copy) || (copyIsArray = isArray(copy)) ) ) { + if ( copyIsArray ) { + copyIsArray = false; + clone = src && isArray(src) ? src : []; + + } else { + clone = src && isObject(src) ? src : {}; + } + + // Never move original objects, clone them + target[ name ] = extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +isArray = Array.isArray || function( obj ) { + return Object.prototype.toString.call( obj ) === "[object Array]"; +}; + +isFunction = function( obj ) { + return Object.prototype.toString.call( obj ) === "[object Function]"; +}; + +isObject = function( obj ) { + return Object.prototype.toString.call( obj ) === "[object Object]"; +}; + +startsWith = function( value, pattern ) { + return value.indexOf( pattern ) === 0; +}; + +trim = function( value ) { + return ( value + "" ).replace( regexTrim, "" ); +}; + +truncate = function( value ) { + if ( isNaN( value ) ) { + return NaN; + } + return Math[ value < 0 ? "ceil" : "floor" ]( value ); +}; + +zeroPad = function( str, count, left ) { + var l; + for ( l = str.length; l < count; l += 1 ) { + str = ( left ? ("0" + str) : (str + "0") ); + } + return str; +}; + +// +// private Globalization utility functions +// + +appendPreOrPostMatch = function( preMatch, strings ) { + // appends pre- and post- token match strings while removing escaped characters. + // Returns a single quote count which is used to determine if the token occurs + // in a string literal. + var quoteCount = 0, + escaped = false; + for ( var i = 0, il = preMatch.length; i < il; i++ ) { + var c = preMatch.charAt( i ); + switch ( c ) { + case "\'": + if ( escaped ) { + strings.push( "\'" ); + } + else { + quoteCount++; + } + escaped = false; + break; + case "\\": + if ( escaped ) { + strings.push( "\\" ); + } + escaped = !escaped; + break; + default: + strings.push( c ); + escaped = false; + break; + } + } + return quoteCount; +}; + +expandFormat = function( cal, format ) { + // expands unspecified or single character date formats into the full pattern. + format = format || "F"; + var pattern, + patterns = cal.patterns, + len = format.length; + if ( len === 1 ) { + pattern = patterns[ format ]; + if ( !pattern ) { + throw "Invalid date format string \'" + format + "\'."; + } + format = pattern; + } + else if ( len === 2 && format.charAt(0) === "%" ) { + // %X escape format -- intended as a custom format string that is only one character, not a built-in format. + format = format.charAt( 1 ); + } + return format; +}; + +formatDate = function( value, format, culture ) { + var cal = culture.calendar, + convert = cal.convert, + ret; + + if ( !format || !format.length || format === "i" ) { + if ( culture && culture.name.length ) { + if ( convert ) { + // non-gregorian calendar, so we cannot use built-in toLocaleString() + ret = formatDate( value, cal.patterns.F, culture ); + } + else { + var eraDate = new Date( value.getTime() ), + era = getEra( value, cal.eras ); + eraDate.setFullYear( getEraYear(value, cal, era) ); + ret = eraDate.toLocaleString(); + } + } + else { + ret = value.toString(); + } + return ret; + } + + var eras = cal.eras, + sortable = format === "s"; + format = expandFormat( cal, format ); + + // Start with an empty string + ret = []; + var hour, + zeros = [ "0", "00", "000" ], + foundDay, + checkedDay, + dayPartRegExp = /([^d]|^)(d|dd)([^d]|$)/g, + quoteCount = 0, + tokenRegExp = getTokenRegExp(), + converted; + + function padZeros( num, c ) { + var r, s = num + ""; + if ( c > 1 && s.length < c ) { + r = ( zeros[c - 2] + s); + return r.substr( r.length - c, c ); + } + else { + r = s; + } + return r; + } + + function hasDay() { + if ( foundDay || checkedDay ) { + return foundDay; + } + foundDay = dayPartRegExp.test( format ); + checkedDay = true; + return foundDay; + } + + function getPart( date, part ) { + if ( converted ) { + return converted[ part ]; + } + switch ( part ) { + case 0: + return date.getFullYear(); + case 1: + return date.getMonth(); + case 2: + return date.getDate(); + default: + throw "Invalid part value " + part; + } + } + + if ( !sortable && convert ) { + converted = convert.fromGregorian( value ); + } + + for ( ; ; ) { + // Save the current index + var index = tokenRegExp.lastIndex, + // Look for the next pattern + ar = tokenRegExp.exec( format ); + + // Append the text before the pattern (or the end of the string if not found) + var preMatch = format.slice( index, ar ? ar.index : format.length ); + quoteCount += appendPreOrPostMatch( preMatch, ret ); + + if ( !ar ) { + break; + } + + // do not replace any matches that occur inside a string literal. + if ( quoteCount % 2 ) { + ret.push( ar[0] ); + continue; + } + + var current = ar[ 0 ], + clength = current.length; + + switch ( current ) { + case "ddd": + //Day of the week, as a three-letter abbreviation + case "dddd": + // Day of the week, using the full name + var names = ( clength === 3 ) ? cal.days.namesAbbr : cal.days.names; + ret.push( names[value.getDay()] ); + break; + case "d": + // Day of month, without leading zero for single-digit days + case "dd": + // Day of month, with leading zero for single-digit days + foundDay = true; + ret.push( + padZeros( getPart(value, 2), clength ) + ); + break; + case "MMM": + // Month, as a three-letter abbreviation + case "MMMM": + // Month, using the full name + var part = getPart( value, 1 ); + ret.push( + ( cal.monthsGenitive && hasDay() ) ? + ( cal.monthsGenitive[ clength === 3 ? "namesAbbr" : "names" ][ part ] ) : + ( cal.months[ clength === 3 ? "namesAbbr" : "names" ][ part ] ) + ); + break; + case "M": + // Month, as digits, with no leading zero for single-digit months + case "MM": + // Month, as digits, with leading zero for single-digit months + ret.push( + padZeros( getPart(value, 1) + 1, clength ) + ); + break; + case "y": + // Year, as two digits, but with no leading zero for years less than 10 + case "yy": + // Year, as two digits, with leading zero for years less than 10 + case "yyyy": + // Year represented by four full digits + part = converted ? converted[ 0 ] : getEraYear( value, cal, getEra(value, eras), sortable ); + if ( clength < 4 ) { + part = part % 100; + } + ret.push( + padZeros( part, clength ) + ); + break; + case "h": + // Hours with no leading zero for single-digit hours, using 12-hour clock + case "hh": + // Hours with leading zero for single-digit hours, using 12-hour clock + hour = value.getHours() % 12; + if ( hour === 0 ) hour = 12; + ret.push( + padZeros( hour, clength ) + ); + break; + case "H": + // Hours with no leading zero for single-digit hours, using 24-hour clock + case "HH": + // Hours with leading zero for single-digit hours, using 24-hour clock + ret.push( + padZeros( value.getHours(), clength ) + ); + break; + case "m": + // Minutes with no leading zero for single-digit minutes + case "mm": + // Minutes with leading zero for single-digit minutes + ret.push( + padZeros( value.getMinutes(), clength ) + ); + break; + case "s": + // Seconds with no leading zero for single-digit seconds + case "ss": + // Seconds with leading zero for single-digit seconds + ret.push( + padZeros( value.getSeconds(), clength ) + ); + break; + case "t": + // One character am/pm indicator ("a" or "p") + case "tt": + // Multicharacter am/pm indicator + part = value.getHours() < 12 ? ( cal.AM ? cal.AM[0] : " " ) : ( cal.PM ? cal.PM[0] : " " ); + ret.push( clength === 1 ? part.charAt(0) : part ); + break; + case "f": + // Deciseconds + case "ff": + // Centiseconds + case "fff": + // Milliseconds + ret.push( + padZeros( value.getMilliseconds(), 3 ).substr( 0, clength ) + ); + break; + case "z": + // Time zone offset, no leading zero + case "zz": + // Time zone offset with leading zero + hour = value.getTimezoneOffset() / 60; + ret.push( + ( hour <= 0 ? "+" : "-" ) + padZeros( Math.floor(Math.abs(hour)), clength ) + ); + break; + case "zzz": + // Time zone offset with leading zero + hour = value.getTimezoneOffset() / 60; + ret.push( + ( hour <= 0 ? "+" : "-" ) + padZeros( Math.floor(Math.abs(hour)), 2 ) + + // Hard coded ":" separator, rather than using cal.TimeSeparator + // Repeated here for consistency, plus ":" was already assumed in date parsing. + ":" + padZeros( Math.abs(value.getTimezoneOffset() % 60), 2 ) + ); + break; + case "g": + case "gg": + if ( cal.eras ) { + ret.push( + cal.eras[ getEra(value, eras) ].name + ); + } + break; + case "/": + ret.push( cal["/"] ); + break; + default: + throw "Invalid date format pattern \'" + current + "\'."; + } + } + return ret.join( "" ); +}; + +// formatNumber +(function() { + var expandNumber; + + expandNumber = function( number, precision, formatInfo ) { + var groupSizes = formatInfo.groupSizes, + curSize = groupSizes[ 0 ], + curGroupIndex = 1, + factor = Math.pow( 10, precision ), + rounded = Math.round( number * factor ) / factor; + + if ( !isFinite(rounded) ) { + rounded = number; + } + number = rounded; + + var numberString = number+"", + right = "", + split = numberString.split( /e/i ), + exponent = split.length > 1 ? parseInt( split[1], 10 ) : 0; + numberString = split[ 0 ]; + split = numberString.split( "." ); + numberString = split[ 0 ]; + right = split.length > 1 ? split[ 1 ] : ""; + + if ( exponent > 0 ) { + right = zeroPad( right, exponent, false ); + numberString += right.slice( 0, exponent ); + right = right.substr( exponent ); + } + else if ( exponent < 0 ) { + exponent = -exponent; + numberString = zeroPad( numberString, exponent + 1, true ); + right = numberString.slice( -exponent, numberString.length ) + right; + numberString = numberString.slice( 0, -exponent ); + } + + if ( precision > 0 ) { + right = formatInfo[ "." ] + + ( (right.length > precision) ? right.slice(0, precision) : zeroPad(right, precision) ); + } + else { + right = ""; + } + + var stringIndex = numberString.length - 1, + sep = formatInfo[ "," ], + ret = ""; + + while ( stringIndex >= 0 ) { + if ( curSize === 0 || curSize > stringIndex ) { + return numberString.slice( 0, stringIndex + 1 ) + ( ret.length ? (sep + ret + right) : right ); + } + ret = numberString.slice( stringIndex - curSize + 1, stringIndex + 1 ) + ( ret.length ? (sep + ret) : "" ); + + stringIndex -= curSize; + + if ( curGroupIndex < groupSizes.length ) { + curSize = groupSizes[ curGroupIndex ]; + curGroupIndex++; + } + } + + return numberString.slice( 0, stringIndex + 1 ) + sep + ret + right; + }; + + formatNumber = function( value, format, culture ) { + if ( !isFinite(value) ) { + if ( value === Infinity ) { + return culture.numberFormat.positiveInfinity; + } + if ( value === -Infinity ) { + return culture.numberFormat.negativeInfinity; + } + return culture.numberFormat.NaN; + } + if ( !format || format === "i" ) { + return culture.name.length ? value.toLocaleString() : value.toString(); + } + format = format || "D"; + + var nf = culture.numberFormat, + number = Math.abs( value ), + precision = -1, + pattern; + if ( format.length > 1 ) precision = parseInt( format.slice(1), 10 ); + + var current = format.charAt( 0 ).toUpperCase(), + formatInfo; + + switch ( current ) { + case "D": + pattern = "n"; + number = truncate( number ); + if ( precision !== -1 ) { + number = zeroPad( "" + number, precision, true ); + } + if ( value < 0 ) number = "-" + number; + break; + case "N": + formatInfo = nf; + /* falls through */ + case "C": + formatInfo = formatInfo || nf.currency; + /* falls through */ + case "P": + formatInfo = formatInfo || nf.percent; + pattern = value < 0 ? formatInfo.pattern[ 0 ] : ( formatInfo.pattern[1] || "n" ); + if ( precision === -1 ) precision = formatInfo.decimals; + number = expandNumber( number * (current === "P" ? 100 : 1), precision, formatInfo ); + break; + default: + throw "Bad number format specifier: " + current; + } + + var patternParts = /n|\$|-|%/g, + ret = ""; + for ( ; ; ) { + var index = patternParts.lastIndex, + ar = patternParts.exec( pattern ); + + ret += pattern.slice( index, ar ? ar.index : pattern.length ); + + if ( !ar ) { + break; + } + + switch ( ar[0] ) { + case "n": + ret += number; + break; + case "$": + ret += nf.currency.symbol; + break; + case "-": + // don't make 0 negative + if ( /[1-9]/.test(number) ) { + ret += nf[ "-" ]; + } + break; + case "%": + ret += nf.percent.symbol; + break; + } + } + + return ret; + }; + +}()); + +getTokenRegExp = function() { + // regular expression for matching date and time tokens in format strings. + return (/\/|dddd|ddd|dd|d|MMMM|MMM|MM|M|yyyy|yy|y|hh|h|HH|H|mm|m|ss|s|tt|t|fff|ff|f|zzz|zz|z|gg|g/g); +}; + +getEra = function( date, eras ) { + if ( !eras ) return 0; + var start, ticks = date.getTime(); + for ( var i = 0, l = eras.length; i < l; i++ ) { + start = eras[ i ].start; + if ( start === null || ticks >= start ) { + return i; + } + } + return 0; +}; + +getEraYear = function( date, cal, era, sortable ) { + var year = date.getFullYear(); + if ( !sortable && cal.eras ) { + // convert normal gregorian year to era-shifted gregorian + // year by subtracting the era offset + year -= cal.eras[ era ].offset; + } + return year; +}; + +// parseExact +(function() { + var expandYear, + getDayIndex, + getMonthIndex, + getParseRegExp, + outOfRange, + toUpper, + toUpperArray; + + expandYear = function( cal, year ) { + // expands 2-digit year into 4 digits. + if ( year < 100 ) { + var now = new Date(), + era = getEra( now ), + curr = getEraYear( now, cal, era ), + twoDigitYearMax = cal.twoDigitYearMax; + twoDigitYearMax = typeof twoDigitYearMax === "string" ? new Date().getFullYear() % 100 + parseInt( twoDigitYearMax, 10 ) : twoDigitYearMax; + year += curr - ( curr % 100 ); + if ( year > twoDigitYearMax ) { + year -= 100; + } + } + return year; + }; + + getDayIndex = function ( cal, value, abbr ) { + var ret, + days = cal.days, + upperDays = cal._upperDays; + if ( !upperDays ) { + cal._upperDays = upperDays = [ + toUpperArray( days.names ), + toUpperArray( days.namesAbbr ), + toUpperArray( days.namesShort ) + ]; + } + value = toUpper( value ); + if ( abbr ) { + ret = arrayIndexOf( upperDays[1], value ); + if ( ret === -1 ) { + ret = arrayIndexOf( upperDays[2], value ); + } + } + else { + ret = arrayIndexOf( upperDays[0], value ); + } + return ret; + }; + + getMonthIndex = function( cal, value, abbr ) { + var months = cal.months, + monthsGen = cal.monthsGenitive || cal.months, + upperMonths = cal._upperMonths, + upperMonthsGen = cal._upperMonthsGen; + if ( !upperMonths ) { + cal._upperMonths = upperMonths = [ + toUpperArray( months.names ), + toUpperArray( months.namesAbbr ) + ]; + cal._upperMonthsGen = upperMonthsGen = [ + toUpperArray( monthsGen.names ), + toUpperArray( monthsGen.namesAbbr ) + ]; + } + value = toUpper( value ); + var i = arrayIndexOf( abbr ? upperMonths[1] : upperMonths[0], value ); + if ( i < 0 ) { + i = arrayIndexOf( abbr ? upperMonthsGen[1] : upperMonthsGen[0], value ); + } + return i; + }; + + getParseRegExp = function( cal, format ) { + // converts a format string into a regular expression with groups that + // can be used to extract date fields from a date string. + // check for a cached parse regex. + var re = cal._parseRegExp; + if ( !re ) { + cal._parseRegExp = re = {}; + } + else { + var reFormat = re[ format ]; + if ( reFormat ) { + return reFormat; + } + } + + // expand single digit formats, then escape regular expression characters. + var expFormat = expandFormat( cal, format ).replace( /([\^\$\.\*\+\?\|\[\]\(\)\{\}])/g, "\\\\$1" ), + regexp = [ "^" ], + groups = [], + index = 0, + quoteCount = 0, + tokenRegExp = getTokenRegExp(), + match; + + // iterate through each date token found. + while ( (match = tokenRegExp.exec(expFormat)) !== null ) { + var preMatch = expFormat.slice( index, match.index ); + index = tokenRegExp.lastIndex; + + // don't replace any matches that occur inside a string literal. + quoteCount += appendPreOrPostMatch( preMatch, regexp ); + if ( quoteCount % 2 ) { + regexp.push( match[0] ); + continue; + } + + // add a regex group for the token. + var m = match[ 0 ], + len = m.length, + add; + switch ( m ) { + case "dddd": case "ddd": + case "MMMM": case "MMM": + case "gg": case "g": + add = "(\\D+)"; + break; + case "tt": case "t": + add = "(\\D*)"; + break; + case "yyyy": + case "fff": + case "ff": + case "f": + add = "(\\d{" + len + "})"; + break; + case "dd": case "d": + case "MM": case "M": + case "yy": case "y": + case "HH": case "H": + case "hh": case "h": + case "mm": case "m": + case "ss": case "s": + add = "(\\d\\d?)"; + break; + case "zzz": + add = "([+-]?\\d\\d?:\\d{2})"; + break; + case "zz": case "z": + add = "([+-]?\\d\\d?)"; + break; + case "/": + add = "(\\/)"; + break; + default: + throw "Invalid date format pattern \'" + m + "\'."; + } + if ( add ) { + regexp.push( add ); + } + groups.push( match[0] ); + } + appendPreOrPostMatch( expFormat.slice(index), regexp ); + regexp.push( "$" ); + + // allow whitespace to differ when matching formats. + var regexpStr = regexp.join( "" ).replace( /\s+/g, "\\s+" ), + parseRegExp = { "regExp": regexpStr, "groups": groups }; + + // cache the regex for this format. + return re[ format ] = parseRegExp; + }; + + outOfRange = function( value, low, high ) { + return value < low || value > high; + }; + + toUpper = function( value ) { + // "he-IL" has non-breaking space in weekday names. + return value.split( "\u00A0" ).join( " " ).toUpperCase(); + }; + + toUpperArray = function( arr ) { + var results = []; + for ( var i = 0, l = arr.length; i < l; i++ ) { + results[ i ] = toUpper( arr[i] ); + } + return results; + }; + + parseExact = function( value, format, culture ) { + // try to parse the date string by matching against the format string + // while using the specified culture for date field names. + value = trim( value ); + var cal = culture.calendar, + // convert date formats into regular expressions with groupings. + // use the regexp to determine the input format and extract the date fields. + parseInfo = getParseRegExp( cal, format ), + match = new RegExp( parseInfo.regExp ).exec( value ); + if ( match === null ) { + return null; + } + // found a date format that matches the input. + var groups = parseInfo.groups, + era = null, year = null, month = null, date = null, weekDay = null, + hour = 0, hourOffset, min = 0, sec = 0, msec = 0, tzMinOffset = null, + pmHour = false; + // iterate the format groups to extract and set the date fields. + for ( var j = 0, jl = groups.length; j < jl; j++ ) { + var matchGroup = match[ j + 1 ]; + if ( matchGroup ) { + var current = groups[ j ], + clength = current.length, + matchInt = parseInt( matchGroup, 10 ); + switch ( current ) { + case "dd": case "d": + // Day of month. + date = matchInt; + // check that date is generally in valid range, also checking overflow below. + if ( outOfRange(date, 1, 31) ) return null; + break; + case "MMM": case "MMMM": + month = getMonthIndex( cal, matchGroup, clength === 3 ); + if ( outOfRange(month, 0, 11) ) return null; + break; + case "M": case "MM": + // Month. + month = matchInt - 1; + if ( outOfRange(month, 0, 11) ) return null; + break; + case "y": case "yy": + case "yyyy": + year = clength < 4 ? expandYear( cal, matchInt ) : matchInt; + if ( outOfRange(year, 0, 9999) ) return null; + break; + case "h": case "hh": + // Hours (12-hour clock). + hour = matchInt; + if ( hour === 12 ) hour = 0; + if ( outOfRange(hour, 0, 11) ) return null; + break; + case "H": case "HH": + // Hours (24-hour clock). + hour = matchInt; + if ( outOfRange(hour, 0, 23) ) return null; + break; + case "m": case "mm": + // Minutes. + min = matchInt; + if ( outOfRange(min, 0, 59) ) return null; + break; + case "s": case "ss": + // Seconds. + sec = matchInt; + if ( outOfRange(sec, 0, 59) ) return null; + break; + case "tt": case "t": + // AM/PM designator. + // see if it is standard, upper, or lower case PM. If not, ensure it is at least one of + // the AM tokens. If not, fail the parse for this format. + pmHour = cal.PM && ( matchGroup === cal.PM[0] || matchGroup === cal.PM[1] || matchGroup === cal.PM[2] ); + if ( + !pmHour && ( + !cal.AM || ( matchGroup !== cal.AM[0] && matchGroup !== cal.AM[1] && matchGroup !== cal.AM[2] ) + ) + ) return null; + break; + case "f": + // Deciseconds. + case "ff": + // Centiseconds. + case "fff": + // Milliseconds. + msec = matchInt * Math.pow( 10, 3 - clength ); + if ( outOfRange(msec, 0, 999) ) return null; + break; + case "ddd": + // Day of week. + case "dddd": + // Day of week. + weekDay = getDayIndex( cal, matchGroup, clength === 3 ); + if ( outOfRange(weekDay, 0, 6) ) return null; + break; + case "zzz": + // Time zone offset in +/- hours:min. + var offsets = matchGroup.split( /:/ ); + if ( offsets.length !== 2 ) return null; + hourOffset = parseInt( offsets[0], 10 ); + if ( outOfRange(hourOffset, -12, 13) ) return null; + var minOffset = parseInt( offsets[1], 10 ); + if ( outOfRange(minOffset, 0, 59) ) return null; + tzMinOffset = ( hourOffset * 60 ) + ( startsWith(matchGroup, "-") ? -minOffset : minOffset ); + break; + case "z": case "zz": + // Time zone offset in +/- hours. + hourOffset = matchInt; + if ( outOfRange(hourOffset, -12, 13) ) return null; + tzMinOffset = hourOffset * 60; + break; + case "g": case "gg": + var eraName = matchGroup; + if ( !eraName || !cal.eras ) return null; + eraName = trim( eraName.toLowerCase() ); + for ( var i = 0, l = cal.eras.length; i < l; i++ ) { + if ( eraName === cal.eras[i].name.toLowerCase() ) { + era = i; + break; + } + } + // could not find an era with that name + if ( era === null ) return null; + break; + } + } + } + var result = new Date(), defaultYear, convert = cal.convert; + defaultYear = convert ? convert.fromGregorian( result )[ 0 ] : result.getFullYear(); + if ( year === null ) { + year = defaultYear; + } + else if ( cal.eras ) { + // year must be shifted to normal gregorian year + // but not if year was not specified, its already normal gregorian + // per the main if clause above. + year += cal.eras[( era || 0 )].offset; + } + // set default day and month to 1 and January, so if unspecified, these are the defaults + // instead of the current day/month. + if ( month === null ) { + month = 0; + } + if ( date === null ) { + date = 1; + } + // now have year, month, and date, but in the culture's calendar. + // convert to gregorian if necessary + if ( convert ) { + result = convert.toGregorian( year, month, date ); + // conversion failed, must be an invalid match + if ( result === null ) return null; + } + else { + // have to set year, month and date together to avoid overflow based on current date. + result.setFullYear( year, month, date ); + // check to see if date overflowed for specified month (only checked 1-31 above). + if ( result.getDate() !== date ) return null; + // invalid day of week. + if ( weekDay !== null && result.getDay() !== weekDay ) { + return null; + } + } + // if pm designator token was found make sure the hours fit the 24-hour clock. + if ( pmHour && hour < 12 ) { + hour += 12; + } + result.setHours( hour, min, sec, msec ); + if ( tzMinOffset !== null ) { + // adjust timezone to utc before applying local offset. + var adjustedMin = result.getMinutes() - ( tzMinOffset + result.getTimezoneOffset() ); + // Safari limits hours and minutes to the range of -127 to 127. We need to use setHours + // to ensure both these fields will not exceed this range. adjustedMin will range + // somewhere between -1440 and 1500, so we only need to split this into hours. + result.setHours( result.getHours() + parseInt(adjustedMin / 60, 10), adjustedMin % 60 ); + } + return result; + }; +}()); + +parseNegativePattern = function( value, nf, negativePattern ) { + var neg = nf[ "-" ], + pos = nf[ "+" ], + ret; + switch ( negativePattern ) { + case "n -": + neg = " " + neg; + pos = " " + pos; + /* falls through */ + case "n-": + if ( endsWith(value, neg) ) { + ret = [ "-", value.substr(0, value.length - neg.length) ]; + } + else if ( endsWith(value, pos) ) { + ret = [ "+", value.substr(0, value.length - pos.length) ]; + } + break; + case "- n": + neg += " "; + pos += " "; + /* falls through */ + case "-n": + if ( startsWith(value, neg) ) { + ret = [ "-", value.substr(neg.length) ]; + } + else if ( startsWith(value, pos) ) { + ret = [ "+", value.substr(pos.length) ]; + } + break; + case "(n)": + if ( startsWith(value, "(") && endsWith(value, ")") ) { + ret = [ "-", value.substr(1, value.length - 2) ]; + } + break; + } + return ret || [ "", value ]; +}; + +// +// public instance functions +// + +Globalize.prototype.findClosestCulture = function( cultureSelector ) { + return Globalize.findClosestCulture.call( this, cultureSelector ); +}; + +Globalize.prototype.format = function( value, format, cultureSelector ) { + return Globalize.format.call( this, value, format, cultureSelector ); +}; + +Globalize.prototype.localize = function( key, cultureSelector ) { + return Globalize.localize.call( this, key, cultureSelector ); +}; + +Globalize.prototype.parseInt = function( value, radix, cultureSelector ) { + return Globalize.parseInt.call( this, value, radix, cultureSelector ); +}; + +Globalize.prototype.parseFloat = function( value, radix, cultureSelector ) { + return Globalize.parseFloat.call( this, value, radix, cultureSelector ); +}; + +Globalize.prototype.culture = function( cultureSelector ) { + return Globalize.culture.call( this, cultureSelector ); +}; + +// +// public singleton functions +// + +Globalize.addCultureInfo = function( cultureName, baseCultureName, info ) { + + var base = {}, + isNew = false; + + if ( typeof cultureName !== "string" ) { + // cultureName argument is optional string. If not specified, assume info is first + // and only argument. Specified info deep-extends current culture. + info = cultureName; + cultureName = this.culture().name; + base = this.cultures[ cultureName ]; + } else if ( typeof baseCultureName !== "string" ) { + // baseCultureName argument is optional string. If not specified, assume info is second + // argument. Specified info deep-extends specified culture. + // If specified culture does not exist, create by deep-extending default + info = baseCultureName; + isNew = ( this.cultures[ cultureName ] == null ); + base = this.cultures[ cultureName ] || this.cultures[ "default" ]; + } else { + // cultureName and baseCultureName specified. Assume a new culture is being created + // by deep-extending an specified base culture + isNew = true; + base = this.cultures[ baseCultureName ]; + } + + this.cultures[ cultureName ] = extend(true, {}, + base, + info + ); + // Make the standard calendar the current culture if it's a new culture + if ( isNew ) { + this.cultures[ cultureName ].calendar = this.cultures[ cultureName ].calendars.standard; + } +}; + +Globalize.findClosestCulture = function( name ) { + var match; + if ( !name ) { + return this.findClosestCulture( this.cultureSelector ) || this.cultures[ "default" ]; + } + if ( typeof name === "string" ) { + name = name.split( "," ); + } + if ( isArray(name) ) { + var lang, + cultures = this.cultures, + list = name, + i, l = list.length, + prioritized = []; + for ( i = 0; i < l; i++ ) { + name = trim( list[i] ); + var pri, parts = name.split( ";" ); + lang = trim( parts[0] ); + if ( parts.length === 1 ) { + pri = 1; + } + else { + name = trim( parts[1] ); + if ( name.indexOf("q=") === 0 ) { + name = name.substr( 2 ); + pri = parseFloat( name ); + pri = isNaN( pri ) ? 0 : pri; + } + else { + pri = 1; + } + } + prioritized.push({ lang: lang, pri: pri }); + } + prioritized.sort(function( a, b ) { + if ( a.pri < b.pri ) { + return 1; + } else if ( a.pri > b.pri ) { + return -1; + } + return 0; + }); + // exact match + for ( i = 0; i < l; i++ ) { + lang = prioritized[ i ].lang; + match = cultures[ lang ]; + if ( match ) { + return match; + } + } + + // neutral language match + for ( i = 0; i < l; i++ ) { + lang = prioritized[ i ].lang; + do { + var index = lang.lastIndexOf( "-" ); + if ( index === -1 ) { + break; + } + // strip off the last part. e.g. en-US => en + lang = lang.substr( 0, index ); + match = cultures[ lang ]; + if ( match ) { + return match; + } + } + while ( 1 ); + } + + // last resort: match first culture using that language + for ( i = 0; i < l; i++ ) { + lang = prioritized[ i ].lang; + for ( var cultureKey in cultures ) { + var culture = cultures[ cultureKey ]; + if ( culture.language === lang ) { + return culture; + } + } + } + } + else if ( typeof name === "object" ) { + return name; + } + return match || null; +}; + +Globalize.format = function( value, format, cultureSelector ) { + var culture = this.findClosestCulture( cultureSelector ); + if ( value instanceof Date ) { + value = formatDate( value, format, culture ); + } + else if ( typeof value === "number" ) { + value = formatNumber( value, format, culture ); + } + return value; +}; + +Globalize.localize = function( key, cultureSelector ) { + return this.findClosestCulture( cultureSelector ).messages[ key ] || + this.cultures[ "default" ].messages[ key ]; +}; + +Globalize.parseDate = function( value, formats, culture ) { + culture = this.findClosestCulture( culture ); + + var date, prop, patterns; + if ( formats ) { + if ( typeof formats === "string" ) { + formats = [ formats ]; + } + if ( formats.length ) { + for ( var i = 0, l = formats.length; i < l; i++ ) { + var format = formats[ i ]; + if ( format ) { + date = parseExact( value, format, culture ); + if ( date ) { + break; + } + } + } + } + } else { + patterns = culture.calendar.patterns; + for ( prop in patterns ) { + date = parseExact( value, patterns[prop], culture ); + if ( date ) { + break; + } + } + } + + return date || null; +}; + +Globalize.parseInt = function( value, radix, cultureSelector ) { + return truncate( Globalize.parseFloat(value, radix, cultureSelector) ); +}; + +Globalize.parseFloat = function( value, radix, cultureSelector ) { + // radix argument is optional + if ( typeof radix !== "number" ) { + cultureSelector = radix; + radix = 10; + } + + var culture = this.findClosestCulture( cultureSelector ); + var ret = NaN, + nf = culture.numberFormat; + + if ( value.indexOf(culture.numberFormat.currency.symbol) > -1 ) { + // remove currency symbol + value = value.replace( culture.numberFormat.currency.symbol, "" ); + // replace decimal seperator + value = value.replace( culture.numberFormat.currency["."], culture.numberFormat["."] ); + } + + //Remove percentage character from number string before parsing + if ( value.indexOf(culture.numberFormat.percent.symbol) > -1){ + value = value.replace( culture.numberFormat.percent.symbol, "" ); + } + + // remove spaces: leading, trailing and between - and number. Used for negative currency pt-BR + value = value.replace( / /g, "" ); + + // allow infinity or hexidecimal + if ( regexInfinity.test(value) ) { + ret = parseFloat( value ); + } + else if ( !radix && regexHex.test(value) ) { + ret = parseInt( value, 16 ); + } + else { + + // determine sign and number + var signInfo = parseNegativePattern( value, nf, nf.pattern[0] ), + sign = signInfo[ 0 ], + num = signInfo[ 1 ]; + + // #44 - try parsing as "(n)" + if ( sign === "" && nf.pattern[0] !== "(n)" ) { + signInfo = parseNegativePattern( value, nf, "(n)" ); + sign = signInfo[ 0 ]; + num = signInfo[ 1 ]; + } + + // try parsing as "-n" + if ( sign === "" && nf.pattern[0] !== "-n" ) { + signInfo = parseNegativePattern( value, nf, "-n" ); + sign = signInfo[ 0 ]; + num = signInfo[ 1 ]; + } + + sign = sign || "+"; + + // determine exponent and number + var exponent, + intAndFraction, + exponentPos = num.indexOf( "e" ); + if ( exponentPos < 0 ) exponentPos = num.indexOf( "E" ); + if ( exponentPos < 0 ) { + intAndFraction = num; + exponent = null; + } + else { + intAndFraction = num.substr( 0, exponentPos ); + exponent = num.substr( exponentPos + 1 ); + } + // determine decimal position + var integer, + fraction, + decSep = nf[ "." ], + decimalPos = intAndFraction.indexOf( decSep ); + if ( decimalPos < 0 ) { + integer = intAndFraction; + fraction = null; + } + else { + integer = intAndFraction.substr( 0, decimalPos ); + fraction = intAndFraction.substr( decimalPos + decSep.length ); + } + // handle groups (e.g. 1,000,000) + var groupSep = nf[ "," ]; + integer = integer.split( groupSep ).join( "" ); + var altGroupSep = groupSep.replace( /\u00A0/g, " " ); + if ( groupSep !== altGroupSep ) { + integer = integer.split( altGroupSep ).join( "" ); + } + // build a natively parsable number string + var p = sign + integer; + if ( fraction !== null ) { + p += "." + fraction; + } + if ( exponent !== null ) { + // exponent itself may have a number patternd + var expSignInfo = parseNegativePattern( exponent, nf, "-n" ); + p += "e" + ( expSignInfo[0] || "+" ) + expSignInfo[ 1 ]; + } + if ( regexParseFloat.test(p) ) { + ret = parseFloat( p ); + } + } + return ret; +}; + +Globalize.culture = function( cultureSelector ) { + // setter + if ( typeof cultureSelector !== "undefined" ) { + this.cultureSelector = cultureSelector; + } + // getter + return this.findClosestCulture( cultureSelector ) || this.cultures[ "default" ]; +}; + +}( this )); \ No newline at end of file diff --git a/external/jquery-1.12.4/LICENSE.txt b/external/jquery-1.12.4/LICENSE.txt new file mode 100644 index 00000000000..5312a4c864d --- /dev/null +++ b/external/jquery-1.12.4/LICENSE.txt @@ -0,0 +1,36 @@ +Copyright jQuery Foundation and other contributors, https://jquery.org/ + +This software consists of voluntary contributions made by many +individuals. For exact contribution history, see the revision history +available at https://github.com/jquery/jquery + +The following license applies to all parts of this software except as +documented below: + +==== + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +==== + +All files located in the node_modules and external directories are +externally maintained libraries used by this software which have their +own licenses; we recommend you read them, as their terms may differ from +the terms above. diff --git a/external/jquery-1.12.4/jquery.js b/external/jquery-1.12.4/jquery.js new file mode 100644 index 00000000000..7fc60fca78b --- /dev/null +++ b/external/jquery-1.12.4/jquery.js @@ -0,0 +1,11008 @@ +/*! + * jQuery JavaScript Library v1.12.4 + * http://jquery.com/ + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license + * http://jquery.org/license + * + * Date: 2016-05-20T17:17Z + */ + +(function( global, factory ) { + + if ( typeof module === "object" && typeof module.exports === "object" ) { + // For CommonJS and CommonJS-like environments where a proper `window` + // is present, execute the factory and get jQuery. + // For environments that do not have a `window` with a `document` + // (such as Node.js), expose a factory as module.exports. + // This accentuates the need for the creation of a real `window`. + // e.g. var jQuery = require("jquery")(window); + // See ticket #14549 for more info. + module.exports = global.document ? + factory( global, true ) : + function( w ) { + if ( !w.document ) { + throw new Error( "jQuery requires a window with a document" ); + } + return factory( w ); + }; + } else { + factory( global ); + } + +// Pass this if window is not defined yet +}(typeof window !== "undefined" ? window : this, function( window, noGlobal ) { + +// Support: Firefox 18+ +// Can't be in strict mode, several libs including ASP.NET trace +// the stack via arguments.caller.callee and Firefox dies if +// you try to trace through "use strict" call chains. (#13335) +//"use strict"; +var deletedIds = []; + +var document = window.document; + +var slice = deletedIds.slice; + +var concat = deletedIds.concat; + +var push = deletedIds.push; + +var indexOf = deletedIds.indexOf; + +var class2type = {}; + +var toString = class2type.toString; + +var hasOwn = class2type.hasOwnProperty; + +var support = {}; + + + +var + version = "1.12.4", + + // 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 ); + }, + + // Support: Android<4.1, IE<9 + // Make sure we trim BOM and NBSP + rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, + + // Matches dashed string for camelizing + rmsPrefix = /^-ms-/, + rdashAlpha = /-([\da-z])/gi, + + // Used by jQuery.camelCase as callback to replace() + fcamelCase = function( all, letter ) { + return letter.toUpperCase(); + }; + +jQuery.fn = jQuery.prototype = { + + // The current version of jQuery being used + jquery: version, + + constructor: jQuery, + + // Start with an empty selector + selector: "", + + // The default length of a jQuery object is 0 + length: 0, + + toArray: function() { + return slice.call( this ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + return num != null ? + + // Return just the one element from the set + ( num < 0 ? this[ num + this.length ] : this[ num ] ) : + + // Return all the elements in a clean array + slice.call( this ); + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems ) { + + // Build a new jQuery matched element set + var ret = jQuery.merge( this.constructor(), elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + ret.context = this.context; + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + each: function( callback ) { + return jQuery.each( this, callback ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map( this, function( elem, i ) { + return callback.call( elem, i, elem ); + } ) ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ) ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + eq: function( i ) { + var len = this.length, + j = +i + ( i < 0 ? len : 0 ); + return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); + }, + + end: function() { + return this.prevObject || this.constructor(); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: deletedIds.sort, + splice: deletedIds.splice +}; + +jQuery.extend = jQuery.fn.extend = function() { + var src, copyIsArray, copy, name, options, 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++; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !jQuery.isFunction( target ) ) { + target = {}; + } + + // extend jQuery itself if only one argument is passed + if ( i === length ) { + target = this; + i--; + } + + for ( ; i < length; i++ ) { + + // Only deal with non-null/undefined values + if ( ( options = arguments[ i ] ) != null ) { + + // Extend the base object + for ( name in options ) { + src = target[ name ]; + copy = options[ name ]; + + // Prevent never-ending loop + if ( target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject( copy ) || + ( copyIsArray = jQuery.isArray( copy ) ) ) ) { + + if ( copyIsArray ) { + copyIsArray = false; + clone = src && jQuery.isArray( src ) ? src : []; + + } else { + clone = src && jQuery.isPlainObject( src ) ? src : {}; + } + + // 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; +}; + +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: function( msg ) { + throw new Error( msg ); + }, + + noop: function() {}, + + // See test/unit/core.js for details concerning isFunction. + // Since version 1.3, DOM methods and functions like alert + // aren't supported. They return false on IE (#2968). + isFunction: function( obj ) { + return jQuery.type( obj ) === "function"; + }, + + isArray: Array.isArray || function( obj ) { + return jQuery.type( obj ) === "array"; + }, + + isWindow: function( obj ) { + /* jshint eqeqeq: false */ + return obj != null && obj == obj.window; + }, + + isNumeric: function( obj ) { + + // parseFloat NaNs numeric-cast false positives (null|true|false|"") + // ...but misinterprets leading-number strings, particularly hex literals ("0x...") + // subtraction forces infinities to NaN + // adding 1 corrects loss of precision from parseFloat (#15100) + var realStringObj = obj && obj.toString(); + return !jQuery.isArray( obj ) && ( realStringObj - parseFloat( realStringObj ) + 1 ) >= 0; + }, + + isEmptyObject: function( obj ) { + var name; + for ( name in obj ) { + return false; + } + return true; + }, + + isPlainObject: function( obj ) { + var key; + + // Must be an Object. + // Because of IE, we also have to check the presence of the constructor property. + // Make sure that DOM nodes and window objects don't pass through, as well + if ( !obj || jQuery.type( obj ) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { + return false; + } + + try { + + // Not own constructor property must be Object + if ( obj.constructor && + !hasOwn.call( obj, "constructor" ) && + !hasOwn.call( obj.constructor.prototype, "isPrototypeOf" ) ) { + return false; + } + } catch ( e ) { + + // IE8,9 Will throw exceptions on certain host objects #9897 + return false; + } + + // Support: IE<9 + // Handle iteration over inherited properties before own properties. + if ( !support.ownFirst ) { + for ( key in obj ) { + return hasOwn.call( obj, key ); + } + } + + // Own properties are enumerated firstly, so to speed up, + // if last one is own, then all properties are own. + for ( key in obj ) {} + + return key === undefined || hasOwn.call( obj, key ); + }, + + type: function( obj ) { + if ( obj == null ) { + return obj + ""; + } + return typeof obj === "object" || typeof obj === "function" ? + class2type[ toString.call( obj ) ] || "object" : + typeof obj; + }, + + // Workarounds based on findings by Jim Driscoll + // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context + globalEval: function( data ) { + if ( data && jQuery.trim( data ) ) { + + // We use execScript on Internet Explorer + // We use an anonymous function so that context is window + // rather than jQuery in Firefox + ( window.execScript || function( data ) { + window[ "eval" ].call( window, data ); // jscs:ignore requireDotNotation + } )( data ); + } + }, + + // Convert dashed to camelCase; used by the css and data modules + // Microsoft forgot to hump their vendor prefix (#9572) + camelCase: function( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); + }, + + nodeName: function( elem, name ) { + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + }, + + each: function( 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; + } + } + } + + return obj; + }, + + // Support: Android<4.1, IE<9 + trim: function( text ) { + return text == null ? + "" : + ( text + "" ).replace( rtrim, "" ); + }, + + // results is for internal usage only + makeArray: function( 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: function( elem, arr, i ) { + var len; + + if ( arr ) { + if ( indexOf ) { + return indexOf.call( arr, elem, i ); + } + + len = arr.length; + i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0; + + for ( ; i < len; i++ ) { + + // Skip accessing in sparse arrays + if ( i in arr && arr[ i ] === elem ) { + return i; + } + } + } + + return -1; + }, + + merge: function( first, second ) { + var len = +second.length, + j = 0, + i = first.length; + + while ( j < len ) { + first[ i++ ] = second[ j++ ]; + } + + // Support: IE<9 + // Workaround casting of .length to NaN on otherwise arraylike objects (e.g., NodeLists) + if ( len !== len ) { + while ( second[ j ] !== undefined ) { + first[ i++ ] = second[ j++ ]; + } + } + + first.length = i; + + return first; + }, + + grep: function( 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; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var length, value, + i = 0, + ret = []; + + // Go through the array, translating each of the items to their new values + if ( isArrayLike( elems ) ) { + length = elems.length; + for ( ; i < length; i++ ) { + value = callback( elems[ i ], 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 concat.apply( [], ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // Bind a function to a context, optionally partially applying any + // arguments. + proxy: function( fn, context ) { + var args, proxy, tmp; + + if ( typeof context === "string" ) { + tmp = fn[ context ]; + context = fn; + fn = tmp; + } + + // Quick check to determine if target is callable, in the spec + // this throws a TypeError, but we will just return undefined. + if ( !jQuery.isFunction( fn ) ) { + return undefined; + } + + // Simulated bind + args = slice.call( arguments, 2 ); + proxy = function() { + return fn.apply( context || this, args.concat( slice.call( arguments ) ) ); + }; + + // Set the guid of unique handler to the same of original handler, so it can be removed + proxy.guid = fn.guid = fn.guid || jQuery.guid++; + + return proxy; + }, + + now: function() { + return +( new Date() ); + }, + + // jQuery.support is not used in Core but other projects attach their + // properties to it so it needs to exist. + support: support +} ); + +// JSHint would error on this code due to the Symbol not being defined in ES5. +// Defining this global in .jshintrc would create a danger of using the global +// unguarded in another place, it seems safer to just disable JSHint for these +// three lines. +/* jshint ignore: start */ +if ( typeof Symbol === "function" ) { + jQuery.fn[ Symbol.iterator ] = deletedIds[ Symbol.iterator ]; +} +/* jshint ignore: end */ + +// 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(); +} ); + +function isArrayLike( obj ) { + + // Support: iOS 8.2 (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 = jQuery.type( obj ); + + if ( type === "function" || jQuery.isWindow( obj ) ) { + return false; + } + + return type === "array" || length === 0 || + typeof length === "number" && length > 0 && ( length - 1 ) in obj; +} +var Sizzle = +/*! + * Sizzle CSS Selector Engine v2.2.1 + * http://sizzlejs.com/ + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license + * http://jquery.org/license + * + * Date: 2015-10-17 + */ +(function( window ) { + +var i, + support, + Expr, + getText, + isXML, + tokenize, + compile, + select, + outermostContext, + sortInput, + hasDuplicate, + + // Local document vars + setDocument, + document, + docElem, + documentIsHTML, + rbuggyQSA, + rbuggyMatches, + matches, + contains, + + // Instance-specific data + expando = "sizzle" + 1 * new Date(), + preferredDoc = window.document, + dirruns = 0, + done = 0, + classCache = createCache(), + tokenCache = createCache(), + compilerCache = createCache(), + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + } + return 0; + }, + + // General-purpose constants + MAX_NEGATIVE = 1 << 31, + + // Instance methods + hasOwn = ({}).hasOwnProperty, + arr = [], + pop = arr.pop, + push_native = arr.push, + push = arr.push, + slice = arr.slice, + // Use a stripped-down indexOf as it's faster than native + // http://jsperf.com/thor-indexof-vs-for/5 + indexOf = function( list, elem ) { + var i = 0, + len = list.length; + for ( ; i < len; i++ ) { + if ( list[i] === elem ) { + return i; + } + } + return -1; + }, + + booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped", + + // Regular expressions + + // http://www.w3.org/TR/css3-selectors/#whitespace + whitespace = "[\\x20\\t\\r\\n\\f]", + + // http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier + identifier = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+", + + // Attribute selectors: http://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" ), + rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), + + rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), + rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ), + + rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ), + + 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, + + rnative = /^[^{]+\{\s*\[native \w/, + + // Easily-parseable/retrievable ID or TAG or CLASS selectors + rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, + + rsibling = /[+~]/, + rescape = /'|\\/g, + + // CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters + runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ), + funescape = function( _, escaped, escapedWhitespace ) { + var high = "0x" + escaped - 0x10000; + // NaN means non-codepoint + // Support: Firefox<24 + // Workaround erroneous numeric interpretation of +"0x" + return high !== high || escapedWhitespace ? + escaped : + high < 0 ? + // BMP codepoint + String.fromCharCode( high + 0x10000 ) : + // Supplemental Plane codepoint (surrogate pair) + String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); + }, + + // Used for iframes + // See setDocument() + // Removing the function wrapper causes a "Permission Denied" + // error in IE + unloadHandler = function() { + setDocument(); + }; + +// Optimize for push.apply( _, NodeList ) +try { + push.apply( + (arr = slice.call( preferredDoc.childNodes )), + preferredDoc.childNodes + ); + // Support: Android<4.0 + // Detect silently failing push.apply + arr[ preferredDoc.childNodes.length ].nodeType; +} catch ( e ) { + push = { apply: arr.length ? + + // Leverage slice if possible + function( target, els ) { + push_native.apply( target, slice.call(els) ); + } : + + // Support: IE<9 + // Otherwise append directly + function( target, els ) { + var j = target.length, + i = 0; + // Can't trust NodeList.length + while ( (target[j++] = els[i++]) ) {} + target.length = j - 1; + } + }; +} + +function Sizzle( selector, context, results, seed ) { + var m, i, elem, nid, nidselect, 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 ) { + + if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) { + 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, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( elem.id === m ) { + results.push( elem ); + return results; + } + } else { + return results; + } + + // Element context + } else { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( newContext && (elem = newContext.getElementById( m )) && + contains( context, elem ) && + elem.id === m ) { + + results.push( elem ); + return results; + } + } + + // Type selector + } else if ( match[2] ) { + push.apply( results, context.getElementsByTagName( selector ) ); + return results; + + // Class selector + } else if ( (m = match[3]) && support.getElementsByClassName && + context.getElementsByClassName ) { + + push.apply( results, context.getElementsByClassName( m ) ); + return results; + } + } + + // Take advantage of querySelectorAll + if ( support.qsa && + !compilerCache[ selector + " " ] && + (!rbuggyQSA || !rbuggyQSA.test( selector )) ) { + + if ( nodeType !== 1 ) { + newContext = context; + newSelector = selector; + + // qSA looks outside Element context, which is not what we want + // Thanks to Andrew Dupont for this workaround technique + // Support: IE <=8 + // Exclude object elements + } else if ( context.nodeName.toLowerCase() !== "object" ) { + + // Capture the context ID, setting it first if necessary + if ( (nid = context.getAttribute( "id" )) ) { + nid = nid.replace( rescape, "\\$&" ); + } else { + context.setAttribute( "id", (nid = expando) ); + } + + // Prefix every selector in the list + groups = tokenize( selector ); + i = groups.length; + nidselect = ridentifier.test( nid ) ? "#" + nid : "[id='" + nid + "']"; + while ( i-- ) { + groups[i] = nidselect + " " + toSelector( groups[i] ); + } + newSelector = groups.join( "," ); + + // Expand context for sibling selectors + newContext = rsibling.test( selector ) && testContext( context.parentNode ) || + context; + } + + if ( newSelector ) { + try { + push.apply( results, + newContext.querySelectorAll( newSelector ) + ); + return results; + } catch ( qsaError ) { + } finally { + if ( nid === expando ) { + context.removeAttribute( "id" ); + } + } + } + } + } + } + + // All others + return select( selector.replace( rtrim, "$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 = []; + + function cache( key, value ) { + // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) + if ( keys.push( key + " " ) > Expr.cacheLength ) { + // Only keep the most recent entries + delete cache[ keys.shift() ]; + } + return (cache[ key + " " ] = value); + } + return cache; +} + +/** + * Mark a function for special use by Sizzle + * @param {Function} fn The function to mark + */ +function markFunction( fn ) { + fn[ expando ] = true; + return fn; +} + +/** + * Support testing using an element + * @param {Function} fn Passed the created div and expects a boolean result + */ +function assert( fn ) { + var div = document.createElement("div"); + + try { + return !!fn( div ); + } catch (e) { + return false; + } finally { + // Remove from its parent by default + if ( div.parentNode ) { + div.parentNode.removeChild( div ); + } + // release memory in IE + div = null; + } +} + +/** + * Adds the same handler for all of the specified attrs + * @param {String} attrs Pipe-separated list of attributes + * @param {Function} handler The method that will be applied + */ +function addHandle( attrs, handler ) { + var arr = attrs.split("|"), + i = arr.length; + + while ( i-- ) { + Expr.attrHandle[ arr[i] ] = handler; + } +} + +/** + * Checks document order of two siblings + * @param {Element} a + * @param {Element} b + * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b + */ +function siblingCheck( a, b ) { + var cur = b && a, + diff = cur && a.nodeType === 1 && b.nodeType === 1 && + ( ~b.sourceIndex || MAX_NEGATIVE ) - + ( ~a.sourceIndex || MAX_NEGATIVE ); + + // Use IE sourceIndex if available on both nodes + if ( diff ) { + return diff; + } + + // Check if b follows a + if ( cur ) { + while ( (cur = cur.nextSibling) ) { + if ( cur === b ) { + return -1; + } + } + } + + return a ? 1 : -1; +} + +/** + * Returns a function to use in pseudos for input types + * @param {String} type + */ +function createInputPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for buttons + * @param {String} type + */ +function createButtonPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for positionals + * @param {Function} fn + */ +function createPositionalPseudo( fn ) { + return markFunction(function( argument ) { + argument = +argument; + 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 Sizzle 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; +} + +// Expose support vars for convenience +support = Sizzle.support = {}; + +/** + * Detects XML nodes + * @param {Element|Object} elem An element or a document + * @returns {Boolean} True iff elem is a non-HTML XML node + */ +isXML = Sizzle.isXML = function( elem ) { + // documentElement is verified for cases where it doesn't yet exist + // (such as loading iframes in IE - #4833) + var documentElement = elem && (elem.ownerDocument || elem).documentElement; + return documentElement ? documentElement.nodeName !== "HTML" : false; +}; + +/** + * Sets document-related variables once based on the current document + * @param {Element|Object} [doc] An element or document object to use to set the document + * @returns {Object} Returns the current document + */ +setDocument = Sizzle.setDocument = function( node ) { + var hasCompare, parent, + doc = node ? node.ownerDocument || node : preferredDoc; + + // Return early if doc is invalid or already selected + if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) { + return document; + } + + // Update global variables + document = doc; + docElem = document.documentElement; + documentIsHTML = !isXML( document ); + + // Support: IE 9-11, Edge + // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) + if ( (parent = document.defaultView) && parent.top !== parent ) { + // Support: IE 11 + if ( parent.addEventListener ) { + parent.addEventListener( "unload", unloadHandler, false ); + + // Support: IE 9 - 10 only + } else if ( parent.attachEvent ) { + parent.attachEvent( "onunload", unloadHandler ); + } + } + + /* Attributes + ---------------------------------------------------------------------- */ + + // Support: IE<8 + // Verify that getAttribute really returns attributes and not properties + // (excepting IE8 booleans) + support.attributes = assert(function( div ) { + div.className = "i"; + return !div.getAttribute("className"); + }); + + /* getElement(s)By* + ---------------------------------------------------------------------- */ + + // Check if getElementsByTagName("*") returns only elements + support.getElementsByTagName = assert(function( div ) { + div.appendChild( document.createComment("") ); + return !div.getElementsByTagName("*").length; + }); + + // Support: IE<9 + support.getElementsByClassName = rnative.test( document.getElementsByClassName ); + + // Support: IE<10 + // Check if getElementById returns elements by name + // The broken getElementById methods don't pick up programatically-set names, + // so use a roundabout getElementsByName test + support.getById = assert(function( div ) { + docElem.appendChild( div ).id = expando; + return !document.getElementsByName || !document.getElementsByName( expando ).length; + }); + + // ID find and filter + if ( support.getById ) { + Expr.find["ID"] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var m = context.getElementById( id ); + return m ? [ m ] : []; + } + }; + Expr.filter["ID"] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + return elem.getAttribute("id") === attrId; + }; + }; + } else { + // Support: IE6/7 + // getElementById is not reliable as a find shortcut + delete Expr.find["ID"]; + + 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; + }; + }; + } + + // Tag + Expr.find["TAG"] = support.getElementsByTagName ? + function( tag, context ) { + if ( typeof context.getElementsByTagName !== "undefined" ) { + return context.getElementsByTagName( tag ); + + // DocumentFragment nodes don't have gEBTN + } else if ( support.qsa ) { + return context.querySelectorAll( tag ); + } + } : + + function( tag, context ) { + var elem, + tmp = [], + i = 0, + // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too + results = context.getElementsByTagName( tag ); + + // Filter out possible comments + if ( tag === "*" ) { + while ( (elem = results[i++]) ) { + if ( elem.nodeType === 1 ) { + tmp.push( elem ); + } + } + + return tmp; + } + return results; + }; + + // Class + Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) { + if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { + return context.getElementsByClassName( className ); + } + }; + + /* QSA/matchesSelector + ---------------------------------------------------------------------- */ + + // QSA and matchesSelector support + + // matchesSelector(:active) reports false when true (IE9/Opera 11.5) + rbuggyMatches = []; + + // qSa(:focus) reports false when true (Chrome 21) + // We allow this because of a bug in IE8/9 that throws an error + // whenever `document.activeElement` is accessed on an iframe + // So, we allow :focus to pass through QSA all the time to avoid the IE error + // See http://bugs.jquery.com/ticket/13378 + rbuggyQSA = []; + + if ( (support.qsa = rnative.test( document.querySelectorAll )) ) { + // Build QSA regex + // Regex strategy adopted from Diego Perini + assert(function( div ) { + // Select is set to empty string on purpose + // This is to test IE's treatment of not explicitly + // setting a boolean content attribute, + // since its presence should be enough + // http://bugs.jquery.com/ticket/12359 + docElem.appendChild( div ).innerHTML = "" + + ""; + + // Support: IE8, Opera 11-12.16 + // Nothing should be selected when empty strings follow ^= or $= or *= + // The test attribute must be unknown in Opera but "safe" for WinRT + // http://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section + if ( div.querySelectorAll("[msallowcapture^='']").length ) { + rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); + } + + // Support: IE8 + // Boolean attributes and "value" are not treated correctly + if ( !div.querySelectorAll("[selected]").length ) { + rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); + } + + // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+ + if ( !div.querySelectorAll( "[id~=" + expando + "-]" ).length ) { + rbuggyQSA.push("~="); + } + + // Webkit/Opera - :checked should return selected option elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + // IE8 throws error here and will not see later tests + if ( !div.querySelectorAll(":checked").length ) { + rbuggyQSA.push(":checked"); + } + + // Support: Safari 8+, iOS 8+ + // https://bugs.webkit.org/show_bug.cgi?id=136851 + // In-page `selector#id sibing-combinator selector` fails + if ( !div.querySelectorAll( "a#" + expando + "+*" ).length ) { + rbuggyQSA.push(".#.+[+~]"); + } + }); + + assert(function( div ) { + // Support: Windows 8 Native Apps + // The type and name attributes are restricted during .innerHTML assignment + var input = document.createElement("input"); + input.setAttribute( "type", "hidden" ); + div.appendChild( input ).setAttribute( "name", "D" ); + + // Support: IE8 + // Enforce case-sensitivity of name attribute + if ( div.querySelectorAll("[name=d]").length ) { + rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); + } + + // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) + // IE8 throws error here and will not see later tests + if ( !div.querySelectorAll(":enabled").length ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Opera 10-11 does not throw on post-comma invalid pseudos + div.querySelectorAll("*,:x"); + rbuggyQSA.push(",.*:"); + }); + } + + if ( (support.matchesSelector = rnative.test( (matches = docElem.matches || + docElem.webkitMatchesSelector || + docElem.mozMatchesSelector || + docElem.oMatchesSelector || + docElem.msMatchesSelector) )) ) { + + assert(function( div ) { + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9) + support.disconnectedMatch = matches.call( div, "div" ); + + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( div, "[s!='']:x" ); + rbuggyMatches.push( "!=", pseudos ); + }); + } + + rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") ); + rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") ); + + /* Contains + ---------------------------------------------------------------------- */ + hasCompare = rnative.test( docElem.compareDocumentPosition ); + + // Element contains another + // Purposefully self-exclusive + // As in, an element does not contain itself + contains = hasCompare || rnative.test( docElem.contains ) ? + function( a, b ) { + var adown = a.nodeType === 9 ? a.documentElement : a, + bup = b && b.parentNode; + return a === bup || !!( bup && bup.nodeType === 1 && ( + adown.contains ? + adown.contains( bup ) : + a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 + )); + } : + function( a, b ) { + if ( b ) { + while ( (b = b.parentNode) ) { + if ( b === a ) { + return true; + } + } + } + return false; + }; + + /* Sorting + ---------------------------------------------------------------------- */ + + // Document order sorting + sortOrder = hasCompare ? + function( a, b ) { + + // Flag for duplicate removal + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + // Sort on method existence if only one input has compareDocumentPosition + var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; + if ( compare ) { + return compare; + } + + // Calculate position if both inputs belong to the same document + 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 + if ( a === document || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) { + return -1; + } + if ( b === document || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) { + return 1; + } + + // Maintain original order + return sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + } + + return compare & 4 ? -1 : 1; + } : + function( a, b ) { + // Exit early if the nodes are identical + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + var cur, + i = 0, + aup = a.parentNode, + bup = b.parentNode, + ap = [ a ], + bp = [ b ]; + + // Parentless nodes are either documents or disconnected + if ( !aup || !bup ) { + return a === document ? -1 : + b === document ? 1 : + aup ? -1 : + bup ? 1 : + sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + + // If the nodes are siblings, we can do a quick check + } else if ( aup === bup ) { + return siblingCheck( a, b ); + } + + // Otherwise we need full lists of their ancestors for comparison + cur = a; + while ( (cur = cur.parentNode) ) { + ap.unshift( cur ); + } + cur = b; + while ( (cur = cur.parentNode) ) { + bp.unshift( cur ); + } + + // Walk down the tree looking for a discrepancy + while ( ap[i] === bp[i] ) { + i++; + } + + return i ? + // Do a sibling check if the nodes have a common ancestor + siblingCheck( ap[i], bp[i] ) : + + // Otherwise nodes in our document sort first + ap[i] === preferredDoc ? -1 : + bp[i] === preferredDoc ? 1 : + 0; + }; + + return document; +}; + +Sizzle.matches = function( expr, elements ) { + return Sizzle( expr, null, null, elements ); +}; + +Sizzle.matchesSelector = function( elem, expr ) { + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + // Make sure that attribute selectors are quoted + expr = expr.replace( rattributeQuotes, "='$1']" ); + + if ( support.matchesSelector && documentIsHTML && + !compilerCache[ expr + " " ] && + ( !rbuggyMatches || !rbuggyMatches.test( 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) {} + } + + return Sizzle( expr, document, null, [ elem ] ).length > 0; +}; + +Sizzle.contains = function( context, elem ) { + // Set document vars if needed + if ( ( context.ownerDocument || context ) !== document ) { + setDocument( context ); + } + return contains( context, elem ); +}; + +Sizzle.attr = function( elem, name ) { + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + var fn = Expr.attrHandle[ name.toLowerCase() ], + // Don't get fooled by Object.prototype properties (jQuery #13807) + val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? + fn( elem, name, !documentIsHTML ) : + undefined; + + return val !== undefined ? + val : + support.attributes || !documentIsHTML ? + elem.getAttribute( name ) : + (val = elem.getAttributeNode(name)) && val.specified ? + val.value : + null; +}; + +Sizzle.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +/** + * Document sorting and removing duplicates + * @param {ArrayLike} results + */ +Sizzle.uniqueSort = function( results ) { + var elem, + duplicates = [], + j = 0, + i = 0; + + // Unless we *know* we can detect duplicates, assume their presence + hasDuplicate = !support.detectDuplicates; + sortInput = !support.sortStable && results.slice( 0 ); + results.sort( sortOrder ); + + if ( hasDuplicate ) { + while ( (elem = results[i++]) ) { + if ( elem === results[ i ] ) { + j = duplicates.push( i ); + } + } + while ( j-- ) { + results.splice( duplicates[ j ], 1 ); + } + } + + // Clear input after sorting to release objects + // See https://github.com/jquery/sizzle/pull/225 + sortInput = null; + + return results; +}; + +/** + * Utility function for retrieving the text value of an array of DOM nodes + * @param {Array|Element} elem + */ +getText = Sizzle.getText = function( elem ) { + var node, + ret = "", + i = 0, + nodeType = elem.nodeType; + + if ( !nodeType ) { + // If no nodeType, this is expected to be an array + while ( (node = elem[i++]) ) { + // Do not traverse comment nodes + ret += getText( node ); + } + } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + // Use textContent for elements + // innerText usage removed for consistency of new lines (jQuery #11153) + if ( typeof elem.textContent === "string" ) { + return elem.textContent; + } else { + // Traverse its children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + ret += getText( elem ); + } + } + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + // Do not include comment or processing instruction nodes + + return ret; +}; + +Expr = Sizzle.selectors = { + + // 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": function( 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 match.slice( 0, 4 ); + }, + + "CHILD": function( 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] ) { + Sizzle.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] ) { + Sizzle.error( match[0] ); + } + + return match; + }, + + "PSEUDO": function( 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": function( nodeNameSelector ) { + var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); + return nodeNameSelector === "*" ? + function() { return true; } : + function( elem ) { + return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; + }; + }, + + "CLASS": function( 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": function( name, operator, check ) { + return function( elem ) { + var result = Sizzle.attr( elem, name ); + + if ( result == null ) { + return operator === "!="; + } + if ( !operator ) { + return true; + } + + result += ""; + + return operator === "=" ? result === check : + operator === "!=" ? result !== check : + operator === "^=" ? check && result.indexOf( check ) === 0 : + operator === "*=" ? check && result.indexOf( check ) > -1 : + operator === "$=" ? check && result.slice( -check.length ) === check : + operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 : + operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : + false; + }; + }, + + "CHILD": function( 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, uniqueCache, 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 ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) { + + return false; + } + } + // Reverse direction for :only-* (if we haven't yet done so) + start = dir = type === "only" && !start && "nextSibling"; + } + 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 + + // ...in a gzip-friendly way + node = parent; + outerCache = node[ expando ] || (node[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + (outerCache[ node.uniqueID ] = {}); + + cache = uniqueCache[ 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 ) { + uniqueCache[ type ] = [ dirruns, nodeIndex, diff ]; + break; + } + } + + } else { + // Use previously-cached element index if available + if ( useCache ) { + // ...in a gzip-friendly way + node = elem; + outerCache = node[ expando ] || (node[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + (outerCache[ node.uniqueID ] = {}); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + 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 ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) && + ++diff ) { + + // Cache the index of each encountered element + if ( useCache ) { + outerCache = node[ expando ] || (node[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + (outerCache[ node.uniqueID ] = {}); + + uniqueCache[ type ] = [ dirruns, diff ]; + } + + if ( node === elem ) { + break; + } + } + } + } + } + + // Incorporate the offset, then check against cycle size + diff -= last; + return diff === first || ( diff % first === 0 && diff / first >= 0 ); + } + }; + }, + + "PSEUDO": function( pseudo, argument ) { + // pseudo-class names are case-insensitive + // http://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() ] || + Sizzle.error( "unsupported pseudo: " + pseudo ); + + // The user may use createPseudo to indicate that + // arguments are needed to create the filter function + // just as Sizzle 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( seed, matched[i] ); + seed[ idx ] = !( matches[ idx ] = matched[i] ); + } + }) : + function( elem ) { + return fn( elem, 0, args ); + }; + } + + 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( rtrim, "$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 (issue #299) + input[0] = null; + return !results.pop(); + }; + }), + + "has": markFunction(function( selector ) { + return function( elem ) { + return Sizzle( selector, elem ).length > 0; + }; + }), + + "contains": markFunction(function( text ) { + text = text.replace( runescape, funescape ); + return function( elem ) { + return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; + }; + }), + + // "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." + // http://www.w3.org/TR/selectors/#lang-pseudo + "lang": markFunction( function( lang ) { + // lang value must be a valid identifier + if ( !ridentifier.test(lang || "") ) { + Sizzle.error( "unsupported lang: " + lang ); + } + lang = lang.replace( runescape, funescape ).toLowerCase(); + 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 false; + }; + }), + + // Miscellaneous + "target": function( elem ) { + var hash = window.location && window.location.hash; + return hash && hash.slice( 1 ) === elem.id; + }, + + "root": function( elem ) { + return elem === docElem; + }, + + "focus": function( elem ) { + return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex); + }, + + // Boolean properties + "enabled": function( elem ) { + return elem.disabled === false; + }, + + "disabled": function( elem ) { + return elem.disabled === true; + }, + + "checked": function( elem ) { + // In CSS3, :checked should return both checked and selected elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + var nodeName = elem.nodeName.toLowerCase(); + return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); + }, + + "selected": function( elem ) { + // Accessing this property makes selected-by-default + // options in Safari work properly + if ( elem.parentNode ) { + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + // Contents + "empty": function( elem ) { + // http://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 true; + }, + + "parent": function( elem ) { + return !Expr.pseudos["empty"]( elem ); + }, + + // Element/input types + "header": function( elem ) { + return rheader.test( elem.nodeName ); + }, + + "input": function( elem ) { + return rinputs.test( elem.nodeName ); + }, + + "button": function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === "button" || name === "button"; + }, + + "text": function( elem ) { + var attr; + return elem.nodeName.toLowerCase() === "input" && + elem.type === "text" && + + // Support: IE<8 + // 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 ); + } + return matchIndexes; + }), + + "odd": createPositionalPseudo(function( matchIndexes, length ) { + var i = 1; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; --i >= 0; ) { + matchIndexes.push( i ); + } + 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(); + +tokenize = Sizzle.tokenize = function( 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 = rcombinators.exec( soFar )) ) { + matched = match.shift(); + tokens.push({ + value: matched, + // Cast descendant combinators to space + type: match[0].replace( rtrim, " " ) + }); + soFar = soFar.slice( matched.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: type, + matches: match + }); + soFar = soFar.slice( matched.length ); + } + } + + if ( !matched ) { + break; + } + } + + // Return the length of the invalid excess + // if we're just parsing + // Otherwise, throw an error or return tokens + return parseOnly ? + soFar.length : + soFar ? + Sizzle.error( selector ) : + // Cache the tokens + tokenCache( selector, groups ).slice( 0 ); +}; + +function toSelector( tokens ) { + var i = 0, + len = tokens.length, + selector = ""; + for ( ; i < len; i++ ) { + selector += tokens[i].value; + } + return selector; +} + +function addCombinator( matcher, combinator, base ) { + var dir = combinator.dir, + checkNonElements = base && dir === "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 ); + } + } + } : + + // Check against all ancestor/preceding elements + function( elem, context, xml ) { + var oldCache, uniqueCache, 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 ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ elem.uniqueID ] || (outerCache[ elem.uniqueID ] = {}); + + if ( (oldCache = uniqueCache[ dir ]) && + 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 + uniqueCache[ dir ] = newCache; + + // A match means we're done; a fail means we have to keep checking + if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) { + return true; + } + } + } + } + } + }; +} + +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++ ) { + Sizzle( 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, + 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, + + matcherOut = matcher ? + // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, + postFinder || ( seed ? preFilter : preexisting || postFilter ) ? + + // ...intermediate processing is necessary + [] : + + // ...otherwise use results directly + results : + matcherIn; + + // Find primary matches + if ( matcher ) { + matcher( matcherIn, matcherOut, context, xml ); + } + + // 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( 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( checkContext, elem ) > -1; + }, implicitRelative, true ), + matchers = [ function( elem, context, xml ) { + var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( + (checkContext = context).nodeType ? + matchContext( elem, context, xml ) : + matchAnyContext( elem, context, xml ) ); + // Avoid hanging onto element (issue #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( rtrim, "$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 ) { + outermostContext = context === document || context || outermost; + } + + // Add elements passing elementMatchers directly to results + // Support: IE<9, Safari + // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id + for ( ; i !== len && (elem = elems[i]) != null; i++ ) { + if ( byElement && elem ) { + j = 0; + if ( !context && elem.ownerDocument !== document ) { + setDocument( elem ); + xml = !documentIsHTML; + } + while ( (matcher = elementMatchers[j++]) ) { + if ( matcher( elem, context || document, xml) ) { + results.push( 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 ) { + + Sizzle.uniqueSort( results ); + } + } + + // Override manipulation of globals by nested matchers + if ( outermost ) { + dirruns = dirrunsUnique; + outermostContext = contextBackup; + } + + return unmatched; + }; + + return bySet ? + markFunction( superMatcher ) : + superMatcher; +} + +compile = Sizzle.compile = function( 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 Sizzle's compiled + * selector functions + * @param {String|Function} selector A selector or a pre-compiled + * selector function built with Sizzle.compile + * @param {Element} context + * @param {Array} [results] + * @param {Array} [seed] A set of elements to match against + */ +select = Sizzle.select = function( 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" && + support.getById && 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 + +// Sort stability +support.sortStable = expando.split("").sort( sortOrder ).join("") === expando; + +// Support: Chrome 14-35+ +// Always assume duplicates if they aren't passed to the comparison function +support.detectDuplicates = !!hasDuplicate; + +// Initialize against the default document +setDocument(); + +// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) +// Detached nodes confoundingly follow *each other* +support.sortDetached = assert(function( div1 ) { + // Should return 1, but returns 4 (following) + return div1.compareDocumentPosition( document.createElement("div") ) & 1; +}); + +// Support: IE<8 +// Prevent attribute/property "interpolation" +// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx +if ( !assert(function( div ) { + div.innerHTML = ""; + return div.firstChild.getAttribute("href") === "#" ; +}) ) { + addHandle( "type|href|height|width", function( elem, name, isXML ) { + if ( !isXML ) { + return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); + } + }); +} + +// Support: IE<9 +// Use defaultValue in place of getAttribute("value") +if ( !support.attributes || !assert(function( div ) { + div.innerHTML = ""; + div.firstChild.setAttribute( "value", "" ); + return div.firstChild.getAttribute( "value" ) === ""; +}) ) { + addHandle( "value", function( elem, name, isXML ) { + if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { + return elem.defaultValue; + } + }); +} + +// Support: IE<9 +// Use getAttributeNode to fetch booleans when getAttribute lies +if ( !assert(function( div ) { + return div.getAttribute("disabled") == null; +}) ) { + addHandle( booleans, function( elem, name, isXML ) { + var val; + if ( !isXML ) { + return elem[ name ] === true ? name.toLowerCase() : + (val = elem.getAttributeNode( name )) && val.specified ? + val.value : + null; + } + }); +} + +return Sizzle; + +})( window ); + + + +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; +jQuery.expr[ ":" ] = jQuery.expr.pseudos; +jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; + + + +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 = ( /^<([\w-]+)\s*\/?>(?:<\/\1>|)$/ ); + + + +var risSimple = /^.[^:#\[\.,]*$/; + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, not ) { + if ( jQuery.isFunction( qualifier ) ) { + return jQuery.grep( elements, function( elem, i ) { + /* jshint -W018 */ + return !!qualifier.call( elem, i, elem ) !== not; + } ); + + } + + if ( qualifier.nodeType ) { + return jQuery.grep( elements, function( elem ) { + return ( elem === qualifier ) !== not; + } ); + + } + + if ( typeof qualifier === "string" ) { + if ( risSimple.test( qualifier ) ) { + return jQuery.filter( qualifier, elements, not ); + } + + qualifier = jQuery.filter( qualifier, elements ); + } + + return jQuery.grep( elements, function( elem ) { + return ( jQuery.inArray( elem, qualifier ) > -1 ) !== not; + } ); +} + +jQuery.filter = function( expr, elems, not ) { + var elem = elems[ 0 ]; + + if ( not ) { + expr = ":not(" + expr + ")"; + } + + return elems.length === 1 && elem.nodeType === 1 ? + jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] : + jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { + return elem.nodeType === 1; + } ) ); +}; + +jQuery.fn.extend( { + find: function( selector ) { + var i, + ret = [], + self = this, + len = self.length; + + 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; + } + } + } ) ); + } + + for ( i = 0; i < len; i++ ) { + jQuery.find( selector, self[ i ], ret ); + } + + // Needed because $( selector, context ) becomes $( context ).find( selector ) + ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret ); + ret.selector = this.selector ? this.selector + " " + selector : selector; + return ret; + }, + filter: function( selector ) { + return this.pushStack( winnow( this, selector || [], false ) ); + }, + not: function( selector ) { + return this.pushStack( winnow( this, selector || [], true ) ); + }, + is: function( 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 (#9521) + // Strict HTML recognition (#11290: must start with <) + rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/, + + init = jQuery.fn.init = function( selector, context, root ) { + var match, elem; + + // HANDLE: $(""), $(null), $(undefined), $(false) + if ( !selector ) { + return this; + } + + // 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.charAt( 0 ) === "<" && + selector.charAt( 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; + + // 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 ( jQuery.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 ] ); + + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + if ( elem && elem.parentNode ) { + + // Handle the case where IE and Opera return items + // by name instead of ID + if ( elem.id !== match[ 2 ] ) { + return rootjQuery.find( selector ); + } + + // Otherwise, we inject the element directly into the jQuery object + this.length = 1; + this[ 0 ] = elem; + } + + this.context = document; + this.selector = selector; + 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.context = this[ 0 ] = selector; + this.length = 1; + return this; + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( jQuery.isFunction( selector ) ) { + return typeof root.ready !== "undefined" ? + root.ready( selector ) : + + // Execute immediately if ready is not present + selector( jQuery ); + } + + if ( selector.selector !== undefined ) { + this.selector = selector.selector; + this.context = selector.context; + } + + 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: function( target ) { + var i, + targets = jQuery( target, this ), + len = targets.length; + + return this.filter( function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( this, targets[ i ] ) ) { + return true; + } + } + } ); + }, + + closest: function( selectors, context ) { + var cur, + i = 0, + l = this.length, + matched = [], + pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ? + jQuery( selectors, context || this.context ) : + 0; + + for ( ; i < l; i++ ) { + for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) { + + // Always skip document fragments + if ( cur.nodeType < 11 && ( pos ? + pos.index( cur ) > -1 : + + // Don't pass non-elements to Sizzle + 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 matched set of elements + index: function( 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 jQuery.inArray( this[ 0 ], jQuery( elem ) ); + } + + // Locate the position of the desired element + return jQuery.inArray( + + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[ 0 ] : elem, this ); + }, + + add: function( selector, context ) { + return this.pushStack( + jQuery.uniqueSort( + jQuery.merge( this.get(), jQuery( selector, context ) ) + ) + ); + }, + + addBack: function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter( selector ) + ); + } +} ); + +function sibling( cur, dir ) { + do { + cur = cur[ dir ]; + } while ( cur && cur.nodeType !== 1 ); + + return cur; +} + +jQuery.each( { + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, i, until ) { + return dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return sibling( elem, "nextSibling" ); + }, + prev: function( elem ) { + return sibling( elem, "previousSibling" ); + }, + nextAll: function( elem ) { + return dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, i, until ) { + return dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, i, until ) { + return dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return siblings( ( elem.parentNode || {} ).firstChild, elem ); + }, + children: function( elem ) { + return siblings( elem.firstChild ); + }, + contents: function( elem ) { + return jQuery.nodeName( elem, "iframe" ) ? + elem.contentDocument || elem.contentWindow.document : + jQuery.merge( [], elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var ret = jQuery.map( this, fn, until ); + + if ( name.slice( -5 ) !== "Until" ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + ret = jQuery.filter( selector, ret ); + } + + if ( this.length > 1 ) { + + // Remove duplicates + if ( !guaranteedUnique[ name ] ) { + ret = jQuery.uniqueSort( ret ); + } + + // Reverse order for parents* and prev-derivatives + if ( rparentsprev.test( name ) ) { + ret = ret.reverse(); + } + } + + return this.pushStack( ret ); + }; +} ); +var rnotwhite = ( /\S+/g ); + + + +// Convert String-formatted options into Object-formatted ones +function createOptions( options ) { + var object = {}; + jQuery.each( options.match( rnotwhite ) || [], 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 = 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: function() { + 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 ( jQuery.isFunction( arg ) ) { + if ( !options.unique || !self.has( arg ) ) { + list.push( arg ); + } + } else if ( arg && arg.length && jQuery.type( arg ) !== "string" ) { + + // Inspect recursively + add( arg ); + } + } ); + } )( arguments ); + + if ( memory && !firing ) { + fire(); + } + } + return this; + }, + + // Remove a callback from the list + remove: function() { + 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: function( fn ) { + return fn ? + jQuery.inArray( fn, list ) > -1 : + list.length > 0; + }, + + // Remove all callbacks from the list + empty: function() { + if ( list ) { + list = []; + } + return this; + }, + + // Disable .fire and .add + // Abort any current/pending executions + // Clear all callbacks and values + disable: function() { + locked = queue = []; + list = memory = ""; + return this; + }, + disabled: function() { + return !list; + }, + + // Disable .fire + // Also disable .add unless we have memory (since it would have no effect) + // Abort any pending executions + lock: function() { + locked = true; + if ( !memory ) { + self.disable(); + } + return this; + }, + locked: function() { + return !!locked; + }, + + // Call all callbacks with the given context and arguments + fireWith: function( 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: function() { + self.fireWith( this, arguments ); + return this; + }, + + // To know if the callbacks have already been called at least once + fired: function() { + return !!fired; + } + }; + + return self; +}; + + +jQuery.extend( { + + Deferred: function( func ) { + var tuples = [ + + // action, add listener, listener list, final state + [ "resolve", "done", jQuery.Callbacks( "once memory" ), "resolved" ], + [ "reject", "fail", jQuery.Callbacks( "once memory" ), "rejected" ], + [ "notify", "progress", jQuery.Callbacks( "memory" ) ] + ], + state = "pending", + promise = { + state: function() { + return state; + }, + always: function() { + deferred.done( arguments ).fail( arguments ); + return this; + }, + then: function( /* fnDone, fnFail, fnProgress */ ) { + var fns = arguments; + return jQuery.Deferred( function( newDefer ) { + jQuery.each( tuples, function( i, tuple ) { + var fn = jQuery.isFunction( fns[ i ] ) && fns[ i ]; + + // deferred[ done | fail | progress ] for forwarding actions to newDefer + deferred[ tuple[ 1 ] ]( function() { + var returned = fn && fn.apply( this, arguments ); + if ( returned && jQuery.isFunction( returned.promise ) ) { + returned.promise() + .progress( newDefer.notify ) + .done( newDefer.resolve ) + .fail( newDefer.reject ); + } else { + newDefer[ tuple[ 0 ] + "With" ]( + this === promise ? newDefer.promise() : this, + fn ? [ returned ] : arguments + ); + } + } ); + } ); + fns = null; + } ).promise(); + }, + + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + return obj != null ? jQuery.extend( obj, promise ) : promise; + } + }, + deferred = {}; + + // Keep pipe for back-compat + promise.pipe = promise.then; + + // Add list-specific methods + jQuery.each( tuples, function( i, tuple ) { + var list = tuple[ 2 ], + stateString = tuple[ 3 ]; + + // promise[ done | fail | progress ] = list.add + promise[ tuple[ 1 ] ] = list.add; + + // Handle state + if ( stateString ) { + list.add( function() { + + // state = [ resolved | rejected ] + state = stateString; + + // [ reject_list | resolve_list ].disable; progress_list.lock + }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock ); + } + + // deferred[ resolve | reject | notify ] + deferred[ tuple[ 0 ] ] = function() { + deferred[ tuple[ 0 ] + "With" ]( this === deferred ? promise : this, arguments ); + return this; + }; + 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: function( subordinate /* , ..., subordinateN */ ) { + var i = 0, + resolveValues = slice.call( arguments ), + length = resolveValues.length, + + // the count of uncompleted subordinates + remaining = length !== 1 || + ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0, + + // the master Deferred. + // If resolveValues consist of only a single Deferred, just use that. + deferred = remaining === 1 ? subordinate : jQuery.Deferred(), + + // Update function for both resolve and progress values + updateFunc = function( i, contexts, values ) { + return function( value ) { + contexts[ i ] = this; + values[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; + if ( values === progressValues ) { + deferred.notifyWith( contexts, values ); + + } else if ( !( --remaining ) ) { + deferred.resolveWith( contexts, values ); + } + }; + }, + + progressValues, progressContexts, resolveContexts; + + // add listeners to Deferred subordinates; treat others as resolved + if ( length > 1 ) { + progressValues = new Array( length ); + progressContexts = new Array( length ); + resolveContexts = new Array( length ); + for ( ; i < length; i++ ) { + if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) { + resolveValues[ i ].promise() + .progress( updateFunc( i, progressContexts, progressValues ) ) + .done( updateFunc( i, resolveContexts, resolveValues ) ) + .fail( deferred.reject ); + } else { + --remaining; + } + } + } + + // if we're not waiting on anything, resolve the master + if ( !remaining ) { + deferred.resolveWith( resolveContexts, resolveValues ); + } + + return deferred.promise(); + } +} ); + + +// The deferred used on DOM ready +var readyList; + +jQuery.fn.ready = function( fn ) { + + // Add the callback + jQuery.ready.promise().done( fn ); + + 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 #6781 + readyWait: 1, + + // Hold (or release) the ready event + holdReady: function( hold ) { + if ( hold ) { + jQuery.readyWait++; + } else { + jQuery.ready( true ); + } + }, + + // Handle when the DOM is ready + ready: function( 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 ] ); + + // Trigger any bound ready events + if ( jQuery.fn.triggerHandler ) { + jQuery( document ).triggerHandler( "ready" ); + jQuery( document ).off( "ready" ); + } + } +} ); + +/** + * Clean-up method for dom ready events + */ +function detach() { + if ( document.addEventListener ) { + document.removeEventListener( "DOMContentLoaded", completed ); + window.removeEventListener( "load", completed ); + + } else { + document.detachEvent( "onreadystatechange", completed ); + window.detachEvent( "onload", completed ); + } +} + +/** + * The ready event handler and self cleanup method + */ +function completed() { + + // readyState === "complete" is good enough for us to call the dom ready in oldIE + if ( document.addEventListener || + window.event.type === "load" || + document.readyState === "complete" ) { + + detach(); + jQuery.ready(); + } +} + +jQuery.ready.promise = function( obj ) { + if ( !readyList ) { + + readyList = jQuery.Deferred(); + + // Catch cases where $(document).ready() is called + // after the browser event has already occurred. + // Support: IE6-10 + // 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 ); + + // Standards-based browsers support DOMContentLoaded + } else if ( document.addEventListener ) { + + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", completed ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", completed ); + + // If IE event model is used + } else { + + // Ensure firing before onload, maybe late but safe also for iframes + document.attachEvent( "onreadystatechange", completed ); + + // A fallback to window.onload, that will always work + window.attachEvent( "onload", completed ); + + // If IE and not a frame + // continually check to see if the document is ready + var top = false; + + try { + top = window.frameElement == null && document.documentElement; + } catch ( e ) {} + + if ( top && top.doScroll ) { + ( function doScrollCheck() { + if ( !jQuery.isReady ) { + + try { + + // Use the trick by Diego Perini + // http://javascript.nwbox.com/IEContentLoaded/ + top.doScroll( "left" ); + } catch ( e ) { + return window.setTimeout( doScrollCheck, 50 ); + } + + // detach all dom ready events + detach(); + + // and execute any waiting functions + jQuery.ready(); + } + } )(); + } + } + } + return readyList.promise( obj ); +}; + +// Kick off the DOM ready check even if the user does not +jQuery.ready.promise(); + + + + +// Support: IE<9 +// Iteration over object's inherited properties before its own +var i; +for ( i in jQuery( support ) ) { + break; +} +support.ownFirst = i === "0"; + +// Note: most support tests are defined in their respective modules. +// false until the test is run +support.inlineBlockNeedsLayout = false; + +// Execute ASAP in case we need to set body.style.zoom +jQuery( function() { + + // Minified: var a,b,c,d + var val, div, body, container; + + body = document.getElementsByTagName( "body" )[ 0 ]; + if ( !body || !body.style ) { + + // Return for frameset docs that don't have a body + return; + } + + // Setup + div = document.createElement( "div" ); + container = document.createElement( "div" ); + container.style.cssText = "position:absolute;border:0;width:0;height:0;top:0;left:-9999px"; + body.appendChild( container ).appendChild( div ); + + if ( typeof div.style.zoom !== "undefined" ) { + + // Support: IE<8 + // Check if natively block-level elements act like inline-block + // elements when setting their display to 'inline' and giving + // them layout + div.style.cssText = "display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1"; + + support.inlineBlockNeedsLayout = val = div.offsetWidth === 3; + if ( val ) { + + // Prevent IE 6 from affecting layout for positioned elements #11048 + // Prevent IE from shrinking the body in IE 7 mode #12869 + // Support: IE<8 + body.style.zoom = 1; + } + } + + body.removeChild( container ); +} ); + + +( function() { + var div = document.createElement( "div" ); + + // Support: IE<9 + support.deleteExpando = true; + try { + delete div.test; + } catch ( e ) { + support.deleteExpando = false; + } + + // Null elements to avoid leaks in IE. + div = null; +} )(); +var acceptData = function( elem ) { + var noData = jQuery.noData[ ( elem.nodeName + " " ).toLowerCase() ], + nodeType = +elem.nodeType || 1; + + // Do not set data on non-element DOM nodes because it will not be cleared (#8335). + return nodeType !== 1 && nodeType !== 9 ? + false : + + // Nodes accept data unless otherwise specified; rejection can be conditional + !noData || noData !== true && elem.getAttribute( "classid" ) === noData; +}; + + + + +var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, + rmultiDash = /([A-Z])/g; + +function dataAttr( elem, key, data ) { + + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + + var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase(); + + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = data === "true" ? true : + data === "false" ? false : + data === "null" ? null : + + // Only convert to a number if it doesn't change the string + +data + "" === data ? +data : + rbrace.test( data ) ? jQuery.parseJSON( data ) : + data; + } catch ( e ) {} + + // Make sure we set the data so it isn't changed later + jQuery.data( elem, key, data ); + + } else { + data = undefined; + } + } + + return data; +} + +// checks a cache object for emptiness +function isEmptyDataObject( obj ) { + var name; + for ( name in obj ) { + + // if the public data object is empty, the private is still empty + if ( name === "data" && jQuery.isEmptyObject( obj[ name ] ) ) { + continue; + } + if ( name !== "toJSON" ) { + return false; + } + } + + return true; +} + +function internalData( elem, name, data, pvt /* Internal Use Only */ ) { + if ( !acceptData( elem ) ) { + return; + } + + var ret, thisCache, + internalKey = jQuery.expando, + + // We have to handle DOM nodes and JS objects differently because IE6-7 + // can't GC object references properly across the DOM-JS boundary + isNode = elem.nodeType, + + // Only DOM nodes need the global jQuery cache; JS object data is + // attached directly to the object so GC can occur automatically + cache = isNode ? jQuery.cache : elem, + + // Only defining an ID for JS objects if its cache already exists allows + // the code to shortcut on the same path as a DOM node with no cache + id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey; + + // Avoid doing any more work than we need to when trying to get data on an + // object that has no data at all + if ( ( !id || !cache[ id ] || ( !pvt && !cache[ id ].data ) ) && + data === undefined && typeof name === "string" ) { + return; + } + + if ( !id ) { + + // Only DOM nodes need a new unique ID for each element since their data + // ends up in the global cache + if ( isNode ) { + id = elem[ internalKey ] = deletedIds.pop() || jQuery.guid++; + } else { + id = internalKey; + } + } + + if ( !cache[ id ] ) { + + // Avoid exposing jQuery metadata on plain JS objects when the object + // is serialized using JSON.stringify + cache[ id ] = isNode ? {} : { toJSON: jQuery.noop }; + } + + // An object can be passed to jQuery.data instead of a key/value pair; this gets + // shallow copied over onto the existing cache + if ( typeof name === "object" || typeof name === "function" ) { + if ( pvt ) { + cache[ id ] = jQuery.extend( cache[ id ], name ); + } else { + cache[ id ].data = jQuery.extend( cache[ id ].data, name ); + } + } + + thisCache = cache[ id ]; + + // jQuery data() is stored in a separate object inside the object's internal data + // cache in order to avoid key collisions between internal data and user-defined + // data. + if ( !pvt ) { + if ( !thisCache.data ) { + thisCache.data = {}; + } + + thisCache = thisCache.data; + } + + if ( data !== undefined ) { + thisCache[ jQuery.camelCase( name ) ] = data; + } + + // Check for both converted-to-camel and non-converted data property names + // If a data property was specified + if ( typeof name === "string" ) { + + // First Try to find as-is property data + ret = thisCache[ name ]; + + // Test for null|undefined property data + if ( ret == null ) { + + // Try to find the camelCased property + ret = thisCache[ jQuery.camelCase( name ) ]; + } + } else { + ret = thisCache; + } + + return ret; +} + +function internalRemoveData( elem, name, pvt ) { + if ( !acceptData( elem ) ) { + return; + } + + var thisCache, i, + isNode = elem.nodeType, + + // See jQuery.data for more information + cache = isNode ? jQuery.cache : elem, + id = isNode ? elem[ jQuery.expando ] : jQuery.expando; + + // If there is already no cache entry for this object, there is no + // purpose in continuing + if ( !cache[ id ] ) { + return; + } + + if ( name ) { + + thisCache = pvt ? cache[ id ] : cache[ id ].data; + + if ( thisCache ) { + + // Support array or space separated string names for data keys + if ( !jQuery.isArray( name ) ) { + + // try the string as a key before any manipulation + if ( name in thisCache ) { + name = [ name ]; + } else { + + // split the camel cased version by spaces unless a key with the spaces exists + name = jQuery.camelCase( name ); + if ( name in thisCache ) { + name = [ name ]; + } else { + name = name.split( " " ); + } + } + } else { + + // If "name" is an array of keys... + // When data is initially created, via ("key", "val") signature, + // keys will be converted to camelCase. + // Since there is no way to tell _how_ a key was added, remove + // both plain key and camelCase key. #12786 + // This will only penalize the array argument path. + name = name.concat( jQuery.map( name, jQuery.camelCase ) ); + } + + i = name.length; + while ( i-- ) { + delete thisCache[ name[ i ] ]; + } + + // If there is no data left in the cache, we want to continue + // and let the cache object itself get destroyed + if ( pvt ? !isEmptyDataObject( thisCache ) : !jQuery.isEmptyObject( thisCache ) ) { + return; + } + } + } + + // See jQuery.data for more information + if ( !pvt ) { + delete cache[ id ].data; + + // Don't destroy the parent cache unless the internal data object + // had been the only thing left in it + if ( !isEmptyDataObject( cache[ id ] ) ) { + return; + } + } + + // Destroy the cache + if ( isNode ) { + jQuery.cleanData( [ elem ], true ); + + // Use delete when supported for expandos or `cache` is not a window per isWindow (#10080) + /* jshint eqeqeq: false */ + } else if ( support.deleteExpando || cache != cache.window ) { + /* jshint eqeqeq: true */ + delete cache[ id ]; + + // When all else fails, undefined + } else { + cache[ id ] = undefined; + } +} + +jQuery.extend( { + cache: {}, + + // The following elements (space-suffixed to avoid Object.prototype collisions) + // throw uncatchable exceptions if you attempt to set expando properties + noData: { + "applet ": true, + "embed ": true, + + // ...but Flash objects (which have this classid) *can* handle expandos + "object ": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" + }, + + hasData: function( elem ) { + elem = elem.nodeType ? jQuery.cache[ elem[ jQuery.expando ] ] : elem[ jQuery.expando ]; + return !!elem && !isEmptyDataObject( elem ); + }, + + data: function( elem, name, data ) { + return internalData( elem, name, data ); + }, + + removeData: function( elem, name ) { + return internalRemoveData( elem, name ); + }, + + // For internal use only. + _data: function( elem, name, data ) { + return internalData( elem, name, data, true ); + }, + + _removeData: function( elem, name ) { + return internalRemoveData( elem, name, true ); + } +} ); + +jQuery.fn.extend( { + data: function( key, value ) { + var i, name, data, + elem = this[ 0 ], + attrs = elem && elem.attributes; + + // Special expections of .data basically thwart jQuery.access, + // so implement the relevant behavior ourselves + + // Gets all values + if ( key === undefined ) { + if ( this.length ) { + data = jQuery.data( elem ); + + if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) { + i = attrs.length; + while ( i-- ) { + + // Support: IE11+ + // The attrs elements can be null (#14894) + if ( attrs[ i ] ) { + name = attrs[ i ].name; + if ( name.indexOf( "data-" ) === 0 ) { + name = jQuery.camelCase( name.slice( 5 ) ); + dataAttr( elem, name, data[ name ] ); + } + } + } + jQuery._data( elem, "parsedAttrs", true ); + } + } + + return data; + } + + // Sets multiple values + if ( typeof key === "object" ) { + return this.each( function() { + jQuery.data( this, key ); + } ); + } + + return arguments.length > 1 ? + + // Sets one value + this.each( function() { + jQuery.data( this, key, value ); + } ) : + + // Gets one value + // Try to fetch any internally stored data first + elem ? dataAttr( elem, key, jQuery.data( elem, key ) ) : undefined; + }, + + removeData: function( key ) { + return this.each( function() { + jQuery.removeData( this, key ); + } ); + } +} ); + + +jQuery.extend( { + queue: function( elem, type, data ) { + var queue; + + if ( elem ) { + type = ( type || "fx" ) + "queue"; + queue = jQuery._data( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !queue || jQuery.isArray( data ) ) { + queue = jQuery._data( elem, type, jQuery.makeArray( data ) ); + } else { + queue.push( data ); + } + } + return queue || []; + } + }, + + dequeue: function( 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 ); + }; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + startLength--; + } + + 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; + fn.call( elem, next, hooks ); + } + + if ( !startLength && hooks ) { + hooks.empty.fire(); + } + }, + + // not intended for public consumption - generates a queueHooks object, + // or returns the current one + _queueHooks: function( elem, type ) { + var key = type + "queueHooks"; + return jQuery._data( elem, key ) || jQuery._data( elem, key, { + empty: jQuery.Callbacks( "once memory" ).add( function() { + jQuery._removeData( elem, type + "queue" ); + jQuery._removeData( elem, key ); + } ) + } ); + } +} ); + +jQuery.fn.extend( { + queue: function( type, data ) { + var setter = 2; + + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + setter--; + } + + if ( arguments.length < setter ) { + return jQuery.queue( this[ 0 ], type ); + } + + return data === undefined ? + this : + this.each( function() { + var queue = jQuery.queue( this, type, data ); + + // ensure a hooks for this queue + jQuery._queueHooks( this, type ); + + if ( type === "fx" && queue[ 0 ] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + } ); + }, + dequeue: function( type ) { + return this.each( function() { + jQuery.dequeue( this, type ); + } ); + }, + clearQueue: function( 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: function( 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"; + + while ( i-- ) { + tmp = jQuery._data( elements[ i ], type + "queueHooks" ); + if ( tmp && tmp.empty ) { + count++; + tmp.empty.add( resolve ); + } + } + resolve(); + return defer.promise( obj ); + } +} ); + + +( function() { + var shrinkWrapBlocksVal; + + support.shrinkWrapBlocks = function() { + if ( shrinkWrapBlocksVal != null ) { + return shrinkWrapBlocksVal; + } + + // Will be changed later if needed. + shrinkWrapBlocksVal = false; + + // Minified: var b,c,d + var div, body, container; + + body = document.getElementsByTagName( "body" )[ 0 ]; + if ( !body || !body.style ) { + + // Test fired too early or in an unsupported environment, exit. + return; + } + + // Setup + div = document.createElement( "div" ); + container = document.createElement( "div" ); + container.style.cssText = "position:absolute;border:0;width:0;height:0;top:0;left:-9999px"; + body.appendChild( container ).appendChild( div ); + + // Support: IE6 + // Check if elements with layout shrink-wrap their children + if ( typeof div.style.zoom !== "undefined" ) { + + // Reset CSS: box-sizing; display; margin; border + div.style.cssText = + + // Support: Firefox<29, Android 2.3 + // Vendor-prefix box-sizing + "-webkit-box-sizing:content-box;-moz-box-sizing:content-box;" + + "box-sizing:content-box;display:block;margin:0;border:0;" + + "padding:1px;width:1px;zoom:1"; + div.appendChild( document.createElement( "div" ) ).style.width = "5px"; + shrinkWrapBlocksVal = div.offsetWidth !== 3; + } + + body.removeChild( container ); + + return shrinkWrapBlocksVal; + }; + +} )(); +var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source; + +var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ); + + +var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; + +var isHidden = function( elem, el ) { + + // isHidden might be called from jQuery#filter function; + // in that case, element will be second argument + elem = el || elem; + return jQuery.css( elem, "display" ) === "none" || + !jQuery.contains( elem.ownerDocument, elem ); + }; + + + +function adjustCSS( elem, prop, valueParts, tween ) { + var adjusted, + scale = 1, + 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 = ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && + rcssNum.exec( jQuery.css( elem, prop ) ); + + if ( initialInUnit && initialInUnit[ 3 ] !== unit ) { + + // Trust units reported by jQuery.css + unit = unit || initialInUnit[ 3 ]; + + // Make sure we update the tween properties later on + valueParts = valueParts || []; + + // Iteratively approximate from a nonzero starting point + initialInUnit = +initial || 1; + + do { + + // If previous iteration zeroed out, double until we get *something*. + // Use string for doubling so we don't accidentally see scale as unchanged below + scale = scale || ".5"; + + // Adjust and apply + initialInUnit = initialInUnit / scale; + jQuery.style( elem, prop, initialInUnit + unit ); + + // Update scale, tolerating zero or NaN from tween.cur() + // Break the loop if scale is unchanged or perfect, or if we've just had enough. + } while ( + scale !== ( scale = currentValue() / initial ) && scale !== 1 && --maxIterations + ); + } + + 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 adjusted; +} + + +// 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, + length = elems.length, + bulk = key == null; + + // Sets many values + if ( jQuery.type( 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 ( !jQuery.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 < length; i++ ) { + fn( + elems[ i ], + key, + raw ? value : value.call( elems[ i ], i, fn( elems[ i ], key ) ) + ); + } + } + } + + return chainable ? + elems : + + // Gets + bulk ? + fn.call( elems ) : + length ? fn( elems[ 0 ], key ) : emptyGet; +}; +var rcheckableType = ( /^(?:checkbox|radio)$/i ); + +var rtagName = ( /<([\w:-]+)/ ); + +var rscriptType = ( /^$|\/(?:java|ecma)script/i ); + +var rleadingWhitespace = ( /^\s+/ ); + +var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|" + + "details|dialog|figcaption|figure|footer|header|hgroup|main|" + + "mark|meter|nav|output|picture|progress|section|summary|template|time|video"; + + + +function createSafeFragment( document ) { + var list = nodeNames.split( "|" ), + safeFrag = document.createDocumentFragment(); + + if ( safeFrag.createElement ) { + while ( list.length ) { + safeFrag.createElement( + list.pop() + ); + } + } + return safeFrag; +} + + +( function() { + var div = document.createElement( "div" ), + fragment = document.createDocumentFragment(), + input = document.createElement( "input" ); + + // Setup + div.innerHTML = "
      a"; + + // IE strips leading whitespace when .innerHTML is used + support.leadingWhitespace = div.firstChild.nodeType === 3; + + // Make sure that tbody elements aren't automatically inserted + // IE will insert them into empty tables + support.tbody = !div.getElementsByTagName( "tbody" ).length; + + // Make sure that link elements get serialized correctly by innerHTML + // This requires a wrapper element in IE + support.htmlSerialize = !!div.getElementsByTagName( "link" ).length; + + // Makes sure cloning an html5 element does not cause problems + // Where outerHTML is undefined, this still works + support.html5Clone = + document.createElement( "nav" ).cloneNode( true ).outerHTML !== "<:nav>"; + + // Check if a disconnected checkbox will retain its checked + // value of true after appended to the DOM (IE6/7) + input.type = "checkbox"; + input.checked = true; + fragment.appendChild( input ); + support.appendChecked = input.checked; + + // Make sure textarea (and checkbox) defaultValue is properly cloned + // Support: IE6-IE11+ + div.innerHTML = ""; + support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; + + // #11217 - WebKit loses check when the name is after the checked attribute + fragment.appendChild( div ); + + // Support: Windows Web Apps (WWA) + // `name` and `type` must use .setAttribute for WWA (#14901) + input = document.createElement( "input" ); + input.setAttribute( "type", "radio" ); + input.setAttribute( "checked", "checked" ); + input.setAttribute( "name", "t" ); + + div.appendChild( input ); + + // Support: Safari 5.1, iOS 5.1, Android 4.x, Android 2.3 + // old WebKit doesn't clone checked state correctly in fragments + support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Support: IE<9 + // Cloned elements keep attachEvent handlers, we use addEventListener on IE9+ + support.noCloneEvent = !!div.addEventListener; + + // Support: IE<9 + // Since attributes and properties are the same in IE, + // cleanData must set properties to undefined rather than use removeAttribute + div[ jQuery.expando ] = 1; + support.attributes = !div.getAttribute( jQuery.expando ); +} )(); + + +// We have to close these tags to support XHTML (#13200) +var wrapMap = { + option: [ 1, "" ], + legend: [ 1, "
      ", "
      " ], + area: [ 1, "", "" ], + + // Support: IE8 + param: [ 1, "", "" ], + thead: [ 1, "", "
      " ], + tr: [ 2, "", "
      " ], + col: [ 2, "", "
      " ], + td: [ 3, "", "
      " ], + + // IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags, + // unless wrapped in a div with non-breaking characters in front of it. + _default: support.htmlSerialize ? [ 0, "", "" ] : [ 1, "X
      ", "
      " ] +}; + +// Support: IE8-IE9 +wrapMap.optgroup = wrapMap.option; + +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + + +function getAll( context, tag ) { + var elems, elem, + i = 0, + found = typeof context.getElementsByTagName !== "undefined" ? + context.getElementsByTagName( tag || "*" ) : + typeof context.querySelectorAll !== "undefined" ? + context.querySelectorAll( tag || "*" ) : + undefined; + + if ( !found ) { + for ( found = [], elems = context.childNodes || context; + ( elem = elems[ i ] ) != null; + i++ + ) { + if ( !tag || jQuery.nodeName( elem, tag ) ) { + found.push( elem ); + } else { + jQuery.merge( found, getAll( elem, tag ) ); + } + } + } + + return tag === undefined || tag && jQuery.nodeName( context, tag ) ? + jQuery.merge( [ context ], found ) : + found; +} + + +// Mark scripts as having already been evaluated +function setGlobalEval( elems, refElements ) { + var elem, + i = 0; + for ( ; ( elem = elems[ i ] ) != null; i++ ) { + jQuery._data( + elem, + "globalEval", + !refElements || jQuery._data( refElements[ i ], "globalEval" ) + ); + } +} + + +var rhtml = /<|&#?\w+;/, + rtbody = / from table fragments + if ( !support.tbody ) { + + // String was a , *may* have spurious + elem = tag === "table" && !rtbody.test( elem ) ? + tmp.firstChild : + + // String was a bare or + wrap[ 1 ] === "
      " && !rtbody.test( elem ) ? + tmp : + 0; + + j = elem && elem.childNodes.length; + while ( j-- ) { + if ( jQuery.nodeName( ( tbody = elem.childNodes[ j ] ), "tbody" ) && + !tbody.childNodes.length ) { + + elem.removeChild( tbody ); + } + } + } + + jQuery.merge( nodes, tmp.childNodes ); + + // Fix #12392 for WebKit and IE > 9 + tmp.textContent = ""; + + // Fix #12392 for oldIE + while ( tmp.firstChild ) { + tmp.removeChild( tmp.firstChild ); + } + + // Remember the top-level container for proper cleanup + tmp = safe.lastChild; + } + } + } + + // Fix #11356: Clear elements from fragment + if ( tmp ) { + safe.removeChild( tmp ); + } + + // Reset defaultChecked for any radios and checkboxes + // about to be appended to the DOM in IE 6/7 (#8060) + if ( !support.appendChecked ) { + jQuery.grep( getAll( nodes, "input" ), fixDefaultChecked ); + } + + 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; + } + + contains = jQuery.contains( elem.ownerDocument, elem ); + + // Append to fragment + tmp = getAll( safe.appendChild( elem ), "script" ); + + // Preserve script evaluation history + if ( contains ) { + setGlobalEval( tmp ); + } + + // Capture executables + if ( scripts ) { + j = 0; + while ( ( elem = tmp[ j++ ] ) ) { + if ( rscriptType.test( elem.type || "" ) ) { + scripts.push( elem ); + } + } + } + } + + tmp = null; + + return safe; +} + + +( function() { + var i, eventName, + div = document.createElement( "div" ); + + // Support: IE<9 (lack submit/change bubble), Firefox (lack focus(in | out) events) + for ( i in { submit: true, change: true, focusin: true } ) { + eventName = "on" + i; + + if ( !( support[ i ] = eventName in window ) ) { + + // Beware of CSP restrictions (https://developer.mozilla.org/en/Security/CSP) + div.setAttribute( eventName, "t" ); + support[ i ] = div.attributes[ eventName ].expando === false; + } + } + + // Null elements to avoid leaks in IE. + div = null; +} )(); + + +var rformElems = /^(?:input|select|textarea)$/i, + rkeyEvent = /^key/, + rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/, + rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, + rtypenamespace = /^([^.]*)(?:\.(.+)|)/; + +function returnTrue() { + return true; +} + +function returnFalse() { + return false; +} + +// Support: IE9 +// See #13393 for more info +function safeActiveElement() { + try { + return document.activeElement; + } catch ( err ) { } +} + +function on( elem, types, selector, data, fn, one ) { + var origFn, type; + + // 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; + } + for ( type in types ) { + on( elem, type, selector, data, types[ type ], one ); + } + 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; + } else { + + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return elem; + } + + 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++ ); + } + return elem.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + } ); +} + +/* + * 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: function( elem, types, handler, data, selector ) { + var tmp, events, t, handleObjIn, + special, eventHandle, handleObj, + handlers, type, namespaces, origType, + elemData = jQuery._data( elem ); + + // Don't attach events to noData or text/comment nodes (but allow plain objects) + if ( !elemData ) { + return; + } + + // 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; + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure and main handler, if this is the first + if ( !( events = elemData.events ) ) { + events = elemData.events = {}; + } + 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" && + ( !e || jQuery.event.triggered !== e.type ) ? + jQuery.event.dispatch.apply( eventHandle.elem, arguments ) : + undefined; + }; + + // Add elem as a property of the handle fn to prevent a memory leak + // with IE non-native events + eventHandle.elem = elem; + } + + // Handle multiple events separated by a space + types = ( types || "" ).match( rnotwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // There *must* be a type, no attaching namespace-only handlers + if ( !type ) { + continue; + } + + // 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: type, + origType: origType, + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + needsContext: selector && jQuery.expr.match.needsContext.test( selector ), + namespace: namespaces.join( "." ) + }, handleObjIn ); + + // Init the event handler queue if we're the first + if ( !( handlers = events[ type ] ) ) { + handlers = events[ type ] = []; + handlers.delegateCount = 0; + + // Only use addEventListener/attachEvent if the special events handler returns false + if ( !special.setup || + special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + + // Bind the global event handler to the element + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle, false ); + + } else if ( elem.attachEvent ) { + elem.attachEvent( "on" + type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } + + // Keep track of which events have ever been used, for event optimization + jQuery.event.global[ type ] = true; + } + + // Nullify elem to prevent memory leaks in IE + elem = null; + }, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + var j, handleObj, tmp, + origCount, t, events, + special, handlers, type, + namespaces, origType, + elemData = jQuery.hasData( elem ) && jQuery._data( elem ); + + if ( !elemData || !( events = elemData.events ) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = ( types || "" ).match( rnotwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // 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 ); + } + 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; + while ( j-- ) { + handleObj = handlers[ j ]; + + 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 ); + + if ( handleObj.selector ) { + handlers.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + } + + // 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 ); + } + + delete events[ type ]; + } + } + + // Remove the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + delete elemData.handle; + + // removeData also checks for emptiness and clears the expando if empty + // so use it instead of delete + jQuery._removeData( elem, "events" ); + } + }, + + trigger: function( event, data, elem, onlyHandlers ) { + var handle, ontype, cur, + bubbleType, special, tmp, i, + eventPath = [ elem || document ], + type = hasOwn.call( event, "type" ) ? event.type : event, + namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; + + cur = tmp = elem = elem || document; + + // Don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // focus/blur morphs to focusin/out; ensure we're not firing them right now + if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { + return; + } + + if ( type.indexOf( "." ) > -1 ) { + + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split( "." ); + type = namespaces.shift(); + namespaces.sort(); + } + 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 ( !event.target ) { + event.target = elem; + } + + // 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 ] || {}; + if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { + return; + } + + // Determine event propagation path in advance, per W3C events spec (#9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) + if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + if ( !rfocusMorph.test( bubbleType + type ) ) { + cur = cur.parentNode; + } + for ( ; cur; cur = cur.parentNode ) { + eventPath.push( cur ); + tmp = cur; + } + + // 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 ); + } + } + + // Fire handlers on the event path + i = 0; + while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { + + event.type = i > 1 ? + bubbleType : + special.bindType || type; + + // jQuery handler + handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && + jQuery._data( cur, "handle" ); + + if ( handle ) { + handle.apply( cur, data ); + } + + // Native handler + handle = ontype && cur[ ontype ]; + if ( handle && handle.apply && acceptData( cur ) ) { + event.result = handle.apply( cur, data ); + if ( event.result === false ) { + event.preventDefault(); + } + } + } + event.type = type; + + // 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 name as the event. + // Can't use an .isFunction() check here because IE6/7 fails that test. + // Don't do default actions on window, that's where global variables be (#6170) + if ( ontype && elem[ type ] && !jQuery.isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + tmp = elem[ ontype ]; + + if ( tmp ) { + elem[ ontype ] = null; + } + + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + try { + elem[ type ](); + } catch ( e ) { + + // IE<9 dies on focus/blur to hidden element (#1486,#12518) + // only reproducible on winXP IE8 native, not IE9 in IE8 mode + } + jQuery.event.triggered = undefined; + + if ( tmp ) { + elem[ ontype ] = tmp; + } + } + } + } + + return event.result; + }, + + dispatch: function( event ) { + + // Make a writable jQuery.Event from the native event object + event = jQuery.event.fix( event ); + + var i, j, ret, matched, handleObj, + handlerQueue = [], + args = slice.call( arguments ), + handlers = ( jQuery._data( this, "events" ) || {} )[ event.type ] || [], + special = jQuery.event.special[ event.type ] || {}; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[ 0 ] = event; + 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; + } + + // Determine handlers + handlerQueue = jQuery.event.handlers.call( this, event, handlers ); + + // Run delegates first; they may want to stop propagation beneath us + i = 0; + while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) { + event.currentTarget = matched.elem; + + j = 0; + while ( ( handleObj = matched.handlers[ j++ ] ) && + !event.isImmediatePropagationStopped() ) { + + // Triggered event must either 1) have no namespace, or 2) have namespace(s) + // a subset or equal to those in the bound event (both can have no namespace). + if ( !event.rnamespace || 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(); + } + } + } + } + } + + // Call the postDispatch hook for the mapped type + if ( special.postDispatch ) { + special.postDispatch.call( this, event ); + } + + return event.result; + }, + + handlers: function( event, handlers ) { + var i, matches, sel, handleObj, + handlerQueue = [], + delegateCount = handlers.delegateCount, + cur = event.target; + + // Support (at least): Chrome, IE9 + // Find delegate handlers + // Black-hole SVG instance trees (#13180) + // + // Support: Firefox<=42+ + // Avoid non-left-click in FF but don't block IE radio events (#3861, gh-2343) + if ( delegateCount && cur.nodeType && + ( event.type !== "click" || isNaN( event.button ) || event.button < 1 ) ) { + + /* jshint eqeqeq: false */ + for ( ; cur != this; cur = cur.parentNode || this ) { + /* jshint eqeqeq: true */ + + // Don't check non-elements (#13208) + // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) + if ( cur.nodeType === 1 && ( cur.disabled !== true || event.type !== "click" ) ) { + matches = []; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + + // Don't conflict with Object.prototype properties (#13203) + sel = handleObj.selector + " "; + + if ( matches[ sel ] === undefined ) { + matches[ sel ] = handleObj.needsContext ? + jQuery( sel, this ).index( cur ) > -1 : + jQuery.find( sel, this, null, [ cur ] ).length; + } + if ( matches[ sel ] ) { + matches.push( handleObj ); + } + } + if ( matches.length ) { + handlerQueue.push( { elem: cur, handlers: matches } ); + } + } + } + } + + // Add the remaining (directly-bound) handlers + if ( delegateCount < handlers.length ) { + handlerQueue.push( { elem: this, handlers: handlers.slice( delegateCount ) } ); + } + + return handlerQueue; + }, + + fix: function( event ) { + if ( event[ jQuery.expando ] ) { + return event; + } + + // Create a writable copy of the event object and normalize some properties + var i, prop, copy, + type = event.type, + originalEvent = event, + fixHook = this.fixHooks[ type ]; + + if ( !fixHook ) { + this.fixHooks[ type ] = fixHook = + rmouseEvent.test( type ) ? this.mouseHooks : + rkeyEvent.test( type ) ? this.keyHooks : + {}; + } + copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props; + + event = new jQuery.Event( originalEvent ); + + i = copy.length; + while ( i-- ) { + prop = copy[ i ]; + event[ prop ] = originalEvent[ prop ]; + } + + // Support: IE<9 + // Fix target property (#1925) + if ( !event.target ) { + event.target = originalEvent.srcElement || document; + } + + // Support: Safari 6-8+ + // Target should not be a text node (#504, #13143) + if ( event.target.nodeType === 3 ) { + event.target = event.target.parentNode; + } + + // Support: IE<9 + // For mouse/key events, metaKey==false if it's undefined (#3368, #11328) + event.metaKey = !!event.metaKey; + + return fixHook.filter ? fixHook.filter( event, originalEvent ) : event; + }, + + // Includes some event props shared by KeyEvent and MouseEvent + props: ( "altKey bubbles cancelable ctrlKey currentTarget detail eventPhase " + + "metaKey relatedTarget shiftKey target timeStamp view which" ).split( " " ), + + fixHooks: {}, + + keyHooks: { + props: "char charCode key keyCode".split( " " ), + filter: function( event, original ) { + + // Add which for key events + if ( event.which == null ) { + event.which = original.charCode != null ? original.charCode : original.keyCode; + } + + return event; + } + }, + + mouseHooks: { + props: ( "button buttons clientX clientY fromElement offsetX offsetY " + + "pageX pageY screenX screenY toElement" ).split( " " ), + filter: function( event, original ) { + var body, eventDoc, doc, + button = original.button, + fromElement = original.fromElement; + + // Calculate pageX/Y if missing and clientX/Y available + if ( event.pageX == null && original.clientX != null ) { + eventDoc = event.target.ownerDocument || document; + doc = eventDoc.documentElement; + body = eventDoc.body; + + event.pageX = original.clientX + + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - + ( doc && doc.clientLeft || body && body.clientLeft || 0 ); + event.pageY = original.clientY + + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - + ( doc && doc.clientTop || body && body.clientTop || 0 ); + } + + // Add relatedTarget, if necessary + if ( !event.relatedTarget && fromElement ) { + event.relatedTarget = fromElement === event.target ? + original.toElement : + fromElement; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + // Note: button is not normalized, so don't use it + if ( !event.which && button !== undefined ) { + event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) ); + } + + return event; + } + }, + + special: { + load: { + + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + focus: { + + // Fire native event if possible so blur/focus sequence is correct + trigger: function() { + if ( this !== safeActiveElement() && this.focus ) { + try { + this.focus(); + return false; + } catch ( e ) { + + // Support: IE<9 + // If we error on focus to hidden element (#1486, #12518), + // let .trigger() run the handlers + } + } + }, + delegateType: "focusin" + }, + blur: { + trigger: function() { + if ( this === safeActiveElement() && this.blur ) { + this.blur(); + return false; + } + }, + delegateType: "focusout" + }, + click: { + + // For checkbox, fire native event so checked state will be right + trigger: function() { + if ( jQuery.nodeName( this, "input" ) && this.type === "checkbox" && this.click ) { + this.click(); + return false; + } + }, + + // For cross-browser consistency, don't fire native .click() on links + _default: function( event ) { + return jQuery.nodeName( event.target, "a" ); + } + }, + + beforeunload: { + postDispatch: function( 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; + } + } + } + }, + + // Piggyback on a donor event to simulate a different one + simulate: function( type, elem, event ) { + var e = jQuery.extend( + new jQuery.Event(), + event, + { + type: type, + isSimulated: true + + // Previously, `originalEvent: {}` was set here, so stopPropagation call + // would not be triggered on donor event, since in our own + // jQuery.event.stopPropagation function we had a check for existence of + // originalEvent.stopPropagation method, so, consequently it would be a noop. + // + // Guard for simulated events was moved to jQuery.event.stopPropagation function + // since `originalEvent` should point to the original event for the + // constancy with other events and for more focused logic + } + ); + + jQuery.event.trigger( e, null, elem ); + + if ( e.isDefaultPrevented() ) { + event.preventDefault(); + } + } +}; + +jQuery.removeEvent = document.removeEventListener ? + function( elem, type, handle ) { + + // This "if" is needed for plain objects + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle ); + } + } : + function( elem, type, handle ) { + var name = "on" + type; + + if ( elem.detachEvent ) { + + // #8545, #7054, preventing memory leaks for custom events in IE6-8 + // detachEvent needed property on element, by name of that event, + // to properly expose it to GC + if ( typeof elem[ name ] === "undefined" ) { + elem[ name ] = null; + } + + elem.detachEvent( name, handle ); + } + }; + +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: IE < 9, Android < 4.0 + src.returnValue === false ? + returnTrue : + returnFalse; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || jQuery.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// http://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, + + preventDefault: function() { + var e = this.originalEvent; + + this.isDefaultPrevented = returnTrue; + if ( !e ) { + return; + } + + // If preventDefault exists, run it on the original event + if ( e.preventDefault ) { + e.preventDefault(); + + // Support: IE + // Otherwise set the returnValue property of the original event to false + } else { + e.returnValue = false; + } + }, + stopPropagation: function() { + var e = this.originalEvent; + + this.isPropagationStopped = returnTrue; + + if ( !e || this.isSimulated ) { + return; + } + + // If stopPropagation exists, run it on the original event + if ( e.stopPropagation ) { + e.stopPropagation(); + } + + // Support: IE + // Set the cancelBubble property of the original event to true + e.cancelBubble = true; + }, + stopImmediatePropagation: function() { + var e = this.originalEvent; + + this.isImmediatePropagationStopped = returnTrue; + + if ( e && e.stopImmediatePropagation ) { + e.stopImmediatePropagation(); + } + + this.stopPropagation(); + } +}; + +// 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://code.google.com/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: function( 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; + } + return ret; + } + }; +} ); + +// IE submit delegation +if ( !support.submit ) { + + jQuery.event.special.submit = { + setup: function() { + + // Only need this for delegated form submit events + if ( jQuery.nodeName( this, "form" ) ) { + return false; + } + + // Lazy-add a submit handler when a descendant form may potentially be submitted + jQuery.event.add( this, "click._submit keypress._submit", function( e ) { + + // Node name check avoids a VML-related crash in IE (#9807) + var elem = e.target, + form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? + + // Support: IE <=8 + // We use jQuery.prop instead of elem.form + // to allow fixing the IE8 delegated submit issue (gh-2332) + // by 3rd party polyfills/workarounds. + jQuery.prop( elem, "form" ) : + undefined; + + if ( form && !jQuery._data( form, "submit" ) ) { + jQuery.event.add( form, "submit._submit", function( event ) { + event._submitBubble = true; + } ); + jQuery._data( form, "submit", true ); + } + } ); + + // return undefined since we don't need an event listener + }, + + postDispatch: function( event ) { + + // If form was submitted by the user, bubble the event up the tree + if ( event._submitBubble ) { + delete event._submitBubble; + if ( this.parentNode && !event.isTrigger ) { + jQuery.event.simulate( "submit", this.parentNode, event ); + } + } + }, + + teardown: function() { + + // Only need this for delegated form submit events + if ( jQuery.nodeName( this, "form" ) ) { + return false; + } + + // Remove delegated handlers; cleanData eventually reaps submit handlers attached above + jQuery.event.remove( this, "._submit" ); + } + }; +} + +// IE change delegation and checkbox/radio fix +if ( !support.change ) { + + jQuery.event.special.change = { + + setup: function() { + + if ( rformElems.test( this.nodeName ) ) { + + // IE doesn't fire change on a check/radio until blur; trigger it on click + // after a propertychange. Eat the blur-change in special.change.handle. + // This still fires onchange a second time for check/radio after blur. + if ( this.type === "checkbox" || this.type === "radio" ) { + jQuery.event.add( this, "propertychange._change", function( event ) { + if ( event.originalEvent.propertyName === "checked" ) { + this._justChanged = true; + } + } ); + jQuery.event.add( this, "click._change", function( event ) { + if ( this._justChanged && !event.isTrigger ) { + this._justChanged = false; + } + + // Allow triggered, simulated change events (#11500) + jQuery.event.simulate( "change", this, event ); + } ); + } + return false; + } + + // Delegated event; lazy-add a change handler on descendant inputs + jQuery.event.add( this, "beforeactivate._change", function( e ) { + var elem = e.target; + + if ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, "change" ) ) { + jQuery.event.add( elem, "change._change", function( event ) { + if ( this.parentNode && !event.isSimulated && !event.isTrigger ) { + jQuery.event.simulate( "change", this.parentNode, event ); + } + } ); + jQuery._data( elem, "change", true ); + } + } ); + }, + + handle: function( event ) { + var elem = event.target; + + // Swallow native change events from checkbox/radio, we already triggered them above + if ( this !== elem || event.isSimulated || event.isTrigger || + ( elem.type !== "radio" && elem.type !== "checkbox" ) ) { + + return event.handleObj.handler.apply( this, arguments ); + } + }, + + teardown: function() { + jQuery.event.remove( this, "._change" ); + + return !rformElems.test( this.nodeName ); + } + }; +} + +// Support: Firefox +// Firefox doesn't have focus(in | out) events +// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787 +// +// Support: Chrome, Safari +// 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://code.google.com/p/chromium/issues/detail?id=449857 +if ( !support.focusin ) { + jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler on the document while someone wants focusin/focusout + var handler = function( event ) { + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) ); + }; + + jQuery.event.special[ fix ] = { + setup: function() { + var doc = this.ownerDocument || this, + attaches = jQuery._data( doc, fix ); + + if ( !attaches ) { + doc.addEventListener( orig, handler, true ); + } + jQuery._data( doc, fix, ( attaches || 0 ) + 1 ); + }, + teardown: function() { + var doc = this.ownerDocument || this, + attaches = jQuery._data( doc, fix ) - 1; + + if ( !attaches ) { + doc.removeEventListener( orig, handler, true ); + jQuery._removeData( doc, fix ); + } else { + jQuery._data( doc, fix, attaches ); + } + } + }; + } ); +} + +jQuery.fn.extend( { + + on: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn ); + }, + one: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn, 1 ); + }, + off: function( 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 ( typeof types === "object" ) { + + // ( types-object [, selector] ) + for ( type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each( function() { + jQuery.event.remove( this, types, fn, selector ); + } ); + }, + + trigger: function( type, data ) { + return this.each( function() { + jQuery.event.trigger( type, data, this ); + } ); + }, + triggerHandler: function( type, data ) { + var elem = this[ 0 ]; + if ( elem ) { + return jQuery.event.trigger( type, data, elem, true ); + } + } +} ); + + +var rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g, + rnoshimcache = new RegExp( "<(?:" + nodeNames + ")[\\s/>]", "i" ), + rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi, + + // Support: IE 10-11, Edge 10240+ + // In IE/Edge using regex groups here causes severe slowdowns. + // See https://connect.microsoft.com/IE/feedback/details/1736512/ + rnoInnerhtml = /\s*$/g, + safeFragment = createSafeFragment( document ), + fragmentDiv = safeFragment.appendChild( document.createElement( "div" ) ); + +// Support: IE<8 +// Manipulating tables requires a tbody +function manipulationTarget( elem, content ) { + return jQuery.nodeName( elem, "table" ) && + jQuery.nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ? + + elem.getElementsByTagName( "tbody" )[ 0 ] || + elem.appendChild( elem.ownerDocument.createElement( "tbody" ) ) : + elem; +} + +// Replace/restore the type attribute of script elements for safe DOM manipulation +function disableScript( elem ) { + elem.type = ( jQuery.find.attr( elem, "type" ) !== null ) + "/" + elem.type; + return elem; +} +function restoreScript( elem ) { + var match = rscriptTypeMasked.exec( elem.type ); + if ( match ) { + elem.type = match[ 1 ]; + } else { + elem.removeAttribute( "type" ); + } + return elem; +} + +function cloneCopyEvent( src, dest ) { + if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) { + return; + } + + var type, i, l, + oldData = jQuery._data( src ), + curData = jQuery._data( dest, oldData ), + events = oldData.events; + + if ( events ) { + delete curData.handle; + curData.events = {}; + + for ( type in events ) { + for ( i = 0, l = events[ type ].length; i < l; i++ ) { + jQuery.event.add( dest, type, events[ type ][ i ] ); + } + } + } + + // make the cloned public data object a copy from the original + if ( curData.data ) { + curData.data = jQuery.extend( {}, curData.data ); + } +} + +function fixCloneNodeIssues( src, dest ) { + var nodeName, e, data; + + // We do not need to do anything for non-Elements + if ( dest.nodeType !== 1 ) { + return; + } + + nodeName = dest.nodeName.toLowerCase(); + + // IE6-8 copies events bound via attachEvent when using cloneNode. + if ( !support.noCloneEvent && dest[ jQuery.expando ] ) { + data = jQuery._data( dest ); + + for ( e in data.events ) { + jQuery.removeEvent( dest, e, data.handle ); + } + + // Event data gets referenced instead of copied if the expando gets copied too + dest.removeAttribute( jQuery.expando ); + } + + // IE blanks contents when cloning scripts, and tries to evaluate newly-set text + if ( nodeName === "script" && dest.text !== src.text ) { + disableScript( dest ).text = src.text; + restoreScript( dest ); + + // IE6-10 improperly clones children of object elements using classid. + // IE10 throws NoModificationAllowedError if parent is null, #12132. + } else if ( nodeName === "object" ) { + if ( dest.parentNode ) { + dest.outerHTML = src.outerHTML; + } + + // This path appears unavoidable for IE9. When cloning an object + // element in IE9, the outerHTML strategy above is not sufficient. + // If the src has innerHTML and the destination does not, + // copy the src.innerHTML into the dest.innerHTML. #10324 + if ( support.html5Clone && ( src.innerHTML && !jQuery.trim( dest.innerHTML ) ) ) { + dest.innerHTML = src.innerHTML; + } + + } else if ( nodeName === "input" && rcheckableType.test( src.type ) ) { + + // IE6-8 fails to persist the checked state of a cloned checkbox + // or radio button. Worse, IE6-7 fail to give the cloned element + // a checked appearance if the defaultChecked value isn't also set + + dest.defaultChecked = dest.checked = src.checked; + + // IE6-7 get confused and end up setting the value of a cloned + // checkbox/radio button to an empty string instead of "on" + if ( dest.value !== src.value ) { + dest.value = src.value; + } + + // IE6-8 fails to return the selected option to the default selected + // state when cloning options + } else if ( nodeName === "option" ) { + dest.defaultSelected = dest.selected = src.defaultSelected; + + // IE6-8 fails to set the defaultValue to the correct value when + // cloning other types of input fields + } else if ( nodeName === "input" || nodeName === "textarea" ) { + dest.defaultValue = src.defaultValue; + } +} + +function domManip( collection, args, callback, ignored ) { + + // Flatten any nested arrays + args = concat.apply( [], args ); + + var first, node, hasScripts, + scripts, doc, fragment, + i = 0, + l = collection.length, + iNoClone = l - 1, + value = args[ 0 ], + isFunction = jQuery.isFunction( value ); + + // We can't cloneNode fragments that contain checked, in WebKit + if ( isFunction || + ( l > 1 && typeof value === "string" && + !support.checkClone && rchecked.test( value ) ) ) { + return collection.each( function( index ) { + var self = collection.eq( index ); + if ( isFunction ) { + args[ 0 ] = value.call( this, index, self.html() ); + } + domManip( self, args, callback, ignored ); + } ); + } + + if ( l ) { + fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored ); + first = fragment.firstChild; + + if ( fragment.childNodes.length === 1 ) { + fragment = first; + } + + // 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 (#8070). + for ( ; i < l; i++ ) { + node = fragment; + + if ( i !== iNoClone ) { + node = jQuery.clone( node, true, true ); + + // Keep references to cloned scripts for later restoration + if ( hasScripts ) { + + // Support: Android<4.1, PhantomJS<2 + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( scripts, getAll( node, "script" ) ); + } + } + + callback.call( collection[ i ], node, i ); + } + + if ( hasScripts ) { + doc = scripts[ scripts.length - 1 ].ownerDocument; + + // Reenable scripts + jQuery.map( scripts, restoreScript ); + + // Evaluate executable scripts on first document insertion + for ( i = 0; i < hasScripts; i++ ) { + node = scripts[ i ]; + if ( rscriptType.test( node.type || "" ) && + !jQuery._data( node, "globalEval" ) && + jQuery.contains( doc, node ) ) { + + if ( node.src ) { + + // Optional AJAX dependency, but won't run scripts if not present + if ( jQuery._evalUrl ) { + jQuery._evalUrl( node.src ); + } + } else { + jQuery.globalEval( + ( node.text || node.textContent || node.innerHTML || "" ) + .replace( rcleanScript, "" ) + ); + } + } + } + } + + // Fix #11809: Avoid leaking memory + fragment = first = null; + } + } + + return collection; +} + +function remove( elem, selector, keepData ) { + var node, + elems = selector ? jQuery.filter( selector, elem ) : elem, + i = 0; + + for ( ; ( node = elems[ i ] ) != null; i++ ) { + + if ( !keepData && node.nodeType === 1 ) { + jQuery.cleanData( getAll( node ) ); + } + + if ( node.parentNode ) { + if ( keepData && jQuery.contains( node.ownerDocument, node ) ) { + setGlobalEval( getAll( node, "script" ) ); + } + node.parentNode.removeChild( node ); + } + } + + return elem; +} + +jQuery.extend( { + htmlPrefilter: function( html ) { + return html.replace( rxhtmlTag, "<$1>" ); + }, + + clone: function( elem, dataAndEvents, deepDataAndEvents ) { + var destElements, node, clone, i, srcElements, + inPage = jQuery.contains( elem.ownerDocument, elem ); + + if ( support.html5Clone || jQuery.isXMLDoc( elem ) || + !rnoshimcache.test( "<" + elem.nodeName + ">" ) ) { + + clone = elem.cloneNode( true ); + + // IE<=8 does not properly clone detached, unknown element nodes + } else { + fragmentDiv.innerHTML = elem.outerHTML; + fragmentDiv.removeChild( clone = fragmentDiv.firstChild ); + } + + if ( ( !support.noCloneEvent || !support.noCloneChecked ) && + ( elem.nodeType === 1 || elem.nodeType === 11 ) && !jQuery.isXMLDoc( elem ) ) { + + // We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2 + destElements = getAll( clone ); + srcElements = getAll( elem ); + + // Fix all IE cloning issues + for ( i = 0; ( node = srcElements[ i ] ) != null; ++i ) { + + // Ensure that the destination node is not null; Fixes #9587 + if ( destElements[ i ] ) { + fixCloneNodeIssues( node, destElements[ i ] ); + } + } + } + + // Copy the events from the original to the clone + if ( dataAndEvents ) { + if ( deepDataAndEvents ) { + srcElements = srcElements || getAll( elem ); + destElements = destElements || getAll( clone ); + + for ( i = 0; ( node = srcElements[ i ] ) != null; i++ ) { + cloneCopyEvent( node, destElements[ i ] ); + } + } else { + cloneCopyEvent( elem, clone ); + } + } + + // Preserve script evaluation history + destElements = getAll( clone, "script" ); + if ( destElements.length > 0 ) { + setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); + } + + destElements = srcElements = node = null; + + // Return the cloned set + return clone; + }, + + cleanData: function( elems, /* internal */ forceAcceptData ) { + var elem, type, id, data, + i = 0, + internalKey = jQuery.expando, + cache = jQuery.cache, + attributes = support.attributes, + special = jQuery.event.special; + + for ( ; ( elem = elems[ i ] ) != null; i++ ) { + if ( forceAcceptData || acceptData( elem ) ) { + + id = elem[ internalKey ]; + data = id && cache[ id ]; + + if ( data ) { + if ( data.events ) { + for ( type in data.events ) { + if ( special[ type ] ) { + jQuery.event.remove( elem, type ); + + // This is a shortcut to avoid jQuery.event.remove's overhead + } else { + jQuery.removeEvent( elem, type, data.handle ); + } + } + } + + // Remove cache only if it was not already removed by jQuery.event.remove + if ( cache[ id ] ) { + + delete cache[ id ]; + + // Support: IE<9 + // IE does not allow us to delete expando properties from nodes + // IE creates expando attributes along with the property + // IE does not have a removeAttribute function on Document nodes + if ( !attributes && typeof elem.removeAttribute !== "undefined" ) { + elem.removeAttribute( internalKey ); + + // Webkit & Blink performance suffers when deleting properties + // from DOM nodes, so set to undefined instead + // https://code.google.com/p/chromium/issues/detail?id=378607 + } else { + elem[ internalKey ] = undefined; + } + + deletedIds.push( id ); + } + } + } + } + } +} ); + +jQuery.fn.extend( { + + // Keep domManip exposed until 3.0 (gh-2225) + domManip: domManip, + + detach: function( selector ) { + return remove( this, selector, true ); + }, + + remove: function( selector ) { + return remove( this, selector ); + }, + + text: function( value ) { + return access( this, function( value ) { + return value === undefined ? + jQuery.text( this ) : + this.empty().append( + ( this[ 0 ] && this[ 0 ].ownerDocument || document ).createTextNode( value ) + ); + }, null, value, arguments.length ); + }, + + append: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.appendChild( elem ); + } + } ); + }, + + prepend: function() { + 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 ); + } + } ); + }, + + before: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this ); + } + } ); + }, + + after: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this.nextSibling ); + } + } ); + }, + + empty: function() { + var elem, + i = 0; + + for ( ; ( elem = this[ i ] ) != null; i++ ) { + + // Remove element nodes and prevent memory leaks + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + } + + // Remove any remaining nodes + while ( elem.firstChild ) { + elem.removeChild( elem.firstChild ); + } + + // If this is a select, ensure that it displays empty (#12336) + // Support: IE<9 + if ( elem.options && jQuery.nodeName( elem, "select" ) ) { + elem.options.length = 0; + } + } + + return this; + }, + + clone: function( dataAndEvents, deepDataAndEvents ) { + dataAndEvents = dataAndEvents == null ? false : dataAndEvents; + deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; + + return this.map( function() { + return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); + } ); + }, + + html: function( value ) { + return access( this, function( value ) { + var elem = this[ 0 ] || {}, + i = 0, + l = this.length; + + if ( value === undefined ) { + return elem.nodeType === 1 ? + elem.innerHTML.replace( rinlinejQuery, "" ) : + undefined; + } + + // See if we can take a shortcut and just use innerHTML + if ( typeof value === "string" && !rnoInnerhtml.test( value ) && + ( support.htmlSerialize || !rnoshimcache.test( value ) ) && + ( support.leadingWhitespace || !rleadingWhitespace.test( value ) ) && + !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { + + value = jQuery.htmlPrefilter( value ); + + try { + for ( ; i < l; i++ ) { + + // Remove element nodes and prevent memory leaks + elem = this[ i ] || {}; + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + elem.innerHTML = value; + } + } + + elem = 0; + + // If using innerHTML throws an exception, use the fallback method + } catch ( e ) {} + } + + if ( elem ) { + this.empty().append( value ); + } + }, null, value, arguments.length ); + }, + + replaceWith: function() { + var ignored = []; + + // Make the changes, replacing each non-ignored context element with the new content + return domManip( this, arguments, function( elem ) { + var parent = this.parentNode; + + if ( jQuery.inArray( this, ignored ) < 0 ) { + jQuery.cleanData( getAll( this ) ); + if ( parent ) { + parent.replaceChild( elem, this ); + } + } + + // 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, + i = 0, + ret = [], + insert = jQuery( selector ), + last = insert.length - 1; + + for ( ; i <= last; i++ ) { + elems = i === last ? this : this.clone( true ); + jQuery( insert[ i ] )[ original ]( elems ); + + // Modern browsers can apply jQuery collections as arrays, but oldIE needs a .get() + push.apply( ret, elems.get() ); + } + + return this.pushStack( ret ); + }; +} ); + + +var iframe, + elemdisplay = { + + // Support: Firefox + // We have to pre-define these values for FF (#10227) + HTML: "block", + BODY: "block" + }; + +/** + * Retrieve the actual display of a element + * @param {String} name nodeName of the element + * @param {Object} doc Document object + */ + +// Called only from within defaultDisplay +function actualDisplay( name, doc ) { + var elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ), + + display = jQuery.css( elem[ 0 ], "display" ); + + // We don't have any data stored on the element, + // so use "detach" method as fast way to get rid of the element + elem.detach(); + + return display; +} + +/** + * Try to determine the default display value of an element + * @param {String} nodeName + */ +function defaultDisplay( nodeName ) { + var doc = document, + display = elemdisplay[ nodeName ]; + + if ( !display ) { + display = actualDisplay( nodeName, doc ); + + // If the simple way fails, read from inside an iframe + if ( display === "none" || !display ) { + + // Use the already-created iframe if possible + iframe = ( iframe || jQuery( "" ) + .css( { + position: "absolute", + top: "0", + left: "-600px", + width: "500px", + zIndex: 1, + background: "white" + } ) + .attr( { id: "qunit-fixture-iframe", src: fileName } ); + + // Add other iframe styles + if ( iframeStyles ) { + $iframe.css( iframeStyles ); + } + + // Test iframes are expected to invoke this via startIframeTest + // (cf. iframeTest.js) + window.iframeCallback = function() { + var args = Array.prototype.slice.call( arguments ); + + args.unshift( assert ); + + setTimeout( function() { + var result; + + this.iframeCallback = undefined; + + result = func.apply( this, args ); + + function finish() { + func = function() {}; + $iframe.remove(); + done(); + } + + // Wait for promises returned by `func`. + if ( result && result.then ) { + result.then( finish ); + } else { + finish(); + } + } ); + }; + + // Attach iframe to the body for visibility-dependent code. + // It will be removed by either the above code, or the testDone + // callback in qunit.js. + $iframe.prependTo( document.body ); + } ); +}; +window.iframeCallback = undefined; + +return exports; + +} ); diff --git a/tests/lib/qunit-assert-domequal.js b/tests/lib/qunit-assert-domequal.js new file mode 100644 index 00000000000..d99ed06de19 --- /dev/null +++ b/tests/lib/qunit-assert-domequal.js @@ -0,0 +1,202 @@ +/* + * Experimental assertion for comparing DOM objects. + * + * Serializes an element and some properties and attributes and its children if any, + * otherwise the text. Then compares the result using deepEqual(). + */ +define( [ + "qunit", + "jquery" +], function( QUnit, $ ) { +"use strict"; + +var domEqual = QUnit.assert.domEqual = function( selector, modifier, message ) { + + var assert = this; + + // Get current state prior to modifier + var expected = extract( assert, selector, message ); + + function done() { + var actual = extract( assert, selector, message ); + assert.pushResult( { + result: QUnit.equiv( actual, expected ), + actual: actual, + expected: expected, + message: message + } ); + } + + // Run modifier (async or sync), then compare state via done() + if ( modifier.length ) { + modifier( done ); + } else { + modifier(); + done(); + } +}; + +domEqual.properties = [ + "disabled", + "nodeName", + "readOnly" +]; + +domEqual.attributes = [ + "autocomplete", + "aria-activedescendant", + "aria-controls", + "aria-describedby", + "aria-disabled", + "aria-expanded", + "aria-haspopup", + "aria-hidden", + "aria-labelledby", + "aria-pressed", + "aria-selected", + "aria-valuemax", + "aria-valuemin", + "aria-valuenow", + "class", + "href", + "id", + "role", + "tabIndex", + "title" +]; + +function camelCase( string ) { + return string.replace( /-([\da-z])/gi, function( all, letter ) { + return letter.toUpperCase(); + } ); +} + +function getElementStyles( elem ) { + var styles = {}; + var style = elem.ownerDocument.defaultView ? + elem.ownerDocument.defaultView.getComputedStyle( elem, null ) : + elem.currentStyle; + var key, camelKey; + var len = style.length; + + while ( len-- ) { + key = style[ len ]; + camelKey = camelCase( key ); + + if ( typeof style[ key ] === "string" ) { + styles[ camelKey ] = style[ key ]; + } + } + + return styles; +} + +// Returns 0 if v1 == v2, -1 if v1 < v2, 1 if v1 > v2 +function compareVersions( v1, v2 ) { + var i, + rVersionParts = /^(\d+)\.(\d+)\.(\d+)/, + v1p = rVersionParts.exec( v1 ) || [ ], + v2p = rVersionParts.exec( v2 ) || [ ]; + + for ( i = 1; i <= 3; i++ ) { + if ( +v1p[ i ] > +v2p[ i ] ) { + return 1; + } + if ( +v1p[ i ] < +v2p[ i ] ) { + return -1; + } + } + return 0; +} + +function jQueryVersionSince( version ) { + return compareVersions( $.fn.jquery, version ) >= 0; +} + +function extract( assert, selector, message ) { + var elem = $( selector ); + if ( !elem.length ) { + assert.pushResult( { + result: false, + actual: null, + expected: null, + message: "domEqual failed, can't extract " + selector + ", message was: " + message + } ); + return; + } + + var result = {}; + var children; + $.each( domEqual.properties, function( index, attr ) { + var value = elem.prop( attr ); + result[ attr ] = value != null ? value : ""; + } ); + $.each( domEqual.attributes, function( index, attr ) { + var value = elem.attr( attr ); + result[ attr ] = value != null ? value : ""; + } ); + result.style = getElementStyles( elem[ 0 ] ); + result.events = $._data( elem[ 0 ], "events" ); + + // jQuery >=3.4.0 uses a special focus/blur handler pair + // needed to fix various issues with checkboxes/radio buttons + // as well as being able to pass data in focus triggers. + // However, this leaves dummy focus & blur events if any of these + // events were ever listened to at a particular element. There's not + // a lot UI can do to fix this so just skip these handlers for + // data comparisons in tests. + // See https://github.com/jquery/jquery/issues/4496 + if ( result.events && jQueryVersionSince( "3.4.0" ) ) { + $.each( [ "focus", "blur" ], function( index, eventType ) { + if ( !result.events[ eventType ] ) { + return; + } + + // Filter special jQuery focus-related handlers out. + result.events[ eventType ] = result.events[ eventType ] + .filter( function( eventData ) { + var handlerBody = eventData.handler.toString().replace( + /^[^{]+\{[\s\n]*((?:.|\n)*?)\s*;?\s*\}[^}]*$/, + "$1" + ); + + // Only these special jQuery internal handlers + // have the `namespace` field set to `false`; + // all other events use a string value, possibly + // an empty string if no namespace was set. + return eventData.namespace !== false && + + // If a focus event was triggered without adding a handler first, + // jQuery attaches an empty handler at the beginning of a trigger + // call. Ignore this handler as well; it's a function with just + // `return true;` in the body. + // Handle the minified version as well. + handlerBody !== "return true" && handlerBody !== "return!0"; + } ); + + // Remove empty eventData collections to follow jQuery behavior. + if ( !result.events[ eventType ].length ) { + delete result.events[ eventType ]; + } + } ); + + // Simulate empty events collections removal to follow jQuery behavior. + if ( !Object.keys( result.events ).length ) { + result.events = undefined; + } + } + + result.data = $.extend( {}, elem.data() ); + delete result.data[ $.expando ]; + children = elem.children(); + if ( children.length ) { + result.children = elem.children().map( function() { + return extract( assert, $( this ) ); + } ).get(); + } else { + result.text = elem.text(); + } + return result; +} + +} ); diff --git a/tests/lib/qunit.js b/tests/lib/qunit.js new file mode 100644 index 00000000000..c4c96ef5823 --- /dev/null +++ b/tests/lib/qunit.js @@ -0,0 +1,57 @@ +define( [ + "qunit", + "jquery", + "qunit-assert-classes", + "qunit-assert-close", + "lib/qunit-assert-domequal" +], function( QUnit, $ ) { +"use strict"; + +var ajaxSettings = $.ajaxSettings; + +QUnit.config.autostart = false; +QUnit.config.requireExpects = true; + +QUnit.config.urlConfig.push( { + id: "jquery", + label: "jQuery version", + value: [ + "1.12.4", + "2.2.4", + "3.0.0", + "3.1.0", "3.1.1", + "3.2.0", "3.2.1", + "3.3.0", "3.3.1", + "3.4.0", "3.4.1", + "3.5.0", "3.5.1", + "3.6.0", "3.6.1", "3.6.2", "3.6.3", "3.6.4", + "3.7.0", "3.7.1", + "3.x-git", "git", "custom" + ], + tooltip: "Which jQuery Core version to test against" +} ); + +QUnit.config.urlConfig.push( { + id: "migrate", + label: "Enable jquery-migrate" +} ); + +QUnit.testDone( function() { + + // Ensure jQuery events and data on the fixture are properly removed + $( "#qunit-fixture" ).empty(); + + // Remove the iframe fixture + $( "#qunit-fixture-iframe" ).remove(); + + // Reset internal $ state + if ( ajaxSettings ) { + $.ajaxSettings = $.extend( true, {}, ajaxSettings ); + } else { + delete $.ajaxSettings; + } +} ); + +return QUnit; + +} ); diff --git a/tests/lib/testIframe.js b/tests/lib/testIframe.js new file mode 100644 index 00000000000..4db56833c5f --- /dev/null +++ b/tests/lib/testIframe.js @@ -0,0 +1,7 @@ +window.startIframeTest = function() { + var args = Array.prototype.slice.call( arguments ); + + // Note: jQuery may be undefined if page did not load it + args.unshift( window.jQuery, window, document ); + window.parent.iframeCallback.apply( null, args ); +}; diff --git a/tests/lib/vendor/qunit-assert-classes/LICENSE.txt b/tests/lib/vendor/qunit-assert-classes/LICENSE.txt new file mode 100644 index 00000000000..938db036815 --- /dev/null +++ b/tests/lib/vendor/qunit-assert-classes/LICENSE.txt @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2015 Alexander Schmitz + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/tests/lib/vendor/qunit-assert-classes/qunit-assert-classes.js b/tests/lib/vendor/qunit-assert-classes/qunit-assert-classes.js new file mode 100644 index 00000000000..3461f1d906a --- /dev/null +++ b/tests/lib/vendor/qunit-assert-classes/qunit-assert-classes.js @@ -0,0 +1,245 @@ +// With custom modifications - all are marked with +// a "Custom modification" comment. +( function( factory ) { + if ( typeof define === "function" && define.amd ) { + + // AMD. Register as an anonymous module. + define( [ + "qunit" + ], factory ); + } else { + + // Browser globals + factory( QUnit ); + } +}( function( QUnit ) { + + function inArray( haystack, needle ) { + for ( var i = 0; i < haystack.length; i++ ) { + if ( + ( needle instanceof RegExp && needle.test( haystack[ i ] ) )|| + ( typeof needle === "string" && haystack[ i ] === needle ) + ) { + return true; + } + } + return false; + } + + function check( element, search ) { + var i, classAttribute, elementClassArray, + missing = [], + found = []; + + if ( element.jquery && element.length !== 1 ) { + throw new Error( "Class checks can only be performed on a single element on a collection" ); + } + + element = element.jquery ? element[ 0 ] : element; + classAttribute = element.getAttribute( "class" ); + + if ( classAttribute ) { + elementClassArray = splitClasses( classAttribute ); + if ( search instanceof RegExp ) { + if ( inArray( elementClassArray, search ) ) { + found.push( search ); + } else { + missing.push( search ); + } + } else { + for( i = 0; i < search.length; i++ ) { + if ( !inArray( elementClassArray, search[ i ] ) ) { + missing.push( search[ i ] ); + } else { + found.push( search[ i ] ); + } + } + } + } else { + missing = search; + } + + return { + missing: missing, + found: found, + element: element, + classAttribute: classAttribute + }; + } + + function splitClasses( classes ) { + return classes.match( /\S+/g ) || []; + } + + function pluralize( message, classes ) { + return message + ( classes.length > 1 ? "es" : "" ); + } + + // Custom modification: removing QUnit.extend + var key; + var qunitAssertExtensions = { + hasClasses: function( element, classes, message ) { + var classArray = splitClasses( classes ), + results = check( element, classArray ); + + message = message || pluralize( "Element must have class", classArray ); + + // Custom modification: push -> pushResult + this.pushResult( { + result: !results.missing.length, + actual: results.found.join( " " ), + expected: classes, + message: message + } ); + }, + lacksClasses: function( element, classes, message ) { + var classArray = splitClasses( classes ), + results = check( element, classArray ); + + message = message || pluralize( "Element must not have class", classArray ); + + // Custom modification: push -> pushResult + this.pushResult( { + result: !results.found.length, + actual: results.found.join( " " ), + expected: classes, + message: message + } ); + }, + hasClassesStrict: function( element, classes, message ) { + var result, + classArray = splitClasses( classes ), + results = check( element, classArray ); + + message = message || pluralize( "Element must only have class", classArray ); + + result = !results.missing.length && results.element.getAttribute( "class" ) && + splitClasses( results.element.getAttribute( "class" ) ).length === + results.found.length; + + // Custom modification: push -> pushResult + this.pushResult( { + result: result, + actual: results.found.join( " " ), + expected: classes, + message: message + } ); + }, + hasClassRegex: function( element, regex, message ) { + var results = check( element, regex ); + + message = message || "Element must have class matching " + regex; + + // Custom modification: push -> pushResult + this.pushResult( { + result: !!results.found.length, + actual: results.found.join( " " ), + expected: regex, + message: message + } ); + }, + lacksClassRegex: function( element, regex, message ) { + var results = check( element, regex ); + + message = message || "Element must not have class matching " + regex; + + // Custom modification: push -> pushResult + this.pushResult( { + result: results.missing.length, + actual: results.missing.join( " " ), + expected: regex, + message: message + } ); + }, + hasClassStart: function( element, partialClass, message ) { + var results = check( element, new RegExp( "^" + partialClass ) ); + + message = message || "Element must have class starting with " + partialClass; + + // Custom modification: push -> pushResult + this.pushResult( { + result: results.found.length, + actual: results.found.join( " " ), + expected: partialClass, + message: message + } ); + }, + lacksClassStart: function( element, partialClass, message ) { + var results = check( element, new RegExp( "^" + partialClass ) ); + + message = message || "Element must not have class starting with " + partialClass; + + // Custom modification: push -> pushResult + this.pushResult( { + result: results.missing.length, + actual: results.missing.join( " " ), + expected: partialClass, + message: message + } ); + }, + hasClassPartial: function( element, partialClass, message ) { + var results = check( element, new RegExp( partialClass ) ); + + message = message || "Element must have class containing '" + partialClass + "'"; + + // Custom modification: push -> pushResult + this.pushResult( { + result: results.found.length, + actual: results.found.join( " " ), + expected: partialClass, + message: message + } ); + }, + lacksClassPartial: function( element, partialClass, message ) { + var results = check( element, new RegExp( partialClass ) ); + + message = message || "Element must not have class containing '" + partialClass + "'"; + + // Custom modification: push -> pushResult + this.pushResult( { + result: results.missing.length, + actual: results.missing.join( " " ), + expected: partialClass, + message: message + } ); + }, + lacksAllClasses: function( element, message ) { + element = element.jquery ? element[ 0 ] : element; + + var classAttribute = element.getAttribute( "class" ) || "", + classes = splitClasses( classAttribute ); + + message = message || "Element must not have any classes"; + + // Custom modification: push -> pushResult + this.pushResult( { + result: !classes.length, + actual: !classes.length, + expected: true, + message: message + } ); + }, + hasSomeClass: function( element, message ) { + element = element.jquery ? element[ 0 ] : element; + + var classAttribute = element.getAttribute( "class" ) || "", + classes = splitClasses( classAttribute ); + + message = message || "Element must have a class"; + + // Custom modification: push -> pushResult + this.pushResult( { + result: classes.length, + actual: classes.length, + expected: true, + message: message + } ); + } + }; + + // Custom modification: removing QUnit.extend + for ( key in qunitAssertExtensions ) { + QUnit.assert[ key ] = qunitAssertExtensions[ key ]; + } + +} ) ); diff --git a/tests/lib/vendor/qunit-assert-close/MIT-LICENSE.txt b/tests/lib/vendor/qunit-assert-close/MIT-LICENSE.txt new file mode 100644 index 00000000000..aed5dc97ec5 --- /dev/null +++ b/tests/lib/vendor/qunit-assert-close/MIT-LICENSE.txt @@ -0,0 +1,21 @@ +Copyright jQuery Foundation and other contributors +http://jquery.com/ + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/tests/lib/vendor/qunit-assert-close/qunit-assert-close.js b/tests/lib/vendor/qunit-assert-close/qunit-assert-close.js new file mode 100644 index 00000000000..69d40520562 --- /dev/null +++ b/tests/lib/vendor/qunit-assert-close/qunit-assert-close.js @@ -0,0 +1,209 @@ +// With custom modifications - all are marked with +// a "Custom modification" comment. +(function(factory) { + + // NOTE: + // All techniques except for the "browser globals" fallback will extend the + // provided QUnit object but return the isolated API methods + + // For AMD: Register as an anonymous AMD module with a named dependency on "qunit". + if (typeof define === "function" && define.amd) { + define(["qunit"], factory); + } + // For Node.js + else if (typeof module !== "undefined" && module && module.exports && typeof require === "function") { + module.exports = factory(require("qunitjs")); + } + + // Custom modification: remove the non-Node.js CommonJS part due to its + // usage of QUnit.extend. + // + // For browser globals + else { + factory(QUnit); + } + +}(function(QUnit) { + + /** + * Find an appropriate `Assert` context to `push` results to. + * @param * context - An unknown context, possibly `Assert`, `Test`, or neither + * @private + */ + function _getPushContext(context) { + var pushContext; + + if (context && typeof context.push === "function") { + // `context` is an `Assert` context + pushContext = context; + } + else if (context && context.assert && typeof context.assert.push === "function") { + // `context` is a `Test` context + pushContext = context.assert; + } + else if ( + QUnit && QUnit.config && QUnit.config.current && QUnit.config.current.assert && + typeof QUnit.config.current.assert.push === "function" + ) { + // `context` is an unknown context but we can find the `Assert` context via QUnit + pushContext = QUnit.config.current.assert; + } + else if (QUnit && typeof QUnit.push === "function") { + pushContext = QUnit.push; + } + else { + throw new Error("Could not find the QUnit `Assert` context to push results"); + } + + return pushContext; + } + + /** + * Checks that the first two arguments are equal, or are numbers close enough to be considered equal + * based on a specified maximum allowable difference. + * + * @example assert.close(3.141, Math.PI, 0.001); + * + * @param Number actual + * @param Number expected + * @param Number maxDifference (the maximum inclusive difference allowed between the actual and expected numbers) + * @param String message (optional) + */ + function close(actual, expected, maxDifference, message) { + var actualDiff = (actual === expected) ? 0 : Math.abs(actual - expected), + result = actualDiff <= maxDifference, + pushContext = _getPushContext(this); + + message = message || (actual + " should be within " + maxDifference + " (inclusive) of " + expected + (result ? "" : ". Actual: " + actualDiff)); + + // Custom modification: push -> pushResult + pushContext.pushResult({ + result: result, + actual: actual, + expected: expected, + message: message + }); + } + + + /** + * Checks that the first two arguments are equal, or are numbers close enough to be considered equal + * based on a specified maximum allowable difference percentage. + * + * @example assert.close.percent(155, 150, 3.4); // Difference is ~3.33% + * + * @param Number actual + * @param Number expected + * @param Number maxPercentDifference (the maximum inclusive difference percentage allowed between the actual and expected numbers) + * @param String message (optional) + */ + close.percent = function closePercent(actual, expected, maxPercentDifference, message) { + var actualDiff, result, + pushContext = _getPushContext(this); + + if (actual === expected) { + actualDiff = 0; + result = actualDiff <= maxPercentDifference; + } + else if (actual !== 0 && expected !== 0 && expected !== Infinity && expected !== -Infinity) { + actualDiff = Math.abs(100 * (actual - expected) / expected); + result = actualDiff <= maxPercentDifference; + } + else { + // Dividing by zero (0)! Should return `false` unless the max percentage was `Infinity` + actualDiff = Infinity; + result = maxPercentDifference === Infinity; + } + message = message || (actual + " should be within " + maxPercentDifference + "% (inclusive) of " + expected + (result ? "" : ". Actual: " + actualDiff + "%")); + + // Custom modification: push -> pushResult + pushContext.pushResult({ + result: result, + actual: actual, + expected: expected, + message: message + }); + }; + + + /** + * Checks that the first two arguments are numbers with differences greater than the specified + * minimum difference. + * + * @example assert.notClose(3.1, Math.PI, 0.001); + * + * @param Number actual + * @param Number expected + * @param Number minDifference (the minimum exclusive difference allowed between the actual and expected numbers) + * @param String message (optional) + */ + function notClose(actual, expected, minDifference, message) { + var actualDiff = Math.abs(actual - expected), + result = actualDiff > minDifference, + pushContext = _getPushContext(this); + + message = message || (actual + " should not be within " + minDifference + " (exclusive) of " + expected + (result ? "" : ". Actual: " + actualDiff)); + + // Custom modification: push -> pushResult + pushContext.pushResult({ + result: result, + actual: actual, + expected: expected, + message: message + }); + } + + + /** + * Checks that the first two arguments are numbers with differences greater than the specified + * minimum difference percentage. + * + * @example assert.notClose.percent(156, 150, 3.5); // Difference is 4.0% + * + * @param Number actual + * @param Number expected + * @param Number minPercentDifference (the minimum exclusive difference percentage allowed between the actual and expected numbers) + * @param String message (optional) + */ + notClose.percent = function notClosePercent(actual, expected, minPercentDifference, message) { + var actualDiff, result, + pushContext = _getPushContext(this); + + if (actual === expected) { + actualDiff = 0; + result = actualDiff > minPercentDifference; + } + else if (actual !== 0 && expected !== 0 && expected !== Infinity && expected !== -Infinity) { + actualDiff = Math.abs(100 * (actual - expected) / expected); + result = actualDiff > minPercentDifference; + } + else { + // Dividing by zero (0)! Should only return `true` if the min percentage was `Infinity` + actualDiff = Infinity; + result = minPercentDifference !== Infinity; + } + message = message || (actual + " should not be within " + minPercentDifference + "% (exclusive) of " + expected + (result ? "" : ". Actual: " + actualDiff + "%")); + + // Custom modification: push -> pushResult + pushContext.pushResult({ + result: result, + actual: actual, + expected: expected, + message: message + }); + }; + + var key; + var api = { + close: close, + notClose: notClose, + closePercent: close.percent, + notClosePercent: notClose.percent + }; + + for (key in api) { + QUnit.assert[key] = api[key]; + } + + return api; +})); diff --git a/tests/lib/vendor/qunit-composite/LICENSE.txt b/tests/lib/vendor/qunit-composite/LICENSE.txt new file mode 100644 index 00000000000..155d8e86916 --- /dev/null +++ b/tests/lib/vendor/qunit-composite/LICENSE.txt @@ -0,0 +1,36 @@ +Copyright jQuery Foundation and other contributors, https://jquery.org/ + +This software consists of voluntary contributions made by many +individuals. For exact contribution history, see the revision history +available at https://github.com/JamesMGreene/qunit-composite + +The following license applies to all parts of this software except as +documented below: + +==== + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +==== + +All files located in the node_modules directory are externally +maintained libraries used by this software which have their own +licenses; we recommend you read them, as their terms may differ from the +terms above. diff --git a/tests/lib/vendor/qunit-composite/qunit-composite.css b/tests/lib/vendor/qunit-composite/qunit-composite.css new file mode 100644 index 00000000000..a5d06ce7713 --- /dev/null +++ b/tests/lib/vendor/qunit-composite/qunit-composite.css @@ -0,0 +1,47 @@ +.qunit-composite-suite { + position: fixed; + bottom: 0; + left: 0; + + margin: 0; + padding: 0; + border-width: 1px 0 0; + height: 45%; + width: 100%; + + background: #fff; +} + +#qunit-testsuites { + margin: 0; + padding: 0.5em 1.0em; + font-family: "Helvetica Neue Light","HelveticaNeue-Light","Helvetica Neue",Calibri,Helvetica,Arial,sans-serif; + font-size: small; + background-color: #d2e0e6; + border-bottom: 1px solid #fff; +} + +#qunit-testsuites a { + color: #00c; + text-decoration: none; +} + +#qunit-testsuites a:hover { + text-decoration: underline; +} + +#qunit-testsuites > li { + display: inline-block; +} + +#qunit-testsuites > li:first-child::before { + content: "Suites: "; +} + +#qunit-testsuites > li + li::before { + content: "|\a0"; +} + +#qunit-testsuites > li::after { + content: "\a0"; +} diff --git a/tests/lib/vendor/qunit-composite/qunit-composite.js b/tests/lib/vendor/qunit-composite/qunit-composite.js new file mode 100644 index 00000000000..b3c2b749d1e --- /dev/null +++ b/tests/lib/vendor/qunit-composite/qunit-composite.js @@ -0,0 +1,233 @@ +/** + * QUnit Composite + * + * With custom modifications - all are marked with + * a "Custom modification" comment. + * + * https://github.com/JamesMGreene/qunit-composite + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license. + * https://jquery.org/license/ + */ +(function( factory ) { + if ( typeof define === "function" && define.amd ) { + define( [ "qunit" ], factory ); + } else { + factory( QUnit ); + } +}(function( QUnit ) { +var iframe, hasBound, resumeTests, suiteAssert, + modules = 1, + executingComposite = false; + +function hasClass( elem, name ) { + return ( " " + elem.className + " " ).indexOf( " " + name + " " ) > -1; +} + +function addClass( elem, name ) { + if ( !hasClass( elem, name ) ) { + elem.className += ( elem.className ? " " : "" ) + name; + } +} + +function addEvent( elem, type, fn ) { + if ( elem.addEventListener ) { + // Standards-based browsers + elem.addEventListener( type, fn, false ); + } +} + +function runSuite( suite ) { + var path; + + if ( QUnit.is( "object", suite ) ) { + path = suite.path; + suite = suite.name; + } else { + path = suite; + } + + QUnit.test( suite, function( assert ) { + resumeTests = assert.async(); + suiteAssert = assert; + iframe.setAttribute( "src", path ); + // QUnit.start is called from the child iframe's QUnit.done hook. + }); +} + +function initIframe() { + var iframeWin, + body = document.body; + + function onIframeLoad() { + var moduleName, testName, + count = 0; + + if ( !iframe.src ) { + return; + } + + // Deal with QUnit being loaded asynchronously via AMD + if ( !iframeWin.QUnit && iframeWin.define && iframeWin.define.amd ) { + return iframeWin.require( [ "qunit" ], onIframeLoad ); + } + + iframeWin.QUnit.moduleStart(function( data ) { + // Capture module name for messages + moduleName = data.name; + }); + + iframeWin.QUnit.testStart(function( data ) { + // Capture test name for messages + testName = data.name; + }); + iframeWin.QUnit.testDone(function() { + testName = undefined; + }); + + iframeWin.QUnit.log(function( data ) { + if (testName === undefined) { + return; + } + // Pass all test details through to the main page + var message = ( moduleName ? moduleName + ": " : "" ) + testName + ": " + ( data.message || ( data.result ? "okay" : "failed" ) ); + suiteAssert.expect( ++count ); + suiteAssert.pushResult( { + result: data.result, + actual: data.actual, + expected: data.expected, + message: message + } ); + }); + + // Continue the outer test when the iframe's test is done + iframeWin.QUnit.done(function() { + resumeTests(); + }); + } + + iframe = document.createElement( "iframe" ); + iframe.className = "qunit-composite-suite"; + body.appendChild( iframe ); + + addEvent( iframe, "load", onIframeLoad ); + + iframeWin = iframe.contentWindow; +} + +function appendSuitesToHeader( suites ) { + var i, suitesLen, suite, path, name, suitesEl, testResultEl, + newSuiteListItemEl, newSuiteLinkEl; + + suitesEl = document.getElementById("qunit-testsuites"); + + if (!suitesEl) { + testResultEl = document.getElementById("qunit-testresult"); + + if (!testResultEl) { + // QUnit has not been set up yet. Defer until QUnit is ready. + QUnit.begin(function () { + appendSuitesToHeader(suites); + }); + return; + } + + suitesEl = document.createElement("ul"); + suitesEl.id = "qunit-testsuites"; + testResultEl.parentNode.insertBefore(suitesEl, testResultEl); + } + + for (i = 0, suitesLen = suites.length; i < suitesLen; ++i) { + suite = suites[i]; + newSuiteLinkEl = document.createElement("a"); + newSuiteLinkEl.innerHTML = suite.name || suite; + newSuiteLinkEl.href = suite.path || suite; + + newSuiteListItemEl = document.createElement("li"); + newSuiteListItemEl.appendChild(newSuiteLinkEl); + + suitesEl.appendChild(newSuiteListItemEl); + } +} + +/** + * @param {string} [name] Module name to group these test suites. + * @param {Array} suites List of suites where each suite + * may either be a string (path to the html test page), + * or an object with a path and name property. + */ +QUnit.testSuites = function( name, suites ) { + var i, suitesLen; + + if ( arguments.length === 1 ) { + suites = name; + name = "Composition #" + modules++; + } + suitesLen = suites.length; + + appendSuitesToHeader(suites); + + if ( !hasBound ) { + hasBound = true; + QUnit.begin( initIframe ); + + // TODO: Would be better to use something like QUnit.once( 'moduleDone' ) + // after the last test suite. + QUnit.moduleDone( function () { + executingComposite = false; + } ); + + QUnit.done(function() { + iframe.style.display = "none"; + }); + } + + QUnit.module( name, { + beforeEach: function () { + executingComposite = true; + } + }); + + for ( i = 0; i < suitesLen; i++ ) { + runSuite( suites[ i ] ); + } +}; + +QUnit.testDone(function( data ) { + if ( !executingComposite ) { + return; + } + + var i, len, + testId = data.testId, + current = document.getElementById( "qunit-test-output-" + testId ), + children = current && current.children, + src = iframe.src; + + if (!(current && children)) { + return; + } + + addEvent( current, "dblclick", function( e ) { + var target = e && e.target ? e.target : window.event.srcElement; + if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) { + target = target.parentNode; + } + if ( window.location && target.nodeName.toLowerCase() === "strong" ) { + window.location = src; + } + }); + + // Undo QUnit's auto-expansion for bad tests + for ( i = 0, len = children.length; i < len; i++ ) { + if ( children[ i ].nodeName.toLowerCase() === "ol" ) { + addClass( children[ i ], "qunit-collapsed" ); + } + } + + // Update Rerun link to point to the standalone test suite page + current.getElementsByTagName( "a" )[ 0 ].href = src; +}); + +})); diff --git a/tests/static/accordion/default.html b/tests/static/accordion/default.html deleted file mode 100644 index d66463e23d6..00000000000 --- a/tests/static/accordion/default.html +++ /dev/null @@ -1,39 +0,0 @@ - - - - - Accordion Static Test : Default - - - - - - - - -
      -

      - - Accordion Header 1 -

      -
      - Accordion Content 1 -
      -

      - - Accordion Header 2 -

      - -

      - - Accordion Header 3 -

      - -
      - - - diff --git a/tests/static/accordion/dl.html b/tests/static/accordion/dl.html deleted file mode 100644 index b42ad57a587..00000000000 --- a/tests/static/accordion/dl.html +++ /dev/null @@ -1,39 +0,0 @@ - - - - - Accordion Static Test : DL - - - - - - - - -
      -
      - - Accordion Header 1 -
      -
      - Accordion Content 1 -
      -
      - - Accordion Header 2 -
      -
      - Accordion Content 2 -
      -
      - - Accordion Header 3 -
      -
      - Accordion Content 2 -
      -
      - - - diff --git a/tests/static/accordion/ul.html b/tests/static/accordion/ul.html deleted file mode 100644 index c107d21aab3..00000000000 --- a/tests/static/accordion/ul.html +++ /dev/null @@ -1,49 +0,0 @@ - - - - - Accordion Static Test : UL - - - - - - - - - - - - diff --git a/tests/static/button/default.html b/tests/static/button/default.html deleted file mode 100644 index e0e0050907e..00000000000 --- a/tests/static/button/default.html +++ /dev/null @@ -1,161 +0,0 @@ - - - - - Button Static Test : Default - - - - - - - - - -

      Using button elements

      - -
      - - - - - - - - - - - - - -
      - -

      Using anchor elements

      - - - - - -

      Using label elements (used when proxying to radio or check inputs)

      - -
      - - - - - - - - - - - - - -
      - - -

      Button Sets

      - -
      - - - - -
      - - - - - - - diff --git a/tests/static/datepicker/datepicker.html b/tests/static/datepicker/datepicker.html deleted file mode 100644 index 5feaa6eac69..00000000000 --- a/tests/static/datepicker/datepicker.html +++ /dev/null @@ -1,1367 +0,0 @@ - - - - - jQuery UI Datepicker Static Markup Test Page - - - - - - - - - - -
      -
      - Prev - Next -
      - December - 2008 -
      -
      -
      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      SuMoTuWeThFrSa
      123456
      78910111213
      14151617181920
      21222324252627
      28293031
      - - - -
      -
      - Prev - Next -
      - -
      -
      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      SuMoTuWeThFrSa
      123456
      78910111213
      14151617181920
      21222324252627
      28293031
      -
      - - -
      -
      - Prev - Next -
      - - -
      -
      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      SuMoTuWeThFrSa
      123456
      78910111213
      14151617181920
      21222324252627
      28293031
      -
      - - -
      -
      - Prev - Next -
      - - -
      -
      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      SuMoTuWeThFrSa
      123456
      78910111213
      14151617181920
      21222324252627
      28293031
      -
      - - -
      -
      - - -
      -
      -
      - Prev -
      - December - 2008 -
      -
      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      SuMoTuWeThFrSa
      - 123456
      78910111213
      14151617181920
      21222324252627
      28293031 - - -
      -
      -
      -
      - Next -
      - January - 2009 -
      -
      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      SuMoTuWeThFrSa
      - 123456
      78910111213
      14151617181920
      21222324252627
      28293031 - - -
      -
      -
      - - -
      -
      -
      - Prev -
      - December - 2008 -
      -
      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      SuMoTuWeThFrSa
      - 123456
      78910111213
      14151617181920
      21222324252627
      28293031 - - -
      -
      -
      -
      -
      - January - 2009 -
      -
      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      SuMoTuWeThFrSa
      - 123456
      78910111213
      14151617181920
      21222324252627
      28293031 - - -
      -
      -
      -
      - Next -
      - February - 2009 -
      -
      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      SuMoTuWeThFrSa
      - 123456
      78910111213
      14151617181920
      21222324252627
      28293031 - - -
      -
      -
      - - -
      -
      - - -
      -
      -
      - Prev -
      - December - 2008 -
      -
      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      SuMoTuWeThFrSa
      - 123456
      78910111213
      14151617181920
      21222324252627
      28293031 - - -
      -
      -
      -
      -
      - January - 2009 -
      -
      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      SuMoTuWeThFrSa
      1
      2345678
      9101112131415
      16171819202122
      23242526272829
      3031
      -
      -
      -
      -
      - February - 2009 -
      -
      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      SuMoTuWeThFrSa
      - 123456
      78910111213
      14151617181920
      21222324252627
      28293031 - - -
      -
      -
      -
      - Next -
      - March - 2009 -
      -
      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      SuMoTuWeThFrSa
      - 123456
      78910111213
      14151617181920
      21222324252627
      28293031 - - -
      -
      - -
      -
      -
      -
      - April - 2009 -
      -
      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      SuMoTuWeThFrSa
      - 123456
      78910111213
      14151617181920
      21222324252627
      28293031 - - -
      -
      -
      -
      -
      - May - 2009 -
      -
      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      SuMoTuWeThFrSa
      - 123456
      78910111213
      14151617181920
      21222324252627
      28293031 - - -
      -
      -
      -
      -
      - June - 2009 -
      -
      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      SuMoTuWeThFrSa
      - 123456
      78910111213
      14151617181920
      21222324252627
      28293031 - - -
      -
      -
      -
      -
      - July - 2009 -
      -
      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      SuMoTuWeThFrSa
      1
      2345678
      9101112131415
      16171819202122
      23242526272829
      3031
      -
      -
      - - - diff --git a/tests/static/datepicker/default.html b/tests/static/datepicker/default.html deleted file mode 100644 index 09ed399f2ac..00000000000 --- a/tests/static/datepicker/default.html +++ /dev/null @@ -1,86 +0,0 @@ - - - - - Datepicker Static Test : Default - - - - - - - - -
      -
      - Prev - Next -
      - December - 2008 -
      -
      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      SuMoTuWeThFrSa
      - 123456
      78910111213
      14151617181920
      21222324252627
      28293031 - - -
      -
      - - - diff --git a/tests/static/dialog/default.html b/tests/static/dialog/default.html deleted file mode 100644 index 8c2b9f26ea8..00000000000 --- a/tests/static/dialog/default.html +++ /dev/null @@ -1,33 +0,0 @@ - - - - - Dialog Static Test : Default - - - - - - - - - - - - diff --git a/tests/static/dialog/dialog.html b/tests/static/dialog/dialog.html deleted file mode 100644 index b0a8acae665..00000000000 --- a/tests/static/dialog/dialog.html +++ /dev/null @@ -1,38 +0,0 @@ - - - - - jQuery UI Dialog Static Markup Test Page - - - - - - - - - - - - diff --git a/tests/static/draggable/default.html b/tests/static/draggable/default.html deleted file mode 100644 index 49ea5d13cec..00000000000 --- a/tests/static/draggable/default.html +++ /dev/null @@ -1,17 +0,0 @@ - - - - - Draggable Static Test : Default - - - - - - - - -

      Draggable

      - - - diff --git a/tests/static/droppable/default.html b/tests/static/droppable/default.html deleted file mode 100644 index 6ac14c45880..00000000000 --- a/tests/static/droppable/default.html +++ /dev/null @@ -1,17 +0,0 @@ - - - - - Droppable Static Test : Default - - - - - - - - -

      Droppable

      - - - diff --git a/tests/static/highlight_error.html b/tests/static/highlight_error.html deleted file mode 100644 index f93d7fe7454..00000000000 --- a/tests/static/highlight_error.html +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - Themeroller CSS Framework Demo - - - - - - - - -
      -
      -

      - Alert: Sample ui-state-error style.

      -
      - - -
      -

      - Tip! Sample ui-state-highlight style.

      -
      -
      - - diff --git a/tests/static/icons.html b/tests/static/icons.html deleted file mode 100644 index 1917aa275c4..00000000000 --- a/tests/static/icons.html +++ /dev/null @@ -1,246 +0,0 @@ - - - - - jQuery UI CSS Framework Icons Test Page - - - - - - - - - - -

      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      - - - diff --git a/tests/static/index.html b/tests/static/index.html deleted file mode 100644 index ae37825fdf1..00000000000 --- a/tests/static/index.html +++ /dev/null @@ -1,41 +0,0 @@ - - - - - jQuery UI Static Tests - - - - - - - -

      jQuery UI Static Tests

      - -

      Interactions

      - - -

      Widgets

      - - - - diff --git a/tests/static/menu/all-menus-icons.html b/tests/static/menu/all-menus-icons.html deleted file mode 100644 index b23ab0072f5..00000000000 --- a/tests/static/menu/all-menus-icons.html +++ /dev/null @@ -1,172 +0,0 @@ - - - - - Menu Static Test : Default - - - - - - - - - - - - - - - - -
      - - - - - -

      Default

      - - - -

      - -
      - -

      Drilldown

      - - - -
      - -

      - -
      - -

      Flyout / nested

      - - - -
      - - - - diff --git a/tests/static/menu/default.html b/tests/static/menu/default.html deleted file mode 100644 index 1d7cc991901..00000000000 --- a/tests/static/menu/default.html +++ /dev/null @@ -1,39 +0,0 @@ - - - - - Menu Static Test : Default - - - - - - - - - - - - - - diff --git a/tests/static/overlay.html b/tests/static/overlay.html deleted file mode 100644 index 87ccd9668e6..00000000000 --- a/tests/static/overlay.html +++ /dev/null @@ -1,71 +0,0 @@ - - - - - jQuery UI Dialog Static Markup Test Page - - - - - - - - - - - - -
      -
      - Dialog Title - Close -
      -
      -

      Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

      -
      -
      - - - -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      - - - diff --git a/tests/static/progressbar/default.html b/tests/static/progressbar/default.html deleted file mode 100644 index 118a210728d..00000000000 --- a/tests/static/progressbar/default.html +++ /dev/null @@ -1,19 +0,0 @@ - - - - - Progressbar Static Test : Default - - - - - - - - -
      -
      -
      - - - diff --git a/tests/static/progressbar/progressbar.html b/tests/static/progressbar/progressbar.html deleted file mode 100644 index 8c4d65e18b2..00000000000 --- a/tests/static/progressbar/progressbar.html +++ /dev/null @@ -1,19 +0,0 @@ - - - - - jQuery UI Progressbar Static Markup Test Page - - - - - - - - -
      -
      -
      - - - diff --git a/tests/static/resizable/default.html b/tests/static/resizable/default.html deleted file mode 100644 index 1b37e2994b8..00000000000 --- a/tests/static/resizable/default.html +++ /dev/null @@ -1,24 +0,0 @@ - - - - - Resizable Static Test : Default - - - - - - - - -
      -

      - Resizable -

      -
      -
      -
      -
      - - - diff --git a/tests/static/selectable/default.html b/tests/static/selectable/default.html deleted file mode 100644 index 1feee55678b..00000000000 --- a/tests/static/selectable/default.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - Selectable Static Test : Default - - - - - - - - -
      -
      Selectable 1
      -
      Selectable 2
      -
      Selectable 3
      -
      - - - diff --git a/tests/static/slider/default.html b/tests/static/slider/default.html deleted file mode 100644 index 71270035a4e..00000000000 --- a/tests/static/slider/default.html +++ /dev/null @@ -1,17 +0,0 @@ - - - - - Slider Static Test : Default - - - - - - - - -
      - - - diff --git a/tests/static/slider/default_vertical.html b/tests/static/slider/default_vertical.html deleted file mode 100644 index bf4ca01b5ee..00000000000 --- a/tests/static/slider/default_vertical.html +++ /dev/null @@ -1,17 +0,0 @@ - - - - - Slider Static Test : Default vertical - - - - - - - - -
      - - - diff --git a/tests/static/slider/slider_horizontal.html b/tests/static/slider/slider_horizontal.html deleted file mode 100644 index e9b2021ade3..00000000000 --- a/tests/static/slider/slider_horizontal.html +++ /dev/null @@ -1,17 +0,0 @@ - - - - - Slider Static Test : Slider horizontal - - - - - - - - -
      - - - diff --git a/tests/static/slider/slider_horizontal_range.html b/tests/static/slider/slider_horizontal_range.html deleted file mode 100644 index 4f5e3216f63..00000000000 --- a/tests/static/slider/slider_horizontal_range.html +++ /dev/null @@ -1,17 +0,0 @@ - - - - - Slider Static Test : Slider horizontal range - - - - - - - - -
      - - - diff --git a/tests/static/slider/slider_horizontal_range_max.html b/tests/static/slider/slider_horizontal_range_max.html deleted file mode 100644 index 6f354a88c45..00000000000 --- a/tests/static/slider/slider_horizontal_range_max.html +++ /dev/null @@ -1,17 +0,0 @@ - - - - - Slider Static Test : Slider horizontal range max - - - - - - - - -
      - - - diff --git a/tests/static/slider/slider_horizontal_range_min.html b/tests/static/slider/slider_horizontal_range_min.html deleted file mode 100644 index 475ed30b3d8..00000000000 --- a/tests/static/slider/slider_horizontal_range_min.html +++ /dev/null @@ -1,17 +0,0 @@ - - - - - Slider Static Test : Slider horizontal range min - - - - - - - - -
      - - - diff --git a/tests/static/slider/slider_vertical.html b/tests/static/slider/slider_vertical.html deleted file mode 100644 index 7453a3a46ee..00000000000 --- a/tests/static/slider/slider_vertical.html +++ /dev/null @@ -1,17 +0,0 @@ - - - - - Slider Static Test : Slider vertical - - - - - - - - -
      - - - diff --git a/tests/static/slider/slider_vertical_range.html b/tests/static/slider/slider_vertical_range.html deleted file mode 100644 index 377806d057e..00000000000 --- a/tests/static/slider/slider_vertical_range.html +++ /dev/null @@ -1,17 +0,0 @@ - - - - - Slider Static Test : Slider vertical range - - - - - - - - -
      - - - diff --git a/tests/static/slider/slider_vertical_range_max.html b/tests/static/slider/slider_vertical_range_max.html deleted file mode 100644 index 29fa4cf17e8..00000000000 --- a/tests/static/slider/slider_vertical_range_max.html +++ /dev/null @@ -1,17 +0,0 @@ - - - - - Slider Static Test : Slider vertical range max - - - - - - - - -
      - - - diff --git a/tests/static/slider/slider_vertical_range_min.html b/tests/static/slider/slider_vertical_range_min.html deleted file mode 100644 index 66c3c4c1328..00000000000 --- a/tests/static/slider/slider_vertical_range_min.html +++ /dev/null @@ -1,17 +0,0 @@ - - - - - Slider Static Test : Slider vertical range min - - - - - - - - -
      - - - diff --git a/tests/static/sortable/default.html b/tests/static/sortable/default.html deleted file mode 100644 index 7912f360d19..00000000000 --- a/tests/static/sortable/default.html +++ /dev/null @@ -1,17 +0,0 @@ - - - - - Sortable Static Test : Default - - - - - - - - -
      Sortable 1
      Sortable 2
      Sortable 3
      - - - diff --git a/tests/static/static.css b/tests/static/static.css deleted file mode 100644 index 60f25b59a38..00000000000 --- a/tests/static/static.css +++ /dev/null @@ -1 +0,0 @@ -body { font-size: 62.5%; } diff --git a/tests/static/static.js b/tests/static/static.js deleted file mode 100644 index 1c29079ef53..00000000000 --- a/tests/static/static.js +++ /dev/null @@ -1,9 +0,0 @@ -/* static_helpers.js - */ -$(function(){ - //add hover states on the static widgets - $('.ui-state-default:not(.ui-state-disabled, .ui-slider-range, .ui-progressbar-value), a.ui-datepicker-next, a.ui-datepicker-prev, .ui-dialog-titlebar-close').hover( - function(){ $(this).addClass('ui-state-hover'); }, - function(){ $(this).removeClass('ui-state-hover'); } - ); -}); diff --git a/tests/static/tabs/default.html b/tests/static/tabs/default.html deleted file mode 100644 index 1bcfa740166..00000000000 --- a/tests/static/tabs/default.html +++ /dev/null @@ -1,33 +0,0 @@ - - - - - Tabs Static Test : Default - - - - - - - - -
      - -
      - Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. -
      -
      - Phasellus mattis tincidunt nibh. Cras orci urna, blandit id, pretium vel, aliquet ornare, felis. Maecenas scelerisque sem non nisl. Fusce sed lorem in enim dictum bibendum. -
      -
      - Nam dui erat, auctor a, dignissim quis, sollicitudin eu, felis. Pellentesque nisi urna, interdum eget, sagittis et, consequat vestibulum, lacus. Mauris porttitor ullamcorper augue. -
      -
      - - - diff --git a/tests/static/tabs/tabs.html b/tests/static/tabs/tabs.html deleted file mode 100644 index 1bcfa740166..00000000000 --- a/tests/static/tabs/tabs.html +++ /dev/null @@ -1,33 +0,0 @@ - - - - - Tabs Static Test : Default - - - - - - - - -
      - -
      - Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. -
      -
      - Phasellus mattis tincidunt nibh. Cras orci urna, blandit id, pretium vel, aliquet ornare, felis. Maecenas scelerisque sem non nisl. Fusce sed lorem in enim dictum bibendum. -
      -
      - Nam dui erat, auctor a, dignissim quis, sollicitudin eu, felis. Pellentesque nisi urna, interdum eget, sagittis et, consequat vestibulum, lacus. Mauris porttitor ullamcorper augue. -
      -
      - - - diff --git a/tests/unit/accordion/accordion.html b/tests/unit/accordion/accordion.html index c53db8c7568..ce58567552b 100644 --- a/tests/unit/accordion/accordion.html +++ b/tests/unit/accordion/accordion.html @@ -1,100 +1,61 @@ - + - + jQuery UI Accordion Test Suite - - - - - - - - - - - - - - - - - - - - + + + +
      +
      -

      jQuery UI Accordion Test Suite

      -

      -

      -
        -
      - -
      - -
      -
      - There is one obvious advantage: -
      -

      - You've seen it coming! -
      - Buy now and get nothing for free! -
      - Well, at least no free beer. Perhaps a bear, if you can afford it. -

      -
      - Now that you've got... -
      -

      - your bear, you have to admit it! -
      - No, we aren't selling bears. -

      -

      - We could talk about renting one. -

      -
      - Rent one bear, ... -
      -

      - get two for three beer. -

      -

      - And now, for something completely different. -

      -
      -
      +
      +

      There is one obvious advantage:

      +
      +

      + You've seen it coming! +
      + Buy now and get nothing for free! +
      + Well, at least no free beer. Perhaps a bear, if you can afford it. +

      +

      Now that you've got...

      +
      +

      + your bear, you have to admit it! +
      + No, we aren't selling bears. +

      +

      + We could talk about renting one. +

      +
      +

      Rent one bear, ...

      +
      +

      + get two for three beer. +

      +

      + And now, for something completely different. +

      +
      +
      +
      +
      + Accordion Header 1 +
      +
      + Accordion Content 1 +
      +
      + Accordion Header 2 +
      +
      + Accordion Content 2 +
      +
      + Accordion Header 3 +
      +
      + Accordion Content 3 +
      +
      + +
      +
      +

      Header

      +
      +

      + The calculated height of this accordion should be the same + regardless of whether the accordion was collapsed or not + when the height was calculated. +

      +
      +
      +
      diff --git a/tests/unit/accordion/accordion_core.js b/tests/unit/accordion/accordion_core.js deleted file mode 100644 index 2bef43149b9..00000000000 --- a/tests/unit/accordion/accordion_core.js +++ /dev/null @@ -1,33 +0,0 @@ -/* - * accordion_core.js - */ - - -(function($) { - -module("accordion: core"); - -test("handle click on header-descendant", function() { - var ac = $('#navigation').accordion({ autoHeight: false }); - $('#navigation h2:eq(1) a').trigger("click"); - state(ac, 0, 1, 0); -}); - -test("accessibility", function () { - expect(9); - var ac = $('#list1').accordion().accordion("activate", 1); - var headers = $(".ui-accordion-header"); - - equals( headers.eq(1).attr("tabindex"), "0", "active header should have tabindex=0"); - equals( headers.eq(0).attr("tabindex"), "-1", "inactive header should have tabindex=-1"); - equals( ac.attr("role"), "tablist", "main role"); - equals( headers.attr("role"), "tab", "tab roles"); - equals( headers.next().attr("role"), "tabpanel", "tabpanel roles"); - equals( headers.eq(1).attr("aria-expanded"), "true", "active tab has aria-expanded"); - equals( headers.eq(0).attr("aria-expanded"), "false", "inactive tab has aria-expanded"); - ac.accordion("activate", 0); - equals( headers.eq(0).attr("aria-expanded"), "true", "newly active tab has aria-expanded"); - equals( headers.eq(1).attr("aria-expanded"), "false", "newly inactive tab has aria-expanded"); -}); - -})(jQuery); diff --git a/tests/unit/accordion/accordion_defaults.js b/tests/unit/accordion/accordion_defaults.js deleted file mode 100644 index e472734bc61..00000000000 --- a/tests/unit/accordion/accordion_defaults.js +++ /dev/null @@ -1,20 +0,0 @@ -/* - * accordion_defaults.js - */ - -var accordion_defaults = { - active: 0, - animated: false, - autoHeight: true, - clearStyle: false, - collapsible: false, - disabled: false, - event: "click", - fillSpace: false, - header: "> li > :first-child,> :not(li):even", - icons: { "header": "ui-icon-triangle-1-e", "headerSelected": "ui-icon-triangle-1-s" }, - navigation: false, - navigationFilter: function() {} -}; - -commonWidgetTests('accordion', { defaults: accordion_defaults }); diff --git a/tests/unit/accordion/accordion_events.js b/tests/unit/accordion/accordion_events.js deleted file mode 100644 index e9e14996ce3..00000000000 --- a/tests/unit/accordion/accordion_events.js +++ /dev/null @@ -1,30 +0,0 @@ -/* - * accordion_events.js - */ -(function($) { - -module("accordion: events"); - -test("accordionchange event, open closed and close again", function() { - expect(8); - $("#list1").accordion({ - active: false, - collapsible: true - }) - .one("accordionchange", function(event, ui) { - equals( ui.oldHeader.size(), 0 ); - equals( ui.oldContent.size(), 0 ); - equals( ui.newHeader.size(), 1 ); - equals( ui.newContent.size(), 1 ); - }) - .accordion("activate", 0) - .one("accordionchange", function(event, ui) { - equals( ui.oldHeader.size(), 1 ); - equals( ui.oldContent.size(), 1 ); - equals( ui.newHeader.size(), 0 ); - equals( ui.newContent.size(), 0 ); - }) - .accordion("activate", 0); -}); - -})(jQuery); diff --git a/tests/unit/accordion/accordion_methods.js b/tests/unit/accordion/accordion_methods.js deleted file mode 100644 index 73faff27cb2..00000000000 --- a/tests/unit/accordion/accordion_methods.js +++ /dev/null @@ -1,131 +0,0 @@ -/* - * accordion_methods.js - */ -(function($) { - -module("accordion: methods"); - -test("init", function() { - $("
      ").appendTo('body').accordion().remove(); - ok(true, '.accordion() called on element'); - - $([]).accordion().remove(); - ok(true, '.accordion() called on empty collection'); - - $('
      ').accordion().remove(); - ok(true, '.accordion() called on disconnected DOMElement - never connected'); - - $('
      ').appendTo('body').remove().accordion().remove(); - ok(true, '.accordion() called on disconnected DOMElement - removed'); - - $('
      ').accordion().accordion("foo").remove(); - ok(true, 'arbitrary method called after init'); - - var el = $('
      ').accordion(); - var foo = el.accordion("option", "foo"); - el.remove(); - ok(true, 'arbitrary option getter after init'); - - $('
      ').accordion().accordion("option", "foo", "bar").remove(); - ok(true, 'arbitrary option setter after init'); -}); - -test("destroy", function() { - var beforeHtml = $("#list1").find("div").css("font-style", "normal").end().parent().html(); - var afterHtml = $("#list1").accordion().accordion("destroy").parent().html(); - // Opera 9 outputs role="" instead of removing the attribute like everyone else - if ($.browser.opera) { - afterHtml = afterHtml.replace(/ role=""/g, ""); - } - equal( afterHtml, beforeHtml ); -}); - -test("enable", function() { - var expected = $('#list1').accordion(), - actual = expected.accordion('enable'); - equals(actual, expected, 'enable is chainable'); - state(expected, 1, 0, 0) -}); - -test("disable", function() { - var expected = $('#list1').accordion(), - actual = expected.accordion('disable'); - equals(actual, expected, 'disable is chainable'); - - state(expected, 1, 0, 0) - expected.accordion("activate", 1); - state(expected, 1, 0, 0) - expected.accordion("enable"); - expected.accordion("activate", 1); - state(expected, 0, 1, 0) -}); - -test("activate", function() { - var expected = $('#list1').accordion(), - actual = expected.accordion('activate', 2); - equals(actual, expected, 'activate is chainable'); -}); - -test("activate, numeric", function() { - var ac = $('#list1').accordion({ active: 1 }); - state(ac, 0, 1, 0); - ac.accordion("activate", 2); - state(ac, 0, 0, 1); - ac.accordion("activate", 0); - state(ac, 1, 0, 0); - ac.accordion("activate", 1); - state(ac, 0, 1, 0); - ac.accordion("activate", 2); - state(ac, 0, 0, 1); -}); - -test("activate, boolean and numeric, collapsible:true", function() { - var ac = $('#list1').accordion({collapsible: true}).accordion("activate", 2); - state(ac, 0, 0, 1); - ok("x", "----"); - ac.accordion("activate", 0); - state(ac, 1, 0, 0); - ok("x", "----"); - ac.accordion("activate", -1); - state(ac, 0, 0, 0); -}); - -test("activate, boolean, collapsible: false", function() { - var ac = $('#list1').accordion().accordion("activate", 2); - state(ac, 0, 0, 1); - ac.accordion("activate", false); - state(ac, 0, 0, 1); -}); - -test("activate, string expression", function() { - var ac = $('#list1').accordion({ active: "a:last" }); - state(ac, 0, 0, 1); - ac.accordion("activate", ":first"); - state(ac, 1, 0, 0); - ac.accordion("activate", ":eq(1)"); - state(ac, 0, 1, 0); - ac.accordion("activate", ":last"); - state(ac, 0, 0, 1); -}); - -test("activate, jQuery or DOM element", function() { - var ac = $('#list1').accordion({ active: $("#list1 a:last") }); - state(ac, 0, 0, 1); - ac.accordion("activate", $("#list1 a:first")); - state(ac, 1, 0, 0); - ac.accordion("activate", $("#list1 a")[1]); - state(ac, 0, 1, 0); -}); - -test("resize", function() { - var expected = $('#navigation').parent().height(300).end().accordion({ - fillSpace: true - }); - equalHeights(expected, 246, 258); - - expected.parent().height(500); - expected.accordion("resize"); - equalHeights(expected, 446, 458); -}); - -})(jQuery); diff --git a/tests/unit/accordion/accordion_options.js b/tests/unit/accordion/accordion_options.js deleted file mode 100644 index 499fec38355..00000000000 --- a/tests/unit/accordion/accordion_options.js +++ /dev/null @@ -1,148 +0,0 @@ -/* - * accordion_options.js - */ -(function($) { - -module("accordion: options"); - -test("{ active: first child }, default", function() { - var ac = $("#list1").accordion(); - equals( ac.accordion('option', 'active'), 0); - state(ac, 1, 0, 0) -}); - -test("{ active: Selector }", function() { - var ac = $("#list1").accordion({ - active: "a:last" - }); - state(ac, 0, 0, 1); - ac.accordion('option', 'active', "a:eq(1)"); - state(ac, 0, 1, 0); -}); - -test("{ active: Element }", function() { - var ac = $("#list1").accordion({ - active: $("#list1 a:last")[0] - }); - state(ac, 0, 0, 1); - ac.accordion('option', 'active', $("#list1 a:eq(1)")[0]); - state(ac, 0, 1, 0); -}); - -test("{ active: jQuery Object }", function() { - var ac = $("#list1").accordion({ - active: $("#list1 a:last") - }); - state(ac, 0, 0, 1); - ac.accordion('option', 'active', $("#list1 a:eq(1)")); - state(ac, 0, 1, 0); -}); - -test("{ active: false }", function() { - var ac = $("#list1").accordion({ - active: false, - collapsible: true - }); - state(ac, 0, 0, 0); - equals( $("#list1 .ui-accordion-header.ui-state-active").size(), 0, "no headers selected" ); - equals( $("#list1").accordion('option', 'active'), false); -}); - -test("{ active: Number }", function() { - expect(4); - $("#list1").accordion({ - active: 0 - }); - equals( $("#list1").accordion('option', 'active'), 0); - - $("#list1").accordion('option', 'active', 1); - equals( $("#list1").accordion('option', 'active'), 1); - - $('.ui-accordion-header:eq(2)', '#list1').click(); - equals( $("#list1").accordion('option', 'active'), 2); - - $("#list1").accordion('activate', 0); - equals( $("#list1").accordion('option', 'active'), 0); -}); - -test("{ autoHeight: true }, default", function() { - equalHeights($('#navigation').accordion({ autoHeight: true }), 95, 130); -}); - -test("{ autoHeight: false }", function() { - var accordion = $('#navigation').accordion({ autoHeight: false }); - var sizes = []; - accordion.find(".ui-accordion-content").each(function() { - sizes.push($(this).height()); - }); - ok( sizes[0] >= 70 && sizes[0] <= 90, "was " + sizes[0] ); - ok( sizes[1] >= 98 && sizes[1] <= 126, "was " + sizes[1] ); - ok( sizes[2] >= 42 && sizes[2] <= 54, "was " + sizes[2] ); -}); - -test("{ collapsible: false }, default", function() { - var ac = $("#list1").accordion(); - ac.accordion("activate", false); - state(ac, 1, 0, 0); -}); - -test("{ collapsible: true }", function() { - var ac = $("#list1").accordion({ - active: 1, - collapsible: true - }); - var header = $('#list1 .ui-accordion-header:eq(1)').click(); - equals( $("#list1").accordion('option', 'active'), false); - state(ac, 0, 0, 0); -}); - -// fillSpace: false == autoHeight: true, covered above -test("{ fillSpace: true }", function() { - $("#navigationWrapper").height(500); - equalHeights($('#navigation').accordion({ fillSpace: true }), 446, 458); -}); - -test("{ header: '> li > :first-child,> :not(li):even' }, default", function() { - state($("#list1").accordion(), 1, 0, 0); - state($("#navigation").accordion(), 1, 0, 0); -}); - -test("{ icons: false }", function() { - var list = $("#list1"); - function icons(on) { - same($("span.ui-icon", list).length, on ? 3 : 0); - same( list.hasClass("ui-accordion-icons"), on ); - } - list.accordion(); - icons(true); - list.accordion("destroy").accordion({ - icons: false - }); - icons(false); - list.accordion("option", "icons", $.ui.accordion.prototype.options.icons); - icons(true); - list.accordion("option", "icons", false); - icons(false); -}); - -test("{ navigation: true, navigationFilter: header }", function() { - $("#navigation").accordion({ - navigation: true, - navigationFilter: function() { - return /\?p=1\.1\.3$/.test(this.href); - } - }); - equals( $("#navigation .ui-accordion-content:eq(2)").size(), 1, "third content active" ); -}); - -test("{ navigation: true, navigationFilter: content }", function() { - $("#navigation").accordion({ - navigation: true, - navigationFilter: function() { - return /\?p=1\.1\.3\.2$/.test(this.href); - } - }); - equals( $("#navigation .ui-accordion-content:eq(2)").size(), 1, "third content active" ); -}); - -})(jQuery); diff --git a/tests/unit/accordion/accordion_tickets.js b/tests/unit/accordion/accordion_tickets.js deleted file mode 100644 index 98d8fbe4c0c..00000000000 --- a/tests/unit/accordion/accordion_tickets.js +++ /dev/null @@ -1,8 +0,0 @@ -/* - * accordion_tickets.js - */ -(function($) { - -module("accordion: tickets"); - -})(jQuery); diff --git a/tests/unit/accordion/all.html b/tests/unit/accordion/all.html new file mode 100644 index 00000000000..71593dd3900 --- /dev/null +++ b/tests/unit/accordion/all.html @@ -0,0 +1,26 @@ + + + + + jQuery UI Accordion Test Suite + + + + + + + + + + + + + +
      +
      + +
      + + diff --git a/tests/unit/accordion/common.js b/tests/unit/accordion/common.js new file mode 100644 index 00000000000..4f1ba7e5da0 --- /dev/null +++ b/tests/unit/accordion/common.js @@ -0,0 +1,44 @@ +define( [ + "lib/common", + "ui/widgets/accordion" +], function( common ) { + +common.testWidget( "accordion", { + defaults: { + active: 0, + animate: {}, + classes: { + "ui-accordion-header": "ui-corner-top", + "ui-accordion-header-collapsed": "ui-corner-all", + "ui-accordion-content": "ui-corner-bottom" + }, + collapsible: false, + disabled: false, + event: "click", + header: function( elem ) { + return elem + .find( "> li > :first-child" ) + .add( + elem.find( "> :not(li)" ) + + // Support: jQuery <3.5 only + // We could use `.even()` but that's unavailable in older jQuery. + .filter( function( i ) { + return i % 2 === 0; + } ) + ); + }, + heightStyle: "auto", + icons: { + "activeHeader": "ui-icon-triangle-1-s", + "header": "ui-icon-triangle-1-e" + }, + + // Callbacks + activate: null, + beforeActivate: null, + create: null + } +} ); + +} ); diff --git a/tests/unit/accordion/core.js b/tests/unit/accordion/core.js new file mode 100644 index 00000000000..4e899439f4a --- /dev/null +++ b/tests/unit/accordion/core.js @@ -0,0 +1,171 @@ +define( [ + "qunit", + "jquery", + "./helper", + "ui/widgets/accordion" +], function( QUnit, $, testHelper ) { +"use strict"; + +var beforeAfterEach = testHelper.beforeAfterEach, + state = testHelper.state; + +QUnit.module( "accordion: core", beforeAfterEach() ); + +$.each( { div: "#list1", ul: "#navigation", dl: "#accordion-dl" }, function( type, selector ) { + QUnit.test( "markup structure: " + type, function( assert ) { + assert.expect( 10 ); + var element = $( selector ).accordion(), + headers = element.find( ".ui-accordion-header" ), + content = headers.next(); + + assert.hasClasses( element, "ui-accordion ui-widget" ); + assert.equal( headers.length, 3, ".ui-accordion-header elements exist, correct number" ); + assert.hasClasses( headers[ 0 ], + "ui-accordion-header ui-accordion-header-active ui-accordion-icons" ); + assert.hasClasses( headers[ 1 ], + "ui-accordion-header ui-accordion-header-collapsed ui-accordion-icons" ); + assert.hasClasses( headers[ 2 ], + "ui-accordion-header ui-accordion-header-collapsed ui-accordion-icons" ); + assert.equal( content.length, 3, ".ui-accordion-content elements exist, correct number" ); + assert.hasClasses( content[ 0 ], + "ui-accordion-content ui-widget-content ui-accordion-content-active" ); + assert.hasClasses( content[ 1 ], "ui-accordion-content ui-widget-content" ); + assert.hasClasses( content[ 2 ], "ui-accordion-content ui-widget-content" ); + assert.deepEqual( element.find( ".ui-accordion-header" ).next().get(), + element.find( ".ui-accordion-content" ).get(), + "content panels come immediately after headers" ); + } ); +} ); + +QUnit.test( "handle click on header-descendant", function( assert ) { + assert.expect( 1 ); + var element = $( "#navigation" ).accordion(); + $( "#navigation h2" ).eq( 1 ).find( "a" ).trigger( "click" ); + state( assert, element, 0, 1, 0 ); +} ); + +QUnit.test( "accessibility", function( assert ) { + assert.expect( 61 ); + var element = $( "#list1" ).accordion( { + active: 1, + collapsible: true + } ), + headers = element.find( ".ui-accordion-header" ); + + assert.equal( element.attr( "role" ), "tablist", "element role" ); + headers.each( function( i ) { + var header = headers.eq( i ), + panel = header.next(); + assert.equal( header.attr( "role" ), "tab", "header " + i + " role" ); + assert.equal( header.attr( "aria-controls" ), panel.attr( "id" ), "header " + i + " aria-controls" ); + assert.equal( panel.attr( "role" ), "tabpanel", "panel " + i + " role" ); + assert.equal( panel.attr( "aria-labelledby" ), header.attr( "id" ), "panel " + i + " aria-labelledby" ); + } ); + + assert.equal( headers.eq( 1 ).attr( "tabindex" ), 0, "active header has tabindex=0" ); + assert.equal( headers.eq( 1 ).attr( "aria-selected" ), "true", "active tab (1) has aria-selected=true" ); + assert.equal( headers.eq( 1 ).attr( "aria-expanded" ), "true", "active tab (1) has aria-expanded=true" ); + assert.equal( headers.eq( 1 ).next().attr( "aria-hidden" ), "false", "active tabpanel (1) has aria-hidden=false" ); + assert.equal( headers.eq( 0 ).attr( "tabindex" ), -1, "inactive header (0) has tabindex=-1" ); + assert.equal( headers.eq( 0 ).attr( "aria-selected" ), "false", "inactive tab (0) has aria-selected=false" ); + assert.equal( headers.eq( 0 ).attr( "aria-expanded" ), "false", "inactive tab (0) has aria-expanded=false" ); + assert.equal( headers.eq( 0 ).next().attr( "aria-hidden" ), "true", "inactive tabpanel (0) has aria-hidden=true" ); + assert.equal( headers.eq( 2 ).attr( "tabindex" ), -1, "inactive header (2) has tabindex=-1" ); + assert.equal( headers.eq( 2 ).attr( "aria-selected" ), "false", "inactive tab (2) has aria-selected=false" ); + assert.equal( headers.eq( 2 ).attr( "aria-expanded" ), "false", "inactive tab (2) has aria-expanded=false" ); + assert.equal( headers.eq( 2 ).next().attr( "aria-hidden" ), "true", "inactive tabpanel (2) has aria-hidden=true" ); + + element.accordion( "option", "active", 0 ); + assert.equal( headers.eq( 0 ).attr( "tabindex" ), 0, "active header (0) has tabindex=0" ); + assert.equal( headers.eq( 0 ).attr( "aria-selected" ), "true", "active tab (0) has aria-selected=true" ); + assert.equal( headers.eq( 0 ).attr( "aria-expanded" ), "true", "active tab (0) has aria-expanded=true" ); + assert.equal( headers.eq( 0 ).next().attr( "aria-hidden" ), "false", "active tabpanel (0) has aria-hidden=false" ); + assert.equal( headers.eq( 1 ).attr( "tabindex" ), -1, "inactive header (1) has tabindex=-1" ); + assert.equal( headers.eq( 1 ).attr( "aria-selected" ), "false", "inactive tab (1) has aria-selected=false" ); + assert.equal( headers.eq( 1 ).attr( "aria-expanded" ), "false", "inactive tab (1) has aria-expanded=false" ); + assert.equal( headers.eq( 1 ).next().attr( "aria-hidden" ), "true", "inactive tabpanel (1) has aria-hidden=true" ); + assert.equal( headers.eq( 2 ).attr( "tabindex" ), -1, "inactive header (2) has tabindex=-1" ); + assert.equal( headers.eq( 2 ).attr( "aria-selected" ), "false", "inactive tab (2) has aria-selected=false" ); + assert.equal( headers.eq( 2 ).attr( "aria-expanded" ), "false", "inactive tab (2) has aria-expanded=false" ); + assert.equal( headers.eq( 2 ).next().attr( "aria-hidden" ), "true", "inactive tabpanel (2) has aria-hidden=true" ); + + element.accordion( "option", "active", false ); + assert.equal( headers.eq( 0 ).attr( "tabindex" ), 0, "previously active header (0) has tabindex=0" ); + assert.equal( headers.eq( 0 ).attr( "aria-selected" ), "false", "inactive tab (0) has aria-selected=false" ); + assert.equal( headers.eq( 0 ).attr( "aria-expanded" ), "false", "inactive tab (0) has aria-expanded=false" ); + assert.equal( headers.eq( 0 ).next().attr( "aria-hidden" ), "true", "inactive tabpanel (0) has aria-hidden=true" ); + assert.equal( headers.eq( 1 ).attr( "tabindex" ), -1, "inactive header (1) has tabindex=-1" ); + assert.equal( headers.eq( 1 ).attr( "aria-selected" ), "false", "inactive tab (1) has aria-selected=false" ); + assert.equal( headers.eq( 1 ).attr( "aria-expanded" ), "false", "inactive tab (1) has aria-expanded=false" ); + assert.equal( headers.eq( 1 ).next().attr( "aria-hidden" ), "true", "inactive tabpanel (1) has aria-hidden=true" ); + assert.equal( headers.eq( 2 ).attr( "tabindex" ), -1, "inactive header (2) has tabindex=-1" ); + assert.equal( headers.eq( 2 ).attr( "aria-selected" ), "false", "inactive tab (2) has aria-selected=false" ); + assert.equal( headers.eq( 2 ).attr( "aria-expanded" ), "false", "inactive tab (2) has aria-expanded=false" ); + assert.equal( headers.eq( 2 ).next().attr( "aria-hidden" ), "true", "inactive tabpanel (2) has aria-hidden=true" ); + + element.accordion( "option", "active", 1 ); + assert.equal( headers.eq( 1 ).attr( "tabindex" ), 0, "active header has tabindex=0" ); + assert.equal( headers.eq( 1 ).attr( "aria-selected" ), "true", "active tab (1) has aria-selected=true" ); + assert.equal( headers.eq( 1 ).attr( "aria-expanded" ), "true", "active tab (1) has aria-expanded=true" ); + assert.equal( headers.eq( 1 ).next().attr( "aria-hidden" ), "false", "active tabpanel (1) has aria-hidden=false" ); + assert.equal( headers.eq( 0 ).attr( "tabindex" ), -1, "inactive header (0) has tabindex=-1" ); + assert.equal( headers.eq( 0 ).attr( "aria-selected" ), "false", "inactive tab (0) has aria-selected=false" ); + assert.equal( headers.eq( 0 ).attr( "aria-expanded" ), "false", "inactive tab (0) has aria-expanded=false" ); + assert.equal( headers.eq( 0 ).next().attr( "aria-hidden" ), "true", "inactive tabpanel (0) has aria-hidden=true" ); + assert.equal( headers.eq( 2 ).attr( "tabindex" ), -1, "inactive header (2) has tabindex=-1" ); + assert.equal( headers.eq( 2 ).attr( "aria-selected" ), "false", "inactive tab (2) has aria-selected=false" ); + assert.equal( headers.eq( 2 ).attr( "aria-expanded" ), "false", "inactive tab (2) has aria-expanded=false" ); + assert.equal( headers.eq( 2 ).next().attr( "aria-hidden" ), "true", "inactive tabpanel (2) has aria-hidden=true" ); + +} ); + +QUnit.test( "keyboard support", function( assert ) { + var ready = assert.async(); + assert.expect( 13 ); + var element = $( "#list1" ).accordion(), + headers = element.find( ".ui-accordion-header" ), + anchor = headers.eq( 1 ).next().find( "a" ).eq( 0 ), + keyCode = $.ui.keyCode; + assert.equal( headers.filter( ".ui-state-focus" ).length, 0, "no headers focused on init" ); + headers.eq( 0 ).simulate( "focus" ); + setTimeout( step1 ); + + function step1() { + assert.hasClasses( headers.eq( 0 ), "ui-state-focus", "first header has focus" ); + headers.eq( 0 ).simulate( "keydown", { keyCode: keyCode.DOWN } ); + assert.hasClasses( headers.eq( 1 ), "ui-state-focus", "DOWN moves focus to next header" ); + headers.eq( 1 ).simulate( "keydown", { keyCode: keyCode.RIGHT } ); + assert.hasClasses( headers.eq( 2 ), "ui-state-focus", "RIGHT moves focus to next header" ); + headers.eq( 2 ).simulate( "keydown", { keyCode: keyCode.DOWN } ); + assert.hasClasses( headers.eq( 0 ), "ui-state-focus", "DOWN wraps focus to first header" ); + + headers.eq( 0 ).simulate( "keydown", { keyCode: keyCode.UP } ); + assert.hasClasses( headers.eq( 2 ), "ui-state-focus", "UP wraps focus to last header" ); + headers.eq( 2 ).simulate( "keydown", { keyCode: keyCode.LEFT } ); + assert.hasClasses( headers.eq( 1 ), + "ui-state-focus", "LEFT moves focus to previous header" ); + + headers.eq( 1 ).simulate( "keydown", { keyCode: keyCode.HOME } ); + assert.hasClasses( headers.eq( 0 ), "ui-state-focus", "HOME moves focus to first header" ); + headers.eq( 0 ).simulate( "keydown", { keyCode: keyCode.END } ); + assert.hasClasses( headers.eq( 2 ), "ui-state-focus", "END moves focus to last header" ); + + headers.eq( 2 ).simulate( "keydown", { keyCode: keyCode.ENTER } ); + assert.equal( element.accordion( "option", "active" ), 2, "ENTER activates panel" ); + headers.eq( 1 ).simulate( "keydown", { keyCode: keyCode.SPACE } ); + assert.equal( element.accordion( "option", "active" ), 1, "SPACE activates panel" ); + + anchor.simulate( "focus" ); + setTimeout( step2 ); + } + + function step2() { + assert.lacksClasses( headers.eq( 1 ), "ui-state-focus", + "header loses focus when focusing inside the panel" ); + anchor.simulate( "keydown", { keyCode: keyCode.UP, ctrlKey: true } ); + assert.hasClasses( headers.eq( 1 ), "ui-state-focus", "CTRL+UP moves focus to header" ); + ready(); + } +} ); + +} ); diff --git a/tests/unit/accordion/events.js b/tests/unit/accordion/events.js new file mode 100644 index 00000000000..2c5e791a169 --- /dev/null +++ b/tests/unit/accordion/events.js @@ -0,0 +1,170 @@ +define( [ + "qunit", + "jquery", + "./helper", + "ui/widgets/accordion" +], function( QUnit, $, testHelper ) { +"use strict"; + +var beforeAfterEach = testHelper.beforeAfterEach, + state = testHelper.state; + +QUnit.module( "accordion: events", beforeAfterEach() ); + +QUnit.test( "create", function( assert ) { + assert.expect( 10 ); + + var element = $( "#list1" ), + headers = element.children( "h3" ), + contents = headers.next(); + + element.accordion( { + create: function( event, ui ) { + assert.equal( ui.header.length, 1, "header length" ); + assert.strictEqual( ui.header[ 0 ], headers[ 0 ], "header" ); + assert.equal( ui.panel.length, 1, "panel length" ); + assert.strictEqual( ui.panel[ 0 ], contents[ 0 ], "panel" ); + } + } ); + element.accordion( "destroy" ); + + element.accordion( { + active: 2, + create: function( event, ui ) { + assert.equal( ui.header.length, 1, "header length" ); + assert.strictEqual( ui.header[ 0 ], headers[ 2 ], "header" ); + assert.equal( ui.panel.length, 1, "panel length" ); + assert.strictEqual( ui.panel[ 0 ], contents[ 2 ], "panel" ); + } + } ); + element.accordion( "destroy" ); + + element.accordion( { + active: false, + collapsible: true, + create: function( event, ui ) { + assert.equal( ui.header.length, 0, "header length" ); + assert.equal( ui.panel.length, 0, "panel length" ); + } + } ); + element.accordion( "destroy" ); +} ); + +QUnit.test( "beforeActivate", function( assert ) { + assert.expect( 38 ); + var element = $( "#list1" ).accordion( { + active: false, + collapsible: true + } ), + headers = element.find( ".ui-accordion-header" ), + content = element.find( ".ui-accordion-content" ); + + element.one( "accordionbeforeactivate", function( event, ui ) { + assert.ok( !( "originalEvent" in event ) ); + assert.equal( ui.oldHeader.length, 0 ); + assert.equal( ui.oldPanel.length, 0 ); + assert.equal( ui.newHeader.length, 1 ); + assert.strictEqual( ui.newHeader[ 0 ], headers[ 0 ] ); + assert.equal( ui.newPanel.length, 1 ); + assert.strictEqual( ui.newPanel[ 0 ], content[ 0 ] ); + state( assert, element, 0, 0, 0 ); + } ); + element.accordion( "option", "active", 0 ); + state( assert, element, 1, 0, 0 ); + + element.one( "accordionbeforeactivate", function( event, ui ) { + assert.equal( event.originalEvent.type, "click" ); + assert.equal( ui.oldHeader.length, 1 ); + assert.strictEqual( ui.oldHeader[ 0 ], headers[ 0 ] ); + assert.equal( ui.oldPanel.length, 1 ); + assert.strictEqual( ui.oldPanel[ 0 ], content[ 0 ] ); + assert.equal( ui.newHeader.length, 1 ); + assert.strictEqual( ui.newHeader[ 0 ], headers[ 1 ] ); + assert.equal( ui.newPanel.length, 1 ); + assert.strictEqual( ui.newPanel[ 0 ], content[ 1 ] ); + state( assert, element, 1, 0, 0 ); + } ); + headers.eq( 1 ).trigger( "click" ); + state( assert, element, 0, 1, 0 ); + + element.one( "accordionbeforeactivate", function( event, ui ) { + assert.ok( !( "originalEvent" in event ) ); + assert.equal( ui.oldHeader.length, 1 ); + assert.strictEqual( ui.oldHeader[ 0 ], headers[ 1 ] ); + assert.equal( ui.oldPanel.length, 1 ); + assert.strictEqual( ui.oldPanel[ 0 ], content[ 1 ] ); + assert.equal( ui.newHeader.length, 0 ); + assert.equal( ui.newPanel.length, 0 ); + state( assert, element, 0, 1, 0 ); + } ); + element.accordion( "option", "active", false ); + state( assert, element, 0, 0, 0 ); + + element.one( "accordionbeforeactivate", function( event, ui ) { + assert.ok( !( "originalEvent" in event ) ); + assert.equal( ui.oldHeader.length, 0 ); + assert.equal( ui.oldPanel.length, 0 ); + assert.equal( ui.newHeader.length, 1 ); + assert.strictEqual( ui.newHeader[ 0 ], headers[ 2 ] ); + assert.equal( ui.newPanel.length, 1 ); + assert.strictEqual( ui.newPanel[ 0 ], content[ 2 ] ); + event.preventDefault(); + state( assert, element, 0, 0, 0 ); + } ); + element.accordion( "option", "active", 2 ); + state( assert, element, 0, 0, 0 ); +} ); + +QUnit.test( "activate", function( assert ) { + assert.expect( 21 ); + var element = $( "#list1" ).accordion( { + active: false, + collapsible: true + } ), + headers = element.find( ".ui-accordion-header" ), + content = element.find( ".ui-accordion-content" ); + + element.one( "accordionactivate", function( event, ui ) { + assert.equal( ui.oldHeader.length, 0 ); + assert.equal( ui.oldPanel.length, 0 ); + assert.equal( ui.newHeader.length, 1 ); + assert.strictEqual( ui.newHeader[ 0 ], headers[ 0 ] ); + assert.equal( ui.newPanel.length, 1 ); + assert.strictEqual( ui.newPanel[ 0 ], content[ 0 ] ); + } ); + element.accordion( "option", "active", 0 ); + + element.one( "accordionactivate", function( event, ui ) { + assert.equal( ui.oldHeader.length, 1 ); + assert.strictEqual( ui.oldHeader[ 0 ], headers[ 0 ] ); + assert.equal( ui.oldPanel.length, 1 ); + assert.strictEqual( ui.oldPanel[ 0 ], content[ 0 ] ); + assert.equal( ui.newHeader.length, 1 ); + assert.strictEqual( ui.newHeader[ 0 ], headers[ 1 ] ); + assert.equal( ui.newPanel.length, 1 ); + assert.strictEqual( ui.newPanel[ 0 ], content[ 1 ] ); + } ); + headers.eq( 1 ).trigger( "click" ); + + element.one( "accordionactivate", function( event, ui ) { + assert.equal( ui.oldHeader.length, 1 ); + assert.strictEqual( ui.oldHeader[ 0 ], headers[ 1 ] ); + assert.equal( ui.oldPanel.length, 1 ); + assert.strictEqual( ui.oldPanel[ 0 ], content[ 1 ] ); + assert.equal( ui.newHeader.length, 0 ); + assert.equal( ui.newPanel.length, 0 ); + } ); + element.accordion( "option", "active", false ); + + // Prevent activation + element.one( "accordionbeforeactivate", function( event ) { + assert.ok( true ); + event.preventDefault(); + } ); + element.one( "accordionactivate", function() { + assert.ok( false ); + } ); + element.accordion( "option", "active", 1 ); +} ); + +} ); diff --git a/tests/unit/accordion/helper.js b/tests/unit/accordion/helper.js new file mode 100644 index 00000000000..b50c389e294 --- /dev/null +++ b/tests/unit/accordion/helper.js @@ -0,0 +1,38 @@ +define( [ + "qunit", + "jquery", + "lib/helper", + "ui/widgets/accordion" +], function( QUnit, $, helper ) { +"use strict"; + +return $.extend( helper, { + equalHeight: function( assert, accordion, height ) { + accordion.find( ".ui-accordion-content" ).each( function() { + assert.equal( $( this ).outerHeight(), height ); + } ); + }, + + beforeAfterEach: function() { + var animate = $.ui.accordion.prototype.options.animate; + return { + beforeEach: function() { + $.ui.accordion.prototype.options.animate = false; + }, + afterEach: function() { + $.ui.accordion.prototype.options.animate = animate; + return helper.moduleAfterEach.apply( this, arguments ); + } + }; + }, + + state: function( assert, accordion ) { + var expected = $.makeArray( arguments ).slice( 2 ), + actual = accordion.find( ".ui-accordion-content" ).map( function() { + return $( this ).css( "display" ) === "none" ? 0 : 1; + } ).get(); + assert.deepEqual( actual, expected ); + } +} ); + +} ); diff --git a/tests/unit/accordion/methods.js b/tests/unit/accordion/methods.js new file mode 100644 index 00000000000..e4ab62ffb13 --- /dev/null +++ b/tests/unit/accordion/methods.js @@ -0,0 +1,139 @@ +define( [ + "qunit", + "jquery", + "./helper", + "ui/widgets/accordion" +], function( QUnit, $, testHelper ) { +"use strict"; + +var equalHeight = testHelper.equalHeight, + beforeAfterEach = testHelper.beforeAfterEach, + state = testHelper.state; + +QUnit.module( "accordion: methods", beforeAfterEach() ); + +QUnit.test( "destroy", function( assert ) { + assert.expect( 1 ); + assert.domEqual( "#list1", function() { + $( "#list1" ).accordion().accordion( "destroy" ); + } ); +} ); + +QUnit.test( "enable/disable", function( assert ) { + assert.expect( 7 ); + var element = $( "#list1" ).accordion(); + state( assert, element, 1, 0, 0 ); + element.accordion( "disable" ); + + assert.hasClasses( element, "ui-state-disabled" ); + + assert.equal( element.attr( "aria-disabled" ), "true", "element gets aria-disabled" ); + assert.hasClasses( element, "ui-accordion-disabled" ); + + // Event does nothing + element.find( ".ui-accordion-header" ).eq( 1 ).trigger( "click" ); + state( assert, element, 1, 0, 0 ); + + // Option still works + element.accordion( "option", "active", 1 ); + state( assert, element, 0, 1, 0 ); + element.accordion( "enable" ); + element.accordion( "option", "active", 2 ); + state( assert, element, 0, 0, 1 ); +} ); + +QUnit.test( "refresh", function( assert ) { + assert.expect( 19 ); + var element = $( "#navigation" ) + .parent() + .height( 300 ) + .end() + .accordion( { + heightStyle: "fill" + } ); + equalHeight( assert, element, 255 ); + + element.parent().height( 500 ); + element.accordion( "refresh" ); + equalHeight( assert, element, 455 ); + + element = $( "#list1" ); + element.accordion(); + state( assert, element, 1, 0, 0 ); + + // Disable panel via markup + element.find( "h3.bar" ).eq( 1 ).addClass( "ui-state-disabled" ); + element.accordion( "refresh" ); + state( assert, element, 1, 0, 0 ); + + // Don't add multiple icons + element.accordion( "refresh" ); + assert.equal( element.find( ".ui-accordion-header-icon" ).length, 3 ); + + // Add a panel + element + .append( "

      new 1

      " ) + .append( "
      new 1
      " ); + element.accordion( "refresh" ); + state( assert, element, 1, 0, 0, 0 ); + + // Remove all tabs + element.find( "h3.bar, div.foo" ).remove(); + element.accordion( "refresh" ); + state( assert, element ); + assert.equal( element.accordion( "option", "active" ), false, "no active accordion panel" ); + + // Add panels + element + .append( "

      new 2

      " ) + .append( "
      new 2
      " ) + .append( "

      new 3

      " ) + .append( "
      new 3
      " ) + .append( "

      new 4

      " ) + .append( "
      new 4
      " ) + .append( "

      new 5

      " ) + .append( "
      new 5
      " ); + element.accordion( "refresh" ); + state( assert, element, 1, 0, 0, 0 ); + + // Activate third tab + element.accordion( "option", "active", 2 ); + state( assert, element, 0, 0, 1, 0 ); + + // Remove fourth panel, third panel should stay active + element.find( "h3.bar" ).eq( 3 ).remove(); + element.find( "div.foo" ).eq( 3 ).remove(); + element.accordion( "refresh" ); + state( assert, element, 0, 0, 1 ); + + // Remove third (active) panel, second panel should become active + element.find( "h3.bar" ).eq( 2 ).remove(); + element.find( "div.foo" ).eq( 2 ).remove(); + element.accordion( "refresh" ); + state( assert, element, 0, 1 ); + + // Remove first panel, previously active panel (now first) should stay active + element.find( "h3.bar" ).eq( 0 ).remove(); + element.find( "div.foo" ).eq( 0 ).remove(); + element.accordion( "refresh" ); + state( assert, element, 1 ); + + // Collapse all panels + element.accordion( "option", { + collapsible: true, + active: false + } ); + state( assert, element, 0 ); + element.accordion( "refresh" ); + state( assert, element, 0 ); +} ); + +QUnit.test( "widget", function( assert ) { + assert.expect( 2 ); + var element = $( "#list1" ).accordion(), + widgetElement = element.accordion( "widget" ); + assert.equal( widgetElement.length, 1, "one element" ); + assert.strictEqual( widgetElement[ 0 ], element[ 0 ], "same element" ); +} ); + +} ); diff --git a/tests/unit/accordion/options.js b/tests/unit/accordion/options.js new file mode 100644 index 00000000000..1a2b55d5e04 --- /dev/null +++ b/tests/unit/accordion/options.js @@ -0,0 +1,515 @@ +define( [ + "qunit", + "jquery", + "./helper", + "ui/widgets/accordion" +], function( QUnit, $, testHelper ) { +"use strict"; + +var equalHeight = testHelper.equalHeight, + beforeAfterEach = testHelper.beforeAfterEach, + state = testHelper.state; + +QUnit.module( "accordion: options", beforeAfterEach() ); + +QUnit.test( "{ active: default }", function( assert ) { + assert.expect( 2 ); + var element = $( "#list1" ).accordion(); + assert.equal( element.accordion( "option", "active" ), 0 ); + state( assert, element, 1, 0, 0 ); +} ); + +QUnit.test( "{ active: null }", function( assert ) { + assert.expect( 2 ); + var element = $( "#list1" ).accordion( { + active: null + } ); + assert.equal( element.accordion( "option", "active" ), 0 ); + state( assert, element, 1, 0, 0 ); +} ); + +QUnit.test( "{ active: false }", function( assert ) { + assert.expect( 7 ); + var element = $( "#list1" ).accordion( { + active: false, + collapsible: true + } ); + state( assert, element, 0, 0, 0 ); + assert.equal( element.find( ".ui-accordion-header.ui-state-active" ).length, 0, "no headers selected" ); + assert.equal( element.accordion( "option", "active" ), false ); + + element.accordion( "option", "collapsible", false ); + state( assert, element, 1, 0, 0 ); + assert.equal( element.accordion( "option", "active" ), 0 ); + + element.accordion( "destroy" ); + element.accordion( { + active: false + } ); + state( assert, element, 1, 0, 0 ); + assert.strictEqual( element.accordion( "option", "active" ), 0 ); +} ); + +// https://bugs.jqueryui.com/ticket/11938 +QUnit.test( "{ active: false, collapsible: true }", function( assert ) { + assert.expect( 1 ); + var element = $( "#collapsible" ).accordion(), + height = element.outerHeight(); + + element + .accordion( "destroy" ) + .accordion( { + active: false, + collapsible: true + } ) + .accordion( "option", "active", 0 ); + assert.equal( element.outerHeight(), height ); +} ); + +QUnit.test( "{ active: Number }", function( assert ) { + assert.expect( 8 ); + var element = $( "#list1" ).accordion( { + active: 2 + } ); + assert.equal( element.accordion( "option", "active" ), 2 ); + state( assert, element, 0, 0, 1 ); + + element.accordion( "option", "active", 0 ); + assert.equal( element.accordion( "option", "active" ), 0 ); + state( assert, element, 1, 0, 0 ); + + element.find( ".ui-accordion-header" ).eq( 1 ).trigger( "click" ); + assert.equal( element.accordion( "option", "active" ), 1 ); + state( assert, element, 0, 1, 0 ); + + element.accordion( "option", "active", 10 ); + assert.equal( element.accordion( "option", "active" ), 1 ); + state( assert, element, 0, 1, 0 ); +} ); + +QUnit.test( "{ active: -Number }", function( assert ) { + assert.expect( 8 ); + var element = $( "#list1" ).accordion( { + active: -1 + } ); + assert.equal( element.accordion( "option", "active" ), 2 ); + state( assert, element, 0, 0, 1 ); + + element.accordion( "option", "active", -2 ); + assert.equal( element.accordion( "option", "active" ), 1 ); + state( assert, element, 0, 1, 0 ); + + element.accordion( "option", "active", -10 ); + assert.equal( element.accordion( "option", "active" ), 1 ); + state( assert, element, 0, 1, 0 ); + + element.accordion( "option", "active", -3 ); + assert.equal( element.accordion( "option", "active" ), 0 ); + state( assert, element, 1, 0, 0 ); +} ); + +QUnit.test( "{ animate: false }", function( assert ) { + assert.expect( 3 ); + var element = $( "#list1" ).accordion( { + animate: false + } ), + panels = element.find( ".ui-accordion-content" ), + animate = $.fn.animate; + $.fn.animate = function() { + assert.ok( false, ".animate() called" ); + }; + + assert.ok( panels.eq( 0 ).is( ":visible" ), "first panel visible" ); + element.accordion( "option", "active", 1 ); + assert.ok( panels.eq( 0 ).is( ":hidden" ), "first panel hidden" ); + assert.ok( panels.eq( 1 ).is( ":visible" ), "second panel visible" ); + $.fn.animate = animate; +} ); + +QUnit.test( "{ animate: Number }", function( assert ) { + var ready = assert.async(); + assert.expect( 7 ); + var element = $( "#list1" ).accordion( { + animate: 100 + } ), + panels = element.find( ".ui-accordion-content" ), + animate = $.fn.animate; + + // Called twice (both panels) + $.fn.animate = function( props, options ) { + assert.equal( options.duration, 100, "correct duration" ); + assert.equal( options.easing, undefined, "default easing" ); + animate.apply( this, arguments ); + }; + + assert.ok( panels.eq( 0 ).is( ":visible" ), "first panel visible" ); + element.accordion( "option", "active", 1 ); + panels.promise().done( function() { + assert.ok( panels.eq( 0 ).is( ":hidden" ), "first panel hidden" ); + assert.ok( panels.eq( 1 ).is( ":visible" ), "second panel visible" ); + $.fn.animate = animate; + ready(); + } ); +} ); + +QUnit.test( "{ animate: String }", function( assert ) { + var ready = assert.async(); + assert.expect( 7 ); + var element = $( "#list1" ).accordion( { + animate: "linear" + } ), + panels = element.find( ".ui-accordion-content" ), + animate = $.fn.animate; + + // Called twice (both panels) + $.fn.animate = function( props, options ) { + assert.equal( options.duration, undefined, "default duration" ); + assert.equal( options.easing, "linear", "correct easing" ); + animate.apply( this, arguments ); + }; + + assert.ok( panels.eq( 0 ).is( ":visible" ), "first panel visible" ); + element.accordion( "option", "active", 1 ); + panels.promise().done( function() { + assert.ok( panels.eq( 0 ).is( ":hidden" ), "first panel hidden" ); + assert.ok( panels.eq( 1 ).is( ":visible" ), "second panel visible" ); + $.fn.animate = animate; + ready(); + } ); +} ); + +QUnit.test( "{ animate: {} }", function( assert ) { + var ready = assert.async(); + assert.expect( 7 ); + var element = $( "#list1" ).accordion( { + animate: {} + } ), + panels = element.find( ".ui-accordion-content" ), + animate = $.fn.animate; + + // Called twice (both panels) + $.fn.animate = function( props, options ) { + assert.equal( options.duration, undefined, "default duration" ); + assert.equal( options.easing, undefined, "default easing" ); + animate.apply( this, arguments ); + }; + + assert.ok( panels.eq( 0 ).is( ":visible" ), "first panel visible" ); + element.accordion( "option", "active", 1 ); + panels.promise().done( function() { + assert.ok( panels.eq( 0 ).is( ":hidden" ), "first panel hidden" ); + assert.ok( panels.eq( 1 ).is( ":visible" ), "second panel visible" ); + $.fn.animate = animate; + ready(); + } ); +} ); + +QUnit.test( "{ animate: { duration, easing } }", function( assert ) { + var ready = assert.async(); + assert.expect( 7 ); + var element = $( "#list1" ).accordion( { + animate: { duration: 100, easing: "linear" } + } ), + panels = element.find( ".ui-accordion-content" ), + animate = $.fn.animate; + + // Called twice (both panels) + $.fn.animate = function( props, options ) { + assert.equal( options.duration, 100, "correct duration" ); + assert.equal( options.easing, "linear", "correct easing" ); + animate.apply( this, arguments ); + }; + + assert.ok( panels.eq( 0 ).is( ":visible" ), "first panel visible" ); + element.accordion( "option", "active", 1 ); + panels.promise().done( function() { + assert.ok( panels.eq( 0 ).is( ":hidden" ), "first panel hidden" ); + assert.ok( panels.eq( 1 ).is( ":visible" ), "second panel visible" ); + $.fn.animate = animate; + ready(); + } ); +} ); + +QUnit.test( "{ animate: { duration, easing } }, animate down", function( assert ) { + var ready = assert.async(); + assert.expect( 7 ); + var element = $( "#list1" ).accordion( { + active: 1, + animate: { duration: 100, easing: "linear" } + } ), + panels = element.find( ".ui-accordion-content" ), + animate = $.fn.animate; + + // Called twice (both panels) + $.fn.animate = function( props, options ) { + assert.equal( options.duration, 100, "correct duration" ); + assert.equal( options.easing, "linear", "correct easing" ); + animate.apply( this, arguments ); + }; + + assert.ok( panels.eq( 1 ).is( ":visible" ), "first panel visible" ); + element.accordion( "option", "active", 0 ); + panels.promise().done( function() { + assert.ok( panels.eq( 1 ).is( ":hidden" ), "first panel hidden" ); + assert.ok( panels.eq( 0 ).is( ":visible" ), "second panel visible" ); + $.fn.animate = animate; + ready(); + } ); +} ); + +QUnit.test( "{ animate: { duration, easing, down } }, animate down", function( assert ) { + var ready = assert.async(); + assert.expect( 7 ); + var element = $( "#list1" ).accordion( { + active: 1, + animate: { + duration: 100, + easing: "linear", + down: { + easing: "swing" + } + } + } ), + panels = element.find( ".ui-accordion-content" ), + animate = $.fn.animate; + + // Called twice (both panels) + $.fn.animate = function( props, options ) { + assert.equal( options.duration, 100, "correct duration" ); + assert.equal( options.easing, "swing", "correct easing" ); + animate.apply( this, arguments ); + }; + + assert.ok( panels.eq( 1 ).is( ":visible" ), "first panel visible" ); + element.accordion( "option", "active", 0 ); + panels.promise().done( function() { + assert.ok( panels.eq( 1 ).is( ":hidden" ), "first panel hidden" ); + assert.ok( panels.eq( 0 ).is( ":visible" ), "second panel visible" ); + $.fn.animate = animate; + ready(); + } ); +} ); + +QUnit.test( "{ collapsible: false }", function( assert ) { + assert.expect( 4 ); + var element = $( "#list1" ).accordion( { + active: 1 + } ); + element.accordion( "option", "active", false ); + assert.equal( element.accordion( "option", "active" ), 1 ); + state( assert, element, 0, 1, 0 ); + + element.find( ".ui-accordion-header" ).eq( 1 ).trigger( "click" ); + assert.equal( element.accordion( "option", "active" ), 1 ); + state( assert, element, 0, 1, 0 ); +} ); + +QUnit.test( "{ collapsible: true }", function( assert ) { + assert.expect( 6 ); + var element = $( "#list1" ).accordion( { + active: 1, + collapsible: true + } ); + + element.accordion( "option", "active", false ); + assert.equal( element.accordion( "option", "active" ), false ); + state( assert, element, 0, 0, 0 ); + + element.accordion( "option", "active", 1 ); + assert.equal( element.accordion( "option", "active" ), 1 ); + state( assert, element, 0, 1, 0 ); + + element.find( ".ui-accordion-header" ).eq( 1 ).trigger( "click" ); + assert.equal( element.accordion( "option", "active" ), false ); + state( assert, element, 0, 0, 0 ); +} ); + +QUnit.test( "{ event: null }", function( assert ) { + assert.expect( 5 ); + var element = $( "#list1" ).accordion( { + event: null + } ); + state( assert, element, 1, 0, 0 ); + + element.accordion( "option", "active", 1 ); + assert.equal( element.accordion( "option", "active" ), 1 ); + state( assert, element, 0, 1, 0 ); + + // Ensure default click handler isn't bound + element.find( ".ui-accordion-header" ).eq( 2 ).trigger( "click" ); + assert.equal( element.accordion( "option", "active" ), 1 ); + state( assert, element, 0, 1, 0 ); +} ); + +QUnit.test( "{ event: custom }", function( assert ) { + assert.expect( 11 ); + var element = $( "#list1" ).accordion( { + event: "custom1 custom2" + } ); + state( assert, element, 1, 0, 0 ); + + element.find( ".ui-accordion-header" ).eq( 1 ).trigger( "custom1" ); + assert.equal( element.accordion( "option", "active" ), 1 ); + state( assert, element, 0, 1, 0 ); + + // Ensure default click handler isn't bound + element.find( ".ui-accordion-header" ).eq( 2 ).trigger( "click" ); + assert.equal( element.accordion( "option", "active" ), 1 ); + state( assert, element, 0, 1, 0 ); + + element.find( ".ui-accordion-header" ).eq( 2 ).trigger( "custom2" ); + assert.equal( element.accordion( "option", "active" ), 2 ); + state( assert, element, 0, 0, 1 ); + + element.accordion( "option", "event", "custom3" ); + + // Ensure old event handlers are unbound + element.find( ".ui-accordion-header" ).eq( 1 ).trigger( "custom1" ); + element.find( ".ui-accordion-header" ).eq( 1 ).trigger( "custom2" ); + assert.equal( element.accordion( "option", "active" ), 2 ); + state( assert, element, 0, 0, 1 ); + + element.find( ".ui-accordion-header" ).eq( 1 ).trigger( "custom3" ); + assert.equal( element.accordion( "option", "active" ), 1 ); + state( assert, element, 0, 1, 0 ); +} ); + +QUnit.test( "{ header: default }", function( assert ) { + assert.expect( 2 ); + + // Default: elem.find( "> li > :first-child" ).add( elem.find( "> :not(li)" ).even() ) + // elem.find( "> :not(li)" ).even() + state( assert, $( "#list1" ).accordion(), 1, 0, 0 ); + + // > li > :first-child + state( assert, $( "#navigation" ).accordion(), 1, 0, 0 ); +} ); + +QUnit.test( "{ header: customString }", function( assert ) { + assert.expect( 6 ); + var element = $( "#navigationWrapper" ).accordion( { + header: "h2" + } ); + element.find( "h2" ).each( function() { + assert.hasClasses( this, "ui-accordion-header" ); + } ); + assert.equal( element.find( ".ui-accordion-header" ).length, 3 ); + state( assert, element, 1, 0, 0 ); + element.accordion( "option", "active", 2 ); + state( assert, element, 0, 0, 1 ); +} ); + +QUnit.test( "{ header: customFunction }", function( assert ) { + assert.expect( 6 ); + var element = $( "#navigationWrapper" ).accordion( { + header: function( elem ) { + return elem.find( "h2" ); + } + } ); + element.find( "h2" ).each( function() { + assert.hasClasses( this, "ui-accordion-header" ); + } ); + assert.equal( element.find( ".ui-accordion-header" ).length, 3 ); + state( assert, element, 1, 0, 0 ); + element.accordion( "option", "active", 2 ); + state( assert, element, 0, 0, 1 ); +} ); + +QUnit.test( "{ heightStyle: 'auto' }", function( assert ) { + assert.expect( 3 ); + var element = $( "#navigation" ).accordion( { heightStyle: "auto" } ); + equalHeight( assert, element, 105 ); +} ); + +QUnit.test( "{ heightStyle: 'content' }", function( assert ) { + assert.expect( 3 ); + var element = $( "#navigation" ).accordion( { heightStyle: "content" } ), + sizes = element.find( ".ui-accordion-content" ).map( function() { + return $( this ).height(); + } ).get(); + assert.equal( sizes[ 0 ], 75 ); + assert.equal( sizes[ 1 ], 105 ); + assert.equal( sizes[ 2 ], 45 ); +} ); + +QUnit.test( "{ heightStyle: 'fill' }", function( assert ) { + assert.expect( 3 ); + $( "#navigationWrapper" ).height( 500 ); + var element = $( "#navigation" ).accordion( { heightStyle: "fill" } ); + equalHeight( assert, element, 455 ); +} ); + +QUnit.test( "{ heightStyle: 'fill' } with sibling", function( assert ) { + assert.expect( 3 ); + $( "#navigationWrapper" ).height( 500 ); + $( "

      Lorem Ipsum

      " ) + .css( { + height: 50, + marginTop: 20, + marginBottom: 30 + } ) + .prependTo( "#navigationWrapper" ); + var element = $( "#navigation" ).accordion( { heightStyle: "fill" } ); + equalHeight( assert, element, 355 ); +} ); + +QUnit.test( "{ heightStyle: 'fill' } with multiple siblings", function( assert ) { + assert.expect( 3 ); + $( "#navigationWrapper" ).height( 500 ); + $( "

      Lorem Ipsum

      " ) + .css( { + height: 50, + marginTop: 20, + marginBottom: 30 + } ) + .prependTo( "#navigationWrapper" ); + $( "

      Lorem Ipsum

      " ) + .css( { + height: 50, + marginTop: 20, + marginBottom: 30, + position: "absolute" + } ) + .prependTo( "#navigationWrapper" ); + $( "

      Lorem Ipsum

      " ) + .css( { + height: 25, + marginTop: 10, + marginBottom: 15 + } ) + .prependTo( "#navigationWrapper" ); + var element = $( "#navigation" ).accordion( { heightStyle: "fill" } ); + equalHeight( assert, element, 305 ); +} ); + +QUnit.test( "{ icons: false }", function( assert ) { + assert.expect( 8 ); + var element = $( "#list1" ); + function icons( on ) { + assert.deepEqual( element.find( "span.ui-icon" ).length, on ? 3 : 0 ); + assert.deepEqual( element.find( ".ui-accordion-header.ui-accordion-icons" ).length, on ? 3 : 0 ); + } + element.accordion(); + icons( true ); + element.accordion( "destroy" ).accordion( { + icons: false + } ); + icons( false ); + element.accordion( "option", "icons", { header: "foo", activeHeader: "bar" } ); + icons( true ); + element.accordion( "option", "icons", false ); + icons( false ); +} ); + +QUnit.test( "{ icons: hash }", function( assert ) { + assert.expect( 3 ); + var element = $( "#list1" ).accordion( { + icons: { activeHeader: "a1", header: "h1" } + } ); + assert.hasClasses( element.find( ".ui-accordion-header.ui-state-active span.ui-icon" ), "a1" ); + element.accordion( "option", "icons", { activeHeader: "a2", header: "h2" } ); + assert.lacksClasses( element.find( ".ui-accordion-header.ui-state-active span.ui-icon" ), "a1" ); + assert.hasClasses( element.find( ".ui-accordion-header.ui-state-active span.ui-icon" ), "a2" ); +} ); + +} ); diff --git a/tests/unit/all.html b/tests/unit/all.html new file mode 100644 index 00000000000..67d7141301f --- /dev/null +++ b/tests/unit/all.html @@ -0,0 +1,70 @@ + + + + + jQuery UI Test Suite + + + + + + + + + + + + +
      +
      + +
      + + diff --git a/tests/unit/autocomplete/all.html b/tests/unit/autocomplete/all.html new file mode 100644 index 00000000000..94678956aea --- /dev/null +++ b/tests/unit/autocomplete/all.html @@ -0,0 +1,26 @@ + + + + + jQuery UI Autocomplete Test Suite + + + + + + + + + + + + + +
      +
      + +
      + + diff --git a/tests/unit/autocomplete/autocomplete.html b/tests/unit/autocomplete/autocomplete.html index 7ca96eb68f5..484f2d95758 100644 --- a/tests/unit/autocomplete/autocomplete.html +++ b/tests/unit/autocomplete/autocomplete.html @@ -1,44 +1,23 @@ - + - + jQuery UI Autocomplete Test Suite - - - - - - - - - - - - - - - - - - - - - + + + - + -

      jQuery UI Autocomplete Test Suite

      -

      -

      -
        -
      +
      +
      -
      - -
      +
      +
      +
      +
      - diff --git a/tests/unit/autocomplete/autocomplete_core.js b/tests/unit/autocomplete/autocomplete_core.js deleted file mode 100644 index 9b8709abb6a..00000000000 --- a/tests/unit/autocomplete/autocomplete_core.js +++ /dev/null @@ -1,43 +0,0 @@ -/* - * autocomplete_core.js - */ - - -(function($) { - -module("autocomplete: core", { - teardown: function() { - $( ":ui-autocomplete" ).autocomplete( "destroy" ); - } -}); - -test("close-on-blur is properly delayed", function() { - var ac = $("#autocomplete").autocomplete({ - source: ["java", "javascript"] - }).val("ja").autocomplete("search"); - same( $(".ui-menu:visible").length, 1 ); - ac.blur(); - same( $(".ui-menu:visible").length, 1 ); - stop(); - setTimeout(function() { - same( $(".ui-menu:visible").length, 0 ); - start(); - }, 200); -}) - -test("close-on-blur is cancelled when starting a search", function() { - var ac = $("#autocomplete").autocomplete({ - source: ["java", "javascript"] - }).val("ja").autocomplete("search"); - same( $(".ui-menu:visible").length, 1 ); - ac.blur(); - same( $(".ui-menu:visible").length, 1 ); - ac.autocomplete("search"); - stop(); - setTimeout(function() { - same( $(".ui-menu:visible").length, 1 ); - start(); - }, 200); -}) - -})(jQuery); diff --git a/tests/unit/autocomplete/autocomplete_defaults.js b/tests/unit/autocomplete/autocomplete_defaults.js deleted file mode 100644 index c6017d62ca6..00000000000 --- a/tests/unit/autocomplete/autocomplete_defaults.js +++ /dev/null @@ -1,12 +0,0 @@ -/* - * autocomplete_defaults.js - */ - -var autocomplete_defaults = { - delay: 300, - disabled: false, - minLength: 1, - source: undefined -}; - -commonWidgetTests('autocomplete', { defaults: autocomplete_defaults }); diff --git a/tests/unit/autocomplete/autocomplete_events.js b/tests/unit/autocomplete/autocomplete_events.js deleted file mode 100644 index a8924e192a4..00000000000 --- a/tests/unit/autocomplete/autocomplete_events.js +++ /dev/null @@ -1,142 +0,0 @@ -/* - * autocomplete_events.js - */ -(function($) { - -module("autocomplete: events", { - teardown: function() { - $( ":ui-autocomplete" ).autocomplete( "destroy" ); - } -}); - -var data = ["c++", "java", "php", "coldfusion", "javascript", "asp", "ruby", "python", "c", "scala", "groovy", "haskell", "perl"]; - -test("all events", function() { - expect(12); - var ac = $("#autocomplete").autocomplete({ - delay: 0, - source: data, - search: function(event) { - same(event.type, "autocompletesearch"); - }, - open: function(event) { - same(event.type, "autocompleteopen"); - }, - focus: function(event, ui) { - same(event.type, "autocompletefocus"); - same(ui.item, {label:"java", value:"java"}); - }, - close: function(event) { - same(event.type, "autocompleteclose"); - same( $(".ui-menu:visible").length, 1 ); - }, - select: function(event, ui) { - same(event.type, "autocompleteselect"); - same(ui.item, {label:"java", value:"java"}); - }, - change: function(event, ui) { - same(event.type, "autocompletechange"); - same(ui.item, {label:"java", value:"java"}); - same( $(".ui-menu:visible").length, 0 ); - start(); - } - }); - stop(); - ac.focus().val("ja").keydown(); - setTimeout(function() { - same( $(".ui-menu:visible").length, 1 ); - ac.simulate("keydown", { keyCode: $.ui.keyCode.DOWN }); - ac.simulate("keydown", { keyCode: $.ui.keyCode.ENTER }); - $.browser.msie ? ac.simulate("blur") : ac.blur(); - }, 50); -}); - -test("change without selection", function() { - expect(2); - stop(); - var ac = $("#autocomplete").autocomplete({ - delay: 0, - source: data, - change: function(event, ui) { - same(event.type, "autocompletechange"); - same(ui.item, null); - start(); - } - }); - ac.triggerHandler("focus"); - ac.val("ja").triggerHandler("blur"); -}); - -test("cancel search", function() { - expect(6); - var first = true; - var ac = $("#autocomplete").autocomplete({ - delay: 0, - source: data, - search: function() { - if (first) { - same( ac.val(), "ja" ); - first = false; - return false; - } - same( ac.val(), "java" ); - }, - open: function() { - ok(true); - } - }); - stop(); - ac.val("ja").keydown(); - setTimeout(function() { - same( $(".ui-menu:visible").length, 0 ); - ac.val("java").keydown(); - setTimeout(function() { - same( $(".ui-menu:visible").length, 1 ); - same( $(".ui-menu .ui-menu-item").length, 2 ); - start(); - }, 50); - }, 50); -}); - -test("cancel focus", function() { - expect(1); - var customVal = 'custom value'; - var ac = $("#autocomplete").autocomplete({ - delay: 0, - source: data, - focus: function(event, ui) { - $(this).val(customVal); - return false; - } - }); - stop(); - ac.val("ja").keydown(); - setTimeout(function() { - ac.simulate("keydown", { keyCode: $.ui.keyCode.DOWN }); - same( ac.val(), customVal ); - start(); - }, 50); -}); - -test("cancel select", function() { - expect(1); - var customVal = 'custom value'; - var ac = $("#autocomplete").autocomplete({ - delay: 0, - source: data, - select: function(event, ui) { - $(this).val(customVal); - return false; - } - }); - stop(); - ac.val("ja").keydown(); - setTimeout(function() { - ac.simulate("keydown", { keyCode: $.ui.keyCode.DOWN }); - ac.simulate("keydown", { keyCode: $.ui.keyCode.ENTER }); - same( ac.val(), customVal ); - start(); - }, 50); -}); - -})(jQuery); diff --git a/tests/unit/autocomplete/autocomplete_methods.js b/tests/unit/autocomplete/autocomplete_methods.js deleted file mode 100644 index 05a7d6e1448..00000000000 --- a/tests/unit/autocomplete/autocomplete_methods.js +++ /dev/null @@ -1,43 +0,0 @@ -/* - * autocomplete_methods.js - */ -(function($) { - - -module("autocomplete: methods", { - teardown: function() { - $( ":ui-autocomplete" ).autocomplete( "destroy" ); - } -}); - -test("destroy", function() { - var beforeHtml = $("#autocomplete").parent().html(); - var afterHtml = $("#autocomplete").autocomplete().autocomplete("destroy").parent().html(); - // Opera 9 outputs role="" instead of removing the attribute like everyone else - if ($.browser.opera) { - afterHtml = afterHtml.replace(/ role=""/g, ""); - } - equal( afterHtml, beforeHtml, "before/after html should be the same" ); -}) - -var data = ["c++", "java", "php", "coldfusion", "javascript", "asp", "ruby", "python", "c", "scala", "groovy", "haskell", "perl"]; - -test("search", function() { - var ac = $("#autocomplete").autocomplete({ - source: data, - minLength: 0 - }); - ac.autocomplete("search"); - same( $(".ui-menu .ui-menu-item").length, data.length, "all items for a blank search" ); - - ac.val("has"); - ac.autocomplete("search") - same( $(".ui-menu .ui-menu-item").text(), "haskell", "only one item for set input value" ); - - ac.autocomplete("search", "ja"); - same( $(".ui-menu .ui-menu-item").length, 2, "only java and javascript for 'ja'" ); - - $("#autocomplete").autocomplete("destroy"); -}) - -})(jQuery); diff --git a/tests/unit/autocomplete/autocomplete_options.js b/tests/unit/autocomplete/autocomplete_options.js deleted file mode 100644 index c5aa7c96151..00000000000 --- a/tests/unit/autocomplete/autocomplete_options.js +++ /dev/null @@ -1,178 +0,0 @@ -/* - * autocomplete_options.js - */ -(function($) { - -module("autocomplete: options", { - teardown: function() { - $( ":ui-autocomplete" ).autocomplete( "destroy" ); - } -}); - - -/* disabled until autocomplete actually has built-in support for caching -// returns at most 4 items -function source(request) { - ok(true, "handling a request"); - switch(request.term) { - case "cha": - return ["Common Pochard", "Common Chiffchaff", "Common Chaffinch", "Iberian Chiffchaff"] - case "chaf": - case "chaff": - return ["Common Chiffchaff", "Common Chaffinch", "Iberian Chiffchaff"] - case "chaffi": - return ["Common Chaffinch"] - case "schi": - return ["schifpre"] - } -} - -function search(input) { - var autocomplete = input.data("autocomplete"); - autocomplete.search("cha"); - autocomplete.close(); - autocomplete.search("chaf"); - autocomplete.close(); - autocomplete.search("chaff"); - autocomplete.close(); - autocomplete.search("chaffi"); - autocomplete.close(); - autocomplete.search("schi"); -} - -test("cache: default", function() { - expect(2); - search($("#autocomplete").autocomplete({ - source: source - })); -}); - -test("cache: {limit:4}", function() { - expect(3); - search($("#autocomplete").autocomplete({ - cache: { - limit: 4 - }, - source: source - })); -}); - -test("cache: false", function() { - expect(5); - search($("#autocomplete").autocomplete({ - cache: false, - source: source - })); -}); -*/ - -var data = ["c++", "java", "php", "coldfusion", "javascript", "asp", "ruby", "python", "c", "scala", "groovy", "haskell", "perl"]; - -test("delay", function() { - var ac = $("#autocomplete").autocomplete({ - source: data, - delay: 50 - }); - ac.val("ja").keydown(); - - same( $(".ui-menu:visible").length, 0 ); - - // wait half a second for the default delay to open the menu - stop(); - setTimeout(function() { - same( $(".ui-menu:visible").length, 1 ); - ac.autocomplete("destroy"); - start(); - }, 100); -}); - -test("minLength", function() { - var ac = $("#autocomplete").autocomplete({ - source: data - }); - ac.autocomplete("search", ""); - same( $(".ui-menu:visible").length, 0, "blank not enough for minLength: 1" ); - - ac.autocomplete("option", "minLength", 0); - ac.autocomplete("search", ""); - same( $(".ui-menu:visible").length, 1, "blank enough for minLength: 0" ); - ac.autocomplete("destroy"); -}); - -test("source, local string array", function() { - var ac = $("#autocomplete").autocomplete({ - source: data - }); - ac.val("ja").autocomplete("search"); - same( $(".ui-menu .ui-menu-item").text(), "javajavascript" ); - ac.autocomplete("destroy"); -}); - -function source_test(source, async) { - var ac = $("#autocomplete").autocomplete({ - source: source - }); - ac.val("ja").autocomplete("search"); - function result(){ - same( $(".ui-menu .ui-menu-item").text(), "javajavascript" ); - ac.autocomplete("destroy"); - async && start(); - } - if (async) { - stop(); - $(document).one("ajaxStop", result); - } else { - result(); - } -} - -test("source, local object array, only label property", function() { - source_test([ - {label:"java"}, - {label:"php"}, - {label:"coldfusion"}, - {label:"javascript"} - ]); -}); - -test("source, local object array, only value property", function() { - source_test([ - {value:"java"}, - {value:"php"}, - {value:"coldfusion"}, - {value:"javascript"} - ]); -}); - -test("source, url string with remote json string array", function() { - source_test("remote_string_array.txt", true); -}); - -test("source, url string with remote json object array, only value properties", function() { - source_test("remote_object_array_values.txt", true); -}); - -test("source, url string with remote json object array, only label properties", function() { - source_test("remote_object_array_labels.txt", true); -}); - -test("source, custom", function() { - source_test(function(request, response) { - same( request.term, "ja" ); - response(["java", "javascript"]); - }); -}); - -test("source, update after init", function() { - var ac = $("#autocomplete").autocomplete({ - source: ["java", "javascript", "haskell"] - }); - ac.val("ja").autocomplete("search"); - same( $(".ui-menu .ui-menu-item").text(), "javajavascript" ); - ac.autocomplete("option", "source", ["php", "asp"]); - ac.val("ph").autocomplete("search"); - same( $(".ui-menu .ui-menu-item").text(), "php" ); - ac.autocomplete("destroy"); -}); - -})(jQuery); diff --git a/tests/unit/autocomplete/autocomplete_tickets.js b/tests/unit/autocomplete/autocomplete_tickets.js deleted file mode 100644 index bde9faffdc7..00000000000 --- a/tests/unit/autocomplete/autocomplete_tickets.js +++ /dev/null @@ -1,14 +0,0 @@ -/* - * autocomplete_tickets.js - */ -(function($) { - -module("autocomplete: tickets", { - teardown: function() { - $( ":ui-autocomplete" ).autocomplete( "destroy" ); - } -}); - - - -})(jQuery); diff --git a/tests/unit/autocomplete/common.js b/tests/unit/autocomplete/common.js new file mode 100644 index 00000000000..a4d57f95db9 --- /dev/null +++ b/tests/unit/autocomplete/common.js @@ -0,0 +1,37 @@ +define( [ + "lib/common", + "ui/widgets/autocomplete" +], function( common ) { + +common.testWidget( "autocomplete", { + defaults: { + appendTo: null, + autoFocus: false, + classes: {}, + delay: 300, + disabled: false, + messages: { + noResults: "No search results.", + results: $.ui.autocomplete.prototype.options.messages.results + }, + minLength: 1, + position: { + my: "left top", + at: "left bottom", + collision: "none" + }, + source: null, + + // Callbacks + change: null, + close: null, + create: null, + focus: null, + open: null, + response: null, + search: null, + select: null + } +} ); + +} ); diff --git a/tests/unit/autocomplete/core.js b/tests/unit/autocomplete/core.js new file mode 100644 index 00000000000..2083e16b1aa --- /dev/null +++ b/tests/unit/autocomplete/core.js @@ -0,0 +1,469 @@ +define( [ + "qunit", + "jquery", + "lib/helper", + "ui/widgets/autocomplete" +], function( QUnit, $, helper ) { +"use strict"; + +QUnit.module( "autocomplete: core", { afterEach: helper.moduleAfterEach } ); + +QUnit.test( "markup structure", function( assert ) { + assert.expect( 2 ); + var element = $( "#autocomplete" ).autocomplete(), + menu = element.autocomplete( "widget" ); + + assert.hasClasses( element, "ui-autocomplete-input" ); + assert.hasClasses( menu, "ui-autocomplete ui-widget ui-widget-content" ); +} ); + +QUnit.test( "prevent form submit on enter when menu is active", function( assert ) { + assert.expect( 2 ); + var event, + element = $( "#autocomplete" ) + .autocomplete( { + source: [ "java", "javascript" ] + } ) + .val( "ja" ) + .autocomplete( "search" ), + menu = element.autocomplete( "widget" ); + + event = $.Event( "keydown" ); + event.keyCode = $.ui.keyCode.DOWN; + element.trigger( event ); + assert.equal( menu.find( ".ui-menu-item-wrapper.ui-state-active" ).length, 1, + "menu item is active" ); + + event = $.Event( "keydown" ); + event.keyCode = $.ui.keyCode.ENTER; + element.trigger( event ); + assert.ok( event.isDefaultPrevented(), "default action is prevented" ); +} ); + +QUnit.test( "allow form submit on enter when menu is not active", function( assert ) { + assert.expect( 1 ); + var event, + element = $( "#autocomplete" ) + .autocomplete( { + autoFocus: false, + source: [ "java", "javascript" ] + } ) + .val( "ja" ) + .autocomplete( "search" ); + + event = $.Event( "keydown" ); + event.keyCode = $.ui.keyCode.ENTER; + element.trigger( event ); + assert.ok( !event.isDefaultPrevented(), "default action is prevented" ); +} ); + +( function() { + QUnit.test( "up arrow invokes search - input", function( assert ) { + arrowsInvokeSearch( assert, "#autocomplete", true, true ); + } ); + + QUnit.test( "down arrow invokes search - input", function( assert ) { + arrowsInvokeSearch( assert, "#autocomplete", false, true ); + } ); + + QUnit.test( "up arrow invokes search - textarea", function( assert ) { + arrowsInvokeSearch( assert, "#autocomplete-textarea", true, false ); + } ); + + QUnit.test( "down arrow invokes search - textarea", function( assert ) { + arrowsInvokeSearch( assert, "#autocomplete-textarea", false, false ); + } ); + + QUnit.test( "up arrow invokes search - contenteditable", function( assert ) { + arrowsInvokeSearch( assert, "#autocomplete-contenteditable", true, false ); + } ); + + QUnit.test( "down arrow invokes search - contenteditable", function( assert ) { + arrowsInvokeSearch( assert, "#autocomplete-contenteditable", false, false ); + } ); + + QUnit.test( "up arrow moves focus - input", function( assert ) { + arrowsMoveFocus( assert, "#autocomplete", true ); + } ); + + QUnit.test( "down arrow moves focus - input", function( assert ) { + arrowsMoveFocus( assert, "#autocomplete", false ); + } ); + + QUnit.test( "up arrow moves focus - textarea", function( assert ) { + arrowsMoveFocus( assert, "#autocomplete-textarea", true ); + } ); + + QUnit.test( "down arrow moves focus - textarea", function( assert ) { + arrowsMoveFocus( assert, "#autocomplete-textarea", false ); + } ); + + QUnit.test( "up arrow moves focus - contenteditable", function( assert ) { + arrowsMoveFocus( assert, "#autocomplete-contenteditable", true ); + } ); + + QUnit.test( "down arrow moves focus - contenteditable", function( assert ) { + arrowsMoveFocus( assert, "#autocomplete-contenteditable", false ); + } ); + + QUnit.test( "up arrow moves cursor - input", function( assert ) { + arrowsNavigateElement( assert, "#autocomplete", true, false ); + } ); + + QUnit.test( "down arrow moves cursor - input", function( assert ) { + arrowsNavigateElement( assert, "#autocomplete", false, false ); + } ); + + QUnit.test( "up arrow moves cursor - textarea", function( assert ) { + arrowsNavigateElement( assert, "#autocomplete-textarea", true, true ); + } ); + + QUnit.test( "down arrow moves cursor - textarea", function( assert ) { + arrowsNavigateElement( assert, "#autocomplete-textarea", false, true ); + } ); + + QUnit.test( "up arrow moves cursor - contenteditable", function( assert ) { + arrowsNavigateElement( assert, "#autocomplete-contenteditable", true, true ); + } ); + + QUnit.test( "down arrow moves cursor - contenteditable", function( assert ) { + arrowsNavigateElement( assert, "#autocomplete-contenteditable", false, true ); + } ); + + function arrowsInvokeSearch( assert, id, isKeyUp, shouldMove ) { + assert.expect( 1 ); + + var didMove = false, + element = $( id ).autocomplete( { + source: [ "a" ], + delay: 0, + minLength: 0 + } ); + element.autocomplete( "instance" )._move = function() { + didMove = true; + }; + element.simulate( "keydown", { keyCode: ( isKeyUp ? $.ui.keyCode.UP : $.ui.keyCode.DOWN ) } ); + assert.equal( didMove, shouldMove, "respond to arrow" ); + } + + function arrowsMoveFocus( assert, id, isKeyUp ) { + assert.expect( 1 ); + + var element = $( id ).autocomplete( { + source: [ "a" ], + delay: 0, + minLength: 0 + } ); + element.autocomplete( "instance" )._move = function() { + assert.ok( true, "repsond to arrow" ); + }; + element.autocomplete( "search" ); + element.simulate( "keydown", { keyCode: ( isKeyUp ? $.ui.keyCode.UP : $.ui.keyCode.DOWN ) } ); + } + + function arrowsNavigateElement( assert, id, isKeyUp, shouldMove ) { + assert.expect( 1 ); + + var didMove = false, + element = $( id ).autocomplete( { + source: [ "a" ], + delay: 0, + minLength: 0 + } ); + element.on( "keypress", function( e ) { + didMove = !e.isDefaultPrevented(); + } ); + element.simulate( "keydown", { keyCode: ( isKeyUp ? $.ui.keyCode.UP : $.ui.keyCode.DOWN ) } ); + element.simulate( "keypress" ); + assert.equal( didMove, shouldMove, "respond to arrow" ); + } +} )(); + +QUnit.test( "past end of menu in multiline autocomplete", function( assert ) { + var ready = assert.async(); + assert.expect( 2 ); + + var customVal = "custom value", + element = $( "#autocomplete-contenteditable" ).autocomplete( { + delay: 0, + source: [ "javascript" ], + focus: function( event, ui ) { + assert.equal( ui.item.value, "javascript", "Item gained focus" ); + $( this ).text( customVal ); + event.preventDefault(); + } + } ); + + element + .simulate( "focus" ) + .autocomplete( "search", "ja" ); + + setTimeout( function() { + element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } ); + element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } ); + assert.equal( element.text(), customVal ); + ready(); + } ); +} ); + +QUnit.test( "ESCAPE in multiline autocomplete", function( assert ) { + var ready = assert.async(); + assert.expect( 2 ); + + var customVal = "custom value", + element = $( "#autocomplete-contenteditable" ).autocomplete( { + delay: 0, + source: [ "javascript" ], + focus: function( event, ui ) { + assert.equal( ui.item.value, "javascript", "Item gained focus" ); + $( this ).text( customVal ); + event.preventDefault(); + } + } ); + + element + .simulate( "focus" ) + .autocomplete( "search", "ja" ); + + setTimeout( function() { + element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } ); + element.simulate( "keydown", { keyCode: $.ui.keyCode.ESCAPE } ); + assert.equal( element.text(), customVal ); + ready(); + } ); +} ); + +QUnit.test( "handle race condition", function( assert ) { + var ready = assert.async(); + assert.expect( 3 ); + var count = 0, + element = $( "#autocomplete" ).autocomplete( { + source: function( request, response ) { + count++; + if ( request.term.length === 1 ) { + assert.equal( count, 1, "request with 1 character is first" ); + setTimeout( function() { + response( [ "one" ] ); + setTimeout( checkResults ); + } ); + return; + } + assert.equal( count, 2, "request with 2 characters is second" ); + response( [ "two" ] ); + } + } ); + + element.autocomplete( "search", "a" ); + element.autocomplete( "search", "ab" ); + + function checkResults() { + assert.equal( element.autocomplete( "widget" ).find( ".ui-menu-item" ).text(), "two", + "correct results displayed" ); + ready(); + } +} ); + +QUnit.test( "simultaneous searches (#9334)", function( assert ) { + var ready = assert.async(); + assert.expect( 2 ); + var element = $( "#autocomplete" ).autocomplete( { + source: function( request, response ) { + setTimeout( function() { + response( [ request.term ] ); + } ); + }, + response: function() { + assert.ok( true, "response from first instance" ); + } + } ), + element2 = $( "#autocomplete-textarea" ).autocomplete( { + source: function( request, response ) { + setTimeout( function() { + response( [ request.term ] ); + } ); + }, + response: function() { + assert.ok( true, "response from second instance" ); + ready(); + } + } ); + + element.autocomplete( "search", "test" ); + element2.autocomplete( "search", "test" ); +} ); + +QUnit.test( "ARIA", function( assert ) { + var ready = assert.async(); + assert.expect( 13 ); + var element = $( "#autocomplete" ).autocomplete( { + source: [ "java", "javascript" ] + } ), + liveRegion = element.autocomplete( "instance" ).liveRegion; + + assert.equal( liveRegion.children().length, 0, "Empty live region on create" ); + assert.equal( liveRegion.attr( "aria-live" ), "assertive", + "Live region's aria-live attribute must be assertive" ); + assert.equal( liveRegion.attr( "aria-relevant" ), "additions", + "Live region's aria-relevant attribute must be additions" ); + assert.equal( liveRegion.attr( "role" ), "status", + "Live region's role attribute must be status" ); + + element.autocomplete( "search", "j" ); + setTimeout( function() { + assert.equal( liveRegion.children().first().text(), + "2 results are available, use up and down arrow keys to navigate.", + "Live region for multiple values" ); + + element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } ); + setTimeout( function() { + assert.equal( liveRegion.children().filter( ":visible" ).text(), "java", + "Live region changed on keydown to announce the highlighted value" ); + + element.one( "autocompletefocus", function( event ) { + event.preventDefault(); + } ); + element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } ); + setTimeout( function() { + assert.equal( liveRegion.children().filter( ":visible" ).text(), "javascript", + "Live region updated when default focus is prevented" ); + element.autocomplete( "search", "javas" ); + setTimeout( function() { + assert.equal( liveRegion.children().filter( ":visible" ).text(), + "1 result is available, use up and down arrow keys to navigate.", + "Live region for one value" ); + element.autocomplete( "search", "z" ); + setTimeout( function() { + assert.equal( liveRegion.children().filter( ":visible" ).text(), "No search results.", + "Live region for no values" ); + assert.equal( liveRegion.children().length, 1, + "Should be one child in the live region after the above" ); + assert.equal( liveRegion.children().filter( ":visible" ).length, 1, + "Only one should be still visible" ); + assert.ok( liveRegion.children().filter( ":visible" )[ 0 ] === liveRegion.children().last()[ 0 ], + "The last one should be the visible one" ); + element.autocomplete( "destroy" ); + assert.equal( liveRegion.parent().length, 0, + "The liveRegion should be detached after destroy" ); + ready(); + }, 110 ); + }, 110 ); + }, 110 ); + }, 110 ); + }, 110 ); +} ); + +QUnit.test( "ARIA, aria-label announcement", function( assert ) { + var ready = assert.async(); + assert.expect( 1 ); + $.widget( "custom.catcomplete", $.ui.autocomplete, { + _renderMenu: function( ul, items ) { + var that = this; + $.each( items, function( index, item ) { + that._renderItemData( ul, item ) + .attr( "aria-label", item.category + " : " + item.label ); + } ); + } + } ); + var element = $( "#autocomplete" ).catcomplete( { + source: [ { label: "anders andersson", category: "People" } ] + } ), + liveRegion = element.catcomplete( "instance" ).liveRegion; + element.catcomplete( "search", "a" ); + element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } ); + setTimeout( function() { + assert.equal( liveRegion.children().filter( ":visible" ).text(), "People : anders andersson", + "Live region changed on keydown to announce the highlighted value's aria-label attribute" ); + ready(); + }, 110 ); +} ); + +QUnit.test( "ARIA, init on detached input", function( assert ) { + assert.expect( 1 ); + var element = $( "" ).autocomplete( { + source: [ "java", "javascript" ] + } ), + liveRegion = element.autocomplete( "instance" ).liveRegion; + assert.equal( liveRegion.parent().length, 1, "liveRegion must have a parent" ); +} ); + +QUnit.test( ".replaceWith() (#9172)", function( assert ) { + assert.expect( 1 ); + + var element = $( "#autocomplete" ).autocomplete(), + replacement = "
      test
      ", + parent = element.parent(); + element.replaceWith( replacement ); + assert.equal( parent.html().toLowerCase(), replacement ); +} ); + +QUnit.test( "Search if the user retypes the same value (#7434)", function( assert ) { + var ready = assert.async(); + assert.expect( 3 ); + var element = $( "#autocomplete" ).autocomplete( { + source: [ "java", "javascript" ], + delay: 0 + } ), + menu = element.autocomplete( "instance" ).menu.element; + + element.val( "j" ).simulate( "keydown" ); + setTimeout( function() { + assert.ok( menu.is( ":visible" ), "menu displays initially" ); + element.trigger( "blur" ); + assert.ok( !menu.is( ":visible" ), "menu hidden after blur" ); + element.val( "j" ).simulate( "keydown" ); + setTimeout( function() { + assert.ok( menu.is( ":visible" ), "menu displays after typing the same value" ); + ready(); + } ); + } ); +} ); + +QUnit.test( "Close on click outside when focus remains", function( assert ) { + var ready = assert.async(); + assert.expect( 2 ); + + var element = $( "#autocomplete" ).autocomplete( { + source: [ "java", "javascript" ], + delay: 0 + } ); + var menu = element.autocomplete( "widget" ); + + $( "body" ).on( "mousedown", function( event ) { + event.preventDefault(); + } ); + + element.val( "j" ).autocomplete( "search", "j" ); + setTimeout( function() { + assert.ok( menu.is( ":visible" ), "menu displays initially" ); + $( "body" ).simulate( "mousedown" ); + setTimeout( function() { + assert.ok( menu.is( ":hidden" ), "menu closes after clicking elsewhere" ); + ready(); + } ); + } ); +} ); + +QUnit.test( "extra listeners created during typing (trac-15082, trac-15095)", function( assert ) { + assert.expect( 2 ); + + var origRemoveListenersCount; + var element = $( "#autocomplete" ).autocomplete( { + source: [ "java", "javascript" ], + delay: 0 + } ); + + element.val( "j" ).autocomplete( "search", "j" ); + origRemoveListenersCount = jQuery._data( element[ 0 ], "events" ).remove.length; + + element.val( "ja" ).autocomplete( "search", "ja" ); + assert.equal( jQuery._data( element[ 0 ], "events" ).remove.length, + origRemoveListenersCount, + "No extra listeners after typing multiple letters" ); + + element.val( "jav" ).autocomplete( "search", "jav" ); + assert.equal( jQuery._data( element[ 0 ], "events" ).remove.length, + origRemoveListenersCount, + "No extra listeners after typing multiple letters" ); +} ); + +} ); diff --git a/tests/unit/autocomplete/events.js b/tests/unit/autocomplete/events.js new file mode 100644 index 00000000000..9ee3a92e4a6 --- /dev/null +++ b/tests/unit/autocomplete/events.js @@ -0,0 +1,191 @@ +define( [ + "qunit", + "jquery", + "lib/helper", + "ui/widgets/autocomplete" +], function( QUnit, $, helper ) { +"use strict"; + +QUnit.module( "autocomplete: events", { afterEach: helper.moduleAfterEach } ); + +var data = [ "Clojure", "COBOL", "ColdFusion", "Java", "JavaScript", "Scala", "Scheme" ]; + +$.each( [ + { + type: "input", + selector: "#autocomplete", + valueMethod: "val" + }, + { + type: "textarea", + selector: "#autocomplete-textarea", + valueMethod: "val" + }, + { + type: "contenteditable", + selector: "#autocomplete-contenteditable", + valueMethod: "text" + } +], function( i, settings ) { + QUnit.test( "all events - " + settings.type, function( assert ) { + var ready = assert.async(); + assert.expect( 13 ); + var element = $( settings.selector ) + .autocomplete( { + autoFocus: false, + delay: 0, + source: data, + search: function( event ) { + assert.equal( event.originalEvent.type, "keydown", "search originalEvent" ); + }, + response: function( event, ui ) { + assert.deepEqual( ui.content, [ + { label: "Clojure", value: "Clojure" }, + { label: "Java", value: "Java" }, + { label: "JavaScript", value: "JavaScript" } + ], "response ui.content" ); + ui.content.splice( 0, 1 ); + }, + open: function() { + assert.ok( menu.is( ":visible" ), "menu open on open" ); + }, + focus: function( event, ui ) { + assert.equal( event.originalEvent.type, "menufocus", "focus originalEvent" ); + assert.deepEqual( ui.item, { label: "Java", value: "Java" }, "focus ui.item" ); + }, + close: function( event ) { + assert.equal( event.originalEvent.type, "menuselect", "close originalEvent" ); + assert.ok( menu.is( ":hidden" ), "menu closed on close" ); + }, + select: function( event, ui ) { + assert.equal( event.originalEvent.type, "menuselect", "select originalEvent" ); + assert.deepEqual( ui.item, { label: "Java", value: "Java" }, "select ui.item" ); + }, + change: function( event, ui ) { + assert.equal( event.originalEvent.type, "blur", "change originalEvent" ); + assert.deepEqual( ui.item, { label: "Java", value: "Java" }, "change ui.item" ); + assert.ok( menu.is( ":hidden" ), "menu closed on change" ); + ready(); + } + } ), + menu = element.autocomplete( "widget" ); + + element.simulate( "focus" )[ settings.valueMethod ]( "j" ).trigger( "keydown" ); + setTimeout( function() { + assert.ok( menu.is( ":visible" ), "menu is visible after delay" ); + element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } ); + element.simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + element.simulate( "blur" ); + } ); + } ); +} ); + +QUnit.test( "change without selection", function( assert ) { + var ready = assert.async(); + assert.expect( 1 ); + var element = $( "#autocomplete" ).autocomplete( { + delay: 0, + source: data, + change: function( event, ui ) { + assert.strictEqual( ui.item, null ); + ready(); + } + } ); + element.triggerHandler( "focus" ); + element.val( "ja" ).triggerHandler( "blur" ); +} ); + +QUnit.test( "cancel search", function( assert ) { + var ready = assert.async(); + assert.expect( 6 ); + var first = true, + element = $( "#autocomplete" ).autocomplete( { + delay: 0, + source: data, + search: function() { + if ( first ) { + assert.equal( element.val(), "ja", "val on first search" ); + first = false; + return false; + } + assert.equal( element.val(), "java", "val on second search" ); + }, + open: function() { + assert.ok( true, "menu opened" ); + } + } ), + menu = element.autocomplete( "widget" ); + element.val( "ja" ).trigger( "keydown" ); + setTimeout( function() { + assert.ok( menu.is( ":hidden" ), "menu is hidden after first search" ); + element.val( "java" ).trigger( "keydown" ); + setTimeout( function() { + assert.ok( menu.is( ":visible" ), "menu is visible after second search" ); + assert.equal( menu.find( ".ui-menu-item" ).length, 2, "# of menu items" ); + ready(); + } ); + } ); +} ); + +QUnit.test( "cancel focus", function( assert ) { + var ready = assert.async(); + assert.expect( 1 ); + var customVal = "custom value", + element = $( "#autocomplete" ).autocomplete( { + delay: 0, + source: data, + focus: function() { + $( this ).val( customVal ); + return false; + } + } ); + element.val( "ja" ).trigger( "keydown" ); + setTimeout( function() { + element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } ); + assert.equal( element.val(), customVal ); + ready(); + } ); +} ); + +QUnit.test( "cancel select", function( assert ) { + var ready = assert.async(); + assert.expect( 1 ); + var customVal = "custom value", + element = $( "#autocomplete" ).autocomplete( { + delay: 0, + source: data, + select: function() { + $( this ).val( customVal ); + return false; + } + } ); + element.val( "ja" ).trigger( "keydown" ); + setTimeout( function() { + element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } ); + element.simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + assert.equal( element.val(), customVal ); + ready(); + } ); +} ); + +QUnit.test( "blur during remote search", function( assert ) { + var ready = assert.async(); + assert.expect( 1 ); + var ac = $( "#autocomplete" ).autocomplete( { + delay: 0, + source: function( request, response ) { + assert.ok( true, "trigger request" ); + ac.simulate( "blur" ); + setTimeout( function() { + response( [ "result" ] ); + ready(); + }, 25 ); + }, + open: function() { + assert.ok( false, "opened after a blur" ); + } + } ); + ac.val( "ro" ).trigger( "keydown" ); +} ); + +} ); diff --git a/tests/unit/autocomplete/methods.js b/tests/unit/autocomplete/methods.js new file mode 100644 index 00000000000..cb0f95332d1 --- /dev/null +++ b/tests/unit/autocomplete/methods.js @@ -0,0 +1,51 @@ +define( [ + "qunit", + "jquery", + "lib/helper", + "ui/widgets/autocomplete" +], function( QUnit, $, helper ) { +"use strict"; + +QUnit.module( "autocomplete: methods", { afterEach: helper.moduleAfterEach } ); + +QUnit.test( "destroy", function( assert ) { + assert.expect( 1 ); + assert.domEqual( "#autocomplete", function() { + $( "#autocomplete" ).autocomplete().autocomplete( "destroy" ); + } ); +} ); + +QUnit.test( "search, close", function( assert ) { + assert.expect( 6 ); + var data = [ "c++", "java", "php", "coldfusion", "javascript", "asp", "ruby", "python", "c", "scala", "groovy", "haskell", "perl" ], + element = $( "#autocomplete" ).autocomplete( { + source: data, + minLength: 0 + } ), + menu = element.autocomplete( "widget" ); + + assert.ok( menu.is( ":hidden" ), "menu is hidden on init" ); + + element.autocomplete( "search" ); + assert.ok( menu.is( ":visible" ), "menu is visible after search" ); + assert.equal( menu.find( ".ui-menu-item" ).length, data.length, "all items for a blank search" ); + + element.val( "has" ).autocomplete( "search" ); + assert.equal( menu.find( ".ui-menu-item" ).text(), "haskell", "only one item for set input value" ); + + element.autocomplete( "search", "ja" ); + assert.equal( menu.find( ".ui-menu-item" ).length, 2, "only java and javascript for 'ja'" ); + + element.autocomplete( "close" ); + assert.ok( menu.is( ":hidden" ), "menu is hidden after close" ); +} ); + +QUnit.test( "widget", function( assert ) { + assert.expect( 2 ); + var element = $( "#autocomplete" ).autocomplete(), + widgetElement = element.autocomplete( "widget" ); + assert.equal( widgetElement.length, 1, "one element" ); + assert.hasClasses( widgetElement, "ui-menu" ); +} ); + +} ); diff --git a/tests/unit/autocomplete/options.js b/tests/unit/autocomplete/options.js new file mode 100644 index 00000000000..b66a71577a4 --- /dev/null +++ b/tests/unit/autocomplete/options.js @@ -0,0 +1,326 @@ +define( [ + "qunit", + "jquery", + "lib/helper", + "ui/widgets/autocomplete" +], function( QUnit, $, helper ) { +"use strict"; + +QUnit.module( "autocomplete: options", { afterEach: helper.moduleAfterEach } ); + +var data = [ "c++", "java", "php", "coldfusion", "javascript", "asp", "ruby", + "python", "c", "scala", "groovy", "haskell", "perl" ]; + +QUnit.test( "appendTo: null", function( assert ) { + assert.expect( 1 ); + var element = $( "#autocomplete" ).autocomplete(); + assert.equal( element.autocomplete( "widget" ).parent()[ 0 ], document.body, + "defaults to body" ); + element.autocomplete( "destroy" ); +} ); + +QUnit.test( "appendTo: explicit", function( assert ) { + assert.expect( 6 ); + var detached = $( "
      " ), + element = $( "#autocomplete" ); + + element.autocomplete( { + appendTo: ".autocomplete-wrap" + } ); + assert.equal( element.autocomplete( "widget" ).parent()[ 0 ], + $( "#autocomplete-wrap1" )[ 0 ], "first found element" ); + assert.equal( $( "#autocomplete-wrap2 .ui-autocomplete" ).length, 0, + "only appends to one element" ); + element.autocomplete( "destroy" ); + + element.autocomplete().autocomplete( "option", "appendTo", "#autocomplete-wrap1" ); + assert.equal( element.autocomplete( "widget" ).parent()[ 0 ], + $( "#autocomplete-wrap1" )[ 0 ], "modified after init" ); + element.autocomplete( "destroy" ); + + element.autocomplete( { + appendTo: detached + } ); + assert.equal( element.autocomplete( "widget" ).parent()[ 0 ], detached[ 0 ], + "detached jQuery object" ); + element.autocomplete( "destroy" ); + + element.autocomplete( { + appendTo: detached[ 0 ] + } ); + assert.equal( element.autocomplete( "widget" ).parent()[ 0 ], detached[ 0 ], + "detached DOM element" ); + element.autocomplete( "destroy" ); + + element.autocomplete().autocomplete( "option", "appendTo", detached ); + assert.equal( element.autocomplete( "widget" ).parent()[ 0 ], detached[ 0 ], + "detached DOM element via option()" ); + element.autocomplete( "destroy" ); +} ); + +QUnit.test( "appendTo: ui-front", function( assert ) { + assert.expect( 2 ); + var element = $( "#autocomplete" ); + + $( "#autocomplete-wrap2" ).addClass( "ui-front" ); + element.autocomplete(); + assert.equal( element.autocomplete( "widget" ).parent()[ 0 ], + $( "#autocomplete-wrap2" )[ 0 ], "null, inside .ui-front" ); + element.autocomplete( "destroy" ); + + element.autocomplete( { + appendTo: $() + } ); + assert.equal( element.autocomplete( "widget" ).parent()[ 0 ], + $( "#autocomplete-wrap2" )[ 0 ], "empty jQuery object, inside .ui-front" ); +} ); + +function autoFocusTest( assert, afValue, focusedLength ) { + var ready = assert.async(); + var element = $( "#autocomplete" ).autocomplete( { + autoFocus: afValue, + delay: 0, + source: data, + open: function() { + assert.equal( + element.autocomplete( "widget" ) + .find( ".ui-menu-item-wrapper.ui-state-active" ) + .length, + focusedLength, + "first item is " + ( afValue ? "" : "not" ) + " auto focused" ); + ready(); + } + } ); + element.val( "ja" ).trigger( "keydown" ); +} + +QUnit.test( "autoFocus: false", function( assert ) { + assert.expect( 1 ); + autoFocusTest( assert, false, 0 ); +} ); + +QUnit.test( "autoFocus: true", function( assert ) { + assert.expect( 1 ); + autoFocusTest( assert, true, 1 ); +} ); + +QUnit.test( "delay", function( assert ) { + var ready = assert.async(); + assert.expect( 2 ); + var element = $( "#autocomplete" ).autocomplete( { + source: data, + delay: 25 + } ), + menu = element.autocomplete( "widget" ); + element.val( "ja" ).trigger( "keydown" ); + + assert.ok( menu.is( ":hidden" ), "menu is closed immediately after search" ); + + setTimeout( function() { + assert.ok( menu.is( ":visible" ), "menu is open after delay" ); + ready(); + }, 50 ); +} ); + +QUnit.test( "disabled", function( assert ) { + var ready = assert.async(); + assert.expect( 5 ); + var element = $( "#autocomplete" ).autocomplete( { + source: data, + delay: 0 + } ), + menu = element.autocomplete( "disable" ).autocomplete( "widget" ); + element.val( "ja" ).trigger( "keydown" ); + + assert.ok( menu.is( ":hidden" ) ); + + assert.lacksClasses( element, "ui-state-disabled" ); + assert.hasClasses( menu, "ui-autocomplete-disabled" ); + assert.ok( !element.attr( "aria-disabled" ), "element doesn't get aria-disabled" ); + + setTimeout( function() { + assert.ok( menu.is( ":hidden" ) ); + ready(); + } ); +} ); + +QUnit.test( "minLength", function( assert ) { + assert.expect( 2 ); + var element = $( "#autocomplete" ).autocomplete( { + source: data + } ), + menu = element.autocomplete( "widget" ); + element.autocomplete( "search", "" ); + assert.ok( menu.is( ":hidden" ), "blank not enough for minLength: 1" ); + + element.autocomplete( "option", "minLength", 0 ); + element.autocomplete( "search", "" ); + assert.ok( menu.is( ":visible" ), "blank enough for minLength: 0" ); +} ); + +QUnit.test( "minLength, exceed then drop below", function( assert ) { + var ready = assert.async(); + assert.expect( 4 ); + var element = $( "#autocomplete" ).autocomplete( { + minLength: 2, + source: function( req, res ) { + assert.equal( req.term, "12", "correct search term" ); + setTimeout( function() { + res( [ "item" ] ); + } ); + } + } ), + menu = element.autocomplete( "widget" ); + + assert.ok( menu.is( ":hidden" ), "menu is hidden before first search" ); + element.autocomplete( "search", "12" ); + + assert.ok( menu.is( ":hidden" ), "menu is hidden before second search" ); + element.autocomplete( "search", "1" ); + + setTimeout( function() { + assert.ok( menu.is( ":hidden" ), "menu is hidden after searches" ); + ready(); + } ); +} ); + +QUnit.test( "minLength, exceed then drop below then exceed", function( assert ) { + assert.expect( 3 ); + var _res = [], + element = $( "#autocomplete" ).autocomplete( { + minLength: 2, + source: function( req, res ) { + _res.push( res ); + } + } ), + menu = element.autocomplete( "widget" ); + + // Trigger a valid search + assert.ok( menu.is( ":hidden" ), "menu is hidden before first search" ); + element.autocomplete( "search", "12" ); + + // Trigger a search below the minLength, to turn on cancelSearch flag + assert.ok( menu.is( ":hidden" ), "menu is hidden before second search" ); + element.autocomplete( "search", "1" ); + + // Trigger a valid search + element.autocomplete( "search", "13" ); + + // React as if the first search was cancelled (default ajax behavior) + _res[ 0 ]( [] ); + + // React to second search + _res[ 1 ]( [ "13" ] ); + + assert.ok( menu.is( ":visible" ), "menu is visible after searches" ); +} ); + +QUnit.test( "source, local string array", function( assert ) { + assert.expect( 1 ); + var element = $( "#autocomplete" ).autocomplete( { + source: data + } ), + menu = element.autocomplete( "widget" ); + element.val( "ja" ).autocomplete( "search" ); + assert.equal( menu.find( ".ui-menu-item" ).text(), "javajavascript" ); +} ); + +function sourceTest( assert, source, async ) { + var ready; + var element = $( "#autocomplete" ).autocomplete( { + source: source + } ), + menu = element.autocomplete( "widget" ); + function result() { + var items = menu.find( ".ui-menu-item" ); + assert.equal( items.length, 3, "Should find three results." ); + assert.deepEqual( items.eq( 0 ).data( "ui-autocomplete-item" ), { + label: "java", + value: "java" + } ); + assert.deepEqual( items.eq( 1 ).data( "ui-autocomplete-item" ), { + label: "javascript", + value: "javascript" + } ); + assert.deepEqual( items.eq( 2 ).data( "ui-autocomplete-item" ), { + label: "clojure", + value: "clojure" + } ); + element.autocomplete( "destroy" ); + if ( async ) { + ready(); + } + } + if ( async ) { + ready = assert.async(); + $( document ).one( "ajaxStop", result ); + } + element.val( "j" ).autocomplete( "search" ); + if ( !async ) { + result(); + } +} + +QUnit.test( "source, local object array, only labels", function( assert ) { + assert.expect( 4 ); + sourceTest( assert, [ + { label: "java", value: null }, + { label: "php", value: null }, + { label: "coldfusion", value: "" }, + { label: "javascript", value: "" }, + { label: "clojure" } + ] ); +} ); + +QUnit.test( "source, local object array, only values", function( assert ) { + assert.expect( 4 ); + sourceTest( assert, [ + { value: "java", label: null }, + { value: "php", label: null }, + { value: "coldfusion", label: "" }, + { value: "javascript", label: "" }, + { value: "clojure" } + ] ); +} ); + +QUnit.test( "source, url string with remote json string array", function( assert ) { + assert.expect( 4 ); + sourceTest( assert, "remote_string_array.txt", true ); +} ); + +QUnit.test( "source, url string with remote json object array, only value properties", function( assert ) { + assert.expect( 4 ); + sourceTest( assert, "remote_object_array_values.txt", true ); +} ); + +QUnit.test( "source, url string with remote json object array, only label properties", function( assert ) { + assert.expect( 4 ); + sourceTest( assert, "remote_object_array_labels.txt", true ); +} ); + +QUnit.test( "source, custom", function( assert ) { + assert.expect( 5 ); + sourceTest( assert, function( request, response ) { + assert.equal( request.term, "j" ); + response( [ + "java", + { label: "javascript", value: null }, + { value: "clojure", label: null } + ] ); + } ); +} ); + +QUnit.test( "source, update after init", function( assert ) { + assert.expect( 2 ); + var element = $( "#autocomplete" ).autocomplete( { + source: [ "java", "javascript", "haskell" ] + } ), + menu = element.autocomplete( "widget" ); + element.val( "ja" ).autocomplete( "search" ); + assert.equal( menu.find( ".ui-menu-item" ).text(), "javajavascript" ); + element.autocomplete( "option", "source", [ "php", "asp" ] ); + element.val( "ph" ).autocomplete( "search" ); + assert.equal( menu.find( ".ui-menu-item" ).text(), "php" ); +} ); + +} ); diff --git a/tests/unit/autocomplete/remote_object_array_labels.txt b/tests/unit/autocomplete/remote_object_array_labels.txt index 502496c2503..f6be4c86f8c 100644 --- a/tests/unit/autocomplete/remote_object_array_labels.txt +++ b/tests/unit/autocomplete/remote_object_array_labels.txt @@ -1 +1,5 @@ -[{"label":"java"},{"label":"javascript"}] \ No newline at end of file +[ + { "label": "java", "value": null }, + { "label": "javascript", "value": "" }, + { "label": "clojure" } +] diff --git a/tests/unit/autocomplete/remote_object_array_values.txt b/tests/unit/autocomplete/remote_object_array_values.txt index 029cbb9dfd0..d55252b98ae 100644 --- a/tests/unit/autocomplete/remote_object_array_values.txt +++ b/tests/unit/autocomplete/remote_object_array_values.txt @@ -1 +1,5 @@ -[{"value":"java"},{"value":"javascript"}] \ No newline at end of file +[ + { "value": "java", "label": null }, + { "value": "javascript", "label": "" }, + { "value": "clojure" } +] diff --git a/tests/unit/autocomplete/remote_string_array.txt b/tests/unit/autocomplete/remote_string_array.txt index 3b24c8e4bef..76134f302b8 100644 --- a/tests/unit/autocomplete/remote_string_array.txt +++ b/tests/unit/autocomplete/remote_string_array.txt @@ -1 +1 @@ -["java", "javascript"] \ No newline at end of file +[ "java", "javascript", "clojure" ] diff --git a/tests/unit/button/all.html b/tests/unit/button/all.html new file mode 100644 index 00000000000..2d9f4a396a1 --- /dev/null +++ b/tests/unit/button/all.html @@ -0,0 +1,26 @@ + + + + + jQuery UI Button Test Suite + + + + + + + + + + + + + +
      +
      + +
      + + diff --git a/tests/unit/button/button.html b/tests/unit/button/button.html index 7c6d0597742..1c3d10199f0 100644 --- a/tests/unit/button/button.html +++ b/tests/unit/button/button.html @@ -1,66 +1,29 @@ - + - + jQuery UI Button Test Suite - - - - - - - - - - - - - - - - - - - + + + -

      jQuery UI Button Test Suite

      -

      -

      -
        -
      +
      +
      +
      +
      +
      -
      +
      + +
      + -
      - -
      - - - -
      - -
      - - - -
      -
      -
      -
      - - - -
      -
      - - - -
      + Anchor Button +
      - diff --git a/tests/unit/button/button_core.js b/tests/unit/button/button_core.js deleted file mode 100644 index 5b30aa860d1..00000000000 --- a/tests/unit/button/button_core.js +++ /dev/null @@ -1,70 +0,0 @@ -/* - * button_core.js - */ - - -(function($) { - -module("button: core"); - -test("checkbox", function() { - var input = $("#check"); - label = $("label[for=check]"); - ok( input.is(":visible") ); - ok( label.is(":not(.ui-button)") ); - input.button(); - ok( input.is(".ui-helper-hidden-accessible") ); - ok( label.is(".ui-button") ); -}); - -test("radios", function() { - var inputs = $("#radio0 input"); - labels = $("#radio0 label"); - ok( inputs.is(":visible") ); - ok( labels.is(":not(.ui-button)") ); - inputs.button(); - ok( inputs.is(".ui-helper-hidden-accessible") ); - ok( labels.is(".ui-button") ); -}); - -function assert(noForm, form1, form2) { - ok( $("#radio0 .ui-button" + noForm).is(".ui-state-active") ); - ok( $("#radio1 .ui-button" + form1).is(".ui-state-active") ); - ok( $("#radio2 .ui-button" + form2).is(".ui-state-active") ); -} - -test("radio groups", function() { - $(":radio").button(); - assert(":eq(0)", ":eq(1)", ":eq(2)"); - - // click outside of forms - $("#radio0 .ui-button:eq(1)").click(); - assert(":eq(1)", ":eq(1)", ":eq(2)"); - - // click in first form - $("#radio1 .ui-button:eq(0)").click(); - assert(":eq(1)", ":eq(0)", ":eq(2)"); - - // click in second form - $("#radio2 .ui-button:eq(0)").click(); - assert(":eq(1)", ":eq(0)", ":eq(0)"); -}); - -test("input type submit, don't create child elements", function() { - var input = $("#submit") - same( input.children().length, 0 ); - input.button(); - same( input.children().length, 0 ); -}); - -test("buttonset", function() { - var set = $("#radio1").buttonset(); - ok( set.is(".ui-buttonset") ); - same( set.children(".ui-button").length, 3 ); - same( set.children("input:radio.ui-helper-hidden-accessible").length, 3 ); - ok( set.children("label:eq(0)").is(".ui-button.ui-corner-left:not(.ui-corner-all)") ); - ok( set.children("label:eq(1)").is(".ui-button:not(.ui-corner-all)") ); - ok( set.children("label:eq(2)").is(".ui-button.ui-corner-right:not(.ui-corner-all)") ); -}); - -})(jQuery); diff --git a/tests/unit/button/button_defaults.js b/tests/unit/button/button_defaults.js deleted file mode 100644 index e1657854a15..00000000000 --- a/tests/unit/button/button_defaults.js +++ /dev/null @@ -1,15 +0,0 @@ -/* - * button_defaults.js - */ - -var button_defaults = { - disabled: false, - text: true, - label: null, - icons: { - primary: null, - secondary: null - } -}; - -commonWidgetTests('button', { defaults: button_defaults }); diff --git a/tests/unit/button/button_events.js b/tests/unit/button/button_events.js deleted file mode 100644 index a2154021df2..00000000000 --- a/tests/unit/button/button_events.js +++ /dev/null @@ -1,8 +0,0 @@ -/* - * button_events.js - */ -(function($) { - -module("button: events"); - -})(jQuery); diff --git a/tests/unit/button/button_methods.js b/tests/unit/button/button_methods.js deleted file mode 100644 index a83a73ba406..00000000000 --- a/tests/unit/button/button_methods.js +++ /dev/null @@ -1,19 +0,0 @@ -/* - * button_methods.js - */ -(function($) { - - -module("button: methods"); - -test("destroy", function() { - var beforeHtml = $("#button").parent().html(); - var afterHtml = $("#button").button().button("destroy").parent().html(); - // Opera 9 outputs role="" instead of removing the attribute like everyone else - if ($.browser.opera) { - afterHtml = afterHtml.replace(/ role=""/g, ""); - } - equal( afterHtml, beforeHtml ); -}); - -})(jQuery); diff --git a/tests/unit/button/button_options.js b/tests/unit/button/button_options.js deleted file mode 100644 index 6ee8ab541e2..00000000000 --- a/tests/unit/button/button_options.js +++ /dev/null @@ -1,69 +0,0 @@ -/* - * button_options.js - */ -(function($) { - -module("button: options"); - -test("text false without icon", function() { - $("#button").button({ - text: false - }); - ok( $("#button").is(".ui-button-text-only:not(.ui-button-icon-only)") ); - - $("#button").button("destroy"); -}); - -test("text false with icon", function() { - $("#button").button({ - text: false, - icons: { - primary: "iconclass" - } - }); - ok( $("#button").is(".ui-button-icon-only:not(.ui-button-text):has(span.ui-icon.iconclass)") ); - - $("#button").button("destroy"); -}); - -test("label, default", function() { - $("#button").button(); - same( $("#button").text(), "Label" ); - - $("#button").button("destroy"); -}); - -test("label", function() { - $("#button").button({ - label: "xxx" - }); - same( $("#button").text(), "xxx" ); - - $("#button").button("destroy"); -}); - -test("label default with input type submit", function() { - same( $("#submit").button().val(), "Label" ); -}); - -test("label with input type submit", function() { - var label = $("#submit").button({ - label: "xxx" - }).val(); - same( label, "xxx" ); -}); - -test("icons", function() { - $("#button").button({ - text: false, - icons: { - primary: "iconclass", - secondary: "iconclass2" - } - }); - ok( $("#button").is(":has(span.ui-icon.ui-button-icon-primary.iconclass):has(span.ui-icon.ui-button-icon-secondary.iconclass2)") ); - - $("#button").button("destroy"); -}); - -})(jQuery); diff --git a/tests/unit/button/button_tickets.js b/tests/unit/button/button_tickets.js deleted file mode 100644 index 7f972513df6..00000000000 --- a/tests/unit/button/button_tickets.js +++ /dev/null @@ -1,10 +0,0 @@ -/* - * button_tickets.js - */ -(function($) { - -module("button: tickets"); - - - -})(jQuery); diff --git a/tests/unit/button/common-deprecated.js b/tests/unit/button/common-deprecated.js new file mode 100644 index 00000000000..0f03bdba271 --- /dev/null +++ b/tests/unit/button/common-deprecated.js @@ -0,0 +1,27 @@ +define( [ + "lib/common", + "ui/widgets/button" +], function( common ) { + +common.testWidget( "button", { + defaults: { + classes: { + "ui-button": "ui-corner-all" + }, + disabled: null, + icon: null, + iconPosition: "beginning", + icons: { + primary: null, + secondary: null + }, + label: null, + showLabel: true, + text: true, + + // Callbacks + create: null + } +} ); + +} ); diff --git a/tests/unit/button/common.js b/tests/unit/button/common.js new file mode 100644 index 00000000000..91ce1cff981 --- /dev/null +++ b/tests/unit/button/common.js @@ -0,0 +1,22 @@ +define( [ + "lib/common", + "ui/widgets/button" +], function( common ) { + +common.testWidget( "button", { + defaults: { + classes: { + "ui-button": "ui-corner-all" + }, + disabled: null, + icon: null, + iconPosition: "beginning", + label: null, + showLabel: true, + + // Callbacks + create: null + } +} ); + +} ); diff --git a/tests/unit/button/core.js b/tests/unit/button/core.js new file mode 100644 index 00000000000..ae4b870eda9 --- /dev/null +++ b/tests/unit/button/core.js @@ -0,0 +1,27 @@ +define( [ + "qunit", + "jquery", + "lib/helper", + "ui/widgets/button" +], function( QUnit, $, helper ) { +"use strict"; + +QUnit.module( "Button: core", { afterEach: helper.moduleAfterEach } ); + +QUnit.test( "Disabled button loses focus", function( assert ) { + var ready = assert.async(); + assert.expect( 2 ); + var element = $( "#button" ).button(); + + element.trigger( "focus" ); + setTimeout( function() { + + assert.equal( element[ 0 ], document.activeElement, "Button is focused" ); + + element.button( "disable" ); + assert.notEqual( element[ 0 ], document.activeElement, "Button has had focus removed" ); + ready(); + } ); +} ); + +} ); diff --git a/tests/unit/button/deprecated.html b/tests/unit/button/deprecated.html new file mode 100644 index 00000000000..8b5270baaa5 --- /dev/null +++ b/tests/unit/button/deprecated.html @@ -0,0 +1,69 @@ + + + + + jQuery UI Button Deprecated Test Suite + + + + + + + +
      +
      + +
      +
      + +
      + + + +
      +
      + + + +
      +
      +
      + + + +
      +
      +
      +
      + + + +
      +
      +
      +
      + + + +
      +
      + + + + +
      + + +Anchor Button + +
      + Anchor + + + + +
      + +
      + + diff --git a/tests/unit/button/deprecated.js b/tests/unit/button/deprecated.js new file mode 100644 index 00000000000..e1e6176085e --- /dev/null +++ b/tests/unit/button/deprecated.js @@ -0,0 +1,217 @@ +define( [ + "qunit", + "jquery", + "lib/helper", + "ui/widgets/button" +], function( QUnit, $, helper ) { +"use strict"; + +QUnit.module( "Button (deprecated): core", { afterEach: helper.moduleAfterEach } ); + +QUnit.test( "Calling button on a checkbox input calls checkboxradio widget", function( assert ) { + var checkbox = $( "#checkbox01" ); + + assert.expect( 2 ); + checkbox.button(); + + assert.ok( !!checkbox.checkboxradio( "instance" ), + "Calling button on a checkbox creates checkboxradio instance" ); + assert.ok( !checkbox.checkboxradio( "option", "icon" ), + "Calling button on a checkbox sets the checkboxradio icon option to false" ); +} ); + +QUnit.test( "Calling buttonset calls controlgroup", function( assert ) { + var controlgroup = $( ".buttonset" ); + + assert.expect( 1 ); + controlgroup.buttonset(); + + assert.ok( controlgroup.is( ":ui-controlgroup" ), "Calling buttonset creates controlgroup instance" ); +} ); + +QUnit.module( "Button (deprecated): methods", { afterEach: helper.moduleAfterEach } ); + +QUnit.test( "destroy", function( assert ) { + assert.expect( 1 ); + assert.domEqual( "#checkbox02", function() { + $( "#checkbox02" ).button().button( "destroy" ); + } ); +} ); + +QUnit.test( "refresh: Ensure disabled state is preserved correctly.", function( assert ) { + assert.expect( 5 ); + var element = null; + + element = $( "#checkbox02" ); + element.button( { disabled: true } ).button( "refresh" ); + assert.ok( element.button( "option", "disabled" ), "Checkboxes should remain disabled after refresh" ); + assert.ok( element.prop( "disabled" ), "Input remains disabled after refresh" ); + + element = $( "#radio02" ); + element.button( { disabled: true } ).button( "refresh" ); + assert.ok( element.button( "option", "disabled" ), "Radio buttons should remain disabled after refresh" ); + + element = $( "#checkbox02" ); + element.button( { disabled: true } ).prop( "disabled", false ).button( "refresh" ); + assert.ok( !element.button( "option", "disabled" ), "Changing a checkbox's disabled property should update the state after refresh." ); + + element = $( "#radio02" ); + element.button( { disabled: true } ).prop( "disabled", false ).button( "refresh" ); + assert.ok( !element.button( "option", "disabled" ), "Changing a radio button's disabled property should update the state after refresh." ); + +} ); + +QUnit.module( "button (deprecated): options", { afterEach: helper.moduleAfterEach } ); + +QUnit.test( "Setting items option on buttonset sets the button properties on the items option", function( assert ) { + assert.expect( 2 ); + + var controlgroup = $( ".buttonset" ); + + controlgroup.buttonset( { items: "bar" } ); + assert.equal( controlgroup.controlgroup( "option", "items.button" ), "bar", + "items.button set when setting items option on init on buttonset" ); + + controlgroup.buttonset( "option", "items", "foo" ); + assert.equal( controlgroup.controlgroup( "option", "items.button" ), "foo", + "items.button set when setting items option on buttonset" ); +} ); + +QUnit.test( "disabled, null", function( assert ) { + assert.expect( 2 ); + + $( "#radio02" ).prop( "disabled", true ).button( { disabled: null } ); + assert.deepEqual( $( "#radio02" ).button( "option", "disabled" ), true, + "disabled option set to true" ); + assert.deepEqual( true, $( "#radio02" ).prop( "disabled" ), "element is not disabled" ); +} ); + +QUnit.test( "text / showLabel options proxied", function( assert ) { + assert.expect( 8 ); + var button = $( "#button" ); + button.button( { + text: false, + icon: "ui-icon-gear" + } ); + assert.equal( button.button( "option", "showLabel" ), false, + "Setting the text option to false sets the showLabel option to false on init" ); + button.button( "option", "showLabel", true ); + assert.equal( button.button( "option", "text" ), true, + "Setting showLabel true with option method sets text option to true" ); + button.button( "option", "text", false ); + assert.equal( button.button( "option", "showLabel" ), false, + "Setting text false with option method sets showLabel option to false" ); + button.button( "option", "text", true ); + assert.equal( button.button( "option", "showLabel" ), true, + "Setting text true with option method sets showLabel option to true" ); + button.button( "option", "showLabel", false ); + assert.equal( button.button( "option", "text" ), false, + "Setting showLabel false with option method sets text option to false" ); + button.button( "destroy" ); + button.button( { + text: true, + icon: "ui-icon-gear" + } ); + assert.equal( button.button( "option", "showLabel" ), true, + "Setting the text option to true sets the showLabel option to true on init" ); + button.button( "destroy" ); + button.button( { + showLabel: true, + icon: "ui-icon-gear" + } ); + assert.equal( button.button( "option", "text" ), true, + "Setting the showLabel option to true sets the text option to true on init" ); + button.button( "destroy" ); + button.button( { + showLabel: false, + icon: "ui-icon-gear" + } ); + assert.equal( button.button( "option", "text" ), false, + "Setting the showLabel option to false sets the text option to false on init" ); +} ); + +QUnit.test( "icon / icons options properly proxied", function( assert ) { + assert.expect( 10 ); + + var button = $( "#button" ); + + button.button( { + icon: "foo" + } ); + + assert.equal( button.button( "option", "icons.primary" ), "foo", + "Icon option properly proxied on init" ); + + button.button( { + icon: "bar" + } ); + + assert.equal( button.button( "option", "icons.primary" ), "bar", + "Icon option properly proxied with option method" ); + + button.button( { + icons: { + primary: "foo" + } + } ); + + assert.equal( button.button( "option", "icon" ), "foo", + "Icons primary option properly proxied with option method" ); + assert.equal( button.button( "option", "iconPosition" ), "beginning", + "Icons primary option sets iconPosition option to beginning" ); + + button.button( { + icons: { + secondary: "bar" + } + } ); + + assert.equal( button.button( "option", "icon" ), "bar", + "Icons secondary option properly proxied with option method" ); + assert.equal( button.button( "option", "iconPosition" ), "end", + "Icons secondary option sets iconPosition option to end" ); + + button.button( "destroy" ); + + button.button( { + icons: { + primary: "foo" + } + } ); + + assert.equal( button.button( "option", "icon" ), "foo", + "Icons primary option properly proxied on init" ); + assert.equal( button.button( "option", "iconPosition" ), "beginning", + "Icons primary option sets iconPosition option to beginning on init" ); + + button.button( { + icons: { + secondary: "bar" + } + } ); + + assert.equal( button.button( "option", "icon" ), "bar", + "Icons secondary option properly proxied on init" ); + assert.equal( button.button( "option", "iconPosition" ), "end", + "Icons secondary option sets iconPosition option to end on init" ); +} ); + +QUnit.test( "Calling button on a collection of mixed types works correctly", function( assert ) { + assert.expect( 5 ); + + var group = $( ".mixed" ).children(); + + group.button(); + + $.each( { + anchor: "button", + button: "button", + check: "checkboxradio", + input: "button", + radio: "checkboxradio" + }, function( type, widget ) { + assert.ok( $( "#mixed-" + type )[ widget ]( "instance" ), type + " is a " + widget ); + } ); +} ); + +} ); diff --git a/tests/unit/button/events.js b/tests/unit/button/events.js new file mode 100644 index 00000000000..a5d02a127c0 --- /dev/null +++ b/tests/unit/button/events.js @@ -0,0 +1,25 @@ +define( [ + "qunit", + "jquery", + "lib/helper", + "ui/widgets/button" +], function( QUnit, $, helper ) { +"use strict"; + +QUnit.module( "Button: events", { afterEach: helper.moduleAfterEach } ); + +QUnit.test( "Anchor recieves click event when spacebar is pressed", function( assert ) { + var ready = assert.async(); + assert.expect( 1 ); + var element = $( "#anchor-button" ).button(); + + element.on( "click", function( event ) { + event.preventDefault(); + assert.ok( true, "click occcured as a result of spacebar" ); + ready(); + } ); + + element.trigger( $.Event( "keyup", { keyCode: $.ui.keyCode.SPACE } ) ); +} ); + +} ); diff --git a/tests/unit/button/methods.js b/tests/unit/button/methods.js new file mode 100644 index 00000000000..71909f87f70 --- /dev/null +++ b/tests/unit/button/methods.js @@ -0,0 +1,37 @@ +define( [ + "qunit", + "jquery", + "lib/helper", + "ui/widgets/button" +], function( QUnit, $, helper ) { +"use strict"; + +QUnit.module( "Button: methods", { afterEach: helper.moduleAfterEach } ); + +QUnit.test( "destroy", function( assert ) { + assert.expect( 1 ); + assert.domEqual( "#button", function() { + $( "#button" ).button().button( "destroy" ); + } ); +} ); + +QUnit.test( "refresh: Ensure disabled state is preserved correctly.", function( assert ) { + assert.expect( 3 ); + + var element = $( "" ); + element.button( { disabled: true } ).button( "refresh" ); + assert.ok( element.button( "option", "disabled" ), + "Anchor button should remain disabled after refresh" ); + + element = $( "" ); + element.button( { disabled: true } ).button( "refresh" ); + assert.ok( element.button( "option", "disabled" ), "" ); + element.button( { disabled: true } ).prop( "disabled", false ).button( "refresh" ); + assert.ok( !element.button( "option", "disabled" ), + "Changing a + + + + +
      + + + + +
      + +
      + + +
      +
      + + + +
      +
      + +
      +
      + +
      +
      + +
      +
      + + +
      +
      + + diff --git a/tests/unit/controlgroup/core.js b/tests/unit/controlgroup/core.js new file mode 100644 index 00000000000..d5cc5c7327b --- /dev/null +++ b/tests/unit/controlgroup/core.js @@ -0,0 +1,202 @@ +define( [ + "qunit", + "jquery", + "lib/helper", + "ui/widgets/controlgroup", + "ui/widgets/checkboxradio", + "ui/widgets/selectmenu", + "ui/widgets/button", + "ui/widgets/spinner" +], function( QUnit, $, helper ) { +"use strict"; + +QUnit.module( "Controlgroup: Core", { afterEach: helper.moduleAfterEach } ); + +QUnit.test( "selectmenu: open/close corners", function( assert ) { + assert.expect( 12 ); + var element = $( ".controlgroup" ).controlgroup(), + selects = element.find( "select" ), + selectButton = selects.eq( 0 ).selectmenu( "widget" ); + + selects.eq( 0 ).selectmenu( "open" ); + assert.hasClasses( selectButton, "ui-corner-tl", + "Horizontal: First selectmenu gets ui-corner-tl when opened" ); + + selects.eq( 0 ).selectmenu( "close" ); + assert.hasClasses( selectButton, "ui-corner-left", + "Horizontal: First selectmenu gets ui-corner-left when closed" ); + + selectButton = selects.eq( 1 ).selectmenu( "widget" ); + selects.eq( 1 ).selectmenu( "open" ); + assert.lacksClassStart( selectButton, "ui-corner" ); + + selects.eq( 1 ).selectmenu( "close" ); + assert.lacksClassStart( selectButton, "ui-corner" ); + + selectButton = selects.eq( 2 ).selectmenu( "widget" ); + selects.eq( 2 ).selectmenu( "open" ); + assert.hasClasses( selectButton, "ui-corner-tr", + "Horizontal: Last selectmenu gets ui-corner-tr when opened" ); + + selects.eq( 2 ).selectmenu( "close" ); + assert.hasClasses( selectButton, "ui-corner-right", + "Horizontal: Last selectmenu gets ui-corner-right when closed" ); + + element.controlgroup( "option", "direction", "vertical" ); + selectButton = selects.eq( 0 ).selectmenu( "widget" ); + selects.eq( 0 ).selectmenu( "open" ); + assert.hasClasses( selectButton, "ui-corner-top", + "vertical: First selectmenu gets ui-corner-top when opened" ); + + selects.eq( 0 ).selectmenu( "close" ); + assert.hasClasses( selectButton, "ui-corner-top", + "vertical: First selectmenu gets ui-corner-top when closed" ); + + selectButton = selects.eq( 1 ).selectmenu( "widget" ); + selects.eq( 1 ).selectmenu( "open" ); + assert.lacksClassStart( selectButton, "ui-corner" ); + + selects.eq( 1 ).selectmenu( "close" ); + assert.lacksClassStart( selectButton, "ui-corner" ); + + selectButton = selects.eq( 2 ).selectmenu( "widget" ); + selects.eq( 2 ).selectmenu( "open" ); + assert.lacksClassStart( selectButton, "ui-corner" ); + + selects.eq( 2 ).selectmenu( "close" ); + assert.hasClasses( selectButton, "ui-corner-bottom", + "vertical: Last selectmenu gets ui-corner-bottom when closed" ); +} ); + +QUnit.test( "selectmenu: controlgroupLabel", function( assert ) { + assert.expect( 2 ); + var element = $( ".controlgroup" ).controlgroup(); + var label = element.find( ".ui-controlgroup-label" ); + + assert.hasClasses( label, "ui-widget ui-widget-content ui-state-default ui-controlgroup-item" ); + assert.hasClasses( label.find( "span" ), "ui-controlgroup-label-contents" ); +} ); + +var assertSanatized = function( assert, initClasses, expectedClasses, message ) { + var selectmenu = $( "#select-sanatize" ).selectmenu( { + classes: { + "ui-selectmenu-button-open": initClasses + } + } ).selectmenu( "instance" ); + var classes = { + "ui-selectmenu-button-open": "ui-corner-top" + }; + var result = $.ui.controlgroup.prototype._resolveClassesValues( classes, selectmenu ); + assert.deepEqual( result, { + "ui-selectmenu-button-open": expectedClasses + " ui-corner-top" + }, message ); +}; + +QUnit.test( "_resolveClassesValues", function( assert ) { + assert.expect( 6 ); + assertSanatized( assert, "bar ui-corner-bottom", "bar", "Single corner class removed end" ); + assertSanatized( assert, "ui-corner-bottom bar", "bar", "Single corner class removed beginning" ); + assertSanatized( assert, "bar ui-corner-bottom ui-corner-left", "bar", "Multiple corner classes removed end" ); + assertSanatized( assert, "ui-corner-bottom ui-corner-left bar", "bar", "Multiple corner classes removed beginning" ); + assertSanatized( assert, "bar ui-corner-bottom ui-corner-left foo", "bar foo", "Multiple corner class removed middle" ); + assertSanatized( assert, "bar", "bar", "No corner classes" ); +} ); + +QUnit.test( "Single controlgroup select - horizontal", function( assert ) { + assert.expect( 4 ); + var group = $( ".controlgroup-single-select" ).controlgroup(); + var select = group.find( ".ui-selectmenu-button" ); + + assert.hasClasses( select, "ui-corner-all" ); + assert.lacksClasses( select, + "ui-corner-left ui-corner-right ui-corner-top ui-corner-left" + + " ui-corner-tr ui-corner-tl ui-corner-bl ui corner-br" ); + + group.find( "select" ).selectmenu( "open" ); + assert.hasClasses( select, "ui-corner-top" ); + assert.lacksClasses( select, + "ui-corner-left ui-corner-right ui-corner-all ui-corner-left" + + " ui-corner-tr ui-corner-tl ui-corner-bl ui corner-br" ); +} ); + +QUnit.test( "Single controlgroup select - vertical", function( assert ) { + assert.expect( 4 ); + var group = $( ".controlgroup-single-select" ).controlgroup( { + direction: "verticle" + } ); + var select = group.find( ".ui-selectmenu-button" ); + + assert.hasClasses( select, "ui-corner-all" ); + assert.lacksClasses( select, + "ui-corner-left ui-corner-right ui-corner-top ui-corner-left" + + " ui-corner-tr ui-corner-tl ui-corner-bl ui corner-br" ); + + group.find( "select" ).selectmenu( "open" ); + assert.hasClasses( select, "ui-corner-top" ); + assert.lacksClasses( select, + "ui-corner-left ui-corner-right ui-corner-all ui-corner-left" + + " ui-corner-tr ui-corner-tl ui-corner-bl ui corner-br" ); +} ); + +QUnit.test( "Single controlgroup button - horizontal", function( assert ) { + assert.expect( 2 ); + var group = $( ".controlgroup-single-button" ).controlgroup(); + var button = group.find( "button" ); + + assert.hasClasses( button, "ui-corner-all" ); + assert.lacksClasses( button, + "ui-corner-left ui-corner-right ui-corner-top ui-corner-left" + + " ui-corner-tr ui-corner-tl ui-corner-bl ui corner-br" ); +} ); + +QUnit.test( "Single controlgroup button - vertical", function( assert ) { + assert.expect( 2 ); + var group = $( ".controlgroup-single-button" ).controlgroup( { + direction: "verticle" + } ); + var button = group.find( "button" ); + + assert.hasClasses( button, "ui-corner-all" ); + assert.lacksClasses( button, + "ui-corner-left ui-corner-right ui-corner-top ui-corner-left" + + " ui-corner-tr ui-corner-tl ui-corner-bl ui corner-br" ); +} ); + +QUnit.module( "Controlgroup: Non-empty class key", { + beforeEach: function() { + this.classKey = $.ui.selectmenu.prototype.options.classes[ "ui-selectmenu-button-closed" ]; + $.ui.selectmenu.prototype.options.classes[ "ui-selectmenu-button-closed" ] = + "something-custom"; + }, + afterEach: function() { + $.ui.selectmenu.prototype.options.classes[ "ui-selectmenu-button-closed" ] = this.classKey; + } +} ); + +QUnit.test( "Controlgroup instantiates child widgets with correct options", function( assert ) { + assert.expect( 1 ); + + $( ".controlgroup-class-key-init" ).controlgroup(); + + assert.hasClasses( $( "#class-key-init-child" ).next(), "something-custom" ); +} ); + +QUnit.test( "Controlgroup correctly assigns child widget classes options key", function( assert ) { + assert.expect( 2 ); + + $( ".controlgroup-class-key-dupe" ).controlgroup(); + + assert.strictEqual( + ( $( "#class-key-dupe-first" ) + .selectmenu( "option", "classes.ui-selectmenu-button-closed" ) + .match( /something-custom/g ) || [] ).length, 1, + "Class 'something-custom' appears exactly once in the first widget's class key value" ); + + assert.strictEqual( + ( $( "#class-key-dupe-second" ) + .selectmenu( "option", "classes.ui-selectmenu-button-closed" ) + .match( /something-custom/g ) || [] ).length, 1, + "Class 'something-custom' appears exactly once in the second widget's class key value" ); +} ); + +} ); diff --git a/tests/unit/controlgroup/methods.js b/tests/unit/controlgroup/methods.js new file mode 100644 index 00000000000..8ac310c25b8 --- /dev/null +++ b/tests/unit/controlgroup/methods.js @@ -0,0 +1,190 @@ +define( [ + "qunit", + "jquery", + "lib/helper", + "ui/widgets/controlgroup", + "ui/widgets/checkboxradio", + "ui/widgets/selectmenu", + "ui/widgets/button", + "ui/widgets/spinner" +], function( QUnit, $, helper ) { +"use strict"; + +QUnit.module( "Controlgroup: methods", { afterEach: helper.moduleAfterEach } ); + +QUnit.test( "destroy", function( assert ) { + assert.expect( 1 ); + assert.domEqual( ".controlgroup", function() { + $( ".controlgroup" ).controlgroup().controlgroup( "destroy" ); + $( "#spinner" ).addClass( "ui-spinner-input" ); + } ); +} ); + +QUnit.test( "disable", function( assert ) { + assert.expect( 2 ); + var element = $( ".controlgroup" ).controlgroup().controlgroup( "disable" ); + assert.lacksClasses( element, "ui-state-disabled", + "The widget does not get the disabled class, because we disable each child widget" ); + assert.strictEqual( element.find( ".ui-state-disabled" ).length, 9, + "Child widgets are disabled" ); +} ); + +QUnit.test( "enable", function( assert ) { + assert.expect( 2 ); + var element = $( ".controlgroup" ).controlgroup().controlgroup( "enable" ); + assert.lacksClasses( element, "ui-state-disabled", + "ui-state-disabled is not present on widget after enabling" ); + assert.strictEqual( element.find( "ui-state-disabled" ).length, 0, + "Child widgets are disabled" ); +} ); + +var tests = { + "checkboxradio": "", + "selectmenu": "", + "button": "", + "spinner": "" + }, + orientations = { + "horizontal": [ + "ui-corner-left", + false, + false, + "ui-corner-right" + ], + "vertical": [ + "ui-corner-top", + false, + false, + "ui-corner-bottom" + ] + }; + +// Iterate through supported element markup +$.each( tests, function( widget, html ) { + + // Check in both horizontal and vertical orientations + $.each( orientations, function( name, classes ) { + + QUnit.test( "refresh: " + widget + ": " + name, function( assert ) { + assert.expect( 41 ); + + var i, control, label, currentClasses, + controls = [], + element = $( "
      " ).controlgroup( { + direction: name + } ).appendTo( "body" ); + + // Checks the elements with in the controlgroup against the expected class list + function checkCornerClasses( classList ) { + for ( var j = 0; j < 4; j++ ) { + if ( classList[ j ] ) { + assert.hasClasses( controls[ j ][ widget ]( "widget" ), classList[ j ] ); + } else { + assert.lacksClassStart( controls[ j ][ widget ]( "widget" ), "ui-corner" ); + } + } + } + + function showElements( index, value ) { + $( value )[ widget ]( "widget" ).show(); + } + + // Hide each element and check the corner classes + function iterateHidden( onlyVisible ) { + for ( i = 0; i < 4; i++ ) { + + $( controls ).each( showElements ); + + controls[ i ][ widget ]( "widget" ).hide(); + + currentClasses = classes.slice( 0 ); + if ( onlyVisible ) { + if ( i === 0 ) { + currentClasses[ i + 1 ] = classes[ i ]; + currentClasses[ i ] = false; + } else if ( i === 3 ) { + currentClasses[ i - 1 ] = classes[ i ]; + currentClasses[ i ] = false; + } + } + element.controlgroup( "refresh" ); + checkCornerClasses( currentClasses ); + } + } + + // Add a label for each element and then append the element to the control group + for ( i = 0; i < 4; i++ ) { + control = $( html ).attr( "id", "id" + i ); + label = $( "" ).attr( "for", "id" + i ); + + controls.push( control ); + element.append( control, label ); + } + + // Refresh the controlgroup now that its populated + element.controlgroup( "refresh" ); + for ( i = 0; i < 4; i++ ) { + assert.strictEqual( controls[ i ].is( ":ui-" + widget ), true, + name + ": " + widget + " " + i + ": is a " + widget + " widget" ); + } + + // Check that we have the right classes + checkCornerClasses( classes ); + + // Hide each element and then check its classes + iterateHidden( true ); + + // Set the exclude option to false so we no longer care about hidden + element.controlgroup( "option", "onlyVisible", false ); + + // Iterate hiding the elements again and check their corner classes + iterateHidden(); + + // Disable the first control + if ( widget === "spinner" ) { + controls[ 0 ].spinner( "disable" ); + } + controls[ 0 ].prop( "disabled", true ); + + element.controlgroup( "refresh" ); + + assert.hasClasses( controls[ 0 ][ widget ]( "widget" ), "ui-state-disabled" ); + + // Remove the controlgroup before we start the next set + element.remove(); + } ); + } ); +} ); + +QUnit.test( "Child Classes Option: init", function( assert ) { + assert.expect( 1 ); + var selectmenu = $( "#select-pre" ).selectmenu( { + classes: { + "ui-selectmenu-button-closed": "test-class" + } + } ); + $( ".controlgroup-pre" ).controlgroup(); + assert.hasClasses( selectmenu.selectmenu( "widget" ), "test-class" ); +} ); + +QUnit.test( "Child Classes Option: refresh", function( assert ) { + assert.expect( 1 ); + var controlgroup = $( ".controlgroup-refresh" ).controlgroup(); + var selectmenu = $( "#select-refresh" ).selectmenu( { + classes: { + "ui-selectmenu-button-closed": "test-class" + } + } ); + controlgroup.controlgroup( "refresh" ); + assert.hasClasses( selectmenu.selectmenu( "widget" ), "test-class" ); +} ); + +QUnit.test( "Controlgroup Label: refresh", function( assert ) { + assert.expect( 1 ); + var controlgroup = $( ".controlgroup-refresh" ).controlgroup(); + controlgroup.controlgroup( "refresh" ); + assert.strictEqual( controlgroup.find( ".ui-controlgroup-label-contents" ).length, 1, + "Controlgroup label does not re-wrap on refresh" ); +} ); + +} ); diff --git a/tests/unit/controlgroup/options.js b/tests/unit/controlgroup/options.js new file mode 100644 index 00000000000..31be89b2788 --- /dev/null +++ b/tests/unit/controlgroup/options.js @@ -0,0 +1,113 @@ +define( [ + "qunit", + "jquery", + "lib/helper", + "ui/widgets/controlgroup", + "ui/widgets/checkboxradio", + "ui/widgets/selectmenu", + "ui/widgets/button", + "ui/widgets/spinner" +], function( QUnit, $, helper ) { +"use strict"; + +QUnit.module( "Controlgroup: options", { afterEach: helper.moduleAfterEach } ); + +QUnit.test( "disabled", function( assert ) { + assert.expect( 4 ); + var element = $( ".controlgroup" ).controlgroup().controlgroup( "option", "disabled", true ); + assert.lacksClasses( element, "ui-state-disabled" ); + assert.equal( element.find( ".ui-state-disabled" ).length, 9, "Child widgets are disabled" ); + + element.controlgroup( "option", "disabled", false ); + assert.lacksClasses( element, "ui-state-disabled" ); + assert.strictEqual( element.find( ".ui-state-disabled" ).length, 0, "Child widgets are not disabled" ); + +} ); + +QUnit.test( "items - null", function( assert ) { + assert.expect( 2 ); + var element = $( ".controlgroup" ).controlgroup( { + items: { + "button": null, + "selectmenu": null, + "checkboxradio": null + } + } ); + + assert.strictEqual( element.children( ".ui-button" ).length, 0, + "Child widgets are not called when selector is null" ); + + element.controlgroup( "option", "items", { + "button": "button" + } ); + assert.strictEqual( element.children( ".ui-button" ).length, 2, + "Correct child widgets are called when selector is updated" ); +} ); + +QUnit.test( "items: custom selector", function( assert ) { + assert.expect( 1 ); + var element = $( ".controlgroup" ).controlgroup( { + items: { + "button": ".button" + } + } ); + assert.strictEqual( element.children( ".ui-button" ).length, 4, + "Correct child widgets are called when custom selector used" ); +} ); + +$.widget( "ui.test", { + _create: function() { + this.element.addClass( "ui-test ui-button" ); + }, + + // Controlgroup requires a refresh method to exist + refresh: $.noop +} ); + +QUnit.test( "items: custom widget", function( assert ) { + assert.expect( 2 ); + var element = $( ".controlgroup" ).controlgroup( { + items: { + "test": ".test" + } + } ); + + assert.strictEqual( element.children( ".ui-button" ).length, 7, + "Correct child widgets are called when custom selector used" ); + assert.strictEqual( element.children( ".ui-test" ).length, 1, + "Custom widget called" ); +} ); + +QUnit.test( "onlyVisible", function( assert ) { + assert.expect( 4 ); + var element = $( ".controlgroup" ).controlgroup( { + onlyVisible: false + } ), + buttons = element.children( ".ui-button" ); + + assert.lacksClassStart( buttons.eq( 1 ), "ui-corner" ); + assert.hasClasses( buttons.eq( 0 ), "ui-corner-left", + "onlyVisible: false: First button hidden second button doesn't get a corner class" ); + + element.controlgroup( "option", "onlyVisible", true ); + assert.lacksClassStart( buttons.eq( 0 ), "ui-corner" ); + assert.hasClasses( buttons.eq( 1 ), "ui-corner-left", + "onlyVisible: true: First button is hidden second button get corner class" ); +} ); + +QUnit.test( "direction", function( assert ) { + assert.expect( 6 ); + var element = $( ".controlgroup" ).controlgroup(), + buttons = element.children( ".ui-button" ).filter( ":visible" ); + + assert.hasClasses( element, "ui-controlgroup-horizontal" ); + assert.hasClasses( buttons.first(), "ui-corner-left" ); + assert.hasClasses( buttons.last(), "ui-corner-right" ); + + element.controlgroup( "option", "direction", "vertical" ); + assert.hasClasses( element, "ui-controlgroup-vertical" ); + assert.hasClasses( buttons.first(), "ui-corner-top" ); + assert.hasClasses( buttons.last(), "ui-corner-bottom" ); +} ); + +} ); diff --git a/tests/unit/core/all.html b/tests/unit/core/all.html new file mode 100644 index 00000000000..1fe23e1950c --- /dev/null +++ b/tests/unit/core/all.html @@ -0,0 +1,26 @@ + + + + + jQuery UI Core Test Suite + + + + + + + + + + + + + +
      +
      + +
      + + diff --git a/tests/unit/core/core.html b/tests/unit/core/core.html index 468c962e5ee..7434a1e1fd4 100644 --- a/tests/unit/core/core.html +++ b/tests/unit/core/core.html @@ -1,135 +1,222 @@ - + - + jQuery UI Core Test Suite - - - - - - - - - - - - + + + -

      jQuery UI Core Test Suite

      -

      -

      -
        -
      +
      +
      -
      + + + + + + + + -
      - - - - - - - - - - xxx - anchor - anchor - - - - - x -
      x
      - x -
      x
      +
      + +
      + +
      + +
      + +
      +
      + +
      +
      + +
      +
      + +
      + + + + + + + + + + xxx + anchor + anchor + x +
      x
      + x +
      x
      +
      + +
      + + + + + + + + + +
      + +
      + - -
      - - - - - - - - - + + + +
      + . +
      - + + + + . + + + + + + + + + +
      .
      +
      + +
      + + + + + + . + . + . + . +
      + +
      + + +
      + +
      + +
      +
      - +
      +
      + + +
      + + +
      + + +
      +
      + + +
      +
      +
      + + + +
      + + +
      +
      + + +
      +
      diff --git a/tests/unit/core/core.js b/tests/unit/core/core.js index df811093bbf..5d9eee07ca8 100644 --- a/tests/unit/core/core.js +++ b/tests/unit/core/core.js @@ -1,69 +1,206 @@ -/* - * core unit tests - */ -(function($) { - -module('core - jQuery extensions'); - -test("attr - aria", function() { - expect(6); - - var el = $('#aria'); - - ok(!el.attr('role'), 'role is empty via attr'); - equals(el.attr('role', 'tablist').attr('role'), 'tablist', 'role is tablist'); - - equals(el.attr('aria-expanded'), undefined, 'aria expanded is undefined'); - - el.attr('aria-expanded', true); - equals(el.attr('aria-expanded'), 'true', 'aria expanded is true'); - - el.removeAttr('aria-expanded'); - equals(el.attr('aria-expanded'), undefined, 'aria expanded is undefined after removing'); - - el.attr('aria-expanded', false); - equals(el.attr('aria-expanded'), 'false', 'aria expanded is false'); -}); - -test('focus', function() { - expect(3); - - var el = $('#inputTabindex0'), - // used to remove focus from the main element - other = $('#inputTabindex10'); - - // test original functionality - el.focus(function() { - ok(true, 'event triggered'); - }); - el.focus(); - other.focus(); - - // trigger event handler + callback - stop(); - el.focus(500, function() { - ok(true, 'callback triggered'); - start(); - }); - other.focus(); -}); - -test('zIndex', function() { - var el = $('#zIndexAutoWithParent'), - parent = el.parent(); - equals(el.zIndex(), 100, 'zIndex traverses up to find value'); - equals(parent.zIndex(200), parent, 'zIndex setter is chainable'); - equals(el.zIndex(), 200, 'zIndex setter changed zIndex'); - - el = $('#zIndexAutoWithParentViaCSS'); - equals(el.zIndex(), 0, 'zIndex traverses up to find CSS value, not found because not positioned'); - - el = $('#zIndexAutoWithParentViaCSSPositioned'); - equals(el.zIndex(), 100, 'zIndex traverses up to find CSS value'); - el.parent().zIndex(200); - equals(el.zIndex(), 200, 'zIndex setter changed zIndex, overriding CSS'); - - equals($('#zIndexAutoNoParent').zIndex(), 0, 'zIndex never explicitly set in hierarchy'); -}); - -})(jQuery); +define( [ + "qunit", + "jquery", + "lib/common", + "lib/helper", + "ui/labels", + "ui/unique-id" +], function( QUnit, $, common, helper ) { +"use strict"; + +QUnit.module( "core - jQuery extensions", { afterEach: helper.moduleAfterEach } ); + +QUnit.test( "innerWidth - getter", function( assert ) { + assert.expect( 2 ); + var el = $( "#dimensions" ); + + assert.equal( el.innerWidth(), 122, "getter passthru" ); + el.hide(); + assert.equal( el.innerWidth(), 122, "getter passthru when hidden" ); +} ); + +QUnit.test( "innerWidth - setter", function( assert ) { + assert.expect( 2 ); + var el = $( "#dimensions" ); + + el.innerWidth( 120 ); + assert.equal( el.width(), 98, "width set properly" ); + el.hide(); + el.innerWidth( 100 ); + assert.equal( el.width(), 78, "width set properly when hidden" ); +} ); + +QUnit.test( "innerHeight - getter", function( assert ) { + assert.expect( 2 ); + var el = $( "#dimensions" ); + + assert.equal( el.innerHeight(), 70, "getter passthru" ); + el.hide(); + assert.equal( el.innerHeight(), 70, "getter passthru when hidden" ); +} ); + +QUnit.test( "innerHeight - setter", function( assert ) { + assert.expect( 2 ); + var el = $( "#dimensions" ); + + el.innerHeight( 60 ); + assert.equal( el.height(), 40, "height set properly" ); + el.hide(); + el.innerHeight( 50 ); + assert.equal( el.height(), 30, "height set properly when hidden" ); +} ); + +QUnit.test( "outerWidth - getter", function( assert ) { + assert.expect( 2 ); + var el = $( "#dimensions" ); + + assert.equal( el.outerWidth(), 140, "getter passthru" ); + el.hide(); + assert.equal( el.outerWidth(), 140, "getter passthru when hidden" ); +} ); + +QUnit.test( "outerWidth - setter", function( assert ) { + assert.expect( 2 ); + var el = $( "#dimensions" ); + + el.outerWidth( 130 ); + assert.equal( el.width(), 90, "width set properly" ); + el.hide(); + el.outerWidth( 120 ); + assert.equal( el.width(), 80, "width set properly when hidden" ); +} ); + +QUnit.test( "outerWidth(true) - getter", function( assert ) { + assert.expect( 2 ); + var el = $( "#dimensions" ); + + assert.equal( el.outerWidth( true ), 154, "getter passthru w/ margin" ); + el.hide(); + assert.equal( el.outerWidth( true ), 154, "getter passthru w/ margin when hidden" ); +} ); + +QUnit.test( "outerWidth(true) - setter", function( assert ) { + assert.expect( 2 ); + var el = $( "#dimensions" ); + + el.outerWidth( 130, true ); + assert.equal( el.width(), 76, "width set properly" ); + el.hide(); + el.outerWidth( 120, true ); + assert.equal( el.width(), 66, "width set properly when hidden" ); +} ); + +QUnit.test( "outerHeight - getter", function( assert ) { + assert.expect( 2 ); + var el = $( "#dimensions" ); + + assert.equal( el.outerHeight(), 86, "getter passthru" ); + el.hide(); + assert.equal( el.outerHeight(), 86, "getter passthru when hidden" ); +} ); + +QUnit.test( "outerHeight - setter", function( assert ) { + assert.expect( 2 ); + var el = $( "#dimensions" ); + + el.outerHeight( 80 ); + assert.equal( el.height(), 44, "height set properly" ); + el.hide(); + el.outerHeight( 70 ); + assert.equal( el.height(), 34, "height set properly when hidden" ); +} ); + +QUnit.test( "outerHeight(true) - getter", function( assert ) { + assert.expect( 2 ); + var el = $( "#dimensions" ); + + assert.equal( el.outerHeight( true ), 98, "getter passthru w/ margin" ); + el.hide(); + assert.equal( el.outerHeight( true ), 98, "getter passthru w/ margin when hidden" ); +} ); + +QUnit.test( "outerHeight(true) - setter", function( assert ) { + assert.expect( 2 ); + var el = $( "#dimensions" ); + + el.outerHeight( 90, true ); + assert.equal( el.height(), 42, "height set properly" ); + el.hide(); + el.outerHeight( 80, true ); + assert.equal( el.height(), 32, "height set properly when hidden" ); +} ); + +QUnit.test( "uniqueId / removeUniqueId", function( assert ) { + assert.expect( 3 ); + var el = $( "img" ).eq( 0 ); + assert.equal( el.attr( "id" ), null, "element has no initial id" ); + el.uniqueId(); + assert.ok( /ui-id-\d+$/.test( el.attr( "id" ) ), "element has generated id" ); + el.removeUniqueId(); + assert.equal( el.attr( "id" ), null, "unique id has been removed from element" ); +} ); + +QUnit.test( "Labels", function( assert ) { + assert.expect( 3 ); + + var expected = [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" ]; + var dom = $( "#labels-fragment" ); + + function testLabels( testType ) { + var labels = dom.find( "#test" ).labels(); + var found = labels.map( function() { + return String.prototype.trim.call( $( this ).text() ); + } ).get(); + + assert.deepEqual( found, expected, + ".labels() finds all labels in " + testType + ", and sorts them in DOM order" ); + } + + testLabels( "the DOM" ); + + // Detach the dom to test on a fragment + dom.detach(); + testLabels( "document fragments" ); + + assert.equal( $().labels().length, 0, "No element" ); +} ); + +( function() { + var domAttached = $( "#form-test" ); + var domDetached = $( "#form-test-detached" ).detach(); + + function testForm( name, dom ) { + var inputs = dom.find( "input" ); + + inputs.each( function() { + var input = $( this ); + + QUnit.test( name + this.id.replace( /_/g, " " ), function( assert ) { + var ready = assert.async(); + assert.expect( 1 ); + var form = $( input.prop( "form" ) ); + + // If input has a form the value should reset to "" if not it should be "changed" + var value = form.length ? "" : "changed"; + + input.val( "changed" ); + + // If there is a form we reset just that. If there is not a form, reset every form. + // The idea is if a form is found resetting that form should reset the input. + // If no form is found no amount of resetting should change the value. + ( form.length ? form : dom.find( "form" ).addBack( "form" ) ).each( function() { + this.reset(); + } ); + + setTimeout( function() { + assert.equal( input.val(), value, "Proper form found for #" + input.attr( "id" ) ); + ready(); + } ); + } ); + } ); + } + + testForm( "form: attached: ", domAttached ); + testForm( "form: detached: ", domDetached ); +} )(); +} ); diff --git a/tests/unit/core/selector.js b/tests/unit/core/selector.js index 269b77e08c9..062c7a6cc5b 100644 --- a/tests/unit/core/selector.js +++ b/tests/unit/core/selector.js @@ -1,245 +1,299 @@ -/* - * selector unit tests - */ -(function($) { - -module("core - selectors"); - -function isFocusable(selector, msg) { - ok($(selector).is(':focusable'), msg + " - selector " + selector + " is focusable"); -} - -function isNotFocusable(selector, msg) { - ok($(selector).length && !$(selector).is(':focusable'), msg + " - selector " + selector + " is not focusable"); -} - -function isTabbable(selector, msg) { - ok($(selector).is(':tabbable'), msg + " - selector " + selector + " is tabbable"); -} - -function isNotTabbable(selector, msg) { - ok($(selector).length && !$(selector).is(':tabbable'), msg + " - selector " + selector + " is not tabbable"); -} - -test("data", function() { - expect(15); - - var el; - function shouldHaveData(msg) { - ok(el.is(':data(test)'), msg); +define( [ + "qunit", + "jquery", + "lib/helper", + "ui/data", + "ui/focusable", + "ui/tabbable" +], function( QUnit, $, helper ) { +"use strict"; + +QUnit.module( "core - selectors", { afterEach: helper.moduleAfterEach } ); + +QUnit.assert.isFocusable = function( selector, msg ) { + this.pushResult( { + result: $( selector ).is( ":focusable" ), + actual: null, + expected: null, + message: msg + " - selector " + selector + " is focusable" + } ); +}; + +QUnit.assert.isNotFocusable = function( selector, msg ) { + this.pushResult( { + result: $( selector ).length && !$( selector ).is( ":focusable" ), + actual: null, + expected: null, + message: msg + " - selector " + selector + " is not focusable" + } ); +}; + +QUnit.assert.isTabbable = function( selector, msg ) { + this.pushResult( { + result: $( selector ).is( ":tabbable" ), + actual: null, + expected: null, + message: msg + " - selector " + selector + " is tabbable" + } ); +}; + +QUnit.assert.isNotTabbable = function( selector, msg ) { + this.pushResult( { + result: $( selector ).length && !$( selector ).is( ":tabbable" ), + actual: null, + expected: null, + message: msg + " - selector " + selector + " is not tabbable" + } ); +}; + +QUnit.test( "data", function( assert ) { + assert.expect( 15 ); + + var element; + + function shouldHaveData( msg ) { + assert.ok( element.is( ":data(test)" ), msg ); } - function shouldNotHaveData(msg) { - ok(!el.is(':data(test)'), msg); + + function shouldNotHaveData( msg ) { + assert.ok( !element.is( ":data(test)" ), msg ); } - - el = $('
      '); - shouldNotHaveData('data never set'); - - el = $('
      ').data('test', null); - shouldNotHaveData('data is null'); - - el = $('
      ').data('test', true); - shouldHaveData('data set to true'); - - el = $('
      ').data('test', false); - shouldNotHaveData('data set to false'); - - el = $('
      ').data('test', 0); - shouldNotHaveData('data set to 0'); - - el = $('
      ').data('test', 1); - shouldHaveData('data set to 1'); - - el = $('
      ').data('test', ''); - shouldNotHaveData('data set to empty string'); - - el = $('
      ').data('test', 'foo'); - shouldHaveData('data set to string'); - - el = $('
      ').data('test', []); - shouldHaveData('data set to empty array'); - - el = $('
      ').data('test', [1]); - shouldHaveData('data set to array'); - - el = $('
      ').data('test', {}); - shouldHaveData('data set to empty object'); - - el = $('
      ').data('test', {foo: 'bar'}); - shouldHaveData('data set to object'); - - el = $('
      ').data('test', new Date()); - shouldHaveData('data set to date'); - - el = $('
      ').data('test', /test/); - shouldHaveData('data set to regexp'); - - el = $('
      ').data('test', function() {}); - shouldHaveData('data set to function'); -}); - -test("focusable - visible, enabled elements", function() { - expect(18); - - isFocusable('#visibleAncestor-inputTypeNone', 'input, no type'); - isFocusable('#visibleAncestor-inputTypeText', 'input, type text'); - isFocusable('#visibleAncestor-inputTypeCheckbox', 'input, type checkbox'); - isFocusable('#visibleAncestor-inputTypeRadio', 'input, type radio'); - isFocusable('#visibleAncestor-inputTypeButton', 'input, type button'); - isNotFocusable('#visibleAncestor-inputTypeHidden', 'input, type hidden'); - isFocusable('#visibleAncestor-button', 'button'); - isFocusable('#visibleAncestor-select', 'select'); - isFocusable('#visibleAncestor-textarea', 'textarea'); - isFocusable('#visibleAncestor-object', 'object'); - isFocusable('#visibleAncestor-anchorWithHref', 'anchor with href'); - isNotFocusable('#visibleAncestor-anchorWithoutHref', 'anchor without href'); - // fails: $("map").is(":visible") and $("map").is(":hidden") both return true - isFocusable('#visibleAncestor-areaWithHref', 'area with href'); - isNotFocusable('#visibleAncestor-areaWithoutHref', 'area without href'); - isNotFocusable('#visibleAncestor-span', 'span'); - isNotFocusable('#visibleAncestor-div', 'div'); - isFocusable("#visibleAncestor-spanWithTabindex", 'span with tabindex'); - isFocusable("#visibleAncestor-divWithNegativeTabindex", 'div with tabindex'); -}); - -test("focusable - disabled elements", function() { - expect(9); - - isNotFocusable('#disabledElement-inputTypeNone', 'input, no type'); - isNotFocusable('#disabledElement-inputTypeText', 'input, type text'); - isNotFocusable('#disabledElement-inputTypeCheckbox', 'input, type checkbox'); - isNotFocusable('#disabledElement-inputTypeRadio', 'input, type radio'); - isNotFocusable('#disabledElement-inputTypeButton', 'input, type button'); - isNotFocusable('#disabledElement-inputTypeHidden', 'input, type hidden'); - isNotFocusable('#disabledElement-button', 'button'); - isNotFocusable('#disabledElement-select', 'select'); - isNotFocusable('#disabledElement-textarea', 'textarea'); -}); - -test("focusable - hidden styles", function() { - expect(8); - - isNotFocusable('#displayNoneAncestor-input', 'input, display: none parent'); - isNotFocusable('#displayNoneAncestor-span', 'span with tabindex, display: none parent'); - - isNotFocusable('#visibilityHiddenAncestor-input', 'input, visibility: hidden parent'); - isNotFocusable('#visibilityHiddenAncestor-span', 'span with tabindex, visibility: hidden parent'); - - isNotFocusable('#displayNone-input', 'input, display: none'); - isNotFocusable('#visibilityHidden-input', 'input, visibility: hidden'); - - isNotFocusable('#displayNone-span', 'span with tabindex, display: none'); - isNotFocusable('#visibilityHidden-span', 'span with tabindex, visibility: hidden'); -}); - -test("focusable - natively focusable with various tabindex", function() { - expect(4); - - isFocusable('#inputTabindex0', 'input, tabindex 0'); - isFocusable('#inputTabindex10', 'input, tabindex 10'); - isFocusable('#inputTabindex-1', 'input, tabindex -1'); - isFocusable('#inputTabindex-50', 'input, tabindex -50'); -}); - -test("focusable - not natively focusable with various tabindex", function() { - expect(4); - - isFocusable('#spanTabindex0', 'span, tabindex 0'); - isFocusable('#spanTabindex10', 'span, tabindex 10'); - isFocusable('#spanTabindex-1', 'span, tabindex -1'); - isFocusable('#spanTabindex-50', 'span, tabindex -50'); -}); - -test("focusable - invalid tabindex", function() { - expect(4); - - isFocusable('#inputTabindexfoo', 'input, tabindex foo'); - isFocusable('#inputTabindex3foo', 'input, tabindex 3foo'); - isNotFocusable('#spanTabindexfoo', 'span tabindex foo'); - isNotFocusable('#spanTabindex3foo', 'span, tabindex 3foo'); -}); - -test("tabbable - visible, enabled elements", function() { - expect(18); - - isTabbable('#visibleAncestor-inputTypeNone', 'input, no type'); - isTabbable('#visibleAncestor-inputTypeText', 'input, type text'); - isTabbable('#visibleAncestor-inputTypeCheckbox', 'input, type checkbox'); - isTabbable('#visibleAncestor-inputTypeRadio', 'input, type radio'); - isTabbable('#visibleAncestor-inputTypeButton', 'input, type button'); - isNotTabbable('#visibleAncestor-inputTypeHidden', 'input, type hidden'); - isTabbable('#visibleAncestor-button', 'button'); - isTabbable('#visibleAncestor-select', 'select'); - isTabbable('#visibleAncestor-textarea', 'textarea'); - isTabbable('#visibleAncestor-object', 'object'); - isTabbable('#visibleAncestor-anchorWithHref', 'anchor with href'); - isNotTabbable('#visibleAncestor-anchorWithoutHref', 'anchor without href'); - // fails: $("map").is(":visible") and $("map").is(":hidden") both return true - isTabbable('#visibleAncestor-areaWithHref', 'area with href'); - isNotTabbable('#visibleAncestor-areaWithoutHref', 'area without href'); - isNotTabbable('#visibleAncestor-span', 'span'); - isNotTabbable('#visibleAncestor-div', 'div'); - isTabbable("#visibleAncestor-spanWithTabindex", 'span with tabindex'); - isNotTabbable("#visibleAncestor-divWithNegativeTabindex", 'div with tabindex'); -}); - -test("Tabbable - disabled elements", function() { - expect(9); - - isNotTabbable('#disabledElement-inputTypeNone', 'input, no type'); - isNotTabbable('#disabledElement-inputTypeText', 'input, type text'); - isNotTabbable('#disabledElement-inputTypeCheckbox', 'input, type checkbox'); - isNotTabbable('#disabledElement-inputTypeRadio', 'input, type radio'); - isNotTabbable('#disabledElement-inputTypeButton', 'input, type button'); - isNotTabbable('#disabledElement-inputTypeHidden', 'input, type hidden'); - isNotTabbable('#disabledElement-button', 'button'); - isNotTabbable('#disabledElement-select', 'select'); - isNotTabbable('#disabledElement-textarea', 'textarea'); -}); - -test("Tabbable - hidden styles", function() { - expect(8); - - isNotTabbable('#displayNoneAncestor-input', 'input, display: none parent'); - isNotTabbable('#displayNoneAncestor-span', 'span with tabindex, display: none parent'); - - // fails: element hidden by parent-visibility-hidden is still visible according to :visible - isNotTabbable('#visibilityHiddenAncestor-input', 'input, visibility: hidden parent'); - isNotTabbable('#visibilityHiddenAncestor-span', 'span with tabindex, visibility: hidden parent'); - - isNotTabbable('#displayNone-input', 'input, display: none'); - // fails: element hidden by parent-visibility-hidden is still visible according to :visible - isNotTabbable('#visibilityHidden-input', 'input, visibility: hidden'); - - isNotTabbable('#displayNone-span', 'span with tabindex, display: none'); - isNotTabbable('#visibilityHidden-span', 'span with tabindex, visibility: hidden'); -}); - -test("Tabbable - natively tabbable with various tabindex", function() { - expect(4); - - isTabbable('#inputTabindex0', 'input, tabindex 0'); - isTabbable('#inputTabindex10', 'input, tabindex 10'); - isNotTabbable('#inputTabindex-1', 'input, tabindex -1'); - isNotTabbable('#inputTabindex-50', 'input, tabindex -50'); -}); - -test("Tabbable - not natively tabbable with various tabindex", function() { - expect(4); - - isTabbable('#spanTabindex0', 'span, tabindex 0'); - isTabbable('#spanTabindex10', 'span, tabindex 10'); - isNotTabbable('#spanTabindex-1', 'span, tabindex -1'); - isNotTabbable('#spanTabindex-50', 'span, tabindex -50'); -}); - -test("Tabbable - invalid tabindex", function() { - expect(4); - - isTabbable('#inputTabindexfoo', 'input, tabindex foo'); - isTabbable('#inputTabindex3foo', 'input, tabindex 3foo'); - isNotTabbable('#spanTabindexfoo', 'span tabindex foo'); - isNotTabbable('#spanTabindex3foo', 'span, tabindex 3foo'); -}); - -})(jQuery); + + element = $( "
      " ); + shouldNotHaveData( "data never set" ); + + element = $( "
      " ).data( "test", null ); + shouldNotHaveData( "data is null" ); + + element = $( "
      " ).data( "test", true ); + shouldHaveData( "data set to true" ); + + element = $( "
      " ).data( "test", false ); + shouldNotHaveData( "data set to false" ); + + element = $( "
      " ).data( "test", 0 ); + shouldNotHaveData( "data set to 0" ); + + element = $( "
      " ).data( "test", 1 ); + shouldHaveData( "data set to 1" ); + + element = $( "
      " ).data( "test", "" ); + shouldNotHaveData( "data set to empty string" ); + + element = $( "
      " ).data( "test", "foo" ); + shouldHaveData( "data set to string" ); + + element = $( "
      " ).data( "test", [] ); + shouldHaveData( "data set to empty array" ); + + element = $( "
      " ).data( "test", [ 1 ] ); + shouldHaveData( "data set to array" ); + + element = $( "
      " ).data( "test", {} ); + shouldHaveData( "data set to empty object" ); + + element = $( "
      " ).data( "test", { foo: "bar" } ); + shouldHaveData( "data set to object" ); + + element = $( "
      " ).data( "test", new Date() ); + shouldHaveData( "data set to date" ); + + element = $( "
      " ).data( "test", /test/ ); + shouldHaveData( "data set to regexp" ); + + element = $( "
      " ).data( "test", function() {} ); + shouldHaveData( "data set to function" ); +} ); + +QUnit.test( "focusable - visible, enabled elements", function( assert ) { + assert.expect( 22 ); + + assert.isNotFocusable( "#formNoTabindex", "form" ); + assert.isFocusable( "#formTabindex", "form with tabindex" ); + assert.isFocusable( "#enabledFieldset input", "input in enabled fieldset" ); + assert.isNotFocusable( "#disabledFieldset input", "input in disabled fieldset" ); + assert.isFocusable( "#visibleAncestor-inputTypeNone", "input, no type" ); + assert.isFocusable( "#visibleAncestor-inputTypeText", "input, type text" ); + assert.isFocusable( "#visibleAncestor-inputTypeCheckbox", "input, type checkbox" ); + assert.isFocusable( "#visibleAncestor-inputTypeRadio", "input, type radio" ); + assert.isFocusable( "#visibleAncestor-inputTypeButton", "input, type button" ); + assert.isNotFocusable( "#visibleAncestor-inputTypeHidden", "input, type hidden" ); + assert.isFocusable( "#visibleAncestor-button", "button" ); + assert.isFocusable( "#visibleAncestor-select", "select" ); + assert.isFocusable( "#visibleAncestor-textarea", "textarea" ); + assert.isFocusable( "#visibleAncestor-object", "object" ); + assert.isFocusable( "#visibleAncestor-anchorWithHref", "anchor with href" ); + assert.isNotFocusable( "#visibleAncestor-anchorWithoutHref", "anchor without href" ); + assert.isNotFocusable( "#visibleAncestor-span", "span" ); + assert.isNotFocusable( "#visibleAncestor-div", "div" ); + assert.isFocusable( "#visibleAncestor-spanWithTabindex", "span with tabindex" ); + assert.isFocusable( "#visibleAncestor-divWithNegativeTabindex", "div with tabindex" ); + assert.isFocusable( "#nestedVisibilityInheritWithVisibleAncestor", + "span, visibility: inherit inside visibility: visible parent" ); + assert.isFocusable( "#nestedVisibilityInheritWithVisibleAncestor-input", + "input, visibility: inherit inside visibility: visible parent" ); +} ); + +QUnit.test( "focusable - disabled elements", function( assert ) { + assert.expect( 9 ); + + assert.isNotFocusable( "#disabledElement-inputTypeNone", "input, no type" ); + assert.isNotFocusable( "#disabledElement-inputTypeText", "input, type text" ); + assert.isNotFocusable( "#disabledElement-inputTypeCheckbox", "input, type checkbox" ); + assert.isNotFocusable( "#disabledElement-inputTypeRadio", "input, type radio" ); + assert.isNotFocusable( "#disabledElement-inputTypeButton", "input, type button" ); + assert.isNotFocusable( "#disabledElement-inputTypeHidden", "input, type hidden" ); + assert.isNotFocusable( "#disabledElement-button", "button" ); + assert.isNotFocusable( "#disabledElement-select", "select" ); + assert.isNotFocusable( "#disabledElement-textarea", "textarea" ); +} ); + +QUnit.test( "focusable - hidden styles", function( assert ) { + assert.expect( 15 ); + + assert.isNotFocusable( "#displayNoneAncestor-input", "input, display: none parent" ); + assert.isNotFocusable( "#displayNoneAncestor-span", "span with tabindex, display: none parent" ); + + assert.isNotFocusable( "#visibilityHiddenAncestor-input", "input, visibility: hidden parent" ); + assert.isNotFocusable( "#visibilityHiddenAncestor-span", "span with tabindex, visibility: hidden parent" ); + + assert.isFocusable( "#nestedVisibilityOverrideAncestor-input", "input, visibility: visible parent but visibility: hidden grandparent" ); + assert.isFocusable( "#nestedVisibilityOverrideAncestor-span", "span with tabindex, visibility: visible parent but visibility: hidden grandparent " ); + + assert.isNotFocusable( "#nestedVisibilityInheritWithHiddenAncestor", "span, visibility: inherit inside visibility: hidden parent" ); + assert.isNotFocusable( "#nestedVisibilityInheritWithHiddenAncestor-input", "input, visibility: inherit inside visibility: hidden parent" ); + + assert.isNotFocusable( "#displayNone-input", "input, display: none" ); + assert.isNotFocusable( "#visibilityHidden-input", "input, visibility: hidden" ); + assert.isNotFocusable( "#visibilityCollapse-input", "input, visibility: collapse" ); + + assert.isNotFocusable( "#displayNone-span", "span with tabindex, display: none" ); + assert.isNotFocusable( "#visibilityHidden-span", "span with tabindex, visibility: hidden" ); + assert.isNotFocusable( "#visibilityCollapse-span", "span with tabindex, visibility: collapse" ); + + assert.isNotFocusable( "#visibilityCollapse-td", "td with tabindex, visibility: collapse" ); +} ); + +QUnit.test( "focusable - natively focusable with various tabindex", function( assert ) { + assert.expect( 4 ); + + assert.isFocusable( "#inputTabindex0", "input, tabindex 0" ); + assert.isFocusable( "#inputTabindex10", "input, tabindex 10" ); + assert.isFocusable( "#inputTabindex-1", "input, tabindex -1" ); + assert.isFocusable( "#inputTabindex-50", "input, tabindex -50" ); +} ); + +QUnit.test( "focusable - not natively focusable with various tabindex", function( assert ) { + assert.expect( 4 ); + + assert.isFocusable( "#spanTabindex0", "span, tabindex 0" ); + assert.isFocusable( "#spanTabindex10", "span, tabindex 10" ); + assert.isFocusable( "#spanTabindex-1", "span, tabindex -1" ); + assert.isFocusable( "#spanTabindex-50", "span, tabindex -50" ); +} ); + +QUnit.test( "focusable - area elements", function( assert ) { + assert.expect( 3 ); + + assert.isFocusable( "#areaCoordsHref", "coords and href" ); + assert.isFocusable( "#areaNoCoordsHref", "href but no coords" ); + assert.isNotFocusable( "#areaNoImg", "not associated with an image" ); +} ); + +QUnit.test( "focusable - dimensionless parent with overflow", function( assert ) { + assert.expect( 1 ); + + assert.isFocusable( "#dimensionlessParent", "input" ); +} ); + +QUnit.test( "tabbable - visible, enabled elements", function( assert ) { + assert.expect( 20 ); + + assert.isNotTabbable( "#formNoTabindex", "form" ); + assert.isTabbable( "#formTabindex", "form with tabindex" ); + assert.isTabbable( "#enabledFieldset input", "input in enabled fieldset" ); + assert.isNotTabbable( "#disabledFieldset input", "input in disabled fieldset" ); + assert.isTabbable( "#visibleAncestor-inputTypeNone", "input, no type" ); + assert.isTabbable( "#visibleAncestor-inputTypeText", "input, type text" ); + assert.isTabbable( "#visibleAncestor-inputTypeCheckbox", "input, type checkbox" ); + assert.isTabbable( "#visibleAncestor-inputTypeRadio", "input, type radio" ); + assert.isTabbable( "#visibleAncestor-inputTypeButton", "input, type button" ); + assert.isNotTabbable( "#visibleAncestor-inputTypeHidden", "input, type hidden" ); + assert.isTabbable( "#visibleAncestor-button", "button" ); + assert.isTabbable( "#visibleAncestor-select", "select" ); + assert.isTabbable( "#visibleAncestor-textarea", "textarea" ); + assert.isTabbable( "#visibleAncestor-object", "object" ); + assert.isTabbable( "#visibleAncestor-anchorWithHref", "anchor with href" ); + assert.isNotTabbable( "#visibleAncestor-anchorWithoutHref", "anchor without href" ); + assert.isNotTabbable( "#visibleAncestor-span", "span" ); + assert.isNotTabbable( "#visibleAncestor-div", "div" ); + assert.isTabbable( "#visibleAncestor-spanWithTabindex", "span with tabindex" ); + assert.isNotTabbable( "#visibleAncestor-divWithNegativeTabindex", "div with tabindex" ); +} ); + +QUnit.test( "tabbable - disabled elements", function( assert ) { + assert.expect( 9 ); + + assert.isNotTabbable( "#disabledElement-inputTypeNone", "input, no type" ); + assert.isNotTabbable( "#disabledElement-inputTypeText", "input, type text" ); + assert.isNotTabbable( "#disabledElement-inputTypeCheckbox", "input, type checkbox" ); + assert.isNotTabbable( "#disabledElement-inputTypeRadio", "input, type radio" ); + assert.isNotTabbable( "#disabledElement-inputTypeButton", "input, type button" ); + assert.isNotTabbable( "#disabledElement-inputTypeHidden", "input, type hidden" ); + assert.isNotTabbable( "#disabledElement-button", "button" ); + assert.isNotTabbable( "#disabledElement-select", "select" ); + assert.isNotTabbable( "#disabledElement-textarea", "textarea" ); +} ); + +QUnit.test( "tabbable - hidden styles", function( assert ) { + assert.expect( 10 ); + + assert.isNotTabbable( "#displayNoneAncestor-input", "input, display: none parent" ); + assert.isNotTabbable( "#displayNoneAncestor-span", "span with tabindex, display: none parent" ); + + assert.isNotTabbable( "#visibilityHiddenAncestor-input", "input, visibility: hidden parent" ); + assert.isNotTabbable( "#visibilityHiddenAncestor-span", "span with tabindex, visibility: hidden parent" ); + + assert.isTabbable( "#nestedVisibilityOverrideAncestor-input", "input, visibility: visible parent but visibility: hidden grandparent" ); + assert.isTabbable( "#nestedVisibilityOverrideAncestor-span", "span with tabindex, visibility: visible parent but visibility: hidden grandparent " ); + + assert.isNotTabbable( "#displayNone-input", "input, display: none" ); + assert.isNotTabbable( "#visibilityHidden-input", "input, visibility: hidden" ); + + assert.isNotTabbable( "#displayNone-span", "span with tabindex, display: none" ); + assert.isNotTabbable( "#visibilityHidden-span", "span with tabindex, visibility: hidden" ); +} ); + +QUnit.test( "tabbable - natively tabbable with various tabindex", function( assert ) { + assert.expect( 4 ); + + assert.isTabbable( "#inputTabindex0", "input, tabindex 0" ); + assert.isTabbable( "#inputTabindex10", "input, tabindex 10" ); + assert.isNotTabbable( "#inputTabindex-1", "input, tabindex -1" ); + assert.isNotTabbable( "#inputTabindex-50", "input, tabindex -50" ); +} ); + +QUnit.test( "tabbable - not natively tabbable with various tabindex", function( assert ) { + assert.expect( 4 ); + + assert.isTabbable( "#spanTabindex0", "span, tabindex 0" ); + assert.isTabbable( "#spanTabindex10", "span, tabindex 10" ); + assert.isNotTabbable( "#spanTabindex-1", "span, tabindex -1" ); + assert.isNotTabbable( "#spanTabindex-50", "span, tabindex -50" ); +} ); + +QUnit.test( "tabbable - area elements", function( assert ) { + assert.expect( 3 ); + + assert.isTabbable( "#areaCoordsHref", "coords and href" ); + assert.isTabbable( "#areaNoCoordsHref", "href but no coords" ); + assert.isNotTabbable( "#areaNoImg", "not associated with an image" ); +} ); + +QUnit.test( "tabbable - dimensionless parent with overflow", function( assert ) { + assert.expect( 1 ); + + assert.isTabbable( "#dimensionlessParent", "input" ); +} ); + +} ); diff --git a/tests/unit/datepicker/all.html b/tests/unit/datepicker/all.html new file mode 100644 index 00000000000..b3eb6a31ae0 --- /dev/null +++ b/tests/unit/datepicker/all.html @@ -0,0 +1,26 @@ + + + + + jQuery UI Datepicker Test Suite + + + + + + + + + + + + + +
      +
      + +
      + + diff --git a/tests/unit/datepicker/common.js b/tests/unit/datepicker/common.js new file mode 100644 index 00000000000..1eecc85cb50 --- /dev/null +++ b/tests/unit/datepicker/common.js @@ -0,0 +1,7 @@ +/* +TestHelpers.commonWidgetTests( "datepicker", { + defaults: { + disabled: false + } +}); +*/ diff --git a/tests/unit/datepicker/core.js b/tests/unit/datepicker/core.js new file mode 100644 index 00000000000..edc16d005df --- /dev/null +++ b/tests/unit/datepicker/core.js @@ -0,0 +1,543 @@ +define( [ + "qunit", + "jquery", + "lib/common", + "lib/helper", + "./helper", + "ui/widgets/datepicker", + "ui/i18n/datepicker-he" +], function( QUnit, $, common, helper, testHelper ) { +"use strict"; + +QUnit.module( "datepicker: core", { + beforeEach: function() { + $( "body" ).trigger( "focus" ); + }, + afterEach: helper.moduleAfterEach +} ); + +QUnit.test( "initialization - Reinitialization after body had been emptied.", function( assert ) { + assert.expect( 1 ); + var bodyContent = $( "body" ).children(), inp = $( "#inp" ); + $( "#inp" ).datepicker(); + $( "body" ).empty().append( inp ); + $( "#inp" ).datepicker(); + assert.ok( $( "#" + $.datepicker._mainDivId ).length === 1, "Datepicker container added" ); + $( "body" ).empty().append( bodyContent ); // Returning to initial state for later tests +} ); + +QUnit.test( "widget method - empty collection", function( assert ) { + assert.expect( 1 ); + $( "#nonExist" ).datepicker(); // Should create nothing + assert.ok( !$( "#ui-datepicker-div" ).length, "Non init on empty collection" ); +} ); + +QUnit.test( "widget method", function( assert ) { + assert.expect( 1 ); + var actual = $( "#inp" ).datepicker().datepicker( "widget" )[ 0 ]; + assert.deepEqual( $( "body > #ui-datepicker-div:last-child" )[ 0 ], actual ); +} ); + +QUnit.test( "baseStructure", function( assert ) { + var ready = assert.async(); + assert.expect( 58 ); + var header, title, table, thead, week, panel, inl, child, + inp = testHelper.initNewInput(), + dp = $( "#ui-datepicker-div" ); + + function step1() { + testHelper.onFocus( inp, function() { + assert.ok( dp.is( ":visible" ), "Structure - datepicker visible" ); + assert.ok( !dp.is( ".ui-datepicker-rtl" ), "Structure - not right-to-left" ); + assert.ok( !dp.is( ".ui-datepicker-multi" ), "Structure - not multi-month" ); + assert.equal( dp.children().length, 2, "Structure - child count" ); + + header = dp.children().first(); + assert.ok( header.is( "div.ui-datepicker-header" ), "Structure - header division" ); + assert.equal( header.children().length, 3, "Structure - header child count" ); + assert.ok( header.children().first().is( "a.ui-datepicker-prev" ) && header.children().first().html() !== "", "Structure - prev link" ); + assert.ok( header.children().eq( 1 ).is( "a.ui-datepicker-next" ) && header.children().eq( 1 ).html() !== "", "Structure - next link" ); + + title = header.children().last(); + assert.ok( title.is( "div.ui-datepicker-title" ) && title.html() !== "", "Structure - title division" ); + assert.equal( title.children().length, 2, "Structure - title child count" ); + assert.ok( title.children().first().is( "span.ui-datepicker-month" ) && title.children().first().text() !== "", "Structure - month text" ); + assert.ok( title.children().last().is( "span.ui-datepicker-year" ) && title.children().last().text() !== "", "Structure - year text" ); + + table = dp.children().eq( 1 ); + assert.ok( table.is( "table.ui-datepicker-calendar" ), "Structure - month table" ); + assert.ok( table.children().first().is( "thead" ), "Structure - month table thead" ); + + thead = table.children().first().children().first(); + assert.ok( thead.is( "tr" ), "Structure - month table title row" ); + assert.equal( thead.find( "th" ).length, 7, "Structure - month table title cells" ); + assert.ok( table.children().eq( 1 ).is( "tbody" ), "Structure - month table body" ); + assert.ok( table.children().eq( 1 ).children( "tr" ).length >= 4, "Structure - month table week count" ); + + week = table.children().eq( 1 ).children().first(); + assert.ok( week.is( "tr" ), "Structure - month table week row" ); + assert.equal( week.children().length, 7, "Structure - week child count" ); + assert.ok( week.children().first().is( "td.ui-datepicker-week-end" ), "Structure - month table first day cell" ); + assert.ok( week.children().last().is( "td.ui-datepicker-week-end" ), "Structure - month table second day cell" ); + + inp.datepicker( "hide" ).datepicker( "destroy" ); + step2(); + } ); + } + + function step2() { + + // Editable month/year and button panel + inp = testHelper.initNewInput( { + changeMonth: true, + changeYear: true, + showButtonPanel: true + } ); + testHelper.onFocus( inp, function() { + title = dp.find( "div.ui-datepicker-title" ); + assert.ok( title.children().first().is( "select.ui-datepicker-month" ), "Structure - month selector" ); + assert.ok( title.children().last().is( "select.ui-datepicker-year" ), "Structure - year selector" ); + + panel = dp.children().last(); + assert.ok( panel.is( "div.ui-datepicker-buttonpane" ), "Structure - button panel division" ); + assert.equal( panel.children().length, 2, "Structure - button panel child count" ); + assert.ok( panel.children().first().is( "button.ui-datepicker-current" ), "Structure - today button" ); + assert.ok( panel.children().last().is( "button.ui-datepicker-close" ), "Structure - close button" ); + + inp.datepicker( "hide" ).datepicker( "destroy" ); + step3(); + } ); + } + + function step3() { + + // Multi-month 2 + inp = testHelper.initNewInput( { numberOfMonths: 2 } ); + testHelper.onFocus( inp, function() { + assert.ok( dp.is( ".ui-datepicker-multi" ), "Structure multi [2] - multi-month" ); + assert.equal( dp.children().length, 3, "Structure multi [2] - child count" ); + + child = dp.children().first(); + assert.ok( child.is( "div.ui-datepicker-group" ) && child.is( "div.ui-datepicker-group-first" ), "Structure multi [2] - first month division" ); + + child = dp.children().eq( 1 ); + assert.ok( child.is( "div.ui-datepicker-group" ) && child.is( "div.ui-datepicker-group-last" ), "Structure multi [2] - second month division" ); + + child = dp.children().eq( 2 ); + assert.ok( child.is( "div.ui-datepicker-row-break" ), "Structure multi [2] - row break" ); + assert.ok( dp.is( ".ui-datepicker-multi-2" ), "Structure multi [2] - multi-2" ); + + inp.datepicker( "hide" ).datepicker( "destroy" ); + step4(); + } ); + } + + function step4() { + + // Multi-month 3 + inp = testHelper.initNewInput( { numberOfMonths: 3 } ); + testHelper.onFocus( inp, function() { + assert.ok( dp.is( ".ui-datepicker-multi-3" ), "Structure multi [3] - multi-3" ); + assert.ok( !dp.is( ".ui-datepicker-multi-2" ), "Structure multi [3] - Trac #6704" ); + + inp.datepicker( "hide" ).datepicker( "destroy" ); + step5(); + } ); + } + + function step5() { + + // Multi-month [2, 2] + inp = testHelper.initNewInput( { numberOfMonths: [ 2, 2 ] } ); + testHelper.onFocus( inp, function() { + assert.ok( dp.is( ".ui-datepicker-multi" ), "Structure multi - multi-month" ); + assert.equal( dp.children().length, 6, "Structure multi [2,2] - child count" ); + + child = dp.children().first(); + assert.ok( child.is( "div.ui-datepicker-group" ) && child.is( "div.ui-datepicker-group-first" ), "Structure multi [2,2] - first month division" ); + + child = dp.children().eq( 1 ); + assert.ok( child.is( "div.ui-datepicker-group" ) && child.is( "div.ui-datepicker-group-last" ), "Structure multi [2,2] - second month division" ); + + child = dp.children().eq( 2 ); + assert.ok( child.is( "div.ui-datepicker-row-break" ), "Structure multi [2,2] - row break" ); + + child = dp.children().eq( 3 ); + assert.ok( child.is( "div.ui-datepicker-group" ) && child.is( "div.ui-datepicker-group-first" ), "Structure multi [2,2] - third month division" ); + + child = dp.children().eq( 4 ); + assert.ok( child.is( "div.ui-datepicker-group" ) && child.is( "div.ui-datepicker-group-last" ), "Structure multi [2,2] - fourth month division" ); + + child = dp.children().eq( 5 ); + assert.ok( child.is( "div.ui-datepicker-row-break" ), "Structure multi [2,2] - row break" ); + + inp.datepicker( "hide" ).datepicker( "destroy" ); + + // Inline + inl = testHelper.init( "#inl" ); + dp = inl.children(); + + assert.ok( dp.is( ".ui-datepicker-inline" ), "Structure inline - main div" ); + assert.ok( !dp.is( ".ui-datepicker-rtl" ), "Structure inline - not right-to-left" ); + assert.ok( !dp.is( ".ui-datepicker-multi" ), "Structure inline - not multi-month" ); + assert.equal( dp.children().length, 2, "Structure inline - child count" ); + + header = dp.children().first(); + assert.ok( header.is( "div.ui-datepicker-header" ), "Structure inline - header division" ); + assert.equal( header.children().length, 3, "Structure inline - header child count" ); + + table = dp.children().eq( 1 ); + assert.ok( table.is( "table.ui-datepicker-calendar" ), "Structure inline - month table" ); + assert.ok( table.children().first().is( "thead" ), "Structure inline - month table thead" ); + assert.ok( table.children().eq( 1 ).is( "tbody" ), "Structure inline - month table body" ); + + inl.datepicker( "destroy" ); + + // Inline multi-month + inl = testHelper.init( "#inl", { numberOfMonths: 2 } ); + dp = inl.children(); + + assert.ok( dp.is( ".ui-datepicker-inline" ) && dp.is( ".ui-datepicker-multi" ), "Structure inline multi - main div" ); + assert.equal( dp.children().length, 3, "Structure inline multi - child count" ); + + child = dp.children().first(); + assert.ok( child.is( "div.ui-datepicker-group" ) && child.is( "div.ui-datepicker-group-first" ), "Structure inline multi - first month division" ); + + child = dp.children().eq( 1 ); + assert.ok( child.is( "div.ui-datepicker-group" ) && child.is( "div.ui-datepicker-group-last" ), "Structure inline multi - second month division" ); + + child = dp.children().eq( 2 ); + assert.ok( child.is( "div.ui-datepicker-row-break" ), "Structure inline multi - row break" ); + + inl.datepicker( "destroy" ); + ready(); + } ); + } + + step1(); +} ); + +QUnit.test( "customStructure", function( assert ) { + var ready = assert.async(); + assert.expect( 20 ); + var header, panel, title, thead, + inp = testHelper.initNewInput( $.datepicker.regional.he ), + dp = $( "#ui-datepicker-div" ); + + function step1() { + inp.datepicker( "option", "showButtonPanel", true ); + + testHelper.onFocus( inp, function() { + assert.ok( dp.is( ".ui-datepicker-rtl" ), "Structure RTL - right-to-left" ); + + header = dp.children().first(); + assert.ok( header.is( "div.ui-datepicker-header" ), "Structure RTL - header division" ); + assert.equal( header.children().length, 3, "Structure RTL - header child count" ); + assert.ok( header.children().first().is( "a.ui-datepicker-next" ), "Structure RTL - prev link" ); + assert.ok( header.children().eq( 1 ).is( "a.ui-datepicker-prev" ), "Structure RTL - next link" ); + + panel = dp.children().last(); + assert.ok( panel.is( "div.ui-datepicker-buttonpane" ), "Structure RTL - button division" ); + assert.equal( panel.children().length, 2, "Structure RTL - button panel child count" ); + assert.ok( panel.children().first().is( "button.ui-datepicker-close" ), "Structure RTL - close button" ); + assert.ok( panel.children().last().is( "button.ui-datepicker-current" ), "Structure RTL - today button" ); + + inp.datepicker( "hide" ).datepicker( "destroy" ); + step2(); + } ); + } + + // Hide prev/next + function step2() { + inp = testHelper.initNewInput( { + hideIfNoPrevNext: true, + minDate: new Date( 2008, 2 - 1, 4 ), + maxDate: new Date( 2008, 2 - 1, 14 ) + } ); + inp.val( "02/10/2008" ); + + testHelper.onFocus( inp, function() { + header = dp.children().first(); + assert.ok( header.is( "div.ui-datepicker-header" ), "Structure hide prev/next - header division" ); + assert.equal( header.children().length, 1, "Structure hide prev/next - links child count" ); + assert.ok( header.children().first().is( "div.ui-datepicker-title" ), "Structure hide prev/next - title division" ); + + inp.datepicker( "hide" ).datepicker( "destroy" ); + step3(); + } ); + } + + // Changeable Month with read-only year + function step3() { + inp = testHelper.initNewInput( { changeMonth: true } ); + + testHelper.onFocus( inp, function() { + title = dp.children().first().children().last(); + assert.equal( title.children().length, 2, "Structure changeable month - title child count" ); + assert.ok( title.children().first().is( "select.ui-datepicker-month" ), "Structure changeable month - month selector" ); + assert.ok( title.children().last().is( "span.ui-datepicker-year" ), "Structure changeable month - read-only year" ); + + inp.datepicker( "hide" ).datepicker( "destroy" ); + step4(); + } ); + } + + // Changeable year with read-only month + function step4() { + inp = testHelper.initNewInput( { changeYear: true } ); + + testHelper.onFocus( inp, function() { + title = dp.children().first().children().last(); + assert.equal( title.children().length, 2, "Structure changeable year - title child count" ); + assert.ok( title.children().first().is( "span.ui-datepicker-month" ), "Structure changeable year - read-only month" ); + assert.ok( title.children().last().is( "select.ui-datepicker-year" ), "Structure changeable year - year selector" ); + + inp.datepicker( "hide" ).datepicker( "destroy" ); + step5(); + } ); + } + + // Read-only first day of week + function step5() { + inp = testHelper.initNewInput( { changeFirstDay: false } ); + + testHelper.onFocus( inp, function() { + thead = dp.find( ".ui-datepicker-calendar thead tr" ); + assert.equal( thead.children().length, 7, "Structure read-only first day - thead child count" ); + assert.equal( thead.find( "a" ).length, 0, "Structure read-only first day - thead links count" ); + + inp.datepicker( "hide" ).datepicker( "destroy" ); + ready(); + } ); + } + + setTimeout( step1 ); +} ); + +QUnit.test( "keystrokes", function( assert ) { + assert.expect( 26 ); + var inp = testHelper.init( "#inp" ), + date = new Date(); + inp.val( "" ).datepicker( "show" ). + simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), date, "Keystroke enter" ); + inp.val( "02/04/2008" ).datepicker( "show" ). + simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), new Date( 2008, 2 - 1, 4 ), + "Keystroke enter - preset" ); + inp.val( "02/04/2008" ).datepicker( "show" ). + simulate( "keydown", { ctrlKey: true, keyCode: $.ui.keyCode.HOME } ). + simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), date, "Keystroke ctrl+home" ); + inp.val( "02/04/2008" ).datepicker( "show" ). + simulate( "keydown", { ctrlKey: true, keyCode: $.ui.keyCode.END } ); + assert.ok( inp.datepicker( "getDate" ) == null, "Keystroke ctrl+end" ); + inp.val( "" ).datepicker( "show" ). + simulate( "keydown", { keyCode: $.ui.keyCode.ESCAPE } ); + assert.ok( inp.datepicker( "getDate" ) == null, "Keystroke esc" ); + inp.val( "02/04/2008" ).datepicker( "show" ). + simulate( "keydown", { keyCode: $.ui.keyCode.ESCAPE } ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), new Date( 2008, 2 - 1, 4 ), + "Keystroke esc - preset" ); + inp.val( "02/04/2008" ).datepicker( "show" ). + simulate( "keydown", { ctrlKey: true, keyCode: $.ui.keyCode.PAGE_UP } ). + simulate( "keydown", { keyCode: $.ui.keyCode.ESCAPE } ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), new Date( 2008, 2 - 1, 4 ), + "Keystroke esc - abandoned" ); + + // Moving by day or week + inp.val( "" ).datepicker( "show" ). + simulate( "keydown", { ctrlKey: true, keyCode: $.ui.keyCode.LEFT } ). + simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + date.setDate( date.getDate() - 1 ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), date, "Keystroke ctrl+left" ); + inp.val( "" ).datepicker( "show" ). + simulate( "keydown", { keyCode: $.ui.keyCode.LEFT } ). + simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + date.setDate( date.getDate() + 1 ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), date, "Keystroke left" ); + inp.val( "" ).datepicker( "show" ). + simulate( "keydown", { ctrlKey: true, keyCode: $.ui.keyCode.RIGHT } ). + simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + date.setDate( date.getDate() + 1 ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), date, "Keystroke ctrl+right" ); + inp.val( "" ).datepicker( "show" ). + simulate( "keydown", { keyCode: $.ui.keyCode.RIGHT } ). + simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + date.setDate( date.getDate() - 1 ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), date, "Keystroke right" ); + inp.val( "" ).datepicker( "show" ). + simulate( "keydown", { ctrlKey: true, keyCode: $.ui.keyCode.UP } ). + simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + date.setDate( date.getDate() - 7 ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), date, "Keystroke ctrl+up" ); + inp.val( "" ).datepicker( "show" ). + simulate( "keydown", { keyCode: $.ui.keyCode.UP } ). + simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + date.setDate( date.getDate() + 7 ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), date, "Keystroke up" ); + inp.val( "" ).datepicker( "show" ). + simulate( "keydown", { ctrlKey: true, keyCode: $.ui.keyCode.DOWN } ). + simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + date.setDate( date.getDate() + 7 ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), date, "Keystroke ctrl+down" ); + inp.val( "" ).datepicker( "show" ). + simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } ). + simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + date.setDate( date.getDate() - 7 ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), date, "Keystroke down" ); + + // Moving by month or year + inp.val( "02/04/2008" ).datepicker( "show" ). + simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_UP } ). + simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), new Date( 2008, 1 - 1, 4 ), + "Keystroke pgup" ); + inp.val( "02/04/2008" ).datepicker( "show" ). + simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_DOWN } ). + simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), new Date( 2008, 3 - 1, 4 ), + "Keystroke pgdn" ); + inp.val( "02/04/2008" ).datepicker( "show" ). + simulate( "keydown", { ctrlKey: true, keyCode: $.ui.keyCode.PAGE_UP } ). + simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), new Date( 2007, 2 - 1, 4 ), + "Keystroke ctrl+pgup" ); + inp.val( "02/04/2008" ).datepicker( "show" ). + simulate( "keydown", { ctrlKey: true, keyCode: $.ui.keyCode.PAGE_DOWN } ). + simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), new Date( 2009, 2 - 1, 4 ), + "Keystroke ctrl+pgdn" ); + + // Check for moving to short months + inp.val( "03/31/2008" ).datepicker( "show" ). + simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_UP } ). + simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), new Date( 2008, 2 - 1, 29 ), + "Keystroke pgup - Feb" ); + inp.val( "01/30/2008" ).datepicker( "show" ). + simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_DOWN } ). + simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), new Date( 2008, 2 - 1, 29 ), + "Keystroke pgdn - Feb" ); + inp.val( "02/29/2008" ).datepicker( "show" ). + simulate( "keydown", { ctrlKey: true, keyCode: $.ui.keyCode.PAGE_UP } ). + simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), new Date( 2007, 2 - 1, 28 ), + "Keystroke ctrl+pgup - Feb" ); + inp.val( "02/29/2008" ).datepicker( "show" ). + simulate( "keydown", { ctrlKey: true, keyCode: $.ui.keyCode.PAGE_DOWN } ). + simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), new Date( 2009, 2 - 1, 28 ), + "Keystroke ctrl+pgdn - Feb" ); + + // Goto current + inp.datepicker( "option", { gotoCurrent: true } ). + datepicker( "hide" ).val( "02/04/2008" ).datepicker( "show" ). + simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_DOWN } ). + simulate( "keydown", { ctrlKey: true, keyCode: $.ui.keyCode.HOME } ). + simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), new Date( 2008, 2 - 1, 4 ), + "Keystroke ctrl+home" ); + + // Change steps + inp.datepicker( "option", { stepMonths: 2, gotoCurrent: false } ). + datepicker( "hide" ).val( "02/04/2008" ).datepicker( "show" ). + simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_UP } ). + simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), new Date( 2007, 12 - 1, 4 ), + "Keystroke pgup step 2" ); + inp.val( "02/04/2008" ).datepicker( "show" ). + simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_DOWN } ). + simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), new Date( 2008, 4 - 1, 4 ), + "Keystroke pgdn step 2" ); +} ); + +QUnit.test( "mouse", function( assert ) { + assert.expect( 15 ); + var inl, + inp = testHelper.init( "#inp" ), + dp = $( "#ui-datepicker-div" ), + date = new Date(); + inp.val( "" ).datepicker( "show" ); + $( ".ui-datepicker-calendar tbody a:contains(10)", dp ).simulate( "click", {} ); + date.setDate( 10 ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), date, "Mouse click" ); + inp.val( "02/04/2008" ).datepicker( "show" ); + $( ".ui-datepicker-calendar tbody a:contains(12)", dp ).simulate( "click", {} ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), new Date( 2008, 2 - 1, 12 ), + "Mouse click - preset" ); + inp.val( "02/04/2008" ).datepicker( "show" ); + inp.val( "" ).datepicker( "show" ); + $( "button.ui-datepicker-close", dp ).simulate( "click", {} ); + assert.ok( inp.datepicker( "getDate" ) == null, "Mouse click - close" ); + inp.val( "02/04/2008" ).datepicker( "show" ); + $( "button.ui-datepicker-close", dp ).simulate( "click", {} ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), new Date( 2008, 2 - 1, 4 ), + "Mouse click - close + preset" ); + inp.val( "02/04/2008" ).datepicker( "show" ); + $( "a.ui-datepicker-prev", dp ).simulate( "click", {} ); + $( "button.ui-datepicker-close", dp ).simulate( "click", {} ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), new Date( 2008, 2 - 1, 4 ), + "Mouse click - abandoned" ); + + // Current/previous/next + inp.val( "02/04/2008" ).datepicker( "option", { showButtonPanel: true } ).datepicker( "show" ); + $( ".ui-datepicker-current", dp ).simulate( "click", {} ); + $( ".ui-datepicker-calendar tbody a:contains(14)", dp ).simulate( "click", {} ); + date.setDate( 14 ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), date, "Mouse click - current" ); + inp.val( "02/04/2008" ).datepicker( "show" ); + $( ".ui-datepicker-prev", dp ).simulate( "click" ); + $( ".ui-datepicker-calendar tbody a:contains(16)", dp ).simulate( "click" ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), new Date( 2008, 1 - 1, 16 ), + "Mouse click - previous" ); + inp.val( "02/04/2008" ).datepicker( "show" ); + $( ".ui-datepicker-next", dp ).simulate( "click" ); + $( ".ui-datepicker-calendar tbody a:contains(18)", dp ).simulate( "click" ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), new Date( 2008, 3 - 1, 18 ), + "Mouse click - next" ); + + // Previous/next with minimum/maximum + inp.datepicker( "option", { minDate: new Date( 2008, 2 - 1, 2 ), + maxDate: new Date( 2008, 2 - 1, 26 ) } ).val( "02/04/2008" ).datepicker( "show" ); + $( ".ui-datepicker-prev", dp ).simulate( "click" ); + $( ".ui-datepicker-calendar tbody a:contains(16)", dp ).simulate( "click" ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), new Date( 2008, 2 - 1, 16 ), + "Mouse click - previous + min/max" ); + inp.val( "02/04/2008" ).datepicker( "show" ); + $( ".ui-datepicker-next", dp ).simulate( "click" ); + $( ".ui-datepicker-calendar tbody a:contains(18)", dp ).simulate( "click" ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), new Date( 2008, 2 - 1, 18 ), + "Mouse click - next + min/max" ); + + // Inline + inl = testHelper.init( "#inl" ); + dp = $( ".ui-datepicker-inline", inl ); + date = new Date(); + inl.datepicker( "setDate", date ); + $( ".ui-datepicker-calendar tbody a:contains(10)", dp ).simulate( "click", {} ); + date.setDate( 10 ); + testHelper.equalsDate( assert, inl.datepicker( "getDate" ), date, "Mouse click inline" ); + inl.datepicker( "option", { showButtonPanel: true } ).datepicker( "setDate", new Date( 2008, 2 - 1, 4 ) ); + $( ".ui-datepicker-calendar tbody a:contains(12)", dp ).simulate( "click", {} ); + testHelper.equalsDate( assert, inl.datepicker( "getDate" ), new Date( 2008, 2 - 1, 12 ), "Mouse click inline - preset" ); + inl.datepicker( "option", { showButtonPanel: true } ); + $( ".ui-datepicker-current", dp ).simulate( "click", {} ); + $( ".ui-datepicker-calendar tbody a:contains(14)", dp ).simulate( "click", {} ); + date.setDate( 14 ); + testHelper.equalsDate( assert, inl.datepicker( "getDate" ), date, "Mouse click inline - current" ); + inl.datepicker( "setDate", new Date( 2008, 2 - 1, 4 ) ); + $( ".ui-datepicker-prev", dp ).simulate( "click" ); + $( ".ui-datepicker-calendar tbody a:contains(16)", dp ).simulate( "click" ); + testHelper.equalsDate( assert, inl.datepicker( "getDate" ), new Date( 2008, 1 - 1, 16 ), + "Mouse click inline - previous" ); + inl.datepicker( "setDate", new Date( 2008, 2 - 1, 4 ) ); + $( ".ui-datepicker-next", dp ).simulate( "click" ); + $( ".ui-datepicker-calendar tbody a:contains(18)", dp ).simulate( "click" ); + testHelper.equalsDate( assert, inl.datepicker( "getDate" ), new Date( 2008, 3 - 1, 18 ), + "Mouse click inline - next" ); +} ); + +} ); diff --git a/tests/unit/datepicker/datepicker.html b/tests/unit/datepicker/datepicker.html index 9354e7b99c2..26d8de3e0f8 100644 --- a/tests/unit/datepicker/datepicker.html +++ b/tests/unit/datepicker/datepicker.html @@ -1,52 +1,21 @@ - + - + jQuery UI Datepicker Test Suite - - - - - - - - - - - - - - - - - - - - - - + + + -

      jQuery UI Datepicker Test Suite

      -

      -

      -
        -
      +
      +
      -
      -

      -
      +
      +

      +
      diff --git a/tests/unit/datepicker/datepicker_core.js b/tests/unit/datepicker/datepicker_core.js deleted file mode 100644 index 9867022f710..00000000000 --- a/tests/unit/datepicker/datepicker_core.js +++ /dev/null @@ -1,441 +0,0 @@ -/* - * datepicker_core.js - */ - -function equalsDate(d1, d2, message) { - if (!d1 || !d2) { - ok(false, message + ' - missing date'); - return; - } - d1 = new Date(d1.getFullYear(), d1.getMonth(), d1.getDate()); - d2 = new Date(d2.getFullYear(), d2.getMonth(), d2.getDate()); - equals(d1.toString(), d2.toString(), message); -} - -function equalsDateArray(a1, a2, message) { - if (!a1 || !a2) { - ok(false, message + ' - missing dates'); - return; - } - a1[0] = (a1[0] ? new Date(a1[0].getFullYear(), a1[0].getMonth(), a1[0].getDate()) : ''); - a1[1] = (a1[1] ? new Date(a1[1].getFullYear(), a1[1].getMonth(), a1[1].getDate()) : ''); - a2[0] = (a2[0] ? new Date(a2[0].getFullYear(), a2[0].getMonth(), a2[0].getDate()) : ''); - a2[1] = (a2[1] ? new Date(a2[1].getFullYear(), a2[1].getMonth(), a2[1].getDate()) : ''); - same(a1, a2, message); -} - -function addMonths(date, offset) { - var maxDay = 32 - new Date(date.getFullYear(), date.getMonth() + offset, 32).getDate(); - date.setDate(Math.min(date.getDate(), maxDay)); - date.setMonth(date.getMonth() + offset); - return date; -} - -function init(id, options) { - $.datepicker.setDefaults($.datepicker.regional['']); - return $(id).datepicker($.extend({showAnim: ''}, options || {})); -} - -var PROP_NAME = 'datepicker'; - -(function($) { - -module("datepicker: core", { - teardown: function() { - stop(); - setTimeout(start, 13); - } -}); - -test("widget method", function() { - var actual = $("#inp").datepicker().datepicker("widget")[0]; - same($("body > #ui-datepicker-div:last-child")[0], actual); -}); - -test('baseStructure', function() { - var inp = init('#inp'); - inp.focus(); - var dp = $('#ui-datepicker-div'); - var iframe = ($.browser.msie && parseInt($.browser.version) < 7); - ok(dp.is(':visible'), 'Structure - datepicker visible'); - ok(!dp.is('.ui-datepicker-rtl'), 'Structure - not right-to-left'); - ok(!dp.is('.ui-datepicker-multi'), 'Structure - not multi-month'); - equals(dp.children().length, 2 + (iframe ? 1 : 0), 'Structure - child count'); - - var header = dp.children(':first'); - ok(header.is('div.ui-datepicker-header'), 'Structure - header division'); - equals(header.children().length, 3, 'Structure - header child count'); - ok(header.children(':first').is('a.ui-datepicker-prev') && header.children(':first').html() != '', 'Structure - prev link'); - ok(header.children(':eq(1)').is('a.ui-datepicker-next') && header.children(':eq(1)').html() != '', 'Structure - next link'); - - var title = header.children(':last'); - ok(title.is('div.ui-datepicker-title') && title.html() != '','Structure - title division'); - equals(title.children().length, 2, 'Structure - title child count'); - ok(title.children(':first').is('span.ui-datepicker-month') && title.children(':first').text() != '', 'Structure - month text') - ok(title.children(':last').is('span.ui-datepicker-year') && title.children(':last').text() != '', 'Structure - year text') - - var table = dp.children(':eq(1)'); - ok(table.is('table.ui-datepicker-calendar'), 'Structure - month table'); - ok(table.children(':first').is('thead'), 'Structure - month table thead'); - var thead = table.children(':first').children(':first'); - ok(thead.is('tr'), 'Structure - month table title row'); - equals(thead.find('th').length, 7, 'Structure - month table title cells'); - ok(table.children(':eq(1)').is('tbody'), 'Structure - month table body'); - ok(table.children(':eq(1)').children('tr').length >= 4, 'Structure - month table week count'); - var week = table.children(':eq(1)').children(':first'); - ok(week.is('tr'), 'Structure - month table week row'); - equals(week.children().length, 7, 'Structure - week child count'); - ok(week.children(':first').is('td.ui-datepicker-week-end'), 'Structure - month table first day cell'); - ok(week.children(':last').is('td.ui-datepicker-week-end'), 'Structure - month table second day cell'); - ok(dp.children('iframe').length == (iframe ? 1 : 0), 'Structure - iframe'); - inp.datepicker('hide').datepicker('destroy'); - - // Editable month/year and button panel - inp = init('#inp', {changeMonth: true, changeYear: true, showButtonPanel: true}); - inp.focus(); - - var title = dp.find('div.ui-datepicker-title'); - ok(title.children(':first').is('select.ui-datepicker-month'), 'Structure - month selector'); - ok(title.children(':last').is('select.ui-datepicker-year'), 'Structure - year selector'); - - var panel = dp.children(':last'); - ok(panel.is('div.ui-datepicker-buttonpane'), 'Structure - button panel division'); - equals(panel.children().length, 2, 'Structure - button panel child count'); - ok(panel.children(':first').is('button.ui-datepicker-current'), 'Structure - today button'); - ok(panel.children(':last').is('button.ui-datepicker-close'), 'Structure - close button'); - inp.datepicker('hide').datepicker('destroy'); - - // Multi-month 2 - inp = init('#inp', {numberOfMonths: 2}); - inp.focus(); - ok(dp.is('.ui-datepicker-multi'), 'Structure multi [2] - multi-month'); - equals(dp.children().length, 3 + (iframe ? 1 : 0), 'Structure multi [2] - child count'); - var child = dp.children(':first'); - ok(child.is('div.ui-datepicker-group') && child.is('div.ui-datepicker-group-first'), 'Structure multi [2] - first month division'); - child = dp.children(':eq(1)'); - ok(child.is('div.ui-datepicker-group') && child.is('div.ui-datepicker-group-last'), 'Structure multi [2] - second month division'); - child = dp.children(':eq(2)'); - ok(child.is('div.ui-datepicker-row-break'), 'Structure multi [2] - row break'); - inp.datepicker('hide').datepicker('destroy'); - - // Multi-month [2, 2] - inp = init('#inp', {numberOfMonths: [2, 2]}); - inp.focus(); - ok(dp.is('.ui-datepicker-multi'), 'Structure multi - multi-month'); - equals(dp.children().length, 6 + (iframe ? 1 : 0), 'Structure multi [2,2] - child count'); - child = dp.children(':first'); - ok(child.is('div.ui-datepicker-group') && child.is('div.ui-datepicker-group-first'), 'Structure multi [2,2] - first month division'); - child = dp.children(':eq(1)'); - ok(child.is('div.ui-datepicker-group') && child.is('div.ui-datepicker-group-last'), 'Structure multi [2,2] - second month division'); - child = dp.children(':eq(2)'); - ok(child.is('div.ui-datepicker-row-break'), 'Structure multi [2,2] - row break'); - child = dp.children(':eq(3)'); - ok(child.is('div.ui-datepicker-group') && child.is('div.ui-datepicker-group-first'), 'Structure multi [2,2] - third month division'); - child = dp.children(':eq(4)'); - ok(child.is('div.ui-datepicker-group') && child.is('div.ui-datepicker-group-last'), 'Structure multi [2,2] - fourth month division'); - child = dp.children(':eq(5)'); - ok(child.is('div.ui-datepicker-row-break'), 'Structure multi [2,2] - row break'); - inp.datepicker('hide').datepicker('destroy'); - - // Inline - var inl = init('#inl'); - dp = inl.children(); - ok(dp.is('.ui-datepicker-inline'), 'Structure inline - main div'); - ok(!dp.is('.ui-datepicker-rtl'), 'Structure inline - not right-to-left'); - ok(!dp.is('.ui-datepicker-multi'), 'Structure inline - not multi-month'); - equals(dp.children().length, 2, 'Structure inline - child count'); - var header = dp.children(':first'); - ok(header.is('div.ui-datepicker-header'), 'Structure inline - header division'); - equals(header.children().length, 3, 'Structure inline - header child count'); - var table = dp.children(':eq(1)'); - ok(table.is('table.ui-datepicker-calendar'), 'Structure inline - month table'); - ok(table.children(':first').is('thead'), 'Structure inline - month table thead'); - ok(table.children(':eq(1)').is('tbody'), 'Structure inline - month table body'); - inl.datepicker('destroy'); - - // Inline multi-month - inl = init('#inl', {numberOfMonths: 2}); - dp = inl.children(); - ok(dp.is('.ui-datepicker-inline') && dp.is('.ui-datepicker-multi'), 'Structure inline multi - main div'); - equals(dp.children().length, 3 + (iframe ? 1 : 0), 'Structure inline multi - child count'); - child = dp.children(':first'); - ok(child.is('div.ui-datepicker-group') && child.is('div.ui-datepicker-group-first'), 'Structure inline multi - first month division'); - child = dp.children(':eq(1)'); - ok(child.is('div.ui-datepicker-group') && child.is('div.ui-datepicker-group-last'), 'Structure inline multi - second month division'); - child = dp.children(':eq(2)'); - ok(child.is('div.ui-datepicker-row-break'), 'Structure inline multi - row break'); - inl.datepicker('destroy'); -}); - -test('customStructure', function() { - var dp = $('#ui-datepicker-div'); - // Check right-to-left localisation - var inp = init('#inp', $.datepicker.regional['he']); - inp.data('showButtonPanel.datepicker',true); - inp.focus(); - var iframe = ($.browser.msie && parseInt($.browser.version) < 7); - ok(dp.is('.ui-datepicker-rtl'), 'Structure RTL - right-to-left'); - var header = dp.children(':first'); - ok(header.is('div.ui-datepicker-header'), 'Structure RTL - header division'); - equals(header.children().length, 3, 'Structure RTL - header child count'); - ok(header.children(':first').is('a.ui-datepicker-next'), 'Structure RTL - prev link'); - ok(header.children(':eq(1)').is('a.ui-datepicker-prev'), 'Structure RTL - next link'); - var panel = dp.children(':last'); - ok(panel.is('div.ui-datepicker-buttonpane'), 'Structure RTL - button division'); - equals(panel.children().length, 2, 'Structure RTL - button panel child count'); - ok(panel.children(':first').is('button.ui-datepicker-close'), 'Structure RTL - close button'); - ok(panel.children(':last').is('button.ui-datepicker-current'), 'Structure RTL - today button'); - inp.datepicker('hide').datepicker('destroy'); - - // Hide prev/next - inp = init('#inp', {hideIfNoPrevNext: true, minDate: new Date(2008, 2 - 1, 4), maxDate: new Date(2008, 2 - 1, 14)}); - inp.val('02/10/2008').focus(); - var header = dp.children(':first'); - ok(header.is('div.ui-datepicker-header'), 'Structure hide prev/next - header division'); - equals(header.children().length, 1, 'Structure hide prev/next - links child count'); - ok(header.children(':first').is('div.ui-datepicker-title'), 'Structure hide prev/next - title division'); - inp.datepicker('hide').datepicker('destroy'); - - // Changeable Month with read-only year - inp = init('#inp', {changeMonth: true}); - inp.focus(); - var title = dp.children(':first').children(':last'); - equals(title.children().length, 2, 'Structure changeable month - title child count'); - ok(title.children(':first').is('select.ui-datepicker-month'), 'Structure changeable month - month selector'); - ok(title.children(':last').is('span.ui-datepicker-year'), 'Structure changeable month - read-only year'); - inp.datepicker('hide').datepicker('destroy'); - - // Changeable year with read-only month - inp = init('#inp', {changeYear: true}); - inp.focus(); - var title = dp.children(':first').children(':last'); - equals(title.children().length, 2, 'Structure changeable year - title child count'); - ok(title.children(':first').is('span.ui-datepicker-month'), 'Structure changeable year - read-only month'); - ok(title.children(':last').is('select.ui-datepicker-year'), 'Structure changeable year - year selector'); - inp.datepicker('hide').datepicker('destroy'); - - // Read-only first day of week - inp = init('#inp', {changeFirstDay: false}); - inp.focus(); - var thead = dp.find('.ui-datepicker-calendar thead tr'); - equals(thead.children().length, 7, 'Structure read-only first day - thead child count'); - equals(thead.find('a').length, 0, 'Structure read-only first day - thead links count'); - inp.datepicker('hide').datepicker('destroy'); -}); - -test('keystrokes', function() { - var inp = init('#inp'); - var date = new Date(); - inp.val('').datepicker('show'). - simulate('keydown', {keyCode: $.simulate.VK_ENTER}); - equalsDate(inp.datepicker('getDate'), date, 'Keystroke enter'); - inp.val('02/04/2008').datepicker('show'). - simulate('keydown', {keyCode: $.simulate.VK_ENTER}); - equalsDate(inp.datepicker('getDate'), new Date(2008, 2 - 1, 4), - 'Keystroke enter - preset'); - inp.val('02/04/2008').datepicker('show'). - simulate('keydown', {ctrlKey: true, keyCode: $.simulate.VK_HOME}). - simulate('keydown', {keyCode: $.simulate.VK_ENTER}); - equalsDate(inp.datepicker('getDate'), date, 'Keystroke ctrl+home'); - inp.val('02/04/2008').datepicker('show'). - simulate('keydown', {ctrlKey: true, keyCode: $.simulate.VK_END}); - ok(inp.datepicker('getDate') == null, 'Keystroke ctrl+end'); - inp.val('').datepicker('show'). - simulate('keydown', {keyCode: $.simulate.VK_ESC}); - ok(inp.datepicker('getDate') == null, 'Keystroke esc'); - inp.val('02/04/2008').datepicker('show'). - simulate('keydown', {keyCode: $.simulate.VK_ESC}); - equalsDate(inp.datepicker('getDate'), new Date(2008, 2 - 1, 4), - 'Keystroke esc - preset'); - inp.val('02/04/2008').datepicker('show'). - simulate('keydown', {ctrlKey: true, keyCode: $.simulate.VK_PGUP}). - simulate('keydown', {keyCode: $.simulate.VK_ESC}); - equalsDate(inp.datepicker('getDate'), new Date(2008, 2 - 1, 4), - 'Keystroke esc - abandoned'); - // Moving by day or week - inp.val('').datepicker('show'). - simulate('keydown', {ctrlKey: true, keyCode: $.simulate.VK_LEFT}). - simulate('keydown', {keyCode: $.simulate.VK_ENTER}); - date.setDate(date.getDate() - 1); - equalsDate(inp.datepicker('getDate'), date, 'Keystroke ctrl+left'); - inp.val('').datepicker('show'). - simulate('keydown', {keyCode: $.simulate.VK_LEFT}). - simulate('keydown', {keyCode: $.simulate.VK_ENTER}); - date.setDate(date.getDate() + 1); - equalsDate(inp.datepicker('getDate'), date, 'Keystroke left'); - inp.val('').datepicker('show'). - simulate('keydown', {ctrlKey: true, keyCode: $.simulate.VK_RIGHT}). - simulate('keydown', {keyCode: $.simulate.VK_ENTER}); - date.setDate(date.getDate() + 1); - equalsDate(inp.datepicker('getDate'), date, 'Keystroke ctrl+right'); - inp.val('').datepicker('show'). - simulate('keydown', {keyCode: $.simulate.VK_RIGHT}). - simulate('keydown', {keyCode: $.simulate.VK_ENTER}); - date.setDate(date.getDate() - 1); - equalsDate(inp.datepicker('getDate'), date, 'Keystroke right'); - inp.val('').datepicker('show'). - simulate('keydown', {ctrlKey: true, keyCode: $.simulate.VK_UP}). - simulate('keydown', {keyCode: $.simulate.VK_ENTER}); - date.setDate(date.getDate() - 7); - equalsDate(inp.datepicker('getDate'), date, 'Keystroke ctrl+up'); - inp.val('').datepicker('show'). - simulate('keydown', {keyCode: $.simulate.VK_UP}). - simulate('keydown', {keyCode: $.simulate.VK_ENTER}); - date.setDate(date.getDate() + 7); - equalsDate(inp.datepicker('getDate'), date, 'Keystroke up'); - inp.val('').datepicker('show'). - simulate('keydown', {ctrlKey: true, keyCode: $.simulate.VK_DOWN}). - simulate('keydown', {keyCode: $.simulate.VK_ENTER}); - date.setDate(date.getDate() + 7); - equalsDate(inp.datepicker('getDate'), date, 'Keystroke ctrl+down'); - inp.val('').datepicker('show'). - simulate('keydown', {keyCode: $.simulate.VK_DOWN}). - simulate('keydown', {keyCode: $.simulate.VK_ENTER}); - date.setDate(date.getDate() - 7); - equalsDate(inp.datepicker('getDate'), date, 'Keystroke down'); - // Moving by month or year - inp.val('02/04/2008').datepicker('show'). - simulate('keydown', {keyCode: $.simulate.VK_PGUP}). - simulate('keydown', {keyCode: $.simulate.VK_ENTER}); - equalsDate(inp.datepicker('getDate'), new Date(2008, 1 - 1, 4), - 'Keystroke pgup'); - inp.val('02/04/2008').datepicker('show'). - simulate('keydown', {keyCode: $.simulate.VK_PGDN}). - simulate('keydown', {keyCode: $.simulate.VK_ENTER}); - equalsDate(inp.datepicker('getDate'), new Date(2008, 3 - 1, 4), - 'Keystroke pgdn'); - inp.val('02/04/2008').datepicker('show'). - simulate('keydown', {ctrlKey: true, keyCode: $.simulate.VK_PGUP}). - simulate('keydown', {keyCode: $.simulate.VK_ENTER}); - equalsDate(inp.datepicker('getDate'), new Date(2007, 2 - 1, 4), - 'Keystroke ctrl+pgup'); - inp.val('02/04/2008').datepicker('show'). - simulate('keydown', {ctrlKey: true, keyCode: $.simulate.VK_PGDN}). - simulate('keydown', {keyCode: $.simulate.VK_ENTER}); - equalsDate(inp.datepicker('getDate'), new Date(2009, 2 - 1, 4), - 'Keystroke ctrl+pgdn'); - // Check for moving to short months - inp.val('03/31/2008').datepicker('show'). - simulate('keydown', {keyCode: $.simulate.VK_PGUP}). - simulate('keydown', {keyCode: $.simulate.VK_ENTER}); - equalsDate(inp.datepicker('getDate'), new Date(2008, 2 - 1, 29), - 'Keystroke pgup - Feb'); - inp.val('01/30/2008').datepicker('show'). - simulate('keydown', {keyCode: $.simulate.VK_PGDN}). - simulate('keydown', {keyCode: $.simulate.VK_ENTER}); - equalsDate(inp.datepicker('getDate'), new Date(2008, 2 - 1, 29), - 'Keystroke pgdn - Feb'); - inp.val('02/29/2008').datepicker('show'). - simulate('keydown', {ctrlKey: true, keyCode: $.simulate.VK_PGUP}). - simulate('keydown', {keyCode: $.simulate.VK_ENTER}); - equalsDate(inp.datepicker('getDate'), new Date(2007, 2 - 1, 28), - 'Keystroke ctrl+pgup - Feb'); - inp.val('02/29/2008').datepicker('show'). - simulate('keydown', {ctrlKey: true, keyCode: $.simulate.VK_PGDN}). - simulate('keydown', {keyCode: $.simulate.VK_ENTER}); - equalsDate(inp.datepicker('getDate'), new Date(2009, 2 - 1, 28), - 'Keystroke ctrl+pgdn - Feb'); - // Goto current - inp.datepicker('option', {gotoCurrent: true}). - datepicker('hide').val('02/04/2008').datepicker('show'). - simulate('keydown', {keyCode: $.simulate.VK_PGDN}). - simulate('keydown', {ctrlKey: true, keyCode: $.simulate.VK_HOME}). - simulate('keydown', {keyCode: $.simulate.VK_ENTER}); - equalsDate(inp.datepicker('getDate'), new Date(2008, 2 - 1, 4), - 'Keystroke ctrl+home'); - // Change steps - inp.datepicker('option', {stepMonths: 2, gotoCurrent: false}). - datepicker('hide').val('02/04/2008').datepicker('show'). - simulate('keydown', {keyCode: $.simulate.VK_PGUP}). - simulate('keydown', {keyCode: $.simulate.VK_ENTER}); - equalsDate(inp.datepicker('getDate'), new Date(2007, 12 - 1, 4), - 'Keystroke pgup step 2'); - inp.val('02/04/2008').datepicker('show'). - simulate('keydown', {keyCode: $.simulate.VK_PGDN}). - simulate('keydown', {keyCode: $.simulate.VK_ENTER}); - equalsDate(inp.datepicker('getDate'), new Date(2008, 4 - 1, 4), - 'Keystroke pgdn step 2'); -}); - -test('mouse', function() { - var inp = init('#inp'); - var dp = $('#ui-datepicker-div'); - var date = new Date(); - inp.val('').datepicker('show'); - $('.ui-datepicker-calendar tbody a:contains(10)', dp).simulate('click', {}); - date.setDate(10); - equalsDate(inp.datepicker('getDate'), date, 'Mouse click'); - inp.val('02/04/2008').datepicker('show'); - $('.ui-datepicker-calendar tbody a:contains(12)', dp).simulate('click', {}); - equalsDate(inp.datepicker('getDate'), new Date(2008, 2 - 1, 12), - 'Mouse click - preset'); - inp.val('02/04/2008').datepicker('show'); - inp.val('').datepicker('show'); - $('button.ui-datepicker-close', dp).simulate('click', {}); - ok(inp.datepicker('getDate') == null, 'Mouse click - close'); - inp.val('02/04/2008').datepicker('show'); - $('button.ui-datepicker-close', dp).simulate('click', {}); - equalsDate(inp.datepicker('getDate'), new Date(2008, 2 - 1, 4), - 'Mouse click - close + preset'); - inp.val('02/04/2008').datepicker('show'); - $('a.ui-datepicker-prev', dp).simulate('click', {}); - $('button.ui-datepicker-close', dp).simulate('click', {}); - equalsDate(inp.datepicker('getDate'), new Date(2008, 2 - 1, 4), - 'Mouse click - abandoned'); - // Current/previous/next - inp.val('02/04/2008').datepicker('option', {showButtonPanel: true}).datepicker('show'); - $('.ui-datepicker-current', dp).simulate('click', {}); - $('.ui-datepicker-calendar tbody a:contains(14)', dp).simulate('click', {}); - date.setDate(14); - equalsDate(inp.datepicker('getDate'), date, 'Mouse click - current'); - inp.val('02/04/2008').datepicker('show'); - $('.ui-datepicker-prev', dp).simulate('click'); - $('.ui-datepicker-calendar tbody a:contains(16)', dp).simulate('click'); - equalsDate(inp.datepicker('getDate'), new Date(2008, 1 - 1, 16), - 'Mouse click - previous'); - inp.val('02/04/2008').datepicker('show'); - $('.ui-datepicker-next', dp).simulate('click'); - $('.ui-datepicker-calendar tbody a:contains(18)', dp).simulate('click'); - equalsDate(inp.datepicker('getDate'), new Date(2008, 3 - 1, 18), - 'Mouse click - next'); - // Previous/next with minimum/maximum - inp.datepicker('option', {minDate: new Date(2008, 2 - 1, 2), - maxDate: new Date(2008, 2 - 1, 26)}).val('02/04/2008').datepicker('show'); - $('.ui-datepicker-prev', dp).simulate('click'); - $('.ui-datepicker-calendar tbody a:contains(16)', dp).simulate('click'); - equalsDate(inp.datepicker('getDate'), new Date(2008, 2 - 1, 16), - 'Mouse click - previous + min/max'); - inp.val('02/04/2008').datepicker('show'); - $('.ui-datepicker-next', dp).simulate('click'); - $('.ui-datepicker-calendar tbody a:contains(18)', dp).simulate('click'); - equalsDate(inp.datepicker('getDate'), new Date(2008, 2 - 1, 18), - 'Mouse click - next + min/max'); - // Inline - var inl = init('#inl'); - var dp = $('.ui-datepicker-inline', inl); - var date = new Date(); - inl.datepicker('setDate', date); - $('.ui-datepicker-calendar tbody a:contains(10)', dp).simulate('click', {}); - date.setDate(10); - equalsDate(inl.datepicker('getDate'), date, 'Mouse click inline'); - inl.datepicker('option', {showButtonPanel: true}).datepicker('setDate', new Date(2008, 2 - 1, 4)); - $('.ui-datepicker-calendar tbody a:contains(12)', dp).simulate('click', {}); - equalsDate(inl.datepicker('getDate'), new Date(2008, 2 - 1, 12), 'Mouse click inline - preset'); - inl.datepicker('option', {showButtonPanel: true}); - $('.ui-datepicker-current', dp).simulate('click', {}); - $('.ui-datepicker-calendar tbody a:contains(14)', dp).simulate('click', {}); - date.setDate(14); - equalsDate(inl.datepicker('getDate'), date, 'Mouse click inline - current'); - inl.datepicker('setDate', new Date(2008, 2 - 1, 4)); - $('.ui-datepicker-prev', dp).simulate('click'); - $('.ui-datepicker-calendar tbody a:contains(16)', dp).simulate('click'); - equalsDate(inl.datepicker('getDate'), new Date(2008, 1 - 1, 16), - 'Mouse click inline - previous'); - inl.datepicker('setDate', new Date(2008, 2 - 1, 4)); - $('.ui-datepicker-next', dp).simulate('click'); - $('.ui-datepicker-calendar tbody a:contains(18)', dp).simulate('click'); - equalsDate(inl.datepicker('getDate'), new Date(2008, 3 - 1, 18), - 'Mouse click inline - next'); -}); - -})(jQuery); diff --git a/tests/unit/datepicker/datepicker_defaults.js b/tests/unit/datepicker/datepicker_defaults.js deleted file mode 100644 index 4243cf187d8..00000000000 --- a/tests/unit/datepicker/datepicker_defaults.js +++ /dev/null @@ -1,9 +0,0 @@ -/* - * datepicker_defaults.js - */ - -var datepicker_defaults = { - disabled: false -}; - -//commonWidgetTests('datepicker', { defaults: datepicker_defaults }); diff --git a/tests/unit/datepicker/datepicker_events.js b/tests/unit/datepicker/datepicker_events.js deleted file mode 100644 index 0c207097ad2..00000000000 --- a/tests/unit/datepicker/datepicker_events.js +++ /dev/null @@ -1,122 +0,0 @@ -/* - * datepicker_events.js - */ -(function($) { - -module("datepicker: events", { - teardown: function() { - stop(); - setTimeout(start, 13); - } -}); - -var selectedThis = null; -var selectedDate = null; -var selectedInst = null; - -function callback(date, inst) { - selectedThis = this; - selectedDate = date; - selectedInst = inst; -} - -function callback2(year, month, inst) { - selectedThis = this; - selectedDate = year + '/' + month; - selectedInst = inst; -} - -test('events', function() { - var inp = init('#inp', {onSelect: callback}); - var date = new Date(); - // onSelect - inp.val('').datepicker('show'). - simulate('keydown', {keyCode: $.simulate.VK_ENTER}); - equals(selectedThis, inp[0], 'Callback selected this'); - equals(selectedInst, $.data(inp[0], PROP_NAME), 'Callback selected inst'); - equals(selectedDate, $.datepicker.formatDate('mm/dd/yy', date), - 'Callback selected date'); - inp.val('').datepicker('show'). - simulate('keydown', {ctrlKey: true, keyCode: $.simulate.VK_DOWN}). - simulate('keydown', {keyCode: $.simulate.VK_ENTER}); - date.setDate(date.getDate() + 7); - equals(selectedDate, $.datepicker.formatDate('mm/dd/yy', date), - 'Callback selected date - ctrl+down'); - inp.val('').datepicker('show'). - simulate('keydown', {keyCode: $.simulate.VK_ESC}); - equals(selectedDate, $.datepicker.formatDate('mm/dd/yy', date), - 'Callback selected date - esc'); - // onChangeMonthYear - inp.datepicker('option', {onChangeMonthYear: callback2, onSelect: null}). - val('').datepicker('show'); - var newMonthYear = function(date) { - return date.getFullYear() + '/' + (date.getMonth() + 1); - }; - date = new Date(); - date.setDate(1); - inp.simulate('keydown', {keyCode: $.simulate.VK_PGUP}); - date.setMonth(date.getMonth() - 1); - equals(selectedThis, inp[0], 'Callback change month/year this'); - equals(selectedInst, $.data(inp[0], PROP_NAME), 'Callback change month/year inst'); - equals(selectedDate, newMonthYear(date), - 'Callback change month/year date - pgup'); - inp.simulate('keydown', {keyCode: $.simulate.VK_PGDN}); - date.setMonth(date.getMonth() + 1); - equals(selectedDate, newMonthYear(date), - 'Callback change month/year date - pgdn'); - inp.simulate('keydown', {ctrlKey: true, keyCode: $.simulate.VK_PGUP}); - date.setFullYear(date.getFullYear() - 1); - equals(selectedDate, newMonthYear(date), - 'Callback change month/year date - ctrl+pgup'); - inp.simulate('keydown', {ctrlKey: true, keyCode: $.simulate.VK_HOME}); - date.setFullYear(date.getFullYear() + 1); - equals(selectedDate, newMonthYear(date), - 'Callback change month/year date - ctrl+home'); - inp.simulate('keydown', {ctrlKey: true, keyCode: $.simulate.VK_PGDN}); - date.setFullYear(date.getFullYear() + 1); - equals(selectedDate, newMonthYear(date), - 'Callback change month/year date - ctrl+pgdn'); - inp.datepicker('setDate', new Date(2007, 1 - 1, 26)); - equals(selectedDate, '2007/1', 'Callback change month/year date - setDate'); - selectedDate = null; - inp.datepicker('setDate', new Date(2007, 1 - 1, 12)); - ok(selectedDate == null, 'Callback change month/year date - setDate no change'); - // onChangeMonthYear step by 2 - inp.datepicker('option', {stepMonths: 2}). - datepicker('hide').val('').datepicker('show'). - simulate('keydown', {keyCode: $.simulate.VK_PGUP}); - date.setMonth(date.getMonth() - 14); - equals(selectedDate, newMonthYear(date), - 'Callback change month/year by 2 date - pgup'); - inp.simulate('keydown', {ctrlKey: true, keyCode: $.simulate.VK_PGUP}); - date.setMonth(date.getMonth() - 12); - equals(selectedDate, newMonthYear(date), - 'Callback change month/year by 2 date - ctrl+pgup'); - inp.simulate('keydown', {keyCode: $.simulate.VK_PGDN}); - date.setMonth(date.getMonth() + 2); - equals(selectedDate, newMonthYear(date), - 'Callback change month/year by 2 date - pgdn'); - inp.simulate('keydown', {ctrlKey: true, keyCode: $.simulate.VK_PGDN}); - date.setMonth(date.getMonth() + 12); - equals(selectedDate, newMonthYear(date), - 'Callback change month/year by 2 date - ctrl+pgdn'); - // onClose - inp.datepicker('option', {onClose: callback, onChangeMonthYear: null, stepMonths: 1}). - val('').datepicker('show'). - simulate('keydown', {keyCode: $.simulate.VK_ESC}); - equals(selectedThis, inp[0], 'Callback close this'); - equals(selectedInst, $.data(inp[0], PROP_NAME), 'Callback close inst'); - equals(selectedDate, '', 'Callback close date - esc'); - inp.val('').datepicker('show'). - simulate('keydown', {keyCode: $.simulate.VK_ENTER}); - equals(selectedDate, $.datepicker.formatDate('mm/dd/yy', new Date()), - 'Callback close date - enter'); - inp.val('02/04/2008').datepicker('show'). - simulate('keydown', {keyCode: $.simulate.VK_ESC}); - equals(selectedDate, '02/04/2008', 'Callback close date - preset'); - inp.val('02/04/2008').datepicker('show'). - simulate('keydown', {ctrlKey: true, keyCode: $.simulate.VK_END}); - equals(selectedDate, '', 'Callback close date - ctrl+end'); -}); - -})(jQuery); diff --git a/tests/unit/datepicker/datepicker_methods.js b/tests/unit/datepicker/datepicker_methods.js deleted file mode 100644 index c102f7ac30a..00000000000 --- a/tests/unit/datepicker/datepicker_methods.js +++ /dev/null @@ -1,123 +0,0 @@ -/* - * datepicker_methods.js - */ -(function($) { - -module("datepicker: methods", { - teardown: function() { - stop(); - setTimeout(start, 13); - } -}); - -test('destroy', function() { - var inp = init('#inp'); - ok(inp.is('.hasDatepicker'), 'Default - marker class set'); - ok($.data(inp[0], PROP_NAME), 'Default - instance present'); - ok(inp.next().is('#alt'), 'Default - button absent'); - inp.datepicker('destroy'); - inp = $('#inp'); - ok(!inp.is('.hasDatepicker'), 'Default - marker class cleared'); - ok(!$.data(inp[0], PROP_NAME), 'Default - instance absent'); - ok(inp.next().is('#alt'), 'Default - button absent'); - // With button - inp= init('#inp', {showOn: 'both'}); - ok(inp.is('.hasDatepicker'), 'Button - marker class set'); - ok($.data(inp[0], PROP_NAME), 'Button - instance present'); - ok(inp.next().text() == '...', 'Button - button added'); - inp.datepicker('destroy'); - inp = $('#inp'); - ok(!inp.is('.hasDatepicker'), 'Button - marker class cleared'); - ok(!$.data(inp[0], PROP_NAME), 'Button - instance absent'); - ok(inp.next().is('#alt'), 'Button - button removed'); - // With append text - inp = init('#inp', {appendText: 'Testing'}); - ok(inp.is('.hasDatepicker'), 'Append - marker class set'); - ok($.data(inp[0], PROP_NAME), 'Append - instance present'); - ok(inp.next().text() == 'Testing', 'Append - append text added'); - inp.datepicker('destroy'); - inp = $('#inp'); - ok(!inp.is('.hasDatepicker'), 'Append - marker class cleared'); - ok(!$.data(inp[0], PROP_NAME), 'Append - instance absent'); - ok(inp.next().is('#alt'), 'Append - append text removed'); - // With both - inp= init('#inp', {showOn: 'both', buttonImageOnly: true, - buttonImage: 'img/calendar.gif', appendText: 'Testing'}); - ok(inp.is('.hasDatepicker'), 'Both - marker class set'); - ok($.data(inp[0], PROP_NAME), 'Both - instance present'); - ok(inp.next()[0].nodeName.toLowerCase() == 'img', 'Both - button added'); - ok(inp.next().next().text() == 'Testing', 'Both - append text added'); - inp.datepicker('destroy'); - inp = $('#inp'); - ok(!inp.is('.hasDatepicker'), 'Both - marker class cleared'); - ok(!$.data(inp[0], PROP_NAME), 'Both - instance absent'); - ok(inp.next().is('#alt'), 'Both - button and append text absent'); - // Inline - var inl = init('#inl'); - ok(inl.is('.hasDatepicker'), 'Inline - marker class set'); - ok(inl.html() != '', 'Inline - datepicker present'); - ok($.data(inl[0], PROP_NAME), 'Inline - instance present'); - ok(inl.next().length == 0 || inl.next().is('p'), 'Inline - button absent'); - inl.datepicker('destroy'); - inl = $('#inl'); - ok(!inl.is('.hasDatepicker'), 'Inline - marker class cleared'); - ok(inl.html() == '', 'Inline - datepicker absent'); - ok(!$.data(inl[0], PROP_NAME), 'Inline - instance absent'); - ok(inl.next().length == 0 || inl.next().is('p'), 'Inline - button absent'); -}); - -test('enableDisable', function() { - var inp = init('#inp'); - ok(!inp.datepicker('isDisabled'), 'Enable/disable - initially marked as enabled'); - ok(!inp[0].disabled, 'Enable/disable - field initially enabled'); - inp.datepicker('disable'); - ok(inp.datepicker('isDisabled'), 'Enable/disable - now marked as disabled'); - ok(inp[0].disabled, 'Enable/disable - field now disabled'); - inp.datepicker('enable'); - ok(!inp.datepicker('isDisabled'), 'Enable/disable - now marked as enabled'); - ok(!inp[0].disabled, 'Enable/disable - field now enabled'); - inp.datepicker('destroy'); - // With a button - inp = init('#inp', {showOn: 'button'}); - ok(!inp.datepicker('isDisabled'), 'Enable/disable button - initially marked as enabled'); - ok(!inp[0].disabled, 'Enable/disable button - field initially enabled'); - ok(!inp.next('button')[0].disabled, 'Enable/disable button - button initially enabled'); - inp.datepicker('disable'); - ok(inp.datepicker('isDisabled'), 'Enable/disable button - now marked as disabled'); - ok(inp[0].disabled, 'Enable/disable button - field now disabled'); - ok(inp.next('button')[0].disabled, 'Enable/disable button - button now disabled'); - inp.datepicker('enable'); - ok(!inp.datepicker('isDisabled'), 'Enable/disable button - now marked as enabled'); - ok(!inp[0].disabled, 'Enable/disable button - field now enabled'); - ok(!inp.next('button')[0].disabled, 'Enable/disable button - button now enabled'); - inp.datepicker('destroy'); - // With an image button - inp = init('#inp', {showOn: 'button', buttonImageOnly: true, - buttonImage: 'img/calendar.gif'}); - ok(!inp.datepicker('isDisabled'), 'Enable/disable image - initially marked as enabled'); - ok(!inp[0].disabled, 'Enable/disable image - field initially enabled'); - ok(inp.next('img').css('opacity') == 1, 'Enable/disable image - image initially enabled'); - inp.datepicker('disable'); - ok(inp.datepicker('isDisabled'), 'Enable/disable image - now marked as disabled'); - ok(inp[0].disabled, 'Enable/disable image - field now disabled'); - ok(inp.next('img').css('opacity') != 1, 'Enable/disable image - image now disabled'); - inp.datepicker('enable'); - ok(!inp.datepicker('isDisabled'), 'Enable/disable image - now marked as enabled'); - ok(!inp[0].disabled, 'Enable/disable image - field now enabled'); - ok(inp.next('img').css('opacity') == 1, 'Enable/disable image - image now enabled'); - inp.datepicker('destroy'); - // Inline - var inl = init('#inl'); - var dp = $('.ui-datepicker-inline', inl); - ok(!inl.datepicker('isDisabled'), 'Enable/disable inline - initially marked as enabled'); - ok(!dp.children().is('.ui-state-disabled'), 'Enable/disable inline - not visually disabled initially'); - inl.datepicker('disable'); - ok(inl.datepicker('isDisabled'), 'Enable/disable inline - now marked as disabled'); - ok(dp.children().is('.ui-state-disabled'), 'Enable/disable inline - visually disabled'); - inl.datepicker('enable'); - ok(!inl.datepicker('isDisabled'), 'Enable/disable inline - now marked as enabled'); - ok(!dp.children().is('.ui-state-disabled'), 'Enable/disable inline - not visiually disabled'); - inl.datepicker('destroy'); -}); - -})(jQuery); diff --git a/tests/unit/datepicker/datepicker_options.js b/tests/unit/datepicker/datepicker_options.js deleted file mode 100644 index 2769bc582c6..00000000000 --- a/tests/unit/datepicker/datepicker_options.js +++ /dev/null @@ -1,913 +0,0 @@ -/* - * datepicker_options.js - */ - -(function($) { - -module("datepicker: options", { - teardown: function() { - stop(); - setTimeout(start, 13); - } -}); - -test('setDefaults', function() { - var inp = init('#inp'); - equals($.datepicker._defaults.showOn, 'focus', 'Initial showOn'); - $.datepicker.setDefaults({showOn: 'button'}); - equals($.datepicker._defaults.showOn, 'button', 'Change default showOn'); - $.datepicker.setDefaults({showOn: 'focus'}); - equals($.datepicker._defaults.showOn, 'focus', 'Restore showOn'); -}); - -test('option', function() { - var inp = init('#inp'); - var inst = $.data(inp[0], PROP_NAME); - // Set option - equals(inst.settings.showOn, null, 'Initial setting showOn'); - equals($.datepicker._get(inst, 'showOn'), 'focus', 'Initial instance showOn'); - equals($.datepicker._defaults.showOn, 'focus', 'Initial default showOn'); - inp.datepicker('option', 'showOn', 'button'); - equals(inst.settings.showOn, 'button', 'Change setting showOn'); - equals($.datepicker._get(inst, 'showOn'), 'button', 'Change instance showOn'); - equals($.datepicker._defaults.showOn, 'focus', 'Retain default showOn'); - inp.datepicker('option', {showOn: 'both'}); - equals(inst.settings.showOn, 'both', 'Change setting showOn'); - equals($.datepicker._get(inst, 'showOn'), 'both', 'Change instance showOn'); - equals($.datepicker._defaults.showOn, 'focus', 'Retain default showOn'); - inp.datepicker('option', 'showOn', undefined); - equals(inst.settings.showOn, null, 'Clear setting showOn'); - equals($.datepicker._get(inst, 'showOn'), 'focus', 'Restore instance showOn'); - equals($.datepicker._defaults.showOn, 'focus', 'Retain default showOn'); - // Get option - inp = init('#inp'); - equals(inp.datepicker('option', 'showOn'), 'focus', 'Initial setting showOn'); - inp.datepicker('option', 'showOn', 'button'); - equals(inp.datepicker('option', 'showOn'), 'button', 'Change instance showOn'); - inp.datepicker('option', 'showOn', undefined); - equals(inp.datepicker('option', 'showOn'), 'focus', 'Reset instance showOn'); - same(inp.datepicker('option', 'all'), {showAnim: ''}, 'Get instance settings'); - same(inp.datepicker('option', 'defaults'), $.datepicker._defaults, - 'Get default settings'); -}); - -test('change', function() { - var inp = init('#inp'); - var inst = $.data(inp[0], PROP_NAME); - equals(inst.settings.showOn, null, 'Initial setting showOn'); - equals($.datepicker._get(inst, 'showOn'), 'focus', 'Initial instance showOn'); - equals($.datepicker._defaults.showOn, 'focus', 'Initial default showOn'); - inp.datepicker('change', 'showOn', 'button'); - equals(inst.settings.showOn, 'button', 'Change setting showOn'); - equals($.datepicker._get(inst, 'showOn'), 'button', 'Change instance showOn'); - equals($.datepicker._defaults.showOn, 'focus', 'Retain default showOn'); - inp.datepicker('change', {showOn: 'both'}); - equals(inst.settings.showOn, 'both', 'Change setting showOn'); - equals($.datepicker._get(inst, 'showOn'), 'both', 'Change instance showOn'); - equals($.datepicker._defaults.showOn, 'focus', 'Retain default showOn'); - inp.datepicker('change', 'showOn', undefined); - equals(inst.settings.showOn, null, 'Clear setting showOn'); - equals($.datepicker._get(inst, 'showOn'), 'focus', 'Restore instance showOn'); - equals($.datepicker._defaults.showOn, 'focus', 'Retain default showOn'); -}); - -test('invocation', function() { - var inp = init('#inp'); - var dp = $('#ui-datepicker-div'); - var body = $('body'); - // On focus - var button = inp.siblings('button'); - ok(button.length == 0, 'Focus - button absent'); - var image = inp.siblings('img'); - ok(image.length == 0, 'Focus - image absent'); - inp.focus(); - ok(dp.is(':visible'), 'Focus - rendered on focus'); - inp.simulate('keydown', {keyCode: $.simulate.VK_ESC}); - ok(!dp.is(':visible'), 'Focus - hidden on exit'); - inp.focus(); - ok(dp.is(':visible'), 'Focus - rendered on focus'); - body.simulate('mousedown', {}); - ok(!dp.is(':visible'), 'Focus - hidden on external click'); - inp.datepicker('hide').datepicker('destroy'); - // On button - inp = init('#inp', {showOn: 'button', buttonText: 'Popup'}); - ok(!dp.is(':visible'), 'Button - initially hidden'); - button = inp.siblings('button'); - image = inp.siblings('img'); - ok(button.length == 1, 'Button - button present'); - ok(image.length == 0, 'Button - image absent'); - equals(button.text(), 'Popup', 'Button - button text'); - inp.focus(); - ok(!dp.is(':visible'), 'Button - not rendered on focus'); - button.click(); - ok(dp.is(':visible'), 'Button - rendered on button click'); - button.click(); - ok(!dp.is(':visible'), 'Button - hidden on second button click'); - inp.datepicker('hide').datepicker('destroy'); - // On image button - inp = init('#inp', {showOn: 'button', buttonImageOnly: true, - buttonImage: 'img/calendar.gif', buttonText: 'Cal'}); - ok(!dp.is(':visible'), 'Image button - initially hidden'); - button = inp.siblings('button'); - ok(button.length == 0, 'Image button - button absent'); - image = inp.siblings('img'); - ok(image.length == 1, 'Image button - image present'); - equals(image.attr('src'), 'img/calendar.gif', 'Image button - image source'); - equals(image.attr('title'), 'Cal', 'Image button - image text'); - inp.focus(); - ok(!dp.is(':visible'), 'Image button - not rendered on focus'); - image.click(); - ok(dp.is(':visible'), 'Image button - rendered on image click'); - image.click(); - ok(!dp.is(':visible'), 'Image button - hidden on second image click'); - inp.datepicker('hide').datepicker('destroy'); - // On both - inp = init('#inp', {showOn: 'both', buttonImage: 'img/calendar.gif'}); - ok(!dp.is(':visible'), 'Both - initially hidden'); - button = inp.siblings('button'); - ok(button.length == 1, 'Both - button present'); - image = inp.siblings('img'); - ok(image.length == 0, 'Both - image absent'); - image = button.children('img'); - ok(image.length == 1, 'Both - button image present'); - inp.focus(); - ok(dp.is(':visible'), 'Both - rendered on focus'); - body.simulate('mousedown', {}); - ok(!dp.is(':visible'), 'Both - hidden on external click'); - button.click(); - ok(dp.is(':visible'), 'Both - rendered on button click'); - button.click(); - ok(!dp.is(':visible'), 'Both - hidden on second button click'); - inp.datepicker('hide').datepicker('destroy'); -}); - -test('otherMonths', function() { - var inp = init('#inp'); - var pop = $('#ui-datepicker-div'); - inp.val('06/01/2009').datepicker('show'); - equals(pop.find('tbody').text(), '\u00a0123456789101112131415161718192021222324252627282930\u00a0\u00a0\u00a0\u00a0', - 'Other months - none'); - ok(pop.find('td:last *').length == 0, 'Other months - no content'); - inp.datepicker('hide').datepicker('option', 'showOtherMonths', true).datepicker('show'); - equals(pop.find('tbody').text(), '311234567891011121314151617181920212223242526272829301234', - 'Other months - show'); - ok(pop.find('td:last span').length == 1, 'Other months - span content'); - inp.datepicker('hide').datepicker('option', 'selectOtherMonths', true).datepicker('show'); - equals(pop.find('tbody').text(), '311234567891011121314151617181920212223242526272829301234', - 'Other months - select'); - ok(pop.find('td:last a').length == 1, 'Other months - link content'); - inp.datepicker('hide').datepicker('option', 'showOtherMonths', false).datepicker('show'); - equals(pop.find('tbody').text(), '\u00a0123456789101112131415161718192021222324252627282930\u00a0\u00a0\u00a0\u00a0', - 'Other months - none'); - ok(pop.find('td:last *').length == 0, 'Other months - no content'); -}); - -test('defaultDate', function() { - var inp = init('#inp'); - var date = new Date(); - inp.val('').datepicker('show'). - simulate('keydown', {keyCode: $.simulate.VK_ENTER}); - equalsDate(inp.datepicker('getDate'), date, 'Default date null'); - // Numeric values - inp.datepicker('option', {defaultDate: -2}). - datepicker('hide').val('').datepicker('show'). - simulate('keydown', {keyCode: $.simulate.VK_ENTER}); - date.setDate(date.getDate() - 2); - equalsDate(inp.datepicker('getDate'), date, 'Default date -2'); - inp.datepicker('option', {defaultDate: 3}). - datepicker('hide').val('').datepicker('show'). - simulate('keydown', {keyCode: $.simulate.VK_ENTER}); - date.setDate(date.getDate() + 5); - equalsDate(inp.datepicker('getDate'), date, 'Default date 3'); - inp.datepicker('option', {defaultDate: 1 / 0}). - datepicker('hide').val('').datepicker('show'). - simulate('keydown', {keyCode: $.simulate.VK_ENTER}); - date.setDate(date.getDate() - 3); - equalsDate(inp.datepicker('getDate'), date, 'Default date Infinity'); - inp.datepicker('option', {defaultDate: 1 / 'a'}). - datepicker('hide').val('').datepicker('show'). - simulate('keydown', {keyCode: $.simulate.VK_ENTER}); - equalsDate(inp.datepicker('getDate'), date, 'Default date NaN'); - // String offset values - inp.datepicker('option', {defaultDate: '-1d'}). - datepicker('hide').val('').datepicker('show'). - simulate('keydown', {keyCode: $.simulate.VK_ENTER}); - date.setDate(date.getDate() - 1); - equalsDate(inp.datepicker('getDate'), date, 'Default date -1d'); - inp.datepicker('option', {defaultDate: '+3D'}). - datepicker('hide').val('').datepicker('show'). - simulate('keydown', {keyCode: $.simulate.VK_ENTER}); - date.setDate(date.getDate() + 4); - equalsDate(inp.datepicker('getDate'), date, 'Default date +3D'); - inp.datepicker('option', {defaultDate: ' -2 w '}). - datepicker('hide').val('').datepicker('show'). - simulate('keydown', {keyCode: $.simulate.VK_ENTER}); - date = new Date(); - date.setDate(date.getDate() - 14); - equalsDate(inp.datepicker('getDate'), date, 'Default date -2 w'); - inp.datepicker('option', {defaultDate: '+1 W'}). - datepicker('hide').val('').datepicker('show'). - simulate('keydown', {keyCode: $.simulate.VK_ENTER}); - date.setDate(date.getDate() + 21); - equalsDate(inp.datepicker('getDate'), date, 'Default date +1 W'); - inp.datepicker('option', {defaultDate: ' -1 m '}). - datepicker('hide').val('').datepicker('show'). - simulate('keydown', {keyCode: $.simulate.VK_ENTER}); - date = addMonths(new Date(), -1); - equalsDate(inp.datepicker('getDate'), date, 'Default date -1 m'); - inp.datepicker('option', {defaultDate: '+2M'}). - datepicker('hide').val('').datepicker('show'). - simulate('keydown', {keyCode: $.simulate.VK_ENTER}); - date = addMonths(new Date(), 2); - equalsDate(inp.datepicker('getDate'), date, 'Default date +2M'); - inp.datepicker('option', {defaultDate: '-2y'}). - datepicker('hide').val('').datepicker('show'). - simulate('keydown', {keyCode: $.simulate.VK_ENTER}); - date = new Date(); - date.setFullYear(date.getFullYear() - 2); - equalsDate(inp.datepicker('getDate'), date, 'Default date -2y'); - inp.datepicker('option', {defaultDate: '+1 Y '}). - datepicker('hide').val('').datepicker('show'). - simulate('keydown', {keyCode: $.simulate.VK_ENTER}); - date.setFullYear(date.getFullYear() + 3); - equalsDate(inp.datepicker('getDate'), date, 'Default date +1 Y'); - inp.datepicker('option', {defaultDate: '+1M +10d'}). - datepicker('hide').val('').datepicker('show'). - simulate('keydown', {keyCode: $.simulate.VK_ENTER}); - date = addMonths(new Date(), 1); - date.setDate(date.getDate() + 10); - equalsDate(inp.datepicker('getDate'), date, 'Default date +1M +10d'); - // String date values - inp.datepicker('option', {defaultDate: '07/04/2007'}). - datepicker('hide').val('').datepicker('show'). - simulate('keydown', {keyCode: $.simulate.VK_ENTER}); - date = new Date(2007, 7 - 1, 4); - equalsDate(inp.datepicker('getDate'), date, 'Default date 07/04/2007'); - inp.datepicker('option', {dateFormat: 'yy-mm-dd', defaultDate: '2007-04-02'}). - datepicker('hide').val('').datepicker('show'). - simulate('keydown', {keyCode: $.simulate.VK_ENTER}); - date = new Date(2007, 4 - 1, 2); - equalsDate(inp.datepicker('getDate'), date, 'Default date 2007-04-02'); - // Date value - date = new Date(2007, 1 - 1, 26); - inp.datepicker('option', {dateFormat: 'mm/dd/yy', defaultDate: date}). - datepicker('hide').val('').datepicker('show'). - simulate('keydown', {keyCode: $.simulate.VK_ENTER}); - equalsDate(inp.datepicker('getDate'), date, 'Default date 01/26/2007'); -}); - -test('miscellaneous', function() { - var dp = $('#ui-datepicker-div'); - var inp = init('#inp'); - // Year range - var genRange = function(start, offset) { - var range = ''; - for (var i = start; i < start + offset; i++) { - range += i; - } - return range; - }; - var curYear = new Date().getFullYear(); - inp.val('02/04/2008').datepicker('show'); - equals(dp.find('.ui-datepicker-year').text(), '2008', 'Year range - read-only default'); - inp.datepicker('hide').datepicker('option', {changeYear: true}).datepicker('show'); - equals(dp.find('.ui-datepicker-year').text(), genRange(2008 - 10, 21), 'Year range - changeable default'); - inp.datepicker('hide').datepicker('option', {yearRange: 'c-6:c+2', changeYear: true}).datepicker('show'); - equals(dp.find('.ui-datepicker-year').text(), genRange(2008 - 6, 9), 'Year range - c-6:c+2'); - inp.datepicker('hide').datepicker('option', {yearRange: '2000:2010', changeYear: true}).datepicker('show'); - equals(dp.find('.ui-datepicker-year').text(), genRange(2000, 11), 'Year range - 2000:2010'); - inp.datepicker('hide').datepicker('option', {yearRange: '-5:+3', changeYear: true}).datepicker('show'); - equals(dp.find('.ui-datepicker-year').text(), genRange(curYear - 5, 9), 'Year range - -5:+3'); - inp.datepicker('hide').datepicker('option', {yearRange: '2000:-5', changeYear: true}).datepicker('show'); - equals(dp.find('.ui-datepicker-year').text(), genRange(2000, curYear - 2004), 'Year range - 2000:-5'); - inp.datepicker('hide').datepicker('option', {yearRange: '', changeYear: true}).datepicker('show'); - equals(dp.find('.ui-datepicker-year').text(), genRange(curYear, 1), 'Year range - -6:+2'); - - // Navigation as date format - inp.datepicker('option', {showButtonPanel: true}); - equals(dp.find('.ui-datepicker-prev').text(), 'Prev', 'Navigation prev - default'); - equals(dp.find('.ui-datepicker-current').text(), 'Today', 'Navigation current - default'); - equals(dp.find('.ui-datepicker-next').text(), 'Next', 'Navigation next - default'); - inp.datepicker('hide').datepicker('option', {navigationAsDateFormat: true, prevText: '< M', currentText: 'MM', nextText: 'M >'}). - val('02/04/2008').datepicker('show'); - var longNames = $.datepicker.regional[''].monthNames; - var shortNames = $.datepicker.regional[''].monthNamesShort; - var date = new Date(); - equals(dp.find('.ui-datepicker-prev').text(), '< ' + shortNames[0], 'Navigation prev - as date format'); - equals(dp.find('.ui-datepicker-current').text(), - longNames[date.getMonth()], 'Navigation current - as date format'); - equals(dp.find('.ui-datepicker-next').text(), - shortNames[2] + ' >', 'Navigation next - as date format'); - inp.simulate('keydown', {keyCode: $.simulate.VK_PGDN}); - equals(dp.find('.ui-datepicker-prev').text(), - '< ' + shortNames[1], 'Navigation prev - as date format + pgdn'); - equals(dp.find('.ui-datepicker-current').text(), - longNames[date.getMonth()], 'Navigation current - as date format + pgdn'); - equals(dp.find('.ui-datepicker-next').text(), - shortNames[3] + ' >', 'Navigation next - as date format + pgdn'); - inp.datepicker('hide').datepicker('option', {gotoCurrent: true}). - val('02/04/2008').datepicker('show'); - equals(dp.find('.ui-datepicker-prev').text(), - '< ' + shortNames[0], 'Navigation prev - as date format + goto current'); - equals(dp.find('.ui-datepicker-current').text(), - longNames[1], 'Navigation current - as date format + goto current'); - equals(dp.find('.ui-datepicker-next').text(), - shortNames[2] + ' >', 'Navigation next - as date format + goto current'); -}); - -test('minMax', function() { - var inp = init('#inp'); - var lastYear = new Date(2007, 6 - 1, 4); - var nextYear = new Date(2009, 6 - 1, 4); - var minDate = new Date(2008, 2 - 1, 29); - var maxDate = new Date(2008, 12 - 1, 7); - inp.val('06/04/2008').datepicker('show'); - inp.simulate('keydown', {ctrlKey: true, keyCode: $.simulate.VK_PGUP}). - simulate('keydown', {keyCode: $.simulate.VK_ENTER}); - equalsDate(inp.datepicker('getDate'), lastYear, - 'Min/max - null, null - ctrl+pgup'); - inp.val('06/04/2008').datepicker('show'); - inp.simulate('keydown', {ctrlKey: true, keyCode: $.simulate.VK_PGDN}). - simulate('keydown', {keyCode: $.simulate.VK_ENTER}); - equalsDate(inp.datepicker('getDate'), nextYear, - 'Min/max - null, null - ctrl+pgdn'); - inp.datepicker('option', {minDate: minDate}). - datepicker('hide').val('06/04/2008').datepicker('show'); - inp.simulate('keydown', {ctrlKey: true, keyCode: $.simulate.VK_PGUP}). - simulate('keydown', {keyCode: $.simulate.VK_ENTER}); - equalsDate(inp.datepicker('getDate'), minDate, - 'Min/max - 02/29/2008, null - ctrl+pgup'); - inp.val('06/04/2008').datepicker('show'); - inp.simulate('keydown', {ctrlKey: true, keyCode: $.simulate.VK_PGDN}). - simulate('keydown', {keyCode: $.simulate.VK_ENTER}); - equalsDate(inp.datepicker('getDate'), nextYear, - 'Min/max - 02/29/2008, null - ctrl+pgdn'); - inp.datepicker('option', {maxDate: maxDate}). - datepicker('hide').val('06/04/2008').datepicker('show'); - inp.simulate('keydown', {ctrlKey: true, keyCode: $.simulate.VK_PGUP}). - simulate('keydown', {keyCode: $.simulate.VK_ENTER}); - equalsDate(inp.datepicker('getDate'), minDate, - 'Min/max - 02/29/2008, 12/07/2008 - ctrl+pgup'); - inp.val('06/04/2008').datepicker('show'); - inp.simulate('keydown', {ctrlKey: true, keyCode: $.simulate.VK_PGDN}). - simulate('keydown', {keyCode: $.simulate.VK_ENTER}); - equalsDate(inp.datepicker('getDate'), maxDate, - 'Min/max - 02/29/2008, 12/07/2008 - ctrl+pgdn'); - inp.datepicker('option', {minDate: null}). - datepicker('hide').val('06/04/2008').datepicker('show'); - inp.simulate('keydown', {ctrlKey: true, keyCode: $.simulate.VK_PGUP}). - simulate('keydown', {keyCode: $.simulate.VK_ENTER}); - equalsDate(inp.datepicker('getDate'), lastYear, - 'Min/max - null, 12/07/2008 - ctrl+pgup'); - inp.val('06/04/2008').datepicker('show'); - inp.simulate('keydown', {ctrlKey: true, keyCode: $.simulate.VK_PGDN}). - simulate('keydown', {keyCode: $.simulate.VK_ENTER}); - equalsDate(inp.datepicker('getDate'), maxDate, - 'Min/max - null, 12/07/2008 - ctrl+pgdn'); - // Relative dates - var date = new Date(); - date.setDate(date.getDate() - 7); - inp.datepicker('option', {minDate: '-1w', maxDate: '+1 M +10 D '}). - datepicker('hide').val('').datepicker('show'); - inp.simulate('keydown', {ctrlKey: true, keyCode: $.simulate.VK_PGUP}). - simulate('keydown', {keyCode: $.simulate.VK_ENTER}); - equalsDate(inp.datepicker('getDate'), date, - 'Min/max - -1w, +1 M +10 D - ctrl+pgup'); - date = addMonths(new Date(), 1); - date.setDate(date.getDate() + 10); - inp.val('').datepicker('show'); - inp.simulate('keydown', {ctrlKey: true, keyCode: $.simulate.VK_PGDN}). - simulate('keydown', {keyCode: $.simulate.VK_ENTER}); - equalsDate(inp.datepicker('getDate'), date, - 'Min/max - -1w, +1 M +10 D - ctrl+pgdn'); - // With existing date - inp = init('#inp'); - inp.val('06/04/2008').datepicker('option', {minDate: minDate}); - equalsDate(inp.datepicker('getDate'), new Date(2008, 6 - 1, 4), 'Min/max - setDate > min'); - inp.datepicker('option', {minDate: null}).val('01/04/2008').datepicker('option', {minDate: minDate}); - equalsDate(inp.datepicker('getDate'), minDate, 'Min/max - setDate < min'); - inp.datepicker('option', {minDate: null}).val('06/04/2008').datepicker('option', {maxDate: maxDate}); - equalsDate(inp.datepicker('getDate'), new Date(2008, 6 - 1, 4), 'Min/max - setDate < max'); - inp.datepicker('option', {maxDate: null}).val('01/04/2009').datepicker('option', {maxDate: maxDate}); - equalsDate(inp.datepicker('getDate'), maxDate, 'Min/max - setDate > max'); - inp.datepicker('option', {maxDate: null}).val('01/04/2008').datepicker('option', {minDate: minDate, maxDate: maxDate}); - equalsDate(inp.datepicker('getDate'), minDate, 'Min/max - setDate < min'); - inp.datepicker('option', {maxDate: null}).val('06/04/2008').datepicker('option', {minDate: minDate, maxDate: maxDate}); - equalsDate(inp.datepicker('getDate'), new Date(2008, 6 - 1, 4), 'Min/max - setDate > min, < max'); - inp.datepicker('option', {maxDate: null}).val('01/04/2009').datepicker('option', {minDate: minDate, maxDate: maxDate}); - equalsDate(inp.datepicker('getDate'), maxDate, 'Min/max - setDate > max'); -}); - -test('setDate', function() { - var inp = init('#inp'); - var date1 = new Date(2008, 6 - 1, 4); - var date2 = new Date(); - ok(inp.datepicker('getDate') == null, 'Set date - default'); - inp.datepicker('setDate', date1); - equalsDate(inp.datepicker('getDate'), date1, 'Set date - 2008-06-04'); - date1 = new Date(); - date1.setDate(date1.getDate() + 7); - inp.datepicker('setDate', +7); - equalsDate(inp.datepicker('getDate'), date1, 'Set date - +7'); - date2.setFullYear(date2.getFullYear() + 2); - inp.datepicker('setDate', '+2y'); - equalsDate(inp.datepicker('getDate'), date2, 'Set date - +2y'); - inp.datepicker('setDate', date1, date2); - equalsDate(inp.datepicker('getDate'), date1, 'Set date - two dates'); - inp.datepicker('setDate'); - ok(inp.datepicker('getDate') == null, 'Set date - null'); - // Relative to current date - date1 = new Date(); - date1.setDate(date1.getDate() + 7); - inp.datepicker('setDate', 'c +7'); - equalsDate(inp.datepicker('getDate'), date1, 'Set date - c +7'); - date1.setDate(date1.getDate() + 7); - inp.datepicker('setDate', 'c+7'); - equalsDate(inp.datepicker('getDate'), date1, 'Set date - c+7'); - date1.setDate(date1.getDate() - 21); - inp.datepicker('setDate', 'c -3 w'); - equalsDate(inp.datepicker('getDate'), date1, 'Set date - c -3 w'); - // Inline - var inl = init('#inl'); - date1 = new Date(2008, 6 - 1, 4); - date2 = new Date(); - equalsDate(inl.datepicker('getDate'), date2, 'Set date inline - default'); - inl.datepicker('setDate', date1); - equalsDate(inl.datepicker('getDate'), date1, 'Set date inline - 2008-06-04'); - date1 = new Date(); - date1.setDate(date1.getDate() + 7); - inl.datepicker('setDate', +7); - equalsDate(inl.datepicker('getDate'), date1, 'Set date inline - +7'); - date2.setFullYear(date2.getFullYear() + 2); - inl.datepicker('setDate', '+2y'); - equalsDate(inl.datepicker('getDate'), date2, 'Set date inline - +2y'); - inl.datepicker('setDate', date1, date2); - equalsDate(inl.datepicker('getDate'), date1, 'Set date inline - two dates'); - inl.datepicker('setDate'); - ok(inl.datepicker('getDate') == null, 'Set date inline - null'); - // Alternate field - var alt = $('#alt'); - inp.datepicker('option', {altField: '#alt', altFormat: 'yy-mm-dd'}); - date1 = new Date(2008, 6 - 1, 4); - inp.datepicker('setDate', date1); - equals(inp.val(), '06/04/2008', 'Set date alternate - 06/04/2008'); - equals(alt.val(), '2008-06-04', 'Set date alternate - 2008-06-04'); - // With minimum/maximum - inp = init('#inp'); - date1 = new Date(2008, 1 - 1, 4); - date2 = new Date(2008, 6 - 1, 4); - var minDate = new Date(2008, 2 - 1, 29); - var maxDate = new Date(2008, 3 - 1, 28); - inp.val('').datepicker('option', {minDate: minDate}).datepicker('setDate', date2); - equalsDate(inp.datepicker('getDate'), date2, 'Set date min/max - setDate > min'); - inp.datepicker('setDate', date1); - equalsDate(inp.datepicker('getDate'), minDate, 'Set date min/max - setDate < min'); - inp.val('').datepicker('option', {maxDate: maxDate, minDate: null}).datepicker('setDate', date1); - equalsDate(inp.datepicker('getDate'), date1, 'Set date min/max - setDate < max'); - inp.datepicker('setDate', date2); - equalsDate(inp.datepicker('getDate'), maxDate, 'Set date min/max - setDate > max'); - inp.val('').datepicker('option', {minDate: minDate}).datepicker('setDate', date1); - equalsDate(inp.datepicker('getDate'), minDate, 'Set date min/max - setDate < min'); - inp.datepicker('setDate', date2); - equalsDate(inp.datepicker('getDate'), maxDate, 'Set date min/max - setDate > max'); -}); - -test('altField', function() { - var inp = init('#inp'); - var alt = $('#alt'); - // No alternate field set - alt.val(''); - inp.val('06/04/2008').datepicker('show'); - inp.simulate('keydown', {keyCode: $.simulate.VK_ENTER}); - equals(inp.val(), '06/04/2008', 'Alt field - dp - enter'); - equals(alt.val(), '', 'Alt field - alt not set'); - // Alternate field set - alt.val(''); - inp.datepicker('option', {altField: '#alt', altFormat: 'yy-mm-dd'}). - val('06/04/2008').datepicker('show'); - inp.simulate('keydown', {keyCode: $.simulate.VK_ENTER}); - equals(inp.val(), '06/04/2008', 'Alt field - dp - enter'); - equals(alt.val(), '2008-06-04', 'Alt field - alt - enter'); - // Move from initial date - alt.val(''); - inp.val('06/04/2008').datepicker('show'); - inp.simulate('keydown', {keyCode: $.simulate.VK_PGDN}). - simulate('keydown', {keyCode: $.simulate.VK_ENTER}); - equals(inp.val(), '07/04/2008', 'Alt field - dp - pgdn'); - equals(alt.val(), '2008-07-04', 'Alt field - alt - pgdn'); - // Alternate field set - closed - alt.val(''); - inp.val('06/04/2008').datepicker('show'); - inp.simulate('keydown', {keyCode: $.simulate.VK_PGDN}). - simulate('keydown', {keyCode: $.simulate.VK_ESC}); - equals(inp.val(), '06/04/2008', 'Alt field - dp - pgdn/esc'); - equals(alt.val(), '', 'Alt field - alt - pgdn/esc'); - // Clear date and alternate - alt.val(''); - inp.val('06/04/2008').datepicker('show'); - inp.simulate('keydown', {ctrlKey: true, keyCode: $.simulate.VK_END}); - equals(inp.val(), '', 'Alt field - dp - ctrl+end'); - equals(alt.val(), '', 'Alt field - alt - ctrl+end'); - // Verify alt field is updated on keyup - alt.val(''); - inp.val('06/04/200').datepicker('show'); - inp.simulate('keydown', {charCode: '8'.charCodeAt(0)}); - inp.simulate('keypress', {charCode: '8'.charCodeAt(0)}); - inp.simulate('keyup', {charCode: '8'.charCodeAt(0)}); - equals(inp.val(), '06/04/2008', 'Alt field - dp - manual entry'); - equals(alt.val(), '2008-06-04', 'Alt field - manual entry'); - // Verify alt field is not updated on keyup if date is invalid - inp.val('12/04'); - inp.simulate('keydown', {charCode: '/'.charCodeAt(0)}); - inp.simulate('keypress', {charCode: '/'.charCodeAt(0)}); - inp.simulate('keyup', {charCode: '/'.charCodeAt(0)}); - equals(inp.val(), '12/04/', 'Alt field - dp - manual entry incomplete'); - equals(alt.val(), '2008-06-04', 'Alt field - manual entry - not updated'); -}); - -test('autoSize', function() { - var inp = init('#inp'); - equals(inp.attr('size'), 0, 'Auto size - default'); - inp.datepicker('option', 'autoSize', true); - equals(inp.attr('size'), 10, 'Auto size - mm/dd/yy'); - inp.datepicker('option', 'dateFormat', 'm/d/yy'); - equals(inp.attr('size'), 10, 'Auto size - m/d/yy'); - inp.datepicker('option', 'dateFormat', 'D M d yy'); - equals(inp.attr('size'), 15, 'Auto size - D M d yy'); - inp.datepicker('option', 'dateFormat', 'DD, MM dd, yy'); - equals(inp.attr('size'), 29, 'Auto size - DD, MM dd, yy'); - inp.removeAttr('size'); - // French - inp.datepicker('option', $.extend({autoSize: false}, $.datepicker.regional['fr'])); - equals(inp.attr('size'), 0, 'Auto size - fr - default'); - inp.datepicker('option', 'autoSize', true); - equals(inp.attr('size'), 10, 'Auto size - fr - dd/mm/yy'); - inp.datepicker('option', 'dateFormat', 'm/d/yy'); - equals(inp.attr('size'), 10, 'Auto size - fr - m/d/yy'); - inp.datepicker('option', 'dateFormat', 'D M d yy'); - equals(inp.attr('size'), 15, 'Auto size - fr - D M d yy'); - inp.datepicker('option', 'dateFormat', 'DD, MM dd, yy'); - equals(inp.attr('size'), 28, 'Auto size - fr - DD, MM dd, yy'); - inp.removeAttr('size'); - // Hebrew - inp.datepicker('option', $.extend({autoSize: false}, $.datepicker.regional['he'])); - equals(inp.attr('size'), 0, 'Auto size - he - default'); - inp.datepicker('option', 'autoSize', true); - equals(inp.attr('size'), 10, 'Auto size - he - dd/mm/yy'); - inp.datepicker('option', 'dateFormat', 'm/d/yy'); - equals(inp.attr('size'), 10, 'Auto size - he - m/d/yy'); - inp.datepicker('option', 'dateFormat', 'D M d yy'); - equals(inp.attr('size'), 14, 'Auto size - he - D M d yy'); - inp.datepicker('option', 'dateFormat', 'DD, MM dd, yy'); - equals(inp.attr('size'), 23, 'Auto size - he - DD, MM dd, yy'); - inp.removeAttr('size'); -}); - -test('daylightSaving', function() { - var inp = init('#inp'); - var dp = $('#ui-datepicker-div'); - ok(true, 'Daylight saving - ' + new Date()); - // Australia, Sydney - AM change, southern hemisphere - inp.val('04/01/2008').datepicker('show'); - $('.ui-datepicker-calendar td:eq(6) a', dp).simulate('click'); - equals(inp.val(), '04/05/2008', 'Daylight saving - Australia 04/05/2008'); - inp.val('04/01/2008').datepicker('show'); - $('.ui-datepicker-calendar td:eq(7) a', dp).simulate('click'); - equals(inp.val(), '04/06/2008', 'Daylight saving - Australia 04/06/2008'); - inp.val('04/01/2008').datepicker('show'); - $('.ui-datepicker-calendar td:eq(8) a', dp).simulate('click'); - equals(inp.val(), '04/07/2008', 'Daylight saving - Australia 04/07/2008'); - inp.val('10/01/2008').datepicker('show'); - $('.ui-datepicker-calendar td:eq(6) a', dp).simulate('click'); - equals(inp.val(), '10/04/2008', 'Daylight saving - Australia 10/04/2008'); - inp.val('10/01/2008').datepicker('show'); - $('.ui-datepicker-calendar td:eq(7) a', dp).simulate('click'); - equals(inp.val(), '10/05/2008', 'Daylight saving - Australia 10/05/2008'); - inp.val('10/01/2008').datepicker('show'); - $('.ui-datepicker-calendar td:eq(8) a', dp).simulate('click'); - equals(inp.val(), '10/06/2008', 'Daylight saving - Australia 10/06/2008'); - // Brasil, Brasilia - midnight change, southern hemisphere - inp.val('02/01/2008').datepicker('show'); - $('.ui-datepicker-calendar td:eq(20) a', dp).simulate('click'); - equals(inp.val(), '02/16/2008', 'Daylight saving - Brasil 02/16/2008'); - inp.val('02/01/2008').datepicker('show'); - $('.ui-datepicker-calendar td:eq(21) a', dp).simulate('click'); - equals(inp.val(), '02/17/2008', 'Daylight saving - Brasil 02/17/2008'); - inp.val('02/01/2008').datepicker('show'); - $('.ui-datepicker-calendar td:eq(22) a', dp).simulate('click'); - equals(inp.val(), '02/18/2008', 'Daylight saving - Brasil 02/18/2008'); - inp.val('10/01/2008').datepicker('show'); - $('.ui-datepicker-calendar td:eq(13) a', dp).simulate('click'); - equals(inp.val(), '10/11/2008', 'Daylight saving - Brasil 10/11/2008'); - inp.val('10/01/2008').datepicker('show'); - $('.ui-datepicker-calendar td:eq(14) a', dp).simulate('click'); - equals(inp.val(), '10/12/2008', 'Daylight saving - Brasil 10/12/2008'); - inp.val('10/01/2008').datepicker('show'); - $('.ui-datepicker-calendar td:eq(15) a', dp).simulate('click'); - equals(inp.val(), '10/13/2008', 'Daylight saving - Brasil 10/13/2008'); - // Lebanon, Beirut - midnight change, northern hemisphere - inp.val('03/01/2008').datepicker('show'); - $('.ui-datepicker-calendar td:eq(34) a', dp).simulate('click'); - equals(inp.val(), '03/29/2008', 'Daylight saving - Lebanon 03/29/2008'); - inp.val('03/01/2008').datepicker('show'); - $('.ui-datepicker-calendar td:eq(35) a', dp).simulate('click'); - equals(inp.val(), '03/30/2008', 'Daylight saving - Lebanon 03/30/2008'); - inp.val('03/01/2008').datepicker('show'); - $('.ui-datepicker-calendar td:eq(36) a', dp).simulate('click'); - equals(inp.val(), '03/31/2008', 'Daylight saving - Lebanon 03/31/2008'); - inp.val('10/01/2008').datepicker('show'); - $('.ui-datepicker-calendar td:eq(27) a', dp).simulate('click'); - equals(inp.val(), '10/25/2008', 'Daylight saving - Lebanon 10/25/2008'); - inp.val('10/01/2008').datepicker('show'); - $('.ui-datepicker-calendar td:eq(28) a', dp).simulate('click'); - equals(inp.val(), '10/26/2008', 'Daylight saving - Lebanon 10/26/2008'); - inp.val('10/01/2008').datepicker('show'); - $('.ui-datepicker-calendar td:eq(29) a', dp).simulate('click'); - equals(inp.val(), '10/27/2008', 'Daylight saving - Lebanon 10/27/2008'); - // US, Eastern - AM change, northern hemisphere - inp.val('03/01/2008').datepicker('show'); - $('.ui-datepicker-calendar td:eq(13) a', dp).simulate('click'); - equals(inp.val(), '03/08/2008', 'Daylight saving - US 03/08/2008'); - inp.val('03/01/2008').datepicker('show'); - $('.ui-datepicker-calendar td:eq(14) a', dp).simulate('click'); - equals(inp.val(), '03/09/2008', 'Daylight saving - US 03/09/2008'); - inp.val('03/01/2008').datepicker('show'); - $('.ui-datepicker-calendar td:eq(15) a', dp).simulate('click'); - equals(inp.val(), '03/10/2008', 'Daylight saving - US 03/10/2008'); - inp.val('11/01/2008').datepicker('show'); - $('.ui-datepicker-calendar td:eq(6) a', dp).simulate('click'); - equals(inp.val(), '11/01/2008', 'Daylight saving - US 11/01/2008'); - inp.val('11/01/2008').datepicker('show'); - $('.ui-datepicker-calendar td:eq(7) a', dp).simulate('click'); - equals(inp.val(), '11/02/2008', 'Daylight saving - US 11/02/2008'); - inp.val('11/01/2008').datepicker('show'); - $('.ui-datepicker-calendar td:eq(8) a', dp).simulate('click'); - equals(inp.val(), '11/03/2008', 'Daylight saving - US 11/03/2008'); -}); - -var beforeShowThis = null; -var beforeShowInput = null; -var beforeShowInst = null; - -function beforeAll(input, inst) { - beforeShowThis = this; - beforeShowInput = input; - beforeShowInst = inst; - return {currentText: 'Current'}; -} - -var beforeShowDayThis = null; -var beforeShowDayOK = true; - -function beforeDay(date) { - beforeShowDayThis = this; - beforeShowDayOK &= (date > new Date(2008, 1 - 1, 26) && - date < new Date(2008, 3 - 1, 6)); - return [(date.getDate() % 2 == 0), (date.getDate() % 10 == 0 ? 'day10' : ''), - (date.getDate() % 3 == 0 ? 'Divisble by 3' : '')]; -} - -function calcWeek(date) { - var doy = date.getDate() + 6; - for (var m = date.getMonth() - 1; m >= 0; m--) - doy += $.datepicker._getDaysInMonth(date.getFullYear(), m); - // Simple count from 01/01 starting at week 1 - return Math.floor(doy / 7); -} - -test('callbacks', function() { - // Before show - var inp = init('#inp', {beforeShow: beforeAll}); - var inst = $.data(inp[0], 'datepicker'); - equals($.datepicker._get(inst, 'currentText'), 'Today', 'Before show - initial'); - inp.val('02/04/2008').datepicker('show'); - equals($.datepicker._get(inst, 'currentText'), 'Current', 'Before show - changed'); - ok(beforeShowThis.id == inp[0].id, 'Before show - this OK'); - ok(beforeShowInput.id == inp[0].id, 'Before show - input OK'); - deepEqual(beforeShowInst, inst, 'Before show - inst OK'); - inp.datepicker('hide').datepicker('destroy'); - // Before show day - inp = init('#inp', {beforeShowDay: beforeDay}); - var dp = $('#ui-datepicker-div'); - inp.val('02/04/2008').datepicker('show'); - ok(beforeShowDayThis.id == inp[0].id, 'Before show day - this OK'); - ok(beforeShowDayOK, 'Before show day - dates OK'); - var day20 = dp.find('.ui-datepicker-calendar td:contains("20")'); - var day21 = dp.find('.ui-datepicker-calendar td:contains("21")'); - ok(!day20.is('.ui-datepicker-unselectable'), 'Before show day - unselectable 20'); - ok(day21.is('.ui-datepicker-unselectable'), 'Before show day - unselectable 21'); - ok(day20.is('.day10'), 'Before show day - CSS 20'); - ok(!day21.is('.day10'), 'Before show day - CSS 21'); - ok(day20.attr('title') == '', 'Before show day - title 20'); - ok(day21.attr('title') == 'Divisble by 3', 'Before show day - title 21'); - inp.datepicker('hide').datepicker('destroy'); -}); - -test('localisation', function() { - var inp = init('#inp', $.datepicker.regional['fr']); - inp.datepicker('option', {dateFormat: 'DD, d MM yy', showButtonPanel:true, changeMonth:true, changeYear:true}).val('').datepicker('show'); - var dp = $('#ui-datepicker-div'); - equals($('.ui-datepicker-close', dp).text(), 'Fermer', 'Localisation - close'); - $('.ui-datepicker-close', dp).simulate('mouseover'); - equals($('.ui-datepicker-prev', dp).text(), '', 'Localisation - next'); - var month = 0; - $('.ui-datepicker-month option', dp).each(function() { - equals($(this).text(), $.datepicker.regional['fr'].monthNamesShort[month], - 'Localisation - month ' + month); - month++; - }); - var day = 1; - $('.ui-datepicker-calendar th', dp).each(function() { - equals($(this).text(), $.datepicker.regional['fr'].dayNamesMin[day], - 'Localisation - day ' + day); - day = (day + 1) % 7; - }); - inp.simulate('keydown', {keyCode: $.simulate.VK_ENTER}); - var date = new Date(); - equals(inp.val(), $.datepicker.regional['fr'].dayNames[date.getDay()] + ', ' + - date.getDate() + ' ' + $.datepicker.regional['fr'].monthNames[date.getMonth()] + - ' ' + date.getFullYear(), 'Localisation - formatting'); -}); - -test('noWeekends', function() { - for (var i = 1; i <= 31; i++) { - var date = new Date(2001, 1 - 1, i); - deepEqual($.datepicker.noWeekends(date), [(i + 1) % 7 >= 2, ''], - 'No weekends ' + date); - } -}); - -test('iso8601Week', function() { - var date = new Date(2000, 12 - 1, 31); - equals($.datepicker.iso8601Week(date), 52, 'ISO 8601 week ' + date); - date = new Date(2001, 1 - 1, 1); - equals($.datepicker.iso8601Week(date), 1, 'ISO 8601 week ' + date); - date = new Date(2001, 1 - 1, 7); - equals($.datepicker.iso8601Week(date), 1, 'ISO 8601 week ' + date); - date = new Date(2001, 1 - 1, 8); - equals($.datepicker.iso8601Week(date), 2, 'ISO 8601 week ' + date); - date = new Date(2003, 12 - 1, 28); - equals($.datepicker.iso8601Week(date), 52, 'ISO 8601 week ' + date); - date = new Date(2003, 12 - 1, 29); - equals($.datepicker.iso8601Week(date), 1, 'ISO 8601 week ' + date); - date = new Date(2004, 1 - 1, 4); - equals($.datepicker.iso8601Week(date), 1, 'ISO 8601 week ' + date); - date = new Date(2004, 1 - 1, 5); - equals($.datepicker.iso8601Week(date), 2, 'ISO 8601 week ' + date); - date = new Date(2009, 12 - 1, 28); - equals($.datepicker.iso8601Week(date), 53, 'ISO 8601 week ' + date); - date = new Date(2010, 1 - 1, 3); - equals($.datepicker.iso8601Week(date), 53, 'ISO 8601 week ' + date); - date = new Date(2010, 1 - 1, 4); - equals($.datepicker.iso8601Week(date), 1, 'ISO 8601 week ' + date); - date = new Date(2010, 1 - 1, 10); - equals($.datepicker.iso8601Week(date), 1, 'ISO 8601 week ' + date); -}); - -test('parseDate', function() { - init('#inp'); - ok($.datepicker.parseDate('d m y', '') == null, 'Parse date empty'); - equalsDate($.datepicker.parseDate('d m y', '3 2 01'), - new Date(2001, 2 - 1, 3), 'Parse date d m y'); - equalsDate($.datepicker.parseDate('dd mm yy', '03 02 2001'), - new Date(2001, 2 - 1, 3), 'Parse date dd mm yy'); - equalsDate($.datepicker.parseDate('d m y', '13 12 01'), - new Date(2001, 12 - 1, 13), 'Parse date d m y'); - equalsDate($.datepicker.parseDate('dd mm yy', '13 12 2001'), - new Date(2001, 12 - 1, 13), 'Parse date dd mm yy'); - equalsDate($.datepicker.parseDate('y-o', '2001-34'), - new Date(2001, 2 - 1, 3), 'Parse date y-o'); - equalsDate($.datepicker.parseDate('yy-oo', '2001-347'), - new Date(2001, 12 - 1, 13), 'Parse date yy oo'); - equalsDate($.datepicker.parseDate('oo yy', '348 2004'), - new Date(2004, 12 - 1, 13), 'Parse date oo-yy'); - equalsDate($.datepicker.parseDate('D d M y', 'Sat 3 Feb 01'), - new Date(2001, 2 - 1, 3), 'Parse date D d M y'); - equalsDate($.datepicker.parseDate('d MM DD yy', '3 February Saturday 2001'), - new Date(2001, 2 - 1, 3), 'Parse date dd MM DD yy'); - equalsDate($.datepicker.parseDate('DD, MM d, yy', 'Saturday, February 3, 2001'), - new Date(2001, 2 - 1, 3), 'Parse date DD, MM d, yy'); - equalsDate($.datepicker.parseDate('\'day\' d \'of\' MM (\'\'DD\'\'), yy', - 'day 3 of February (\'Saturday\'), 2001'), new Date(2001, 2 - 1, 3), - 'Parse date \'day\' d \'of\' MM (\'\'DD\'\'), yy'); - equalsDate($.datepicker.parseDate('y-m-d', '01-02-03'), - new Date(2001, 2 - 1, 3), 'Parse date y-m-d - default cutoff'); - equalsDate($.datepicker.parseDate('y-m-d', '51-02-03'), - new Date(1951, 2 - 1, 3), 'Parse date y-m-d - default cutoff'); - equalsDate($.datepicker.parseDate('y-m-d', '51-02-03', {shortYearCutoff: 80}), - new Date(2051, 2 - 1, 3), 'Parse date y-m-d - cutoff 80'); - equalsDate($.datepicker.parseDate('y-m-d', '51-02-03', {shortYearCutoff: '+60'}), - new Date(2051, 2 - 1, 3), 'Parse date y-m-d - cutoff +60'); - var gmtDate = new Date(2001, 2 - 1, 3); - gmtDate.setMinutes(gmtDate.getMinutes() - gmtDate.getTimezoneOffset()); - equalsDate($.datepicker.parseDate('@', '981158400000'), gmtDate, 'Parse date @'); - equalsDate($.datepicker.parseDate('!', '631167552000000000'), gmtDate, 'Parse date !'); - var fr = $.datepicker.regional['fr']; - var settings = {dayNamesShort: fr.dayNamesShort, dayNames: fr.dayNames, - monthNamesShort: fr.monthNamesShort, monthNames: fr.monthNames}; - equalsDate($.datepicker.parseDate('D d M y', 'Lun 9 Avr 01', settings), - new Date(2001, 4 - 1, 9), 'Parse date D M y with settings'); - equalsDate($.datepicker.parseDate('d MM DD yy', '9 Avril Lundi 2001', settings), - new Date(2001, 4 - 1, 9), 'Parse date d MM DD yy with settings'); - equalsDate($.datepicker.parseDate('DD, MM d, yy', 'Lundi, Avril 9, 2001', settings), - new Date(2001, 4 - 1, 9), 'Parse date DD, MM d, yy with settings'); - equalsDate($.datepicker.parseDate('\'jour\' d \'de\' MM (\'\'DD\'\'), yy', - 'jour 9 de Avril (\'Lundi\'), 2001', settings), new Date(2001, 4 - 1, 9), - 'Parse date \'jour\' d \'de\' MM (\'\'DD\'\'), yy with settings'); -}); - -test('parseDateErrors', function() { - init('#inp'); - var expectError = function(expr, value, error) { - try { - expr(); - ok(false, 'Parsed error ' + value); - } - catch (e) { - equals(e, error, 'Parsed error ' + value); - } - }; - expectError(function() { $.datepicker.parseDate(null, 'Sat 2 01'); }, - 'Sat 2 01', 'Invalid arguments'); - expectError(function() { $.datepicker.parseDate('d m y', null); }, - 'null', 'Invalid arguments'); - expectError(function() { $.datepicker.parseDate('d m y', 'Sat 2 01'); }, - 'Sat 2 01 - d m y', 'Missing number at position 0'); - expectError(function() { $.datepicker.parseDate('dd mm yy', 'Sat 2 01'); }, - 'Sat 2 01 - dd mm yy', 'Missing number at position 0'); - expectError(function() { $.datepicker.parseDate('d m y', '3 Feb 01'); }, - '3 Feb 01 - d m y', 'Missing number at position 2'); - expectError(function() { $.datepicker.parseDate('dd mm yy', '3 Feb 01'); }, - '3 Feb 01 - dd mm yy', 'Missing number at position 2'); - expectError(function() { $.datepicker.parseDate('d m y', '3 2 AD01'); }, - '3 2 AD01 - d m y', 'Missing number at position 4'); - expectError(function() { $.datepicker.parseDate('d m yy', '3 2 AD01'); }, - '3 2 AD01 - dd mm yy', 'Missing number at position 4'); - expectError(function() { $.datepicker.parseDate('y-o', '2001-D01'); }, - '2001-D01 - y-o', 'Missing number at position 5'); - expectError(function() { $.datepicker.parseDate('yy-oo', '2001-D01'); }, - '2001-D01 - yy-oo', 'Missing number at position 5'); - expectError(function() { $.datepicker.parseDate('D d M y', 'D7 3 Feb 01'); }, - 'D7 3 Feb 01 - D d M y', 'Unknown name at position 0'); - expectError(function() { $.datepicker.parseDate('D d M y', 'Sat 3 M2 01'); }, - 'Sat 3 M2 01 - D d M y', 'Unknown name at position 6'); - expectError(function() { $.datepicker.parseDate('DD, MM d, yy', 'Saturday- Feb 3, 2001'); }, - 'Saturday- Feb 3, 2001 - DD, MM d, yy', 'Unexpected literal at position 8'); - expectError(function() { $.datepicker.parseDate('\'day\' d \'of\' MM (\'\'DD\'\'), yy', - 'day 3 of February ("Saturday"), 2001'); }, - 'day 3 of Mon2 ("Day7"), 2001', 'Unexpected literal at position 19'); - expectError(function() { $.datepicker.parseDate('d m y', '29 2 01'); }, - '29 2 01 - d m y', 'Invalid date'); - var fr = $.datepicker.regional['fr']; - var settings = {dayNamesShort: fr.dayNamesShort, dayNames: fr.dayNames, - monthNamesShort: fr.monthNamesShort, monthNames: fr.monthNames}; - expectError(function() { $.datepicker.parseDate('D d M y', 'Mon 9 Avr 01', settings); }, - 'Mon 9 Avr 01 - D d M y', 'Unknown name at position 0'); - expectError(function() { $.datepicker.parseDate('D d M y', 'Lun 9 Apr 01', settings); }, - 'Lun 9 Apr 01 - D d M y', 'Unknown name at position 6'); -}); - -test('formatDate', function() { - init('#inp'); - equals($.datepicker.formatDate('d m y', new Date(2001, 2 - 1, 3)), - '3 2 01', 'Format date d m y'); - equals($.datepicker.formatDate('dd mm yy', new Date(2001, 2 - 1, 3)), - '03 02 2001', 'Format date dd mm yy'); - equals($.datepicker.formatDate('d m y', new Date(2001, 12 - 1, 13)), - '13 12 01', 'Format date d m y'); - equals($.datepicker.formatDate('dd mm yy', new Date(2001, 12 - 1, 13)), - '13 12 2001', 'Format date dd mm yy'); - equals($.datepicker.formatDate('yy-o', new Date(2001, 2 - 1, 3)), - '2001-34', 'Format date yy-o'); - equals($.datepicker.formatDate('yy-oo', new Date(2001, 2 - 1, 3)), - '2001-034', 'Format date yy-oo'); - equals($.datepicker.formatDate('D M y', new Date(2001, 2 - 1, 3)), - 'Sat Feb 01', 'Format date D M y'); - equals($.datepicker.formatDate('DD MM yy', new Date(2001, 2 - 1, 3)), - 'Saturday February 2001', 'Format date DD MM yy'); - equals($.datepicker.formatDate('DD, MM d, yy', new Date(2001, 2 - 1, 3)), - 'Saturday, February 3, 2001', 'Format date DD, MM d, yy'); - equals($.datepicker.formatDate('\'day\' d \'of\' MM (\'\'DD\'\'), yy', - new Date(2001, 2 - 1, 3)), 'day 3 of February (\'Saturday\'), 2001', - 'Format date \'day\' d \'of\' MM (\'\'DD\'\'), yy'); - var gmtDate = new Date(2001, 2 - 1, 3); - gmtDate.setMinutes(gmtDate.getMinutes() - gmtDate.getTimezoneOffset()); - equals($.datepicker.formatDate('@', gmtDate), '981158400000', 'Format date @'); - equals($.datepicker.formatDate('!', gmtDate), '631167552000000000', 'Format date !'); - var fr = $.datepicker.regional['fr']; - var settings = {dayNamesShort: fr.dayNamesShort, dayNames: fr.dayNames, - monthNamesShort: fr.monthNamesShort, monthNames: fr.monthNames}; - equals($.datepicker.formatDate('D M y', new Date(2001, 4 - 1, 9), settings), - 'Lun Avr 01', 'Format date D M y with settings'); - equals($.datepicker.formatDate('DD MM yy', new Date(2001, 4 - 1, 9), settings), - 'Lundi Avril 2001', 'Format date DD MM yy with settings'); - equals($.datepicker.formatDate('DD, MM d, yy', new Date(2001, 4 - 1, 9), settings), - 'Lundi, Avril 9, 2001', 'Format date DD, MM d, yy with settings'); - equals($.datepicker.formatDate('\'jour\' d \'de\' MM (\'\'DD\'\'), yy', - new Date(2001, 4 - 1, 9), settings), 'jour 9 de Avril (\'Lundi\'), 2001', - 'Format date \'jour\' d \'de\' MM (\'\'DD\'\'), yy with settings'); -}); - -})(jQuery); diff --git a/tests/unit/datepicker/datepicker_tickets.js b/tests/unit/datepicker/datepicker_tickets.js deleted file mode 100644 index 85598f94936..00000000000 --- a/tests/unit/datepicker/datepicker_tickets.js +++ /dev/null @@ -1,32 +0,0 @@ -/* - * datepicker_tickets.js - */ -(function($) { - -module("datepicker: tickets", { - teardown: function() { - stop(); - setTimeout(start, 13); - } -}); - -// http://forum.jquery.com/topic/several-breaking-changes-in-jquery-ui-1-8rc1 -test('beforeShowDay-getDate', function() { - var inp = init('#inp', {beforeShowDay: function(date) { inp.datepicker('getDate'); return [true, '']; }}); - var dp = $('#ui-datepicker-div'); - inp.val('01/01/2010').datepicker('show'); - // result has line-break instead of space inbetween, therefore comparsion fails - equals($('div.ui-datepicker-title').text(), 'January 2010', 'Initial month'); - $('a.ui-datepicker-next', dp).click(); - $('a.ui-datepicker-next', dp).click(); - // fails, see above - equals($('div.ui-datepicker-title').text(), 'March 2010', 'After next clicks'); - inp.datepicker('hide').datepicker('show'); - $('a.ui-datepicker-prev', dp).click(); - $('a.ui-datepicker-prev', dp).click(); - // fails, see above - equals($('div.ui-datepicker-title').text(), 'November 2009', 'After prev clicks'); - inp.datepicker('hide'); -}); - -})(jQuery); diff --git a/tests/unit/datepicker/events.js b/tests/unit/datepicker/events.js new file mode 100644 index 00000000000..c49e0603c32 --- /dev/null +++ b/tests/unit/datepicker/events.js @@ -0,0 +1,169 @@ +define( [ + "qunit", + "jquery", + "./helper", + "ui/widgets/datepicker" +], function( QUnit, $, testHelper ) { +"use strict"; + +var beforeAfterEach = testHelper.beforeAfterEach; + +QUnit.module( "datepicker: events", beforeAfterEach() ); + +var selectedThis = null, +selectedDate = null, +selectedInst = null; + +function callback( date, inst ) { + selectedThis = this; + selectedDate = date; + selectedInst = inst; +} + +function callback2( year, month, inst ) { + selectedThis = this; + selectedDate = year + "/" + month; + selectedInst = inst; +} + +QUnit.test( "events", function( assert ) { + assert.expect( 26 ); + var dateStr, newMonthYear, inp2, + inp = testHelper.init( "#inp", { onSelect: callback } ), + date = new Date(); + + // OnSelect + inp.val( "" ).datepicker( "show" ). + simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + assert.equal( selectedThis, inp[ 0 ], "Callback selected this" ); + assert.equal( selectedInst, $.data( inp[ 0 ], testHelper.PROP_NAME ), "Callback selected inst" ); + assert.equal( selectedDate, $.datepicker.formatDate( "mm/dd/yy", date ), + "Callback selected date" ); + inp.val( "" ).datepicker( "show" ). + simulate( "keydown", { ctrlKey: true, keyCode: $.ui.keyCode.DOWN } ). + simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + date.setDate( date.getDate() + 7 ); + assert.equal( selectedDate, $.datepicker.formatDate( "mm/dd/yy", date ), + "Callback selected date - ctrl+down" ); + inp.val( "" ).datepicker( "show" ). + simulate( "keydown", { keyCode: $.ui.keyCode.ESCAPE } ); + assert.equal( selectedDate, $.datepicker.formatDate( "mm/dd/yy", date ), + "Callback selected date - esc" ); + dateStr = "02/04/2008"; + inp.val( dateStr ).datepicker( "show" ). + simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + assert.equal( dateStr, selectedDate, + "onSelect is called after enter keydown" ); + + // OnChangeMonthYear + inp.datepicker( "option", { onChangeMonthYear: callback2, onSelect: null } ). + val( "" ).datepicker( "show" ); + newMonthYear = function( date ) { + return date.getFullYear() + "/" + ( date.getMonth() + 1 ); + }; + date = new Date(); + date.setDate( 1 ); + inp.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_UP } ); + date.setMonth( date.getMonth() - 1 ); + assert.equal( selectedThis, inp[ 0 ], "Callback change month/year this" ); + assert.equal( selectedInst, $.data( inp[ 0 ], testHelper.PROP_NAME ), "Callback change month/year inst" ); + assert.equal( selectedDate, newMonthYear( date ), + "Callback change month/year date - pgup" ); + inp.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_DOWN } ); + date.setMonth( date.getMonth() + 1 ); + assert.equal( selectedDate, newMonthYear( date ), + "Callback change month/year date - pgdn" ); + inp.simulate( "keydown", { ctrlKey: true, keyCode: $.ui.keyCode.PAGE_UP } ); + date.setFullYear( date.getFullYear() - 1 ); + assert.equal( selectedDate, newMonthYear( date ), + "Callback change month/year date - ctrl+pgup" ); + inp.simulate( "keydown", { ctrlKey: true, keyCode: $.ui.keyCode.HOME } ); + date.setFullYear( date.getFullYear() + 1 ); + assert.equal( selectedDate, newMonthYear( date ), + "Callback change month/year date - ctrl+home" ); + inp.simulate( "keydown", { ctrlKey: true, keyCode: $.ui.keyCode.PAGE_DOWN } ); + date.setFullYear( date.getFullYear() + 1 ); + assert.equal( selectedDate, newMonthYear( date ), + "Callback change month/year date - ctrl+pgdn" ); + inp.datepicker( "setDate", new Date( 2007, 1 - 1, 26 ) ); + assert.equal( selectedDate, "2007/1", "Callback change month/year date - setDate" ); + selectedDate = null; + inp.datepicker( "setDate", new Date( 2007, 1 - 1, 12 ) ); + assert.ok( selectedDate == null, "Callback change month/year date - setDate no change" ); + + // OnChangeMonthYear step by 2 + inp.datepicker( "option", { stepMonths: 2 } ). + datepicker( "hide" ).val( "" ).datepicker( "show" ). + simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_UP } ); + date.setMonth( date.getMonth() - 14 ); + assert.equal( selectedDate, newMonthYear( date ), + "Callback change month/year by 2 date - pgup" ); + inp.simulate( "keydown", { ctrlKey: true, keyCode: $.ui.keyCode.PAGE_UP } ); + date.setMonth( date.getMonth() - 12 ); + assert.equal( selectedDate, newMonthYear( date ), + "Callback change month/year by 2 date - ctrl+pgup" ); + inp.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_DOWN } ); + date.setMonth( date.getMonth() + 2 ); + assert.equal( selectedDate, newMonthYear( date ), + "Callback change month/year by 2 date - pgdn" ); + inp.simulate( "keydown", { ctrlKey: true, keyCode: $.ui.keyCode.PAGE_DOWN } ); + date.setMonth( date.getMonth() + 12 ); + assert.equal( selectedDate, newMonthYear( date ), + "Callback change month/year by 2 date - ctrl+pgdn" ); + + // OnClose + inp.datepicker( "option", { onClose: callback, onChangeMonthYear: null, stepMonths: 1 } ). + val( "" ).datepicker( "show" ). + simulate( "keydown", { keyCode: $.ui.keyCode.ESCAPE } ); + assert.equal( selectedThis, inp[ 0 ], "Callback close this" ); + assert.equal( selectedInst, $.data( inp[ 0 ], testHelper.PROP_NAME ), "Callback close inst" ); + assert.equal( selectedDate, "", "Callback close date - esc" ); + inp.val( "" ).datepicker( "show" ). + simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + assert.equal( selectedDate, $.datepicker.formatDate( "mm/dd/yy", new Date() ), + "Callback close date - enter" ); + inp.val( "02/04/2008" ).datepicker( "show" ). + simulate( "keydown", { keyCode: $.ui.keyCode.ESCAPE } ); + assert.equal( selectedDate, "02/04/2008", "Callback close date - preset" ); + inp.val( "02/04/2008" ).datepicker( "show" ). + simulate( "keydown", { ctrlKey: true, keyCode: $.ui.keyCode.END } ); + assert.equal( selectedDate, "", "Callback close date - ctrl+end" ); + + inp2 = testHelper.init( "#inp2" ); + inp2.datepicker().datepicker( "option", { onClose: callback } ).datepicker( "show" ); + inp.datepicker( "show" ); + assert.equal( selectedThis, inp2[ 0 ], "Callback close this" ); +} ); + +QUnit.test( "beforeShowDay-getDate", function( assert ) { + assert.expect( 3 ); + var inp = testHelper.init( "#inp", { + beforeShowDay: function() { + inp.datepicker( "getDate" ); return [ true, "" ]; + } + } ); + var dp = $( "#ui-datepicker-div" ); + inp.val( "01/01/2010" ).datepicker( "show" ); + + // Contains non-breaking space + assert.equal( $( "div.ui-datepicker-title" ).text(), + + // In IE7/8 with jQuery <1.8, encoded spaces behave in strange ways + $( "January 2010" ).text(), "Initial month" ); + $( "a.ui-datepicker-next", dp ).trigger( "click" ); + $( "a.ui-datepicker-next", dp ).trigger( "click" ); + + // Contains non-breaking space + assert.equal( $( "div.ui-datepicker-title" ).text(), + $( "March 2010" ).text(), "After next clicks" ); + inp.datepicker( "hide" ).datepicker( "show" ); + $( "a.ui-datepicker-prev", dp ).trigger( "click" ); + $( "a.ui-datepicker-prev", dp ).trigger( "click" ); + + // Contains non-breaking space + assert.equal( $( "div.ui-datepicker-title" ).text(), + $( "November 2009" ).text(), "After prev clicks" ); + inp.datepicker( "hide" ); +} ); + +} ); diff --git a/tests/unit/datepicker/helper.js b/tests/unit/datepicker/helper.js new file mode 100644 index 00000000000..652609d542a --- /dev/null +++ b/tests/unit/datepicker/helper.js @@ -0,0 +1,46 @@ +define( [ + "qunit", + "jquery", + "lib/helper", + "ui/widgets/datepicker" +], function( QUnit, $, helper ) { +"use strict"; + +return $.extend( helper, { + addMonths: function( date, offset ) { + var maxDay = 32 - new Date( date.getFullYear(), date.getMonth() + offset, 32 ).getDate(); + date.setDate( Math.min( date.getDate(), maxDay ) ); + date.setMonth( date.getMonth() + offset ); + return date; + }, + + equalsDate: function( assert, d1, d2, message ) { + if ( !d1 || !d2 ) { + assert.ok( false, message + " - missing date" ); + return; + } + d1 = new Date( d1.getFullYear(), d1.getMonth(), d1.getDate() ); + d2 = new Date( d2.getFullYear(), d2.getMonth(), d2.getDate() ); + assert.equal( d1.toString(), d2.toString(), message ); + }, + + beforeAfterEach: function() { + return { + afterEach: helper.moduleAfterEach + }; + }, + + init: function( id, options ) { + $.datepicker.setDefaults( $.datepicker.regional[ "" ] ); + return $( id ).datepicker( $.extend( { showAnim: "" }, options || {} ) ); + }, + + initNewInput: function( options ) { + var id = $( "" ).appendTo( "#qunit-fixture" ); + return this.init( id, options ); + }, + + PROP_NAME: "datepicker" +} ); + +} ); diff --git a/tests/unit/datepicker/images/calendar.gif b/tests/unit/datepicker/images/calendar.gif new file mode 100644 index 00000000000..52f2863c907 Binary files /dev/null and b/tests/unit/datepicker/images/calendar.gif differ diff --git a/tests/unit/datepicker/methods.js b/tests/unit/datepicker/methods.js new file mode 100644 index 00000000000..ec83fb791b0 --- /dev/null +++ b/tests/unit/datepicker/methods.js @@ -0,0 +1,155 @@ +define( [ + "qunit", + "jquery", + "./helper", + "ui/widgets/datepicker" +], function( QUnit, $, testHelper ) { +"use strict"; + +var beforeAfterEach = testHelper.beforeAfterEach; + +QUnit.module( "datepicker: methods", beforeAfterEach() ); + +QUnit.test( "destroy", function( assert ) { + assert.expect( 39 ); + var inl, + inp = testHelper.init( "#inp" ), + dp = $( "#ui-datepicker-div" ); + + // Destroy and clear active reference + inp.datepicker( "show" ); + assert.equal( dp.css( "display" ), "block", "Datepicker - visible" ); + inp.datepicker( "hide" ).datepicker( "destroy" ); + assert.ok( $.datepicker._curInst == null, "Datepicker - destroyed and cleared reference" ); + assert.equal( dp.css( "display" ), "none", "Datepicker - absent" ); + + // Destroy without manual hiding (ensure datepicker is hidden after calling destroy) + inp = testHelper.init( "#inp" ); + inp.datepicker( "show" ); + assert.equal( dp.css( "display" ), "block", "Datepicker - visible" ); + inp.datepicker( "destroy" ); + assert.ok( $.datepicker._curInst == null, "Datepicker - destroyed and cleared reference" ); + assert.equal( dp.css( "display" ), "none", "Datepicker - absent" ); + + inp = testHelper.init( "#inp" ); + assert.ok( inp.is( ".hasDatepicker" ), "Default - marker class set" ); + assert.ok( $.data( inp[ 0 ], testHelper.PROP_NAME ), "Default - instance present" ); + assert.ok( inp.next().is( "#alt" ), "Default - button absent" ); + inp.datepicker( "destroy" ); + inp = $( "#inp" ); + assert.ok( !inp.is( ".hasDatepicker" ), "Default - marker class cleared" ); + assert.ok( !$.data( inp[ 0 ], testHelper.PROP_NAME ), "Default - instance absent" ); + assert.ok( inp.next().is( "#alt" ), "Default - button absent" ); + + // With button + inp = testHelper.init( "#inp", { showOn: "both" } ); + assert.ok( inp.is( ".hasDatepicker" ), "Button - marker class set" ); + assert.ok( $.data( inp[ 0 ], testHelper.PROP_NAME ), "Button - instance present" ); + assert.ok( inp.next().text() === "...", "Button - button added" ); + inp.datepicker( "destroy" ); + inp = $( "#inp" ); + assert.ok( !inp.is( ".hasDatepicker" ), "Button - marker class cleared" ); + assert.ok( !$.data( inp[ 0 ], testHelper.PROP_NAME ), "Button - instance absent" ); + assert.ok( inp.next().is( "#alt" ), "Button - button removed" ); + + // With append text + inp = testHelper.init( "#inp", { appendText: "Testing" } ); + assert.ok( inp.is( ".hasDatepicker" ), "Append - marker class set" ); + assert.ok( $.data( inp[ 0 ], testHelper.PROP_NAME ), "Append - instance present" ); + assert.ok( inp.next().text() === "Testing", "Append - append text added" ); + inp.datepicker( "destroy" ); + inp = $( "#inp" ); + assert.ok( !inp.is( ".hasDatepicker" ), "Append - marker class cleared" ); + assert.ok( !$.data( inp[ 0 ], testHelper.PROP_NAME ), "Append - instance absent" ); + assert.ok( inp.next().is( "#alt" ), "Append - append text removed" ); + + // With both + inp = testHelper.init( "#inp", { showOn: "both", buttonImageOnly: true, + buttonImage: "images/calendar.gif", appendText: "Testing" } ); + assert.ok( inp.is( ".hasDatepicker" ), "Both - marker class set" ); + assert.ok( $.data( inp[ 0 ], testHelper.PROP_NAME ), "Both - instance present" ); + assert.ok( inp.next()[ 0 ].nodeName.toLowerCase() === "img", "Both - button added" ); + assert.ok( inp.next().next().text() === "Testing", "Both - append text added" ); + inp.datepicker( "destroy" ); + inp = $( "#inp" ); + assert.ok( !inp.is( ".hasDatepicker" ), "Both - marker class cleared" ); + assert.ok( !$.data( inp[ 0 ], testHelper.PROP_NAME ), "Both - instance absent" ); + assert.ok( inp.next().is( "#alt" ), "Both - button and append text absent" ); + + // Inline + inl = testHelper.init( "#inl" ); + assert.ok( inl.is( ".hasDatepicker" ), "Inline - marker class set" ); + assert.ok( inl.html() !== "", "Inline - datepicker present" ); + assert.ok( $.data( inl[ 0 ], testHelper.PROP_NAME ), "Inline - instance present" ); + assert.ok( inl.next().length === 0 || inl.next().is( "p" ), "Inline - button absent" ); + inl.datepicker( "destroy" ); + inl = $( "#inl" ); + assert.ok( !inl.is( ".hasDatepicker" ), "Inline - marker class cleared" ); + assert.ok( inl.html() === "", "Inline - datepicker absent" ); + assert.ok( !$.data( inl[ 0 ], testHelper.PROP_NAME ), "Inline - instance absent" ); + assert.ok( inl.next().length === 0 || inl.next().is( "p" ), "Inline - button absent" ); +} ); + +QUnit.test( "enableDisable", function( assert ) { + assert.expect( 33 ); + var inl, dp, + inp = testHelper.init( "#inp" ); + assert.ok( !inp.datepicker( "isDisabled" ), "Enable/disable - initially marked as enabled" ); + assert.ok( !inp[ 0 ].disabled, "Enable/disable - field initially enabled" ); + inp.datepicker( "disable" ); + assert.ok( inp.datepicker( "isDisabled" ), "Enable/disable - now marked as disabled" ); + assert.ok( inp[ 0 ].disabled, "Enable/disable - field now disabled" ); + inp.datepicker( "enable" ); + assert.ok( !inp.datepicker( "isDisabled" ), "Enable/disable - now marked as enabled" ); + assert.ok( !inp[ 0 ].disabled, "Enable/disable - field now enabled" ); + inp.datepicker( "destroy" ); + + // With a button + inp = testHelper.init( "#inp", { showOn: "button" } ); + assert.ok( !inp.datepicker( "isDisabled" ), "Enable/disable button - initially marked as enabled" ); + assert.ok( !inp[ 0 ].disabled, "Enable/disable button - field initially enabled" ); + assert.ok( !inp.next( "button" )[ 0 ].disabled, "Enable/disable button - button initially enabled" ); + inp.datepicker( "disable" ); + assert.ok( inp.datepicker( "isDisabled" ), "Enable/disable button - now marked as disabled" ); + assert.ok( inp[ 0 ].disabled, "Enable/disable button - field now disabled" ); + assert.ok( inp.next( "button" )[ 0 ].disabled, "Enable/disable button - button now disabled" ); + inp.datepicker( "enable" ); + assert.ok( !inp.datepicker( "isDisabled" ), "Enable/disable button - now marked as enabled" ); + assert.ok( !inp[ 0 ].disabled, "Enable/disable button - field now enabled" ); + assert.ok( !inp.next( "button" )[ 0 ].disabled, "Enable/disable button - button now enabled" ); + inp.datepicker( "destroy" ); + + // With an image button + inp = testHelper.init( "#inp", { showOn: "button", buttonImageOnly: true, + buttonImage: "images/calendar.gif" } ); + assert.ok( !inp.datepicker( "isDisabled" ), "Enable/disable image - initially marked as enabled" ); + assert.ok( !inp[ 0 ].disabled, "Enable/disable image - field initially enabled" ); + assert.ok( parseFloat( inp.next( "img" ).css( "opacity" ) ) === 1, "Enable/disable image - image initially enabled" ); + inp.datepicker( "disable" ); + assert.ok( inp.datepicker( "isDisabled" ), "Enable/disable image - now marked as disabled" ); + assert.ok( inp[ 0 ].disabled, "Enable/disable image - field now disabled" ); + assert.ok( parseFloat( inp.next( "img" ).css( "opacity" ) ) !== 1, "Enable/disable image - image now disabled" ); + inp.datepicker( "enable" ); + assert.ok( !inp.datepicker( "isDisabled" ), "Enable/disable image - now marked as enabled" ); + assert.ok( !inp[ 0 ].disabled, "Enable/disable image - field now enabled" ); + assert.ok( parseFloat( inp.next( "img" ).css( "opacity" ) ) === 1, "Enable/disable image - image now enabled" ); + inp.datepicker( "destroy" ); + + // Inline + inl = testHelper.init( "#inl", { changeYear: true } ); + dp = $( ".ui-datepicker-inline", inl ); + assert.ok( !inl.datepicker( "isDisabled" ), "Enable/disable inline - initially marked as enabled" ); + assert.ok( !dp.children().is( ".ui-state-disabled" ), "Enable/disable inline - not visually disabled initially" ); + assert.ok( !dp.find( "select" ).prop( "disabled" ), "Enable/disable inline - form element enabled initially" ); + inl.datepicker( "disable" ); + assert.ok( inl.datepicker( "isDisabled" ), "Enable/disable inline - now marked as disabled" ); + assert.ok( dp.children().is( ".ui-state-disabled" ), "Enable/disable inline - visually disabled" ); + assert.ok( dp.find( "select" ).prop( "disabled" ), "Enable/disable inline - form element disabled" ); + inl.datepicker( "enable" ); + assert.ok( !inl.datepicker( "isDisabled" ), "Enable/disable inline - now marked as enabled" ); + assert.ok( !dp.children().is( ".ui-state-disabled" ), "Enable/disable inline - not visiually disabled" ); + assert.ok( !dp.find( "select" ).prop( "disabled" ), "Enable/disable inline - form element enabled" ); + inl.datepicker( "destroy" ); +} ); + +} ); diff --git a/tests/unit/datepicker/options.js b/tests/unit/datepicker/options.js new file mode 100644 index 00000000000..3055bc19975 --- /dev/null +++ b/tests/unit/datepicker/options.js @@ -0,0 +1,1263 @@ +define( [ + "qunit", + "jquery", + "./helper", + "ui/widgets/datepicker", + "ui/i18n/datepicker-fr", + "ui/i18n/datepicker-he", + "ui/i18n/datepicker-zh-CN" +], function( QUnit, $, testHelper ) { +"use strict"; + +var beforeAfterEach = testHelper.beforeAfterEach; + +QUnit.module( "datepicker: options", beforeAfterEach() ); + +QUnit.test( "setDefaults", function( assert ) { + assert.expect( 3 ); + testHelper.init( "#inp" ); + assert.equal( $.datepicker._defaults.showOn, "focus", "Initial showOn" ); + $.datepicker.setDefaults( { showOn: "button" } ); + assert.equal( $.datepicker._defaults.showOn, "button", "Change default showOn" ); + $.datepicker.setDefaults( { showOn: "focus" } ); + assert.equal( $.datepicker._defaults.showOn, "focus", "Restore showOn" ); +} ); + +QUnit.test( "option", function( assert ) { + assert.expect( 17 ); + var inp = testHelper.init( "#inp" ), + inst = $.data( inp[ 0 ], testHelper.PROP_NAME ); + + // Set option + assert.equal( inst.settings.showOn, null, "Initial setting showOn" ); + assert.equal( $.datepicker._get( inst, "showOn" ), "focus", "Initial instance showOn" ); + assert.equal( $.datepicker._defaults.showOn, "focus", "Initial default showOn" ); + inp.datepicker( "option", "showOn", "button" ); + assert.equal( inst.settings.showOn, "button", "Change setting showOn" ); + assert.equal( $.datepicker._get( inst, "showOn" ), "button", "Change instance showOn" ); + assert.equal( $.datepicker._defaults.showOn, "focus", "Retain default showOn" ); + inp.datepicker( "option", { showOn: "both" } ); + assert.equal( inst.settings.showOn, "both", "Change setting showOn" ); + assert.equal( $.datepicker._get( inst, "showOn" ), "both", "Change instance showOn" ); + assert.equal( $.datepicker._defaults.showOn, "focus", "Retain default showOn" ); + inp.datepicker( "option", "showOn", undefined ); + assert.equal( inst.settings.showOn, null, "Clear setting showOn" ); + assert.equal( $.datepicker._get( inst, "showOn" ), "focus", "Restore instance showOn" ); + assert.equal( $.datepicker._defaults.showOn, "focus", "Retain default showOn" ); + + // Get option + inp = testHelper.init( "#inp" ); + assert.equal( inp.datepicker( "option", "showOn" ), "focus", "Initial setting showOn" ); + inp.datepicker( "option", "showOn", "button" ); + assert.equal( inp.datepicker( "option", "showOn" ), "button", "Change instance showOn" ); + inp.datepicker( "option", "showOn", undefined ); + assert.equal( inp.datepicker( "option", "showOn" ), "focus", "Reset instance showOn" ); + assert.deepEqual( inp.datepicker( "option", "all" ), { showAnim: "" }, "Get instance settings" ); + assert.deepEqual( inp.datepicker( "option", "defaults" ), $.datepicker._defaults, + "Get default settings" ); +} ); + +QUnit.test( "disabled", function( assert ) { + assert.expect( 8 ); + var inp = testHelper.init( "#inp" ); + assert.ok( !inp.datepicker( "isDisabled" ), "Initially marked as enabled" ); + assert.ok( !inp[ 0 ].disabled, "Field initially enabled" ); + inp.datepicker( "option", "disabled", true ); + assert.ok( inp.datepicker( "isDisabled" ), "Marked as disabled" ); + assert.ok( inp[ 0 ].disabled, "Field now disabled" ); + inp.datepicker( "option", "disabled", false ); + assert.ok( !inp.datepicker( "isDisabled" ), "Marked as enabled" ); + assert.ok( !inp[ 0 ].disabled, "Field now enabled" ); + inp.datepicker( "destroy" ); + + inp = testHelper.init( "#inp", { disabled: true } ); + assert.ok( inp.datepicker( "isDisabled" ), "Initially marked as disabled" ); + assert.ok( inp[ 0 ].disabled, "Field initially disabled" ); +} ); + +QUnit.test( "change", function( assert ) { + assert.expect( 12 ); + var inp = testHelper.init( "#inp" ), + inst = $.data( inp[ 0 ], testHelper.PROP_NAME ); + assert.equal( inst.settings.showOn, null, "Initial setting showOn" ); + assert.equal( $.datepicker._get( inst, "showOn" ), "focus", "Initial instance showOn" ); + assert.equal( $.datepicker._defaults.showOn, "focus", "Initial default showOn" ); + inp.datepicker( "change", "showOn", "button" ); + assert.equal( inst.settings.showOn, "button", "Change setting showOn" ); + assert.equal( $.datepicker._get( inst, "showOn" ), "button", "Change instance showOn" ); + assert.equal( $.datepicker._defaults.showOn, "focus", "Retain default showOn" ); + inp.datepicker( "change", { showOn: "both" } ); + assert.equal( inst.settings.showOn, "both", "Change setting showOn" ); + assert.equal( $.datepicker._get( inst, "showOn" ), "both", "Change instance showOn" ); + assert.equal( $.datepicker._defaults.showOn, "focus", "Retain default showOn" ); + inp.datepicker( "change", "showOn", undefined ); + assert.equal( inst.settings.showOn, null, "Clear setting showOn" ); + assert.equal( $.datepicker._get( inst, "showOn" ), "focus", "Restore instance showOn" ); + assert.equal( $.datepicker._defaults.showOn, "focus", "Retain default showOn" ); +} ); + +QUnit.test( "invocation", function( assert ) { + var ready = assert.async(); + var button, image, + body = $( "body" ); + + assert.expect( 29 ); + + function step0() { + var inp = testHelper.initNewInput(), + dp = $( "#ui-datepicker-div" ); + + button = inp.siblings( "button" ); + assert.ok( button.length === 0, "Focus - button absent" ); + image = inp.siblings( "img" ); + assert.ok( image.length === 0, "Focus - image absent" ); + + testHelper.onFocus( inp, function() { + assert.ok( dp.is( ":visible" ), "Focus - rendered on focus" ); + inp.simulate( "keydown", { keyCode: $.ui.keyCode.ESCAPE } ); + assert.ok( !dp.is( ":visible" ), "Focus - hidden on exit" ); + step1(); + } ); + } + + function step1() { + + var inp = testHelper.initNewInput(), + dp = $( "#ui-datepicker-div" ); + + testHelper.onFocus( inp, function() { + assert.ok( dp.is( ":visible" ), "Focus - rendered on focus" ); + body.simulate( "mousedown", {} ); + assert.ok( !dp.is( ":visible" ), "Focus - hidden on external click" ); + inp.datepicker( "hide" ).datepicker( "destroy" ); + + step2(); + } ); + } + + function step2() { + var inp = testHelper.initNewInput( { + showOn: "button", + buttonText: "Popup" + } ), + dp = $( "#ui-datepicker-div" ); + + assert.ok( !dp.is( ":visible" ), "Button - initially hidden" ); + button = inp.siblings( "button" ); + image = inp.siblings( "img" ); + assert.ok( button.length === 1, "Button - button present" ); + assert.ok( image.length === 0, "Button - image absent" ); + assert.equal( button.text(), "Popup", "Button - button text" ); + + testHelper.onFocus( inp, function() { + assert.ok( !dp.is( ":visible" ), "Button - not rendered on focus" ); + button.trigger( "click" ); + assert.ok( dp.is( ":visible" ), "Button - rendered on button click" ); + button.trigger( "click" ); + assert.ok( !dp.is( ":visible" ), "Button - hidden on second button click" ); + inp.datepicker( "hide" ).datepicker( "destroy" ); + + step3(); + } ); + } + + function step3() { + var inp = testHelper.initNewInput( { + showOn: "button", + buttonImageOnly: true, + buttonImage: "images/calendar.gif", + buttonText: "Cal" + } ), + dp = $( "#ui-datepicker-div" ); + + assert.ok( !dp.is( ":visible" ), "Image button - initially hidden" ); + button = inp.siblings( "button" ); + assert.ok( button.length === 0, "Image button - button absent" ); + image = inp.siblings( "img" ); + assert.ok( image.length === 1, "Image button - image present" ); + assert.ok( /images\/calendar\.gif$/.test( image.attr( "src" ) ), "Image button - image source" ); + assert.equal( image.attr( "title" ), "Cal", "Image button - image text" ); + + testHelper.onFocus( inp, function() { + assert.ok( !dp.is( ":visible" ), "Image button - not rendered on focus" ); + image.trigger( "click" ); + assert.ok( dp.is( ":visible" ), "Image button - rendered on image click" ); + image.trigger( "click" ); + assert.ok( !dp.is( ":visible" ), "Image button - hidden on second image click" ); + inp.datepicker( "hide" ).datepicker( "destroy" ); + + step4(); + } ); + } + + function step4() { + var inp = testHelper.initNewInput( { + showOn: "both", + buttonImage: "images/calendar.gif" + } ), + dp = $( "#ui-datepicker-div" ); + + assert.ok( !dp.is( ":visible" ), "Both - initially hidden" ); + button = inp.siblings( "button" ); + assert.ok( button.length === 1, "Both - button present" ); + image = inp.siblings( "img" ); + assert.ok( image.length === 0, "Both - image absent" ); + image = button.children( "img" ); + assert.ok( image.length === 1, "Both - button image present" ); + + testHelper.onFocus( inp, function() { + assert.ok( dp.is( ":visible" ), "Both - rendered on focus" ); + body.simulate( "mousedown", {} ); + assert.ok( !dp.is( ":visible" ), "Both - hidden on external click" ); + button.trigger( "click" ); + assert.ok( dp.is( ":visible" ), "Both - rendered on button click" ); + button.trigger( "click" ); + assert.ok( !dp.is( ":visible" ), "Both - hidden on second button click" ); + inp.datepicker( "hide" ).datepicker( "destroy" ); + + ready(); + } ); + } + + step0(); +} ); + +QUnit.test( "otherMonths", function( assert ) { + assert.expect( 8 ); + var inp = testHelper.init( "#inp" ), + pop = $( "#ui-datepicker-div" ); + inp.val( "06/01/2009" ).datepicker( "show" ); + assert.equal( pop.find( "tbody" ).text(), + + // In IE7/8 with jQuery <1.8, encoded spaces behave in strange ways + $( "\u00a0123456789101112131415161718192021222324252627282930\u00a0\u00a0\u00a0\u00a0" ).text(), + "Other months - none" ); + assert.ok( pop.find( "td" ).last().find( "*" ).length === 0, "Other months - no content" ); + inp.datepicker( "hide" ).datepicker( "option", "showOtherMonths", true ).datepicker( "show" ); + assert.equal( pop.find( "tbody" ).text(), "311234567891011121314151617181920212223242526272829301234", + "Other months - show" ); + assert.ok( pop.find( "td" ).last().find( "span" ).length === 1, "Other months - span content" ); + inp.datepicker( "hide" ).datepicker( "option", "selectOtherMonths", true ).datepicker( "show" ); + assert.equal( pop.find( "tbody" ).text(), "311234567891011121314151617181920212223242526272829301234", + "Other months - select" ); + assert.ok( pop.find( "td" ).last().find( "a" ).length === 1, "Other months - link content" ); + inp.datepicker( "hide" ).datepicker( "option", "showOtherMonths", false ).datepicker( "show" ); + assert.equal( pop.find( "tbody" ).text(), + + // In IE7/8 with jQuery <1.8, encoded spaces behave in strange ways + $( "\u00a0123456789101112131415161718192021222324252627282930\u00a0\u00a0\u00a0\u00a0" ).text(), + "Other months - none" ); + assert.ok( pop.find( "td" ).last().find( "*" ).length === 0, "Other months - no content" ); +} ); + +QUnit.test( "defaultDate", function( assert ) { + assert.expect( 16 ); + var inp = testHelper.init( "#inp" ), + date = new Date(); + inp.val( "" ).datepicker( "show" ). + simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), date, "Default date null" ); + + // Numeric values + inp.datepicker( "option", { defaultDate: -2 } ). + datepicker( "hide" ).val( "" ).datepicker( "show" ). + simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + date.setDate( date.getDate() - 2 ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), date, "Default date -2" ); + + date = new Date(); + inp.datepicker( "option", { defaultDate: 3 } ). + datepicker( "hide" ).val( "" ).datepicker( "show" ). + simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + date.setDate( date.getDate() + 3 ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), date, "Default date 3" ); + + date = new Date(); + inp.datepicker( "option", { defaultDate: 1 / "a" } ). + datepicker( "hide" ).val( "" ).datepicker( "show" ). + simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), date, "Default date NaN" ); + + // String offset values + inp.datepicker( "option", { defaultDate: "-1d" } ). + datepicker( "hide" ).val( "" ).datepicker( "show" ). + simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + date.setDate( date.getDate() - 1 ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), date, "Default date -1d" ); + inp.datepicker( "option", { defaultDate: "+3d" } ). + datepicker( "hide" ).val( "" ).datepicker( "show" ). + simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + date.setDate( date.getDate() + 4 ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), date, "Default date +3d" ); + inp.datepicker( "option", { defaultDate: " -2 w " } ). + datepicker( "hide" ).val( "" ).datepicker( "show" ). + simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + date = new Date(); + date.setDate( date.getDate() - 14 ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), date, "Default date -2 w" ); + inp.datepicker( "option", { defaultDate: "+1 w" } ). + datepicker( "hide" ).val( "" ).datepicker( "show" ). + simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + date.setDate( date.getDate() + 21 ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), date, "Default date +1 w" ); + inp.datepicker( "option", { defaultDate: " -1 m " } ). + datepicker( "hide" ).val( "" ).datepicker( "show" ). + simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + date = testHelper.addMonths( new Date(), -1 ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), date, "Default date -1 m" ); + inp.datepicker( "option", { defaultDate: "+2m" } ). + datepicker( "hide" ).val( "" ).datepicker( "show" ). + simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + date = testHelper.addMonths( new Date(), 2 ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), date, "Default date +2m" ); + inp.datepicker( "option", { defaultDate: "-2y" } ). + datepicker( "hide" ).val( "" ).datepicker( "show" ). + simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + date = new Date(); + date.setFullYear( date.getFullYear() - 2 ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), date, "Default date -2y" ); + inp.datepicker( "option", { defaultDate: "+1 y " } ). + datepicker( "hide" ).val( "" ).datepicker( "show" ). + simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + date.setFullYear( date.getFullYear() + 3 ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), date, "Default date +1 y" ); + inp.datepicker( "option", { defaultDate: "+1m +10d" } ). + datepicker( "hide" ).val( "" ).datepicker( "show" ). + simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + date = testHelper.addMonths( new Date(), 1 ); + date.setDate( date.getDate() + 10 ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), date, "Default date +1m +10d" ); + + // String date values + inp.datepicker( "option", { defaultDate: "07/04/2007" } ). + datepicker( "hide" ).val( "" ).datepicker( "show" ). + simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + date = new Date( 2007, 7 - 1, 4 ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), date, "Default date 07/04/2007" ); + inp.datepicker( "option", { dateFormat: "yy-mm-dd", defaultDate: "2007-04-02" } ). + datepicker( "hide" ).val( "" ).datepicker( "show" ). + simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + date = new Date( 2007, 4 - 1, 2 ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), date, "Default date 2007-04-02" ); + + // Date value + date = new Date( 2007, 1 - 1, 26 ); + inp.datepicker( "option", { dateFormat: "mm/dd/yy", defaultDate: date } ). + datepicker( "hide" ).val( "" ).datepicker( "show" ). + simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), date, "Default date 01/26/2007" ); +} ); + +QUnit.test( "miscellaneous", function( assert ) { + assert.expect( 19 ); + var curYear, longNames, shortNames, date, + dp = $( "#ui-datepicker-div" ), + inp = testHelper.init( "#inp" ); + + // Year range + function genRange( start, offset ) { + var i = start, + range = ""; + for ( ; i < start + offset; i++ ) { + range += i; + } + return range; + } + curYear = new Date().getFullYear(); + inp.val( "02/04/2008" ).datepicker( "show" ); + assert.equal( dp.find( ".ui-datepicker-year" ).text(), "2008", "Year range - read-only default" ); + inp.datepicker( "hide" ).datepicker( "option", { changeYear: true } ).datepicker( "show" ); + assert.equal( dp.find( ".ui-datepicker-year" ).text(), genRange( 2008 - 10, 21 ), "Year range - changeable default" ); + inp.datepicker( "hide" ).datepicker( "option", { yearRange: "c-6:c+2", changeYear: true } ).datepicker( "show" ); + assert.equal( dp.find( ".ui-datepicker-year" ).text(), genRange( 2008 - 6, 9 ), "Year range - c-6:c+2" ); + inp.datepicker( "hide" ).datepicker( "option", { yearRange: "2000:2010", changeYear: true } ).datepicker( "show" ); + assert.equal( dp.find( ".ui-datepicker-year" ).text(), genRange( 2000, 11 ), "Year range - 2000:2010" ); + inp.datepicker( "hide" ).datepicker( "option", { yearRange: "-5:+3", changeYear: true } ).datepicker( "show" ); + assert.equal( dp.find( ".ui-datepicker-year" ).text(), genRange( curYear - 5, 9 ), "Year range - -5:+3" ); + inp.datepicker( "hide" ).datepicker( "option", { yearRange: "2000:-5", changeYear: true } ).datepicker( "show" ); + assert.equal( dp.find( ".ui-datepicker-year" ).text(), genRange( 2000, curYear - 2004 ), "Year range - 2000:-5" ); + inp.datepicker( "hide" ).datepicker( "option", { yearRange: "", changeYear: true } ).datepicker( "show" ); + assert.equal( dp.find( ".ui-datepicker-year" ).text(), genRange( curYear, 1 ), "Year range - -6:+2" ); + + // Navigation as date format + inp.datepicker( "option", { showButtonPanel: true } ); + assert.equal( dp.find( ".ui-datepicker-prev" ).text(), "Prev", "Navigation prev - default" ); + assert.equal( dp.find( ".ui-datepicker-current" ).text(), "Today", "Navigation current - default" ); + assert.equal( dp.find( ".ui-datepicker-next" ).text(), "Next", "Navigation next - default" ); + inp.datepicker( "hide" ).datepicker( "option", { navigationAsDateFormat: true, prevText: "< M", currentText: "MM", nextText: "M >" } ). + val( "02/04/2008" ).datepicker( "show" ); + longNames = $.datepicker.regional[ "" ].monthNames; + shortNames = $.datepicker.regional[ "" ].monthNamesShort; + date = new Date(); + assert.equal( dp.find( ".ui-datepicker-prev" ).text(), "< " + shortNames[ 0 ], "Navigation prev - as date format" ); + assert.equal( dp.find( ".ui-datepicker-current" ).text(), + longNames[ date.getMonth() ], "Navigation current - as date format" ); + assert.equal( dp.find( ".ui-datepicker-next" ).text(), + shortNames[ 2 ] + " >", "Navigation next - as date format" ); + inp.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_DOWN } ); + assert.equal( dp.find( ".ui-datepicker-prev" ).text(), + "< " + shortNames[ 1 ], "Navigation prev - as date format + pgdn" ); + assert.equal( dp.find( ".ui-datepicker-current" ).text(), + longNames[ date.getMonth() ], "Navigation current - as date format + pgdn" ); + assert.equal( dp.find( ".ui-datepicker-next" ).text(), + shortNames[ 3 ] + " >", "Navigation next - as date format + pgdn" ); + inp.datepicker( "hide" ).datepicker( "option", { gotoCurrent: true } ). + val( "02/04/2008" ).datepicker( "show" ); + assert.equal( dp.find( ".ui-datepicker-prev" ).text(), + "< " + shortNames[ 0 ], "Navigation prev - as date format + goto current" ); + assert.equal( dp.find( ".ui-datepicker-current" ).text(), + longNames[ 1 ], "Navigation current - as date format + goto current" ); + assert.equal( dp.find( ".ui-datepicker-next" ).text(), + shortNames[ 2 ] + " >", "Navigation next - as date format + goto current" ); +} ); + +QUnit.test( "minMax", function( assert ) { + assert.expect( 23 ); + var date, + inp = testHelper.init( "#inp" ), + dp = $( "#ui-datepicker-div" ), + lastYear = new Date( 2007, 6 - 1, 4 ), + nextYear = new Date( 2009, 6 - 1, 4 ), + minDate = new Date( 2008, 2 - 1, 29 ), + maxDate = new Date( 2008, 12 - 1, 7 ); + inp.val( "06/04/2008" ).datepicker( "show" ); + inp.simulate( "keydown", { ctrlKey: true, keyCode: $.ui.keyCode.PAGE_UP } ). + simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), lastYear, + "Min/max - null, null - ctrl+pgup" ); + inp.val( "06/04/2008" ).datepicker( "show" ); + inp.simulate( "keydown", { ctrlKey: true, keyCode: $.ui.keyCode.PAGE_DOWN } ). + simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), nextYear, + "Min/max - null, null - ctrl+pgdn" ); + inp.datepicker( "option", { minDate: minDate } ). + datepicker( "hide" ).val( "06/04/2008" ).datepicker( "show" ); + inp.simulate( "keydown", { ctrlKey: true, keyCode: $.ui.keyCode.PAGE_UP } ). + simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), minDate, + "Min/max - 02/29/2008, null - ctrl+pgup" ); + inp.val( "06/04/2008" ).datepicker( "show" ); + inp.simulate( "keydown", { ctrlKey: true, keyCode: $.ui.keyCode.PAGE_DOWN } ). + simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), nextYear, + "Min/max - 02/29/2008, null - ctrl+pgdn" ); + inp.datepicker( "option", { maxDate: maxDate } ). + datepicker( "hide" ).val( "06/04/2008" ).datepicker( "show" ); + inp.simulate( "keydown", { ctrlKey: true, keyCode: $.ui.keyCode.PAGE_UP } ). + simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), minDate, + "Min/max - 02/29/2008, 12/07/2008 - ctrl+pgup" ); + inp.val( "06/04/2008" ).datepicker( "show" ); + inp.simulate( "keydown", { ctrlKey: true, keyCode: $.ui.keyCode.PAGE_DOWN } ). + simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), maxDate, + "Min/max - 02/29/2008, 12/07/2008 - ctrl+pgdn" ); + inp.datepicker( "option", { minDate: null } ). + datepicker( "hide" ).val( "06/04/2008" ).datepicker( "show" ); + inp.simulate( "keydown", { ctrlKey: true, keyCode: $.ui.keyCode.PAGE_UP } ). + simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), lastYear, + "Min/max - null, 12/07/2008 - ctrl+pgup" ); + inp.val( "06/04/2008" ).datepicker( "show" ); + inp.simulate( "keydown", { ctrlKey: true, keyCode: $.ui.keyCode.PAGE_DOWN } ). + simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), maxDate, + "Min/max - null, 12/07/2008 - ctrl+pgdn" ); + + // Relative dates + date = new Date(); + date.setDate( date.getDate() - 7 ); + inp.datepicker( "option", { minDate: "-1w", maxDate: "+1 m +10 d " } ). + datepicker( "hide" ).val( "" ).datepicker( "show" ); + inp.simulate( "keydown", { ctrlKey: true, keyCode: $.ui.keyCode.PAGE_UP } ). + simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), date, + "Min/max - -1w, +1 m +10 d - ctrl+pgup" ); + date = testHelper.addMonths( new Date(), 1 ); + date.setDate( date.getDate() + 10 ); + inp.val( "" ).datepicker( "show" ); + inp.simulate( "keydown", { ctrlKey: true, keyCode: $.ui.keyCode.PAGE_DOWN } ). + simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), date, + "Min/max - -1w, +1 m +10 d - ctrl+pgdn" ); + + // With existing date + inp = testHelper.init( "#inp" ); + inp.val( "06/04/2008" ).datepicker( "option", { minDate: minDate } ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), new Date( 2008, 6 - 1, 4 ), "Min/max - setDate > min" ); + inp.datepicker( "option", { minDate: null } ).val( "01/04/2008" ).datepicker( "option", { minDate: minDate } ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), minDate, "Min/max - setDate < min" ); + inp.datepicker( "option", { minDate: null } ).val( "06/04/2008" ).datepicker( "option", { maxDate: maxDate } ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), new Date( 2008, 6 - 1, 4 ), "Min/max - setDate < max" ); + inp.datepicker( "option", { maxDate: null } ).val( "01/04/2009" ).datepicker( "option", { maxDate: maxDate } ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), maxDate, "Min/max - setDate > max" ); + inp.datepicker( "option", { maxDate: null } ).val( "01/04/2008" ).datepicker( "option", { minDate: minDate, maxDate: maxDate } ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), minDate, "Min/max - setDate < min" ); + inp.datepicker( "option", { maxDate: null } ).val( "06/04/2008" ).datepicker( "option", { minDate: minDate, maxDate: maxDate } ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), new Date( 2008, 6 - 1, 4 ), "Min/max - setDate > min, < max" ); + inp.datepicker( "option", { maxDate: null } ).val( "01/04/2009" ).datepicker( "option", { minDate: minDate, maxDate: maxDate } ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), maxDate, "Min/max - setDate > max" ); + + inp.datepicker( "option", { yearRange: "-0:+1" } ).val( "01/01/" + new Date().getFullYear() ); + assert.ok( dp.find( ".ui-datepicker-prev" ).hasClass( "ui-state-disabled" ), "Year Range Test - previous button disabled at 1/1/minYear" ); + inp.datepicker( "setDate", "12/30/" + new Date().getFullYear() ); + assert.ok( dp.find( ".ui-datepicker-next" ).hasClass( "ui-state-disabled" ), "Year Range Test - next button disabled at 12/30/maxYear" ); + + inp.val( "" ).datepicker( "option", { + minDate: new Date( 1900, 0, 1 ), + maxDate: "-7y", + yearRange: "1900:-7" + } ); + assert.ok( dp.find( ".ui-datepicker-next" ).hasClass( "ui-state-disabled" ), "Year Range Test - relative - next button disabled" ); + assert.ok( !dp.find( ".ui-datepicker-prev" ).hasClass( "ui-state-disabled" ), "Year Range Test - relative - prev button enabled" ); + + inp.val( "" ).datepicker( "option", { + minDate: new Date( 1900, 0, 1 ), + maxDate: "1/25/2007", + yearRange: "1900:2007" + } ); + assert.ok( dp.find( ".ui-datepicker-next" ).hasClass( "ui-state-disabled" ), "Year Range Test - absolute - next button disabled" ); + assert.ok( !dp.find( ".ui-datepicker-prev" ).hasClass( "ui-state-disabled" ), "Year Range Test - absolute - prev button enabled" ); +} ); + +QUnit.test( "setDate", function( assert ) { + assert.expect( 24 ); + var inl, alt, minDate, maxDate, dateAndTimeToSet, dateAndTimeClone, + inp = testHelper.init( "#inp" ), + date1 = new Date( 2008, 6 - 1, 4 ), + date2 = new Date(); + assert.ok( inp.datepicker( "getDate" ) == null, "Set date - default" ); + inp.datepicker( "setDate", date1 ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), date1, "Set date - 2008-06-04" ); + date1 = new Date(); + date1.setDate( date1.getDate() + 7 ); + inp.datepicker( "setDate", +7 ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), date1, "Set date - +7" ); + date2.setFullYear( date2.getFullYear() + 2 ); + inp.datepicker( "setDate", "+2y" ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), date2, "Set date - +2y" ); + inp.datepicker( "setDate", date1, date2 ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), date1, "Set date - two dates" ); + inp.datepicker( "setDate" ); + assert.ok( inp.datepicker( "getDate" ) == null, "Set date - null" ); + + // Relative to current date + date1 = new Date(); + date1.setDate( date1.getDate() + 7 ); + inp.datepicker( "setDate", "c +7" ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), date1, "Set date - c +7" ); + date1.setDate( date1.getDate() + 7 ); + inp.datepicker( "setDate", "c+7" ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), date1, "Set date - c+7" ); + date1.setDate( date1.getDate() - 21 ); + inp.datepicker( "setDate", "c -3 w" ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), date1, "Set date - c -3 w" ); + + // Inline + inl = testHelper.init( "#inl" ); + date1 = new Date( 2008, 6 - 1, 4 ); + date2 = new Date(); + testHelper.equalsDate( assert, inl.datepicker( "getDate" ), date2, "Set date inline - default" ); + inl.datepicker( "setDate", date1 ); + testHelper.equalsDate( assert, inl.datepicker( "getDate" ), date1, "Set date inline - 2008-06-04" ); + date1 = new Date(); + date1.setDate( date1.getDate() + 7 ); + inl.datepicker( "setDate", +7 ); + testHelper.equalsDate( assert, inl.datepicker( "getDate" ), date1, "Set date inline - +7" ); + date2.setFullYear( date2.getFullYear() + 2 ); + inl.datepicker( "setDate", "+2y" ); + testHelper.equalsDate( assert, inl.datepicker( "getDate" ), date2, "Set date inline - +2y" ); + inl.datepicker( "setDate", date1, date2 ); + testHelper.equalsDate( assert, inl.datepicker( "getDate" ), date1, "Set date inline - two dates" ); + inl.datepicker( "setDate" ); + assert.ok( inl.datepicker( "getDate" ) == null, "Set date inline - null" ); + + // Alternate field + alt = $( "#alt" ); + inp.datepicker( "option", { altField: "#alt", altFormat: "yy-mm-dd" } ); + date1 = new Date( 2008, 6 - 1, 4 ); + inp.datepicker( "setDate", date1 ); + assert.equal( inp.val(), "06/04/2008", "Set date alternate - 06/04/2008" ); + assert.equal( alt.val(), "2008-06-04", "Set date alternate - 2008-06-04" ); + + // With minimum/maximum + inp = testHelper.init( "#inp" ); + date1 = new Date( 2008, 1 - 1, 4 ); + date2 = new Date( 2008, 6 - 1, 4 ); + minDate = new Date( 2008, 2 - 1, 29 ); + maxDate = new Date( 2008, 3 - 1, 28 ); + inp.val( "" ).datepicker( "option", { minDate: minDate } ).datepicker( "setDate", date2 ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), date2, "Set date min/max - setDate > min" ); + inp.datepicker( "setDate", date1 ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), minDate, "Set date min/max - setDate < min" ); + inp.val( "" ).datepicker( "option", { maxDate: maxDate, minDate: null } ).datepicker( "setDate", date1 ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), date1, "Set date min/max - setDate < max" ); + inp.datepicker( "setDate", date2 ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), maxDate, "Set date min/max - setDate > max" ); + inp.val( "" ).datepicker( "option", { minDate: minDate } ).datepicker( "setDate", date1 ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), minDate, "Set date min/max - setDate < min" ); + inp.datepicker( "setDate", date2 ); + testHelper.equalsDate( assert, inp.datepicker( "getDate" ), maxDate, "Set date min/max - setDate > max" ); + dateAndTimeToSet = new Date( 2008, 3 - 1, 28, 1, 11, 0 ); + dateAndTimeClone = new Date( 2008, 3 - 1, 28, 1, 11, 0 ); + inp.datepicker( "setDate", dateAndTimeToSet ); + assert.equal( dateAndTimeToSet.getTime(), dateAndTimeClone.getTime(), "Date object passed should not be changed by setDate" ); +} ); + +QUnit.test( "altField", function( assert ) { + assert.expect( 11 ); + + var done = assert.async(), + inp = testHelper.init( "#inp" ), + alt = $( "#alt" ); + + // No alternate field set + alt.val( "" ); + inp.val( "06/04/2008" ).datepicker( "show" ); + inp.simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + assert.equal( inp.val(), "06/04/2008", "Alt field - dp - enter" ); + assert.equal( alt.val(), "", "Alt field - alt not set" ); + + // Alternate field set + alt.val( "" ); + inp.datepicker( "option", { altField: "#alt", altFormat: "yy-mm-dd" } ). + val( "06/04/2008" ).datepicker( "show" ); + inp.simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + assert.equal( inp.val(), "06/04/2008", "Alt field - dp - enter" ); + assert.equal( alt.val(), "2008-06-04", "Alt field - alt - enter" ); + + // Move from initial date + alt.val( "" ); + inp.val( "06/04/2008" ).datepicker( "show" ); + inp.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_DOWN } ). + simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + assert.equal( inp.val(), "07/04/2008", "Alt field - dp - pgdn" ); + assert.equal( alt.val(), "2008-07-04", "Alt field - alt - pgdn" ); + + // Alternate field set - closed + alt.val( "" ); + inp.val( "06/04/2008" ).datepicker( "show" ); + inp.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_DOWN } ). + simulate( "keydown", { keyCode: $.ui.keyCode.ESCAPE } ); + assert.equal( inp.val(), "06/04/2008", "Alt field - dp - pgdn/esc" ); + assert.equal( alt.val(), "", "Alt field - alt - pgdn/esc" ); + + // Clear date and alternate + alt.val( "" ); + inp.val( "06/04/2008" ).datepicker( "show" ); + inp.simulate( "keydown", { ctrlKey: true, keyCode: $.ui.keyCode.END } ); + assert.equal( inp.val(), "", "Alt field - dp - ctrl+end" ); + assert.equal( alt.val(), "", "Alt field - alt - ctrl+end" ); + + // HTML instead of selector + alt.val( "" ); + try { + inp.datepicker( "option", { + altField: "", + altFormat: "yy-mm-dd" + } ).val( "06/04/2008" ).datepicker( "show" ); + inp.simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + } catch ( e ) {} + + setTimeout( function() { + assert.equal( window.globalAltField, undefined, "altField treated as a selector" ); + delete window.globalAltField; + done(); + }, 500 ); +} ); + +QUnit.test( "autoSize", function( assert ) { + assert.expect( 15 ); + var inp = testHelper.init( "#inp" ); + assert.equal( inp.prop( "size" ), 20, "Auto size - default" ); + inp.datepicker( "option", "autoSize", true ); + assert.equal( inp.prop( "size" ), 10, "Auto size - mm/dd/yy" ); + inp.datepicker( "option", "dateFormat", "m/d/yy" ); + assert.equal( inp.prop( "size" ), 10, "Auto size - m/d/yy" ); + inp.datepicker( "option", "dateFormat", "D M d yy" ); + assert.equal( inp.prop( "size" ), 15, "Auto size - D M d yy" ); + inp.datepicker( "option", "dateFormat", "DD, MM dd, yy" ); + assert.equal( inp.prop( "size" ), 29, "Auto size - DD, MM dd, yy" ); + + // French + inp.datepicker( "option", $.extend( { autoSize: false }, $.datepicker.regional.fr ) ); + assert.equal( inp.prop( "size" ), 29, "Auto size - fr - default" ); + inp.datepicker( "option", "autoSize", true ); + assert.equal( inp.prop( "size" ), 10, "Auto size - fr - dd/mm/yy" ); + inp.datepicker( "option", "dateFormat", "m/d/yy" ); + assert.equal( inp.prop( "size" ), 10, "Auto size - fr - m/d/yy" ); + inp.datepicker( "option", "dateFormat", "D M d yy" ); + assert.equal( inp.prop( "size" ), 18, "Auto size - fr - D M d yy" ); + inp.datepicker( "option", "dateFormat", "DD, MM dd, yy" ); + assert.equal( inp.prop( "size" ), 28, "Auto size - fr - DD, MM dd, yy" ); + + // Hebrew + inp.datepicker( "option", $.extend( { autoSize: false }, $.datepicker.regional.he ) ); + assert.equal( inp.prop( "size" ), 28, "Auto size - he - default" ); + inp.datepicker( "option", "autoSize", true ); + assert.equal( inp.prop( "size" ), 10, "Auto size - he - dd/mm/yy" ); + inp.datepicker( "option", "dateFormat", "m/d/yy" ); + assert.equal( inp.prop( "size" ), 10, "Auto size - he - m/d/yy" ); + inp.datepicker( "option", "dateFormat", "D M d yy" ); + assert.equal( inp.prop( "size" ), 16, "Auto size - he - D M d yy" ); + inp.datepicker( "option", "dateFormat", "DD, MM dd, yy" ); + assert.equal( inp.prop( "size" ), 23, "Auto size - he - DD, MM dd, yy" ); +} ); + +QUnit.test( "daylightSaving", function( assert ) { + assert.expect( 25 ); + var inp = testHelper.init( "#inp" ), + dp = $( "#ui-datepicker-div" ); + assert.ok( true, "Daylight saving - " + new Date() ); + + // Australia, Sydney - AM change, southern hemisphere + inp.val( "04/01/2008" ).datepicker( "show" ); + $( ".ui-datepicker-calendar td", dp ).eq( 6 ).find( "a" ).simulate( "click" ); + assert.equal( inp.val(), "04/05/2008", "Daylight saving - Australia 04/05/2008" ); + inp.val( "04/01/2008" ).datepicker( "show" ); + $( ".ui-datepicker-calendar td", dp ).eq( 7 ).find( "a" ).simulate( "click" ); + assert.equal( inp.val(), "04/06/2008", "Daylight saving - Australia 04/06/2008" ); + inp.val( "04/01/2008" ).datepicker( "show" ); + $( ".ui-datepicker-calendar td", dp ).eq( 8 ).find( "a" ).simulate( "click" ); + assert.equal( inp.val(), "04/07/2008", "Daylight saving - Australia 04/07/2008" ); + inp.val( "10/01/2008" ).datepicker( "show" ); + $( ".ui-datepicker-calendar td", dp ).eq( 6 ).find( "a" ).simulate( "click" ); + assert.equal( inp.val(), "10/04/2008", "Daylight saving - Australia 10/04/2008" ); + inp.val( "10/01/2008" ).datepicker( "show" ); + $( ".ui-datepicker-calendar td", dp ).eq( 7 ).find( "a" ).simulate( "click" ); + assert.equal( inp.val(), "10/05/2008", "Daylight saving - Australia 10/05/2008" ); + inp.val( "10/01/2008" ).datepicker( "show" ); + $( ".ui-datepicker-calendar td", dp ).eq( 8 ).find( "a" ).simulate( "click" ); + assert.equal( inp.val(), "10/06/2008", "Daylight saving - Australia 10/06/2008" ); + + // Brasil, Brasilia - midnight change, southern hemisphere + inp.val( "02/01/2008" ).datepicker( "show" ); + $( ".ui-datepicker-calendar td", dp ).eq( 20 ).find( "a" ).simulate( "click" ); + assert.equal( inp.val(), "02/16/2008", "Daylight saving - Brasil 02/16/2008" ); + inp.val( "02/01/2008" ).datepicker( "show" ); + $( ".ui-datepicker-calendar td", dp ).eq( 21 ).find( "a" ).simulate( "click" ); + assert.equal( inp.val(), "02/17/2008", "Daylight saving - Brasil 02/17/2008" ); + inp.val( "02/01/2008" ).datepicker( "show" ); + $( ".ui-datepicker-calendar td", dp ).eq( 22 ).find( "a" ).simulate( "click" ); + assert.equal( inp.val(), "02/18/2008", "Daylight saving - Brasil 02/18/2008" ); + inp.val( "10/01/2008" ).datepicker( "show" ); + $( ".ui-datepicker-calendar td", dp ).eq( 13 ).find( "a" ).simulate( "click" ); + assert.equal( inp.val(), "10/11/2008", "Daylight saving - Brasil 10/11/2008" ); + inp.val( "10/01/2008" ).datepicker( "show" ); + $( ".ui-datepicker-calendar td", dp ).eq( 14 ).find( "a" ).simulate( "click" ); + assert.equal( inp.val(), "10/12/2008", "Daylight saving - Brasil 10/12/2008" ); + inp.val( "10/01/2008" ).datepicker( "show" ); + $( ".ui-datepicker-calendar td", dp ).eq( 15 ).find( "a" ).simulate( "click" ); + assert.equal( inp.val(), "10/13/2008", "Daylight saving - Brasil 10/13/2008" ); + + // Lebanon, Beirut - midnight change, northern hemisphere + inp.val( "03/01/2008" ).datepicker( "show" ); + $( ".ui-datepicker-calendar td", dp ).eq( 34 ).find( "a" ).simulate( "click" ); + assert.equal( inp.val(), "03/29/2008", "Daylight saving - Lebanon 03/29/2008" ); + inp.val( "03/01/2008" ).datepicker( "show" ); + $( ".ui-datepicker-calendar td", dp ).eq( 35 ).find( "a" ).simulate( "click" ); + assert.equal( inp.val(), "03/30/2008", "Daylight saving - Lebanon 03/30/2008" ); + inp.val( "03/01/2008" ).datepicker( "show" ); + $( ".ui-datepicker-calendar td", dp ).eq( 36 ).find( "a" ).simulate( "click" ); + assert.equal( inp.val(), "03/31/2008", "Daylight saving - Lebanon 03/31/2008" ); + inp.val( "10/01/2008" ).datepicker( "show" ); + $( ".ui-datepicker-calendar td", dp ).eq( 27 ).find( "a" ).simulate( "click" ); + assert.equal( inp.val(), "10/25/2008", "Daylight saving - Lebanon 10/25/2008" ); + inp.val( "10/01/2008" ).datepicker( "show" ); + $( ".ui-datepicker-calendar td", dp ).eq( 28 ).find( "a" ).simulate( "click" ); + assert.equal( inp.val(), "10/26/2008", "Daylight saving - Lebanon 10/26/2008" ); + inp.val( "10/01/2008" ).datepicker( "show" ); + $( ".ui-datepicker-calendar td", dp ).eq( 29 ).find( "a" ).simulate( "click" ); + assert.equal( inp.val(), "10/27/2008", "Daylight saving - Lebanon 10/27/2008" ); + + // US, Eastern - AM change, northern hemisphere + inp.val( "03/01/2008" ).datepicker( "show" ); + $( ".ui-datepicker-calendar td", dp ).eq( 13 ).find( "a" ).simulate( "click" ); + assert.equal( inp.val(), "03/08/2008", "Daylight saving - US 03/08/2008" ); + inp.val( "03/01/2008" ).datepicker( "show" ); + $( ".ui-datepicker-calendar td", dp ).eq( 14 ).find( "a" ).simulate( "click" ); + assert.equal( inp.val(), "03/09/2008", "Daylight saving - US 03/09/2008" ); + inp.val( "03/01/2008" ).datepicker( "show" ); + $( ".ui-datepicker-calendar td", dp ).eq( 15 ).find( "a" ).simulate( "click" ); + assert.equal( inp.val(), "03/10/2008", "Daylight saving - US 03/10/2008" ); + inp.val( "11/01/2008" ).datepicker( "show" ); + $( ".ui-datepicker-calendar td", dp ).eq( 6 ).find( "a" ).simulate( "click" ); + assert.equal( inp.val(), "11/01/2008", "Daylight saving - US 11/01/2008" ); + inp.val( "11/01/2008" ).datepicker( "show" ); + $( ".ui-datepicker-calendar td", dp ).eq( 7 ).find( "a" ).simulate( "click" ); + assert.equal( inp.val(), "11/02/2008", "Daylight saving - US 11/02/2008" ); + inp.val( "11/01/2008" ).datepicker( "show" ); + $( ".ui-datepicker-calendar td", dp ).eq( 8 ).find( "a" ).simulate( "click" ); + assert.equal( inp.val(), "11/03/2008", "Daylight saving - US 11/03/2008" ); +} ); + +var beforeShowThis = null, + beforeShowInput = null, + beforeShowInst = null, + beforeShowDayThis = null, + beforeShowDayOK = true, + onUpdateDatepickerThis = null, + onUpdateDatepickerInst = null; + +function beforeAll( input, inst ) { + beforeShowThis = this; + beforeShowInput = input; + beforeShowInst = inst; + return { currentText: "Current" }; +} + +function beforeDay( date ) { + beforeShowDayThis = this; + beforeShowDayOK &= ( date > new Date( 2008, 1 - 1, 26 ) && + date < new Date( 2008, 3 - 1, 6 ) ); + return [ ( date.getDate() % 2 === 0 ), ( date.getDate() % 10 === 0 ? "day10" : "" ), + ( date.getDate() % 3 === 0 ? "Divisble by 3" : "" ) ]; +} + +function onUpdateDatepicker( inst ) { + onUpdateDatepickerThis = this; + onUpdateDatepickerInst = inst; + inst.dpDiv.append( $( "
      " ).addClass( "on-update-datepicker-test" ) ); +} + +QUnit.test( "callbacks", function( assert ) { + assert.expect( 18 ); + + // Before show + var dp, day20, day21, + inp = testHelper.init( "#inp", { beforeShow: beforeAll } ), + inst = $.data( inp[ 0 ], "datepicker" ); + assert.equal( $.datepicker._get( inst, "currentText" ), "Today", "Before show - initial" ); + inp.val( "02/04/2008" ).datepicker( "show" ); + assert.equal( $.datepicker._get( inst, "currentText" ), "Current", "Before show - changed" ); + assert.ok( beforeShowThis.id === inp[ 0 ].id, "Before show - this OK" ); + assert.ok( beforeShowInput.id === inp[ 0 ].id, "Before show - input OK" ); + assert.deepEqual( beforeShowInst, inst, "Before show - inst OK" ); + inp.datepicker( "hide" ).datepicker( "destroy" ); + + // Before show day + inp = testHelper.init( "#inp", { beforeShowDay: beforeDay } ); + dp = $( "#ui-datepicker-div" ); + inp.val( "02/04/2008" ).datepicker( "show" ); + assert.ok( beforeShowDayThis.id === inp[ 0 ].id, "Before show day - this OK" ); + assert.ok( beforeShowDayOK, "Before show day - dates OK" ); + day20 = dp.find( ".ui-datepicker-calendar td:contains('20')" ); + day21 = dp.find( ".ui-datepicker-calendar td:contains('21')" ); + assert.ok( !day20.is( ".ui-datepicker-unselectable" ), "Before show day - unselectable 20" ); + assert.ok( day21.is( ".ui-datepicker-unselectable" ), "Before show day - unselectable 21" ); + assert.ok( day20.is( ".day10" ), "Before show day - CSS 20" ); + assert.ok( !day21.is( ".day10" ), "Before show day - CSS 21" ); + assert.ok( !day20.attr( "title" ), "Before show day - title 20" ); + assert.ok( day21.attr( "title" ) === "Divisble by 3", "Before show day - title 21" ); + inp.datepicker( "hide" ).datepicker( "destroy" ); + + inp = testHelper.init( "#inp", { onUpdateDatepicker: onUpdateDatepicker } ); + inst = $.data( inp[ 0 ], "datepicker" ); + dp = $( "#ui-datepicker-div" ); + inp.val( "02/04/2008" ).datepicker( "show" ); + assert.ok( onUpdateDatepickerThis.id === inp[ 0 ].id, "On update datepicker - this OK" ); + assert.deepEqual( onUpdateDatepickerInst, inst, "On update datepicker - inst OK" ); + assert.ok( dp.find( "div.on-update-datepicker-test" ).length === 1, "On update datepicker - custom element" ); + inp.datepicker( "setDate", "02/05/2008" ); + assert.ok( dp.find( "div.on-update-datepicker-test" ).length === 1, "On update datepicker - custom element after setDate" ); + inp.datepicker( "refresh" ); + assert.ok( dp.find( "div.on-update-datepicker-test" ).length === 1, "On update datepicker - custom element after refresh" ); + inp.datepicker( "hide" ).datepicker( "destroy" ); +} ); + +QUnit.test( "beforeShowDay - tooltips with quotes", function( assert ) { + assert.expect( 1 ); + var inp, dp; + inp = testHelper.init( "#inp", { + beforeShowDay: function() { + return [ true, "", "'" ]; + } + } ); + dp = $( "#ui-datepicker-div" ); + + inp.datepicker( "show" ); + assert.equal( dp.find( ".ui-datepicker-calendar td:contains('9')" ).attr( "title" ), "'" ); + inp.datepicker( "hide" ).datepicker( "destroy" ); +} ); + +QUnit.test( "localisation", function( assert ) { + assert.expect( 24 ); + var dp, month, day, date, + inp = testHelper.init( "#inp", $.datepicker.regional.fr ); + inp.datepicker( "option", { dateFormat: "DD, d MM yy", showButtonPanel: true, changeMonth: true, changeYear: true } ).val( "" ).datepicker( "show" ); + dp = $( "#ui-datepicker-div" ); + assert.equal( $( ".ui-datepicker-close", dp ).text(), "Fermer", "Localisation - close" ); + $( ".ui-datepicker-close", dp ).simulate( "mouseover" ); + assert.equal( $( ".ui-datepicker-prev", dp ).text(), "Précédent", "Localisation - previous" ); + assert.equal( $( ".ui-datepicker-current", dp ).text(), "Aujourd'hui", "Localisation - current" ); + assert.equal( $( ".ui-datepicker-next", dp ).text(), "Suivant", "Localisation - next" ); + month = 0; + $( ".ui-datepicker-month option", dp ).each( function() { + assert.equal( $( this ).text(), $.datepicker.regional.fr.monthNamesShort[ month ], + "Localisation - month " + month ); + month++; + } ); + day = 1; + $( ".ui-datepicker-calendar th", dp ).each( function() { + assert.equal( $( this ).text(), $.datepicker.regional.fr.dayNamesMin[ day ], + "Localisation - day " + day ); + day = ( day + 1 ) % 7; + } ); + inp.simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + date = new Date(); + assert.equal( inp.val(), $.datepicker.regional.fr.dayNames[ date.getDay() ] + ", " + + date.getDate() + " " + $.datepicker.regional.fr.monthNames[ date.getMonth() ] + + " " + date.getFullYear(), "Localisation - formatting" ); +} ); + +QUnit.test( "noWeekends", function( assert ) { + assert.expect( 31 ); + var i, date; + for ( i = 1; i <= 31; i++ ) { + date = new Date( 2001, 1 - 1, i ); + assert.deepEqual( $.datepicker.noWeekends( date ), [ ( i + 1 ) % 7 >= 2, "" ], + "No weekends " + date ); + } +} ); + +QUnit.test( "iso8601Week", function( assert ) { + assert.expect( 12 ); + var date = new Date( 2000, 12 - 1, 31 ); + assert.equal( $.datepicker.iso8601Week( date ), 52, "ISO 8601 week " + date ); + date = new Date( 2001, 1 - 1, 1 ); + assert.equal( $.datepicker.iso8601Week( date ), 1, "ISO 8601 week " + date ); + date = new Date( 2001, 1 - 1, 7 ); + assert.equal( $.datepicker.iso8601Week( date ), 1, "ISO 8601 week " + date ); + date = new Date( 2001, 1 - 1, 8 ); + assert.equal( $.datepicker.iso8601Week( date ), 2, "ISO 8601 week " + date ); + date = new Date( 2003, 12 - 1, 28 ); + assert.equal( $.datepicker.iso8601Week( date ), 52, "ISO 8601 week " + date ); + date = new Date( 2003, 12 - 1, 29 ); + assert.equal( $.datepicker.iso8601Week( date ), 1, "ISO 8601 week " + date ); + date = new Date( 2004, 1 - 1, 4 ); + assert.equal( $.datepicker.iso8601Week( date ), 1, "ISO 8601 week " + date ); + date = new Date( 2004, 1 - 1, 5 ); + assert.equal( $.datepicker.iso8601Week( date ), 2, "ISO 8601 week " + date ); + date = new Date( 2009, 12 - 1, 28 ); + assert.equal( $.datepicker.iso8601Week( date ), 53, "ISO 8601 week " + date ); + date = new Date( 2010, 1 - 1, 3 ); + assert.equal( $.datepicker.iso8601Week( date ), 53, "ISO 8601 week " + date ); + date = new Date( 2010, 1 - 1, 4 ); + assert.equal( $.datepicker.iso8601Week( date ), 1, "ISO 8601 week " + date ); + date = new Date( 2010, 1 - 1, 10 ); + assert.equal( $.datepicker.iso8601Week( date ), 1, "ISO 8601 week " + date ); +} ); + +QUnit.test( "parseDate", function( assert ) { + assert.expect( 26 ); + testHelper.init( "#inp" ); + var currentYear, gmtDate, fr, settings, zh; + assert.ok( $.datepicker.parseDate( "d m y", "" ) == null, "Parse date empty" ); + testHelper.equalsDate( assert, $.datepicker.parseDate( "d m y", "3 2 01" ), + new Date( 2001, 2 - 1, 3 ), "Parse date d m y" ); + testHelper.equalsDate( assert, $.datepicker.parseDate( "dd mm yy", "03 02 2001" ), + new Date( 2001, 2 - 1, 3 ), "Parse date dd mm yy" ); + testHelper.equalsDate( assert, $.datepicker.parseDate( "d m y", "13 12 01" ), + new Date( 2001, 12 - 1, 13 ), "Parse date d m y" ); + testHelper.equalsDate( assert, $.datepicker.parseDate( "dd mm yy", "13 12 2001" ), + new Date( 2001, 12 - 1, 13 ), "Parse date dd mm yy" ); + testHelper.equalsDate( assert, $.datepicker.parseDate( "y-o", "01-34" ), + new Date( 2001, 2 - 1, 3 ), "Parse date y-o" ); + testHelper.equalsDate( assert, $.datepicker.parseDate( "yy-oo", "2001-347" ), + new Date( 2001, 12 - 1, 13 ), "Parse date yy-oo" ); + testHelper.equalsDate( assert, $.datepicker.parseDate( "oo yy", "348 2004" ), + new Date( 2004, 12 - 1, 13 ), "Parse date oo yy" ); + testHelper.equalsDate( assert, $.datepicker.parseDate( "D d M y", "Sat 3 Feb 01" ), + new Date( 2001, 2 - 1, 3 ), "Parse date D d M y" ); + testHelper.equalsDate( assert, $.datepicker.parseDate( "d MM DD yy", "3 February Saturday 2001" ), + new Date( 2001, 2 - 1, 3 ), "Parse date dd MM DD yy" ); + testHelper.equalsDate( assert, $.datepicker.parseDate( "DD, MM d, yy", "Saturday, February 3, 2001" ), + new Date( 2001, 2 - 1, 3 ), "Parse date DD, MM d, yy" ); + testHelper.equalsDate( assert, $.datepicker.parseDate( "'day' d 'of' MM (''DD''), yy", + "day 3 of February ('Saturday'), 2001" ), new Date( 2001, 2 - 1, 3 ), + "Parse date 'day' d 'of' MM (''DD''), yy" ); + currentYear = new Date().getFullYear(); + testHelper.equalsDate( assert, $.datepicker.parseDate( "y-m-d", ( currentYear - 2000 ) + "-02-03" ), + new Date( currentYear, 2 - 1, 3 ), "Parse date y-m-d - default cutuff" ); + testHelper.equalsDate( assert, $.datepicker.parseDate( "y-m-d", ( currentYear - 2000 + 10 ) + "-02-03" ), + new Date( currentYear + 10, 2 - 1, 3 ), "Parse date y-m-d - default cutuff" ); + testHelper.equalsDate( assert, $.datepicker.parseDate( "y-m-d", ( currentYear - 2000 + 11 ) + "-02-03" ), + new Date( currentYear - 89, 2 - 1, 3 ), "Parse date y-m-d - default cutuff" ); + testHelper.equalsDate( assert, $.datepicker.parseDate( "y-m-d", "80-02-03", { shortYearCutoff: 80 } ), + new Date( 2080, 2 - 1, 3 ), "Parse date y-m-d - cutoff 80" ); + testHelper.equalsDate( assert, $.datepicker.parseDate( "y-m-d", "81-02-03", { shortYearCutoff: 80 } ), + new Date( 1981, 2 - 1, 3 ), "Parse date y-m-d - cutoff 80" ); + testHelper.equalsDate( assert, $.datepicker.parseDate( "y-m-d", ( currentYear - 2000 + 60 ) + "-02-03", { shortYearCutoff: "+60" } ), + new Date( currentYear + 60, 2 - 1, 3 ), "Parse date y-m-d - cutoff +60" ); + testHelper.equalsDate( assert, $.datepicker.parseDate( "y-m-d", ( currentYear - 2000 + 61 ) + "-02-03", { shortYearCutoff: "+60" } ), + new Date( currentYear - 39, 2 - 1, 3 ), "Parse date y-m-d - cutoff +60" ); + gmtDate = new Date( 2001, 2 - 1, 3 ); + gmtDate.setMinutes( gmtDate.getMinutes() - gmtDate.getTimezoneOffset() ); + testHelper.equalsDate( assert, $.datepicker.parseDate( "@", "981158400000" ), gmtDate, "Parse date @" ); + testHelper.equalsDate( assert, $.datepicker.parseDate( "!", "631167552000000000" ), gmtDate, "Parse date !" ); + + fr = $.datepicker.regional.fr; + settings = { dayNamesShort: fr.dayNamesShort, dayNames: fr.dayNames, + monthNamesShort: fr.monthNamesShort, monthNames: fr.monthNames }; + testHelper.equalsDate( assert, $.datepicker.parseDate( "D d M y", "Lun. 9 avr. 01", settings ), + new Date( 2001, 4 - 1, 9 ), "Parse date D M y with settings" ); + testHelper.equalsDate( assert, $.datepicker.parseDate( "d MM DD yy", "9 Avril Lundi 2001", settings ), + new Date( 2001, 4 - 1, 9 ), "Parse date d MM DD yy with settings" ); + testHelper.equalsDate( assert, $.datepicker.parseDate( "DD, MM d, yy", "Lundi, Avril 9, 2001", settings ), + new Date( 2001, 4 - 1, 9 ), "Parse date DD, MM d, yy with settings" ); + testHelper.equalsDate( assert, $.datepicker.parseDate( "'jour' d 'de' MM (''DD''), yy", "jour 9 de Avril ('Lundi'), 2001", settings ), + new Date( 2001, 4 - 1, 9 ), "Parse date 'jour' d 'de' MM (''DD''), yy with settings" ); + + zh = $.datepicker.regional[ "zh-CN" ]; + testHelper.equalsDate( assert, $.datepicker.parseDate( "yy M d", "2011 十一月 22", zh ), + new Date( 2011, 11 - 1, 22 ), "Parse date yy M d with zh-CN" ); +} ); + +QUnit.test( "parseDateErrors", function( assert ) { + assert.expect( 18 ); + testHelper.init( "#inp" ); + var fr, settings; + function expectError( expr, value, error ) { + try { + expr(); + assert.ok( false, "Parsed error " + value ); + } catch ( e ) { + assert.equal( e, error, "Parsed error " + value ); + } + } + expectError( function() { + $.datepicker.parseDate( null, "Sat 2 01" ); + }, + "Sat 2 01", "Invalid arguments" ); + expectError( function() { + $.datepicker.parseDate( "d m y", null ); + }, + "null", "Invalid arguments" ); + expectError( function() { + $.datepicker.parseDate( "d m y", "Sat 2 01" ); + }, + "Sat 2 01 - d m y", "Missing number at position 0" ); + expectError( function() { + $.datepicker.parseDate( "dd mm yy", "Sat 2 01" ); + }, + "Sat 2 01 - dd mm yy", "Missing number at position 0" ); + expectError( function() { + $.datepicker.parseDate( "d m y", "3 Feb 01" ); + }, + "3 Feb 01 - d m y", "Missing number at position 2" ); + expectError( function() { + $.datepicker.parseDate( "dd mm yy", "3 Feb 01" ); + }, + "3 Feb 01 - dd mm yy", "Missing number at position 2" ); + expectError( function() { + $.datepicker.parseDate( "mm dd yy", "2 1 01" ); + }, + "2 1 01 - dd mm yy", "Missing number at position 4" ); + expectError( function() { + $.datepicker.parseDate( "d m y", "3 2 AD01" ); + }, + "3 2 AD01 - d m y", "Missing number at position 4" ); + expectError( function() { + $.datepicker.parseDate( "d m yy", "3 2 AD01" ); + }, + "3 2 AD01 - dd mm yy", "Missing number at position 4" ); + expectError( function() { + $.datepicker.parseDate( "y-o", "01-D01" ); + }, + "2001-D01 - y-o", "Missing number at position 3" ); + expectError( function() { + $.datepicker.parseDate( "yy-oo", "2001-D01" ); + }, + "2001-D01 - yy-oo", "Missing number at position 5" ); + expectError( function() { + $.datepicker.parseDate( "D d M y", "D7 3 Feb 01" ); + }, + "D7 3 Feb 01 - D d M y", "Unknown name at position 0" ); + expectError( function() { + $.datepicker.parseDate( "D d M y", "Sat 3 M2 01" ); + }, + "Sat 3 M2 01 - D d M y", "Unknown name at position 6" ); + expectError( function() { + $.datepicker.parseDate( "DD, MM d, yy", "Saturday- Feb 3, 2001" ); + }, + "Saturday- Feb 3, 2001 - DD, MM d, yy", "Unexpected literal at position 8" ); + expectError( function() { + $.datepicker.parseDate( "'day' d 'of' MM (''DD''), yy", + "day 3 of February (\"Saturday\"), 2001" ); + }, + "day 3 of Mon2 ('Day7'), 2001", "Unexpected literal at position 19" ); + expectError( function() { + $.datepicker.parseDate( "d m y", "29 2 01" ); + }, + "29 2 01 - d m y", "Invalid date" ); + fr = $.datepicker.regional.fr; + settings = { dayNamesShort: fr.dayNamesShort, dayNames: fr.dayNames, + monthNamesShort: fr.monthNamesShort, monthNames: fr.monthNames }; + expectError( function() { + $.datepicker.parseDate( "D d M y", "Mon 9 Avr 01", settings ); + }, + "Mon 9 Avr 01 - D d M y", "Unknown name at position 0" ); + expectError( function() { + $.datepicker.parseDate( "D d M y", "Lun. 9 Apr 01", settings ); + }, + "Lun. 9 Apr 01 - D d M y", "Unknown name at position 7" ); +} ); + +QUnit.test( "Ticket #7244: date parser does not fail when too many numbers are passed into the date function", function( assert ) { + assert.expect( 4 ); + var date; + try { + date = $.datepicker.parseDate( "dd/mm/yy", "18/04/19881" ); + assert.ok( false, "Did not properly detect an invalid date" ); + } catch ( e ) { + assert.ok( "invalid date detected" ); + } + + try { + date = $.datepicker.parseDate( "dd/mm/yy", "18/04/1988 @ 2:43 pm" ); + assert.equal( date.getDate(), 18 ); + assert.equal( date.getMonth(), 3 ); + assert.equal( date.getFullYear(), 1988 ); + } catch ( e ) { + assert.ok( false, "Did not properly parse date with extra text separated by whitespace" ); + } +} ); + +QUnit.test( "formatDate", function( assert ) { + assert.expect( 16 ); + testHelper.init( "#inp" ); + var gmtDate, fr, settings; + assert.equal( $.datepicker.formatDate( "d m y", new Date( 2001, 2 - 1, 3 ) ), + "3 2 01", "Format date d m y" ); + assert.equal( $.datepicker.formatDate( "dd mm yy", new Date( 2001, 2 - 1, 3 ) ), + "03 02 2001", "Format date dd mm yy" ); + assert.equal( $.datepicker.formatDate( "d m y", new Date( 2001, 12 - 1, 13 ) ), + "13 12 01", "Format date d m y" ); + assert.equal( $.datepicker.formatDate( "dd mm yy", new Date( 2001, 12 - 1, 13 ) ), + "13 12 2001", "Format date dd mm yy" ); + assert.equal( $.datepicker.formatDate( "yy-o", new Date( 2001, 2 - 1, 3 ) ), + "2001-34", "Format date yy-o" ); + assert.equal( $.datepicker.formatDate( "yy-oo", new Date( 2001, 2 - 1, 3 ) ), + "2001-034", "Format date yy-oo" ); + assert.equal( $.datepicker.formatDate( "D M y", new Date( 2001, 2 - 1, 3 ) ), + "Sat Feb 01", "Format date D M y" ); + assert.equal( $.datepicker.formatDate( "DD MM yy", new Date( 2001, 2 - 1, 3 ) ), + "Saturday February 2001", "Format date DD MM yy" ); + assert.equal( $.datepicker.formatDate( "DD, MM d, yy", new Date( 2001, 2 - 1, 3 ) ), + "Saturday, February 3, 2001", "Format date DD, MM d, yy" ); + assert.equal( $.datepicker.formatDate( "'day' d 'of' MM (''DD''), yy", + new Date( 2001, 2 - 1, 3 ) ), "day 3 of February ('Saturday'), 2001", + "Format date 'day' d 'of' MM ('DD'), yy" ); + gmtDate = new Date( 2001, 2 - 1, 3 ); + gmtDate.setMinutes( gmtDate.getMinutes() - gmtDate.getTimezoneOffset() ); + assert.equal( $.datepicker.formatDate( "@", gmtDate ), "981158400000", "Format date @" ); + assert.equal( $.datepicker.formatDate( "!", gmtDate ), "631167552000000000", "Format date !" ); + fr = $.datepicker.regional.fr; + settings = { dayNamesShort: fr.dayNamesShort, dayNames: fr.dayNames, + monthNamesShort: fr.monthNamesShort, monthNames: fr.monthNames }; + assert.equal( $.datepicker.formatDate( "D M y", new Date( 2001, 4 - 1, 9 ), settings ), + "lun. avr. 01", "Format date D M y with settings" ); + assert.equal( $.datepicker.formatDate( "DD MM yy", new Date( 2001, 4 - 1, 9 ), settings ), + "lundi avril 2001", "Format date DD MM yy with settings" ); + assert.equal( $.datepicker.formatDate( "DD, MM d, yy", new Date( 2001, 4 - 1, 9 ), settings ), + "lundi, avril 9, 2001", "Format date DD, MM d, yy with settings" ); + assert.equal( $.datepicker.formatDate( "'jour' d 'de' MM (''DD''), yy", + new Date( 2001, 4 - 1, 9 ), settings ), "jour 9 de avril ('lundi'), 2001", + "Format date 'jour' d 'de' MM (''DD''), yy with settings" ); +} ); + +// TODO: Fix this test so it isn't mysteriously flaky in Browserstack on certain OS/Browser combos +// test("Ticket 6827: formatDate day of year calculation is wrong during day lights savings time", function(){ +// expect( 1 ); +// var time = $.datepicker.formatDate("oo", new Date("2010/03/30 12:00:00 CDT")); +// equal(time, "089"); +// }); + +QUnit.test( "Ticket 7602: Stop datepicker from appearing with beforeShow event handler", function( assert ) { + assert.expect( 3 ); + + var inp, dp; + + inp = testHelper.init( "#inp", { + beforeShow: function() { + } + } ); + dp = $( "#ui-datepicker-div" ); + inp.datepicker( "show" ); + assert.equal( dp.css( "display" ), "block", "beforeShow returns nothing" ); + inp.datepicker( "hide" ).datepicker( "destroy" ); + + inp = testHelper.init( "#inp", { + beforeShow: function() { + return true; + } + } ); + dp = $( "#ui-datepicker-div" ); + inp.datepicker( "show" ); + assert.equal( dp.css( "display" ), "block", "beforeShow returns true" ); + inp.datepicker( "hide" ); + inp.datepicker( "destroy" ); + + inp = testHelper.init( "#inp", { + beforeShow: function() { + return false; + } + } ); + dp = $( "#ui-datepicker-div" ); + inp.datepicker( "show" ); + assert.equal( dp.css( "display" ), "none", "beforeShow returns false" ); + inp.datepicker( "destroy" ); +} ); + +QUnit.test( "Ticket #15284: escaping text parameters", function( assert ) { + assert.expect( 7 ); + + var done = assert.async(); + + var qf = $( "#qunit-fixture" ); + + window.uiGlobalXss = []; + + var inp = testHelper.init( "#inp", { + showButtonPanel: true, + showOn: "both", + prevText: "", + nextText: "", + currentText: "", + closeText: "", + buttonText: "", + appendText: "" + } ); + + var dp = $( "#ui-datepicker-div" ); + + testHelper.onFocus( inp, function() { + assert.equal( dp.find( ".ui-datepicker-prev" ).text().trim(), + "", + "prevText escaped" ); + assert.equal( dp.find( ".ui-datepicker-next" ).text().trim(), + "", + "nextText escaped" ); + assert.equal( dp.find( ".ui-datepicker-current" ).text().trim(), + "", + "currentText escaped" ); + assert.equal( dp.find( ".ui-datepicker-close" ).text().trim(), + "", + "closeText escaped" ); + + assert.equal( qf.find( ".ui-datepicker-trigger" ).text().trim(), + "", + "buttonText escaped" ); + assert.equal( qf.find( ".ui-datepicker-append" ).text().trim(), + "", + "appendText escaped" ); + + assert.deepEqual( window.uiGlobalXss, [], "No XSS" ); + + delete window.uiGlobalXss; + inp.datepicker( "hide" ).datepicker( "destroy" ); + done(); + } ); +} ); + +} ); diff --git a/tests/unit/defaults.html b/tests/unit/defaults.html deleted file mode 100644 index 48461cd064a..00000000000 --- a/tests/unit/defaults.html +++ /dev/null @@ -1,56 +0,0 @@ - - - - - jQuery UI Defaults - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

      -

      -

      -
        -
      - -
      - -
      - - - diff --git a/tests/unit/dialog/all.html b/tests/unit/dialog/all.html new file mode 100644 index 00000000000..059398995dd --- /dev/null +++ b/tests/unit/dialog/all.html @@ -0,0 +1,26 @@ + + + + + jQuery UI Dialog Test Suite + + + + + + + + + + + + + +
      +
      + +
      + + diff --git a/tests/unit/dialog/common-deprecated.js b/tests/unit/dialog/common-deprecated.js new file mode 100644 index 00000000000..2cdae9681d8 --- /dev/null +++ b/tests/unit/dialog/common-deprecated.js @@ -0,0 +1,55 @@ +define( [ + "lib/common", + "ui/widgets/dialog" +], function( common ) { + +common.testWidget( "dialog", { + defaults: { + appendTo: "body", + autoOpen: true, + buttons: [], + classes: { + "ui-dialog": "ui-corner-all", + "ui-dialog-titlebar": "ui-corner-all" + }, + closeOnEscape: true, + closeText: "Close", + dialogClass: "", + disabled: false, + draggable: true, + height: "auto", + hide: null, + maxHeight: null, + maxWidth: null, + minHeight: 150, + minWidth: 150, + modal: false, + position: { + my: "center", + at: "center", + of: window, + collision: "fit", + using: $.ui.dialog.prototype.options.position.using + }, + resizable: true, + show: null, + title: null, + uiDialogTitleHeadingLevel: 0, + width: 300, + + // Callbacks + beforeClose: null, + close: null, + create: null, + drag: null, + dragStart: null, + dragStop: null, + focus: null, + open: null, + resize: null, + resizeStart: null, + resizeStop: null + } +} ); + +} ); diff --git a/tests/unit/dialog/common.js b/tests/unit/dialog/common.js new file mode 100644 index 00000000000..f3118104760 --- /dev/null +++ b/tests/unit/dialog/common.js @@ -0,0 +1,54 @@ +define( [ + "lib/common", + "ui/widgets/dialog" +], function( common ) { + +common.testWidget( "dialog", { + defaults: { + appendTo: "body", + autoOpen: true, + buttons: [], + classes: { + "ui-dialog": "ui-corner-all", + "ui-dialog-titlebar": "ui-corner-all" + }, + closeOnEscape: true, + closeText: "Close", + disabled: false, + draggable: true, + height: "auto", + hide: null, + maxHeight: null, + maxWidth: null, + minHeight: 150, + minWidth: 150, + modal: false, + position: { + my: "center", + at: "center", + of: window, + collision: "fit", + using: $.ui.dialog.prototype.options.position.using + }, + resizable: true, + show: null, + title: null, + uiDialogTitleHeadingLevel: 0, + width: 300, + + // Callbacks + beforeClose: null, + close: null, + create: null, + drag: null, + dragStart: null, + dragStop: null, + focus: null, + open: null, + resize: null, + resizeStart: null, + resizeStop: null + } +} ); + +} ); diff --git a/tests/unit/dialog/core.js b/tests/unit/dialog/core.js new file mode 100644 index 00000000000..a8cc9678e53 --- /dev/null +++ b/tests/unit/dialog/core.js @@ -0,0 +1,379 @@ +define( [ + "qunit", + "jquery", + "lib/helper", + "ui/widgets/dialog" +], function( QUnit, $, helper ) { +"use strict"; + +// TODO add afterEach callback to remove dialogs +QUnit.module( "dialog: core", { afterEach: helper.moduleAfterEach } ); + +QUnit.test( "markup structure", function( assert ) { + assert.expect( 11 ); + + var element = $( "
      " ).dialog( { + buttons: [ { + text: "Ok", + click: $.noop + } ] + } ), + widget = element.dialog( "widget" ), + titlebar = widget.find( ".ui-dialog-titlebar" ), + title = titlebar.find( ".ui-dialog-title" ), + close = titlebar.find( ".ui-dialog-titlebar-close" ), + buttonpane = widget.find( ".ui-dialog-buttonpane" ), + buttonset = widget.find( ".ui-dialog-buttonset" ), + buttons = buttonset.find( ".ui-button" ); + + assert.hasClasses( widget, "ui-dialog ui-dialog-buttons ui-widget ui-widget-content" ); + assert.hasClasses( titlebar, "ui-dialog-titlebar ui-widget-header" ); + assert.equal( titlebar.length, 1, "Dialog has exactly one titlebar" ); + assert.hasClasses( close, "ui-dialog-titlebar-close ui-widget" ); + assert.equal( close.length, 1, "Titlebar has exactly one close button" ); + assert.equal( title.length, 1, "Titlebar has exactly one title" ); + assert.hasClasses( element, "ui-dialog-content ui-widget-content" ); + assert.hasClasses( buttonpane, "ui-dialog-buttonpane ui-widget-content" ); + assert.equal( buttonpane.length, 1, "Dialog has exactly one buttonpane" ); + assert.equal( buttonset.length, 1, "Buttonpane has exactly one buttonset" ); + assert.equal( buttons.length, 1, "Buttonset contains exactly 1 button when created with 1" ); + +} ); + +QUnit.test( "markup structure - no buttons", function( assert ) { + assert.expect( 7 ); + + var element = $( "
      " ).dialog(), + widget = element.dialog( "widget" ), + titlebar = widget.find( ".ui-dialog-titlebar" ), + title = titlebar.find( ".ui-dialog-title" ), + close = titlebar.find( ".ui-dialog-titlebar-close" ); + + assert.hasClasses( widget, "ui-dialog ui-widget ui-widget-content" ); + assert.hasClasses( titlebar, "ui-dialog-titlebar ui-widget-header" ); + assert.equal( titlebar.length, 1, "Dialog has exactly one titlebar" ); + assert.hasClasses( close, "ui-dialog-titlebar-close ui-widget" ); + assert.equal( close.length, 1, "Titlebar has exactly one close button" ); + assert.equal( title.length, 1, "Titlebar has exactly one title" ); + assert.hasClasses( element, "ui-dialog-content ui-widget-content" ); +} ); + +QUnit.test( "title id", function( assert ) { + assert.expect( 1 ); + + var titleId, + element = $( "
      " ).dialog(); + + titleId = element.dialog( "widget" ).find( ".ui-dialog-title" ).attr( "id" ); + assert.ok( /ui-id-\d+$/.test( titleId ), "auto-numbered title id" ); + element.remove(); +} ); + +QUnit.test( "ARIA", function( assert ) { + assert.expect( 4 ); + + var element = $( "
      " ).dialog(), + wrapper = element.dialog( "widget" ); + assert.equal( wrapper.attr( "role" ), "dialog", "dialog role" ); + assert.equal( wrapper.attr( "aria-labelledby" ), wrapper.find( ".ui-dialog-title" ).attr( "id" ) ); + assert.equal( wrapper.attr( "aria-describedby" ), element.attr( "id" ), "aria-describedby added" ); + element.remove(); + + element = $( "

      descriotion

      " ).dialog(); + assert.equal( element.dialog( "widget" ).attr( "aria-describedby" ), null, "no aria-describedby added, as already present in markup" ); + element.remove(); +} ); + +QUnit.test( "aria-modal", function( assert ) { + assert.expect( 9 ); + + var element, wrapper; + + element = $( "
      " ).dialog( { modal: true } ); + wrapper = element.dialog( "widget" ); + assert.equal( wrapper.attr( "aria-modal" ), "true", "modal option set to true, aria-modal attribute added" ); + element.dialog( "option", "modal", false ); + assert.equal( wrapper.attr( "aria-modal" ), undefined, "modal option set to false, aria-modal attribute not added" ); + element.dialog( "option", "modal", true ); + assert.equal( wrapper.attr( "aria-modal" ), "true", "modal option set to true, aria-modal attribute added" ); + element.remove(); + + element = $( "
      " ).dialog( { modal: false } ); + wrapper = element.dialog( "widget" ); + assert.equal( wrapper.attr( "aria-modal" ), undefined, "modal option set to false, aria-modal attribute not added" ); + element.dialog( "option", "modal", true ); + assert.equal( wrapper.attr( "aria-modal" ), "true", "modal option set to true, aria-modal attribute added" ); + element.dialog( "option", "modal", false ); + assert.equal( wrapper.attr( "aria-modal" ), undefined, "modal option set to false, aria-modal attribute not added" ); + element.remove(); + + element = $( "
      " ).dialog(); + wrapper = element.dialog( "widget" ); + assert.equal( wrapper.attr( "aria-modal" ), undefined, "modal option not set, aria-modal attribute not added" ); + element.dialog( "option", "modal", true ); + assert.equal( wrapper.attr( "aria-modal" ), "true", "modal option set to true, aria-modal attribute added" ); + element.dialog( "option", "modal", false ); + assert.equal( wrapper.attr( "aria-modal" ), undefined, "modal option set to false, aria-modal attribute not added" ); + element.remove(); +} ); + +QUnit.test( "ui dialog title heading level", function( assert ) { + assert.expect( 8 ); + + var element, nodeName; + + element = $( "
      " ).dialog( { modal: true } ); + nodeName = element.dialog( "widget" ).find( ".ui-dialog-title" ).get( 0 ).nodeName.toLowerCase(); + assert.equal( nodeName, "span", "Element wrapping the dialog title is span" ); + + element = $( "
      " ).dialog( { modal: true, uiDialogTitleHeadingLevel: 0 } ); + nodeName = element.dialog( "widget" ).find( ".ui-dialog-title" ).get( 0 ).nodeName.toLowerCase(); + assert.equal( nodeName, "span", "Element wrapping the dialog title is span" ); + + element = $( "
      " ).dialog( { modal: true, uiDialogTitleHeadingLevel: 1 } ); + nodeName = element.dialog( "widget" ).find( ".ui-dialog-title" ).get( 0 ).nodeName.toLowerCase(); + assert.equal( nodeName, "h1", "Element wrapping the dialog title is h1" ); + + element = $( "
      " ).dialog( { modal: true, uiDialogTitleHeadingLevel: 6 } ); + nodeName = element.dialog( "widget" ).find( ".ui-dialog-title" ).get( 0 ).nodeName.toLowerCase(); + assert.equal( nodeName, "h6", "Element wrapping the dialog title is h6" ); + + element = $( "
      " ).dialog( { modal: true, uiDialogTitleHeadingLevel: 9 } ); + nodeName = element.dialog( "widget" ).find( ".ui-dialog-title" ).get( 0 ).nodeName.toLowerCase(); + assert.equal( nodeName, "span", "Element wrapping the dialog title is span" ); + + element = $( "
      " ).dialog( { modal: true, uiDialogTitleHeadingLevel: -9 } ); + nodeName = element.dialog( "widget" ).find( ".ui-dialog-title" ).get( 0 ).nodeName.toLowerCase(); + assert.equal( nodeName, "span", "Element wrapping the dialog title is span" ); + + element = $( "
      " ).dialog( { modal: true, uiDialogTitleHeadingLevel: 2.3 } ); + nodeName = element.dialog( "widget" ).find( ".ui-dialog-title" ).get( 0 ).nodeName.toLowerCase(); + assert.equal( nodeName, "span", "Element wrapping the dialog title is span" ); + + element = $( "
      " ).dialog( { modal: true, uiDialogTitleHeadingLevel: "foo" } ); + nodeName = element.dialog( "widget" ).find( ".ui-dialog-title" ).get( 0 ).nodeName.toLowerCase(); + assert.equal( nodeName, "span", "Element wrapping the dialog title is span" ); +} ); + +QUnit.test( "widget method", function( assert ) { + assert.expect( 1 ); + var dialog = $( "
      " ).appendTo( "#qunit-fixture" ).dialog(); + assert.deepEqual( dialog.parent()[ 0 ], dialog.dialog( "widget" )[ 0 ] ); + dialog.remove(); +} ); + +QUnit.test( "focus tabbable", function( assert ) { + var ready = assert.async(); + assert.expect( 8 ); + var element, + options = { + buttons: [ { + text: "Ok", + click: $.noop + } ] + }; + + function checkFocus( markup, options, testFn, next ) { + element = $( markup ).dialog( options ); + setTimeout( function() { + testFn( function done() { + element.remove(); + setTimeout( next ); + } ); + } ); + } + + function step1() { + checkFocus( "
      ", options, function( done ) { + var input = element.find( "input" ).last().trigger( "focus" ).trigger( "blur" ); + + element.dialog( "instance" )._focusTabbable(); + setTimeout( function() { + assert.equal( document.activeElement, input[ 0 ], + "1. an element that was focused previously." ); + done(); + } ); + }, step2 ); + } + + function step2() { + checkFocus( "
      ", options, function( done ) { + assert.equal( document.activeElement, element.find( "input" )[ 1 ], + "2. first element inside the dialog matching [autofocus]" ); + done(); + }, step3 ); + } + + function step3() { + checkFocus( "
      ", options, function( done ) { + assert.equal( document.activeElement, element.find( "input" )[ 0 ], + "3. tabbable element inside the content element" ); + done(); + }, step4 ); + } + + function step4() { + checkFocus( "
      text
      ", options, function( done ) { + assert.equal( document.activeElement, + element.dialog( "widget" ).find( ".ui-dialog-buttonpane button" )[ 0 ], + "4. tabbable element inside the buttonpane" ); + done(); + }, step5 ); + } + + function step5() { + checkFocus( "
      text
      ", {}, function( done ) { + assert.equal( document.activeElement, + element.dialog( "widget" ).find( ".ui-dialog-titlebar .ui-dialog-titlebar-close" )[ 0 ], + "5. the close button" ); + done(); + }, step6 ); + } + + function step6() { + checkFocus( "
      text
      ", { autoOpen: false }, function( done ) { + element.dialog( "widget" ).find( ".ui-dialog-titlebar-close" ).hide(); + element.dialog( "open" ); + setTimeout( function() { + assert.equal( document.activeElement, element.parent()[ 0 ], "6. the dialog itself" ); + done(); + } ); + }, step7 ); + } + + function step7() { + checkFocus( + "
      ", + { + open: function() { + var inputs = $( this ).find( "input" ); + inputs.last().on( "keydown", function( event ) { + event.preventDefault(); + inputs.first().trigger( "focus" ); + } ); + } + }, + function( done ) { + var inputs = element.find( "input" + ); + assert.equal( document.activeElement, inputs[ 1 ], "Focus starts on second input" ); + inputs.last().simulate( "keydown", { keyCode: $.ui.keyCode.TAB } ); + setTimeout( function() { + assert.equal( document.activeElement, inputs[ 0 ], + "Honor preventDefault, allowing custom focus management" ); + done(); + }, 50 ); + }, + ready + ); + } + + step1(); +} ); + +QUnit.test( "#7960: resizable handles below modal overlays", function( assert ) { + assert.expect( 1 ); + + var resizable = $( "
      " ).resizable(), + dialog = $( "
      " ).dialog( { modal: true } ), + resizableZindex = parseInt( resizable.find( ".ui-resizable-handle" ).css( "zIndex" ), 10 ), + overlayZindex = parseInt( $( ".ui-widget-overlay" ).css( "zIndex" ), 10 ); + + assert.ok( resizableZindex < overlayZindex, "Resizable handles have lower z-index than modal overlay" ); + dialog.dialog( "destroy" ); +} ); + +QUnit.test( "Prevent tabbing out of dialogs", function( assert ) { + var ready = assert.async(); + assert.expect( 3 ); + + var element = $( "
      " ).dialog(), + inputs = element.find( "input" ); + + // Remove close button to test focus on just the two buttons + element.dialog( "widget" ).find( ".ui-button" ).remove(); + + function checkTab() { + assert.equal( document.activeElement, inputs[ 0 ], "Tab key event move d focus within the modal" ); + + // Check shift tab + $( document.activeElement ).simulate( "keydown", { keyCode: $.ui.keyCode.TAB, shiftKey: true } ); + setTimeout( checkShiftTab ); + } + + function checkShiftTab() { + assert.equal( document.activeElement, inputs[ 1 ], "Shift-Tab key event moved focus back to second input" ); + + element.remove(); + setTimeout( ready ); + } + + inputs[ 1 ].focus(); + setTimeout( function() { + assert.equal( document.activeElement, inputs[ 1 ], "Focus set on second input" ); + inputs.eq( 1 ).simulate( "keydown", { keyCode: $.ui.keyCode.TAB } ); + + setTimeout( checkTab ); + } ); +} ); + +QUnit.test( "#9048: multiple modal dialogs opened and closed in different order", + function( assert ) { + var ready = assert.async(); + assert.expect( 1 ); + $( "#dialog1, #dialog2" ).dialog( { autoOpen: false, modal: true } ); + $( "#dialog1" ).dialog( "open" ); + $( "#dialog2" ).dialog( "open" ); + $( "#dialog1" ).dialog( "close" ); + setTimeout( function() { + $( "#dialog2" ).dialog( "close" ); + $( "#favorite-animal" ).trigger( "focus" ); + assert.ok( true, "event handlers cleaned up (no errors thrown)" ); + ready(); + } ); +} ); + +QUnit.test( "interaction between overlay and other dialogs", function( assert ) { + var ready = assert.async(); + $.widget( "ui.testWidget", $.ui.dialog, { + options: { + modal: true, + autoOpen: false + } + } ); + assert.expect( 2 ); + var first = $( "
      " ).dialog( { + modal: true + } ), + firstInput = first.find( "input" ), + second = $( "
      " ).testWidget(), + secondInput = second.find( "input" ); + + // Wait for the modal to init + setTimeout( function() { + + second.testWidget( "open" ); + + // Simulate user tabbing from address bar to an element outside the dialog + $( "#favorite-animal" ).trigger( "focus" ); + setTimeout( function() { + assert.equal( document.activeElement, secondInput[ 0 ] ); + + // Last active dialog must receive focus + firstInput.trigger( "focus" ); + $( "#favorite-animal" ).trigger( "focus" ); + setTimeout( function() { + assert.equal( document.activeElement, firstInput[ 0 ] ); + + // Cleanup + first.remove(); + second.remove(); + delete $.ui.testWidget; + delete $.fn.testWidget; + ready(); + } ); + } ); + } ); +} ); + +} ); diff --git a/tests/unit/dialog/deprecated.html b/tests/unit/dialog/deprecated.html new file mode 100644 index 00000000000..50bab180ddf --- /dev/null +++ b/tests/unit/dialog/deprecated.html @@ -0,0 +1,34 @@ + + + + + jQuery UI Dialog Test Suite + + + + + + + +
      +
      +
      +
      +
      + +
      ...
      +
      + Please share some personal information + + +
      +
      +

      Some more (optional) information

      + +
      +
      +
      +
      +
      + + diff --git a/tests/unit/dialog/deprecated.js b/tests/unit/dialog/deprecated.js new file mode 100644 index 00000000000..b8cf7a9a585 --- /dev/null +++ b/tests/unit/dialog/deprecated.js @@ -0,0 +1,63 @@ +define( [ + "qunit", + "jquery", + "lib/helper", + "ui/widgets/dialog" +], function( QUnit, $, helper ) { +"use strict"; + +QUnit.module( "dialog (deprecated): options", { afterEach: helper.moduleAfterEach } ); + +QUnit.test( "dialogClass", function( assert ) { + assert.expect( 5 ); + + var element = $( "
      " ).dialog(), + widget = element.dialog( "widget" ); + assert.lacksClasses( widget, "foo", "dialogClass not specified. class not added" ); + element.remove(); + + element = $( "
      " ).dialog( { dialogClass: "foo" } ); + widget = element.dialog( "widget" ); + assert.hasClasses( widget, "foo", "dialogClass in init, foo class added" ); + element.dialog( "option", "dialogClass", "foobar" ); + assert.lacksClasses( widget, "foo", "dialogClass changed, previous one was removed" ); + assert.hasClasses( widget, "foobar", "dialogClass changed, new one was added" ); + element.remove(); + + element = $( "
      " ).dialog( { dialogClass: "foo bar" } ); + widget = element.dialog( "widget" ); + assert.hasClasses( widget, "foo bar", "dialogClass in init, two classes." ); + element.remove(); +} ); + +QUnit.test( "buttons - deprecated options", function( assert ) { + assert.expect( 7 ); + + var buttons, + element = $( "
      " ).dialog( { + buttons: [ + { + html: "a button", + "class": "additional-class", + id: "my-button-id", + click: function() { + assert.equal( this, element[ 0 ], "correct context" ); + }, + icons: { primary: "ui-icon-cancel" }, + text: false + } + ] + } ); + + buttons = element.dialog( "widget" ).find( ".ui-dialog-buttonpane button" ); + assert.equal( buttons.length, 1, "correct number of buttons" ); + assert.equal( buttons.attr( "id" ), "my-button-id", "correct id" ); + assert.equal( String.prototype.trim.call( buttons.text() ), "a button", "correct label" ); + assert.hasClasses( buttons, "additional-class" ); + assert.deepEqual( buttons.button( "option", "icon" ), "ui-icon-cancel" ); + assert.equal( buttons.button( "option", "showLabel" ), false ); + buttons.trigger( "click" ); + + element.remove(); +} ); +} ); diff --git a/tests/unit/dialog/dialog.html b/tests/unit/dialog/dialog.html index 97a5d44cd01..30f22c60e21 100644 --- a/tests/unit/dialog/dialog.html +++ b/tests/unit/dialog/dialog.html @@ -1,54 +1,34 @@ - + - + jQuery UI Dialog Test Suite - - - - - - - - - - - - - - - - - - - - - - - - - + + + -

      jQuery UI Dialog Test Suite

      -

      -

      -
        -
      - -
      +
      +
      +
      +
      +
      + +
      ...
      +
      + Please share some personal information + + +
      +
      +

      Some more (optional) information

      + +
      +
      +
      +
      - diff --git a/tests/unit/dialog/dialog_core.js b/tests/unit/dialog/dialog_core.js deleted file mode 100644 index 4618417f0c9..00000000000 --- a/tests/unit/dialog/dialog_core.js +++ /dev/null @@ -1,155 +0,0 @@ -/* - * dialog_core.js - */ - -var el, - offsetBefore, offsetAfter, - heightBefore, heightAfter, - widthBefore, widthAfter, - dragged; - -function dlg() { - return el.dialog('widget'); -} - -function isOpen(why) { - ok(dlg().is(":visible"), why); -} - -function isNotOpen(why) { - ok(!dlg().is(":visible"), why); -} - -function drag(handle, dx, dy) { - var d = dlg(); - offsetBefore = d.offset(); - heightBefore = d.height(); - widthBefore = d.width(); - //this mouseover is to work around a limitation in resizable - //TODO: fix resizable so handle doesn't require mouseover in order to be used - $(handle, d).simulate("mouseover"); - $(handle, d).simulate("drag", { - dx: dx || 0, - dy: dy || 0 - }); - dragged = { dx: dx, dy: dy }; - offsetAfter = d.offset(); - heightAfter = d.height(); - widthAfter = d.width(); -} - -function moved(dx, dy, msg) { - msg = msg ? msg + "." : ""; - var actual = { left: Math.round(offsetAfter.left), top: Math.round(offsetAfter.top) }; - var expected = { left: Math.round(offsetBefore.left + dx), top: Math.round(offsetBefore.top + dy) }; - same(actual, expected, 'dragged[' + dragged.dx + ', ' + dragged.dy + '] ' + msg); -} - -function shouldmove(why) { - var handle = $(".ui-dialog-titlebar", dlg()); - drag(handle, 50, -50); - moved(50, -50, why); -} - -function shouldnotmove(why) { - var handle = $(".ui-dialog-titlebar", dlg()); - drag(handle, 50, -50); - moved(0, 0, why); -} - -function resized(dw, dh, msg) { - msg = msg ? msg + "." : ""; - var actual = { width: widthAfter, height: heightAfter }; - var expected = { width: widthBefore + dw, height: heightBefore + dh }; - same(actual, expected, 'resized[' + dragged.dx + ', ' + dragged.dy + '] ' + msg); -} - -function shouldresize(why) { - var handle = $(".ui-resizable-se", dlg()); - drag(handle, 50, 50); - resized(50, 50, why); -} - -function shouldnotresize(why) { - var handle = $(".ui-resizable-se", dlg()); - drag(handle, 50, 50); - resized(0, 0, why); -} - -function broder(el, side){ - return parseInt(el.css('border-' + side + '-width'), 10); -} - -function margin(el, side) { - return parseInt(el.css('margin-' + side), 10); -} - -(function($) { - -module("dialog: core"); - -test("element types", function() { - var typeNames = ('p,h1,h2,h3,h4,h5,h6,blockquote,ol,ul,dl,div,form' - + ',table,fieldset,address,ins,del,em,strong,q,cite,dfn,abbr' - + ',acronym,code,samp,kbd,var,img,object,hr' - + ',input,button,label,select,iframe').split(','); - - $.each(typeNames, function(i) { - var typeName = typeNames[i]; - el = $(document.createElement(typeName)).appendTo('body'); - (typeName == 'table' && el.append("content")); - el.dialog(); - ok(true, '$("<' + typeName + '/>").dialog()'); - el.dialog("destroy"); - el.remove(); - }); -}); - -test("title id", function() { - expect(3); - - var titleId; - - // reset the uuid so we know what values to expect - $.ui.dialog.uuid = 0; - - el = $('
      ').dialog(); - titleId = dlg().find('.ui-dialog-title').attr('id'); - equals(titleId, 'ui-dialog-title-1', 'auto-numbered title id'); - el.remove(); - - el = $('
      ').dialog(); - titleId = dlg().find('.ui-dialog-title').attr('id'); - equals(titleId, 'ui-dialog-title-2', 'auto-numbered title id'); - el.remove(); - - el = $('
      ').dialog(); - titleId = dlg().find('.ui-dialog-title').attr('id'); - equals(titleId, 'ui-dialog-title-foo', 'carried over title id'); - el.remove(); -}); - -test("ARIA", function() { - expect(4); - - el = $('
      ').dialog(); - - equals(dlg().attr('role'), 'dialog', 'dialog role'); - - var labelledBy = dlg().attr('aria-labelledby'); - ok(labelledBy.length > 0, 'has aria-labelledby attribute'); - equals(dlg().find('.ui-dialog-title').attr('id'), labelledBy, - 'proper aria-labelledby attribute'); - - equals(dlg().find('.ui-dialog-titlebar-close').attr('role'), 'button', - 'close link role'); - - el.remove(); -}); - -test("widget method", function() { - var dialog = $("
      ").appendTo("#main").dialog(); - same(dialog.parent()[0], dialog.dialog("widget")[0]); -}); - -})(jQuery); diff --git a/tests/unit/dialog/dialog_defaults.js b/tests/unit/dialog/dialog_defaults.js deleted file mode 100644 index 999021d9527..00000000000 --- a/tests/unit/dialog/dialog_defaults.js +++ /dev/null @@ -1,29 +0,0 @@ -/* - * dialog_defaults.js - */ - -var dialog_defaults = { - autoOpen: true, - buttons: {}, - closeOnEscape: true, - closeText: 'close', - disabled: false, - dialogClass: '', - draggable: true, - height: 'auto', - hide: null, - maxHeight: false, - maxWidth: false, - minHeight: 150, - minWidth: 150, - modal: false, - position: 'center', - resizable: true, - show: null, - stack: true, - title: '', - width: 300, - zIndex: 1000 -}; - -commonWidgetTests('dialog', { defaults: dialog_defaults }); diff --git a/tests/unit/dialog/dialog_events.js b/tests/unit/dialog/dialog_events.js deleted file mode 100644 index e2b7bd9eeda..00000000000 --- a/tests/unit/dialog/dialog_events.js +++ /dev/null @@ -1,284 +0,0 @@ -/* - * dialog_events.js - */ -(function($) { - -module("dialog: events"); - -test("open", function() { - expect(11); - - el = $("
      "); - el.dialog({ - open: function(ev, ui) { - ok(true, 'autoOpen: true fires open callback'); - equals(this, el[0], "context of callback"); - equals(ev.type, 'dialogopen', 'event type in callback'); - same(ui, {}, 'ui hash in callback'); - } - }); - el.remove(); - - el = $("
      "); - el.dialog({ - autoOpen: false, - open: function(ev, ui) { - ok(true, '.dialog("open") fires open callback'); - equals(this, el[0], "context of callback"); - equals(ev.type, 'dialogopen', 'event type in callback'); - same(ui, {}, 'ui hash in callback'); - } - }).bind('dialogopen', function(ev, ui) { - ok(true, 'dialog("open") fires open event'); - equals(this, el[0], 'context of event'); - same(ui, {}, 'ui hash in event'); - }); - el.dialog("open"); - el.remove(); -}); - -test("dragStart", function() { - expect(9); - - el = $('
      ').dialog({ - dragStart: function(ev, ui) { - ok(true, 'dragging fires dragStart callback'); - equals(this, el[0], "context of callback"); - equals(ev.type, 'dialogdragstart', 'event type in callback'); - ok(ui.position !== undefined, "ui.position in callback"); - ok(ui.offset !== undefined, "ui.offset in callback"); - } - }).bind('dialogdragstart', function(ev, ui) { - ok(true, 'dragging fires dialogdragstart event'); - equals(this, el[0], 'context of event'); - ok(ui.position !== undefined, "ui.position in callback"); - ok(ui.offset !== undefined, "ui.offset in callback"); - }); - var handle = $(".ui-dialog-titlebar", dlg()); - drag(handle, 50, 50); - el.remove(); -}); - -test("drag", function() { - expect(9); - var hasDragged = false; - - el = $('
      ').dialog({ - drag: function(ev, ui) { - if (!hasDragged) { - ok(true, 'dragging fires drag callback'); - equals(this, el[0], "context of callback"); - equals(ev.type, 'dialogdrag', 'event type in callback'); - ok(ui.position !== undefined, "ui.position in callback"); - ok(ui.offset !== undefined, "ui.offset in callback"); - - hasDragged = true; - } - } - }).one('dialogdrag', function(ev, ui) { - ok(true, 'dragging fires dialogdrag event'); - equals(this, el[0], 'context of event'); - ok(ui.position !== undefined, "ui.position in callback"); - ok(ui.offset !== undefined, "ui.offset in callback"); - }); - var handle = $(".ui-dialog-titlebar", dlg()); - drag(handle, 50, 50); - el.remove(); -}); - -test("dragStop", function() { - expect(9); - - el = $('
      ').dialog({ - dragStop: function(ev, ui) { - ok(true, 'dragging fires dragStop callback'); - equals(this, el[0], "context of callback"); - equals(ev.type, 'dialogdragstop', 'event type in callback'); - ok(ui.position !== undefined, "ui.position in callback"); - ok(ui.offset !== undefined, "ui.offset in callback"); - } - }).bind('dialogdragstop', function(ev, ui) { - ok(true, 'dragging fires dialogdragstop event'); - equals(this, el[0], 'context of event'); - ok(ui.position !== undefined, "ui.position in callback"); - ok(ui.offset !== undefined, "ui.offset in callback"); - }); - var handle = $(".ui-dialog-titlebar", dlg()); - drag(handle, 50, 50); - el.remove(); -}); - -test("resizeStart", function() { - expect(13); - - el = $('
      ').dialog({ - resizeStart: function(ev, ui) { - ok(true, 'resizing fires resizeStart callback'); - equals(this, el[0], "context of callback"); - equals(ev.type, 'dialogresizestart', 'event type in callback'); - ok(ui.originalPosition !== undefined, "ui.originalPosition in callback"); - ok(ui.originalSize !== undefined, "ui.originalSize in callback"); - ok(ui.position !== undefined, "ui.position in callback"); - ok(ui.size !== undefined, "ui.size in callback"); - } - }).bind('dialogresizestart', function(ev, ui) { - ok(true, 'resizing fires dialogresizestart event'); - equals(this, el[0], 'context of event'); - ok(ui.originalPosition !== undefined, "ui.originalPosition in callback"); - ok(ui.originalSize !== undefined, "ui.originalSize in callback"); - ok(ui.position !== undefined, "ui.position in callback"); - ok(ui.size !== undefined, "ui.size in callback"); - }); - var handle = $(".ui-resizable-se", dlg()); - drag(handle, 50, 50); - el.remove(); -}); - -test("resize", function() { - expect(13); - var hasResized = false; - - el = $('
      ').dialog({ - resize: function(ev, ui) { - if (!hasResized) { - ok(true, 'resizing fires resize callback'); - equals(this, el[0], "context of callback"); - equals(ev.type, 'dialogresize', 'event type in callback'); - ok(ui.originalPosition !== undefined, "ui.originalPosition in callback"); - ok(ui.originalSize !== undefined, "ui.originalSize in callback"); - ok(ui.position !== undefined, "ui.position in callback"); - ok(ui.size !== undefined, "ui.size in callback"); - - hasResized = true; - } - } - }).one('dialogresize', function(ev, ui) { - ok(true, 'resizing fires dialogresize event'); - equals(this, el[0], 'context of event'); - ok(ui.originalPosition !== undefined, "ui.originalPosition in callback"); - ok(ui.originalSize !== undefined, "ui.originalSize in callback"); - ok(ui.position !== undefined, "ui.position in callback"); - ok(ui.size !== undefined, "ui.size in callback"); - }); - var handle = $(".ui-resizable-se", dlg()); - drag(handle, 50, 50); - el.remove(); -}); - -test("resizeStop", function() { - expect(13); - - el = $('
      ').dialog({ - resizeStop: function(ev, ui) { - ok(true, 'resizing fires resizeStop callback'); - equals(this, el[0], "context of callback"); - equals(ev.type, 'dialogresizestop', 'event type in callback'); - ok(ui.originalPosition !== undefined, "ui.originalPosition in callback"); - ok(ui.originalSize !== undefined, "ui.originalSize in callback"); - ok(ui.position !== undefined, "ui.position in callback"); - ok(ui.size !== undefined, "ui.size in callback"); - } - }).bind('dialogresizestop', function(ev, ui) { - ok(true, 'resizing fires dialogresizestop event'); - equals(this, el[0], 'context of event'); - ok(ui.originalPosition !== undefined, "ui.originalPosition in callback"); - ok(ui.originalSize !== undefined, "ui.originalSize in callback"); - ok(ui.position !== undefined, "ui.position in callback"); - ok(ui.size !== undefined, "ui.size in callback"); - }); - var handle = $(".ui-resizable-se", dlg()); - drag(handle, 50, 50); - el.remove(); -}); - -test("close", function() { - expect(7); - - el = $('
      ').dialog({ - close: function(ev, ui) { - ok(true, '.dialog("close") fires close callback'); - equals(this, el[0], "context of callback"); - equals(ev.type, 'dialogclose', 'event type in callback'); - same(ui, {}, 'ui hash in callback'); - } - }).bind('dialogclose', function(ev, ui) { - ok(true, '.dialog("close") fires dialogclose event'); - equals(this, el[0], 'context of event'); - same(ui, {}, 'ui hash in event'); - }); - el.dialog('close'); - el.remove(); -}); - -//handling of deprecated beforeclose (vs beforeClose) option -//Ticket #4669 http://dev.jqueryui.com/ticket/4669 -//TODO: remove in 1.9pre -test("beforeclose", function() { - expect(10); - - el = $('
      ').dialog({ - beforeclose: function(ev, ui) { - ok(true, '.dialog("close") fires beforeClose callback'); - equals(this, el[0], "context of callback"); - equals(ev.type, 'dialogbeforeclose', 'event type in callback'); - same(ui, {}, 'ui hash in callback'); - return false; - } - }); - el.dialog('close'); - isOpen('beforeclose (deprecated) callback should prevent dialog from closing'); - el.remove(); - - el = $('
      ').dialog(); - el.dialog('option', 'beforeclose', function(ev, ui) { - ok(true, '.dialog("close") fires beforeClose callback'); - equals(this, el[0], "context of callback"); - equals(ev.type, 'dialogbeforeclose', 'event type in callback'); - same(ui, {}, 'ui hash in callback'); - return false; - }); - el.dialog('close'); - isOpen('beforeclose (deprecated) callback should prevent dialog from closing'); - el.remove(); -}); - -test("beforeClose", function() { - expect(14); - - el = $('
      ').dialog({ - beforeClose: function(ev, ui) { - ok(true, '.dialog("close") fires beforeClose callback'); - equals(this, el[0], "context of callback"); - equals(ev.type, 'dialogbeforeclose', 'event type in callback'); - same(ui, {}, 'ui hash in callback'); - return false; - } - }); - el.dialog('close'); - isOpen('beforeClose callback should prevent dialog from closing'); - el.remove(); - - el = $('
      ').dialog(); - el.dialog('option', 'beforeClose', function(ev, ui) { - ok(true, '.dialog("close") fires beforeClose callback'); - equals(this, el[0], "context of callback"); - equals(ev.type, 'dialogbeforeclose', 'event type in callback'); - same(ui, {}, 'ui hash in callback'); - return false; - }); - el.dialog('close'); - isOpen('beforeClose callback should prevent dialog from closing'); - el.remove(); - - el = $('
      ').dialog().bind('dialogbeforeclose', function(ev, ui) { - ok(true, '.dialog("close") triggers dialogbeforeclose event'); - equals(this, el[0], "context of event"); - same(ui, {}, 'ui hash in event'); - return false; - }); - el.dialog('close'); - isOpen('dialogbeforeclose event should prevent dialog from closing'); - el.remove(); -}); - -})(jQuery); diff --git a/tests/unit/dialog/dialog_methods.js b/tests/unit/dialog/dialog_methods.js deleted file mode 100644 index 93d1b25db7b..00000000000 --- a/tests/unit/dialog/dialog_methods.js +++ /dev/null @@ -1,133 +0,0 @@ -/* - * dialog_methods.js - */ -(function($) { - -module("dialog: methods", { - teardown: function() { - $("body>.ui-dialog").remove(); - } -}); - -test("init", function() { - expect(7); - - $("
      ").appendTo('body').dialog().remove(); - ok(true, '.dialog() called on element'); - - $([]).dialog().remove(); - ok(true, '.dialog() called on empty collection'); - - $('
      ').dialog().remove(); - ok(true, '.dialog() called on disconnected DOMElement - never connected'); - - $('
      ').appendTo('body').remove().dialog().remove(); - ok(true, '.dialog() called on disconnected DOMElement - removed'); - - $('
      ').dialog().dialog("foo").remove(); - ok(true, 'arbitrary method called after init'); - - el = $('
      ').dialog(); - var foo = el.dialog("option", "foo"); - el.remove(); - ok(true, 'arbitrary option getter after init'); - - $('
      ').dialog().dialog("option", "foo", "bar").remove(); - ok(true, 'arbitrary option setter after init'); -}); - -test("destroy", function() { - $("
      ").appendTo('body').dialog().dialog("destroy").remove(); - ok(true, '.dialog("destroy") called on element'); - - $([]).dialog().dialog("destroy").remove(); - ok(true, '.dialog("destroy") called on empty collection'); - - $('
      ').dialog().dialog("destroy").remove(); - ok(true, '.dialog("destroy") called on disconnected DOMElement'); - - $('
      ').dialog().dialog("destroy").dialog("foo").remove(); - ok(true, 'arbitrary method called after destroy'); - - var expected = $('
      ').dialog(), - actual = expected.dialog('destroy'); - equals(actual, expected, 'destroy is chainable'); -}); - -test("enable", function() { - var expected = $('
      ').dialog(), - actual = expected.dialog('enable'); - equals(actual, expected, 'enable is chainable'); - - el = $('
      ').dialog({ disabled: true }); - el.dialog('enable'); - equals(el.dialog('option', 'disabled'), false, 'enable method sets disabled option to false'); - ok(!dlg().hasClass('ui-dialog-disabled'), 'enable method removes ui-dialog-disabled class from ui-dialog element'); -}); - -test("disable", function() { - var expected = $('
      ').dialog(), - actual = expected.dialog('disable'); - equals(actual, expected, 'disable is chainable'); - - el = $('
      ').dialog({ disabled: false }); - el.dialog('disable'); - equals(el.dialog('option', 'disabled'), true, 'disable method sets disabled option to true'); - ok(dlg().hasClass('ui-dialog-disabled'), 'disable method adds ui-dialog-disabled class to ui-dialog element'); -}); - -test("close", function() { - var expected = $('
      ').dialog(), - actual = expected.dialog('close'); - equals(actual, expected, 'close is chainable'); - - el = $('
      ').dialog(); - ok(dlg().is(':visible') && !dlg().is(':hidden'), 'dialog visible before close method called'); - el.dialog('close'); - ok(dlg().is(':hidden') && !dlg().is(':visible'), 'dialog hidden after close method called'); -}); - -test("isOpen", function() { - expect(4); - - el = $('
      ').dialog(); - equals(el.dialog('isOpen'), true, "dialog is open after init"); - el.dialog('close'); - equals(el.dialog('isOpen'), false, "dialog is closed"); - el.remove(); - - el = $('
      ').dialog({autoOpen: false}); - equals(el.dialog('isOpen'), false, "dialog is closed after init"); - el.dialog('open'); - equals(el.dialog('isOpen'), true, "dialog is open"); - el.remove(); -}); - -test("moveToTop", function() { - var expected = $('
      ').dialog(), - actual = expected.dialog('moveToTop'); - equals(actual, expected, 'moveToTop is chainable'); - - var d1 = $('
      ').dialog(), dlg1 = d1.parents('.ui-dialog'); - d1.dialog('close'); - d1.dialog('open'); - var d2 = $('
      ').dialog(), dlg2 = d2.parents('.ui-dialog'); - d2.dialog('close'); - d2.dialog('open'); - ok(dlg1.css('zIndex') < dlg2.css('zIndex'), 'dialog 1 under dialog 2 before moveToTop method called'); - d1.dialog('moveToTop'); - ok(dlg1.css('zIndex') > dlg2.css('zIndex'), 'dialog 1 above dialog 2 after moveToTop method called'); -}); - -test("open", function() { - var expected = $('
      ').dialog(), - actual = expected.dialog('open'); - equals(actual, expected, 'open is chainable'); - - el = $('
      ').dialog({ autoOpen: false }); - ok(dlg().is(':hidden') && !dlg().is(':visible'), 'dialog hidden before open method called'); - el.dialog('open'); - ok(dlg().is(':visible') && !dlg().is(':hidden'), 'dialog visible after open method called'); -}); - -})(jQuery); diff --git a/tests/unit/dialog/dialog_options.js b/tests/unit/dialog/dialog_options.js deleted file mode 100644 index 28b3812b55a..00000000000 --- a/tests/unit/dialog/dialog_options.js +++ /dev/null @@ -1,318 +0,0 @@ -/* - * dialog_options.js - */ -(function($) { - -module("dialog: options"); - -test("autoOpen", function() { - expect(2); - - el = $('
      ').dialog({ autoOpen: false }); - isNotOpen('.dialog({ autoOpen: false })'); - el.remove(); - - el = $('
      ').dialog({ autoOpen: true }); - isOpen('.dialog({ autoOpen: true })'); - el.remove(); -}); - -test("buttons", function() { - expect(17); - - var buttons = { - "Ok": function(ev, ui) { - ok(true, "button click fires callback"); - equals(this, el[0], "context of callback"); - equals(ev.target, btn[0], "event target"); - }, - "Cancel": function(ev, ui) { - ok(true, "button click fires callback"); - equals(this, el[0], "context of callback"); - equals(ev.target, btn[1], "event target"); - } - }; - - el = $('
      ').dialog({ buttons: buttons }); - var btn = $("button", dlg()); - equals(btn.length, 2, "number of buttons"); - - var i = 0; - $.each(buttons, function(key, val) { - equals(btn.eq(i).text(), key, "text of button " + (i+1)); - i++; - }); - - ok(btn.parent().hasClass('ui-dialog-buttonpane'), "buttons in container"); - btn.trigger("click"); - - var newButtons = { - "Close": function(ev, ui) { - ok(true, "button click fires callback"); - equals(this, el[0], "context of callback"); - equals(ev.target, btn[0], "event target"); - } - }; - - same(el.dialog("option", "buttons"), buttons, '.dialog("option", "buttons") getter'); - el.dialog("option", "buttons", newButtons); - same(el.dialog("option", "buttons"), newButtons, '.dialog("option", "buttons", ...) setter'); - - btn = $("button", dlg()); - equals(btn.length, 1, "number of buttons after setter"); - btn.trigger('click'); - - i = 0; - $.each(newButtons, function(key, val) { - equals(btn.eq(i).text(), key, "text of button " + (i+1)); - i += 1; - }); - - el.remove(); -}); - -test("closeOnEscape", function() { - el = $('
      ').dialog({ closeOnEscape: false }); - ok(true, 'closeOnEscape: false'); - ok(dlg().is(':visible') && !dlg().is(':hidden'), 'dialog is open before ESC'); - el.simulate('keydown', { keyCode: $.ui.keyCode.ESCAPE }) - .simulate('keypress', { keyCode: $.ui.keyCode.ESCAPE }) - .simulate('keyup', { keyCode: $.ui.keyCode.ESCAPE }); - ok(dlg().is(':visible') && !dlg().is(':hidden'), 'dialog is open after ESC'); - - el.remove(); - - el = $('
      ').dialog({ closeOnEscape: true }); - ok(true, 'closeOnEscape: true'); - ok(dlg().is(':visible') && !dlg().is(':hidden'), 'dialog is open before ESC'); - el.simulate('keydown', { keyCode: $.ui.keyCode.ESCAPE }) - .simulate('keypress', { keyCode: $.ui.keyCode.ESCAPE }) - .simulate('keyup', { keyCode: $.ui.keyCode.ESCAPE }); - ok(dlg().is(':hidden') && !dlg().is(':visible'), 'dialog is closed after ESC'); -}); - -test("closeText", function() { - expect(3); - - el = $('
      ').dialog(); - equals(dlg().find('.ui-dialog-titlebar-close span').text(), 'close', - 'default close text'); - el.remove(); - - el = $('
      ').dialog({ closeText: "foo" }); - equals(dlg().find('.ui-dialog-titlebar-close span').text(), 'foo', - 'closeText on init'); - el.remove(); - - el = $('
      ').dialog().dialog('option', 'closeText', 'bar'); - equals(dlg().find('.ui-dialog-titlebar-close span').text(), 'bar', - 'closeText via option method'); - el.remove(); -}); - -test("dialogClass", function() { - expect(4); - - el = $('
      ').dialog(); - equals(dlg().is(".foo"), false, 'dialogClass not specified. foo class added'); - el.remove(); - - el = $('
      ').dialog({ dialogClass: "foo" }); - equals(dlg().is(".foo"), true, 'dialogClass in init. foo class added'); - el.remove(); - - el = $('
      ').dialog({ dialogClass: "foo bar" }); - equals(dlg().is(".foo"), true, 'dialogClass in init, two classes. foo class added'); - equals(dlg().is(".bar"), true, 'dialogClass in init, two classes. bar class added'); - el.remove(); -}); - -test("draggable", function() { - expect(4); - - el = $('
      ').dialog({ draggable: false }); - shouldnotmove(); - el.dialog('option', 'draggable', true); - shouldmove(); - el.remove(); - - el = $('
      ').dialog({ draggable: true }); - shouldmove(); - el.dialog('option', 'draggable', false); - shouldnotmove(); - el.remove(); -}); - -test("height", function() { - expect(3); - - el = $('
      ').dialog(); - equals(dlg().height(), dialog_defaults.minHeight, "default height"); - el.remove(); - - el = $('
      ').dialog({ height: 437 }); - equals(dlg().height(), 437, "explicit height"); - el.remove(); - - el = $('
      ').dialog(); - el.dialog('option', 'height', 438); - equals(dlg().height(), 438, "explicit height set after init"); - el.remove(); -}); - -test("maxHeight", function() { - expect(3); - - el = $('
      ').dialog({ maxHeight: 400 }); - drag('.ui-resizable-s', 1000, 1000); - equals(heightAfter, 400, "maxHeight"); - el.remove(); - - el = $('
      ').dialog({ maxHeight: 400 }); - drag('.ui-resizable-n', -1000, -1000); - equals(heightAfter, 400, "maxHeight"); - el.remove(); - - el = $('
      ').dialog({ maxHeight: 400 }).dialog('option', 'maxHeight', 600); - drag('.ui-resizable-n', -1000, -1000); - equals(heightAfter, 600, "maxHeight"); - el.remove(); -}); - -test("maxWidth", function() { - expect(3); - - el = $('
      ').dialog({ maxWidth: 400 }); - drag('.ui-resizable-e', 1000, 1000); - equals(widthAfter, 400, "maxWidth"); - el.remove(); - - el = $('
      ').dialog({ maxWidth: 400 }); - drag('.ui-resizable-w', -1000, -1000); - equals(widthAfter, 400, "maxWidth"); - el.remove(); - - el = $('
      ').dialog({ maxWidth: 400 }).dialog('option', 'maxWidth', 600); - drag('.ui-resizable-w', -1000, -1000); - equals(widthAfter, 600, "maxWidth"); - el.remove(); -}); - -test("minHeight", function() { - expect(3); - - el = $('
      ').dialog({ minHeight: 10 }); - drag('.ui-resizable-s', -1000, -1000); - equals(heightAfter, 10, "minHeight"); - el.remove(); - - el = $('
      ').dialog({ minHeight: 10 }); - drag('.ui-resizable-n', 1000, 1000); - equals(heightAfter, 10, "minHeight"); - el.remove(); - - el = $('
      ').dialog({ minHeight: 10 }).dialog('option', 'minHeight', 30); - drag('.ui-resizable-n', 1000, 1000); - equals(heightAfter, 30, "minHeight"); - el.remove(); -}); - -test("minWidth", function() { - expect(3); - - el = $('
      ').dialog({ minWidth: 10 }); - drag('.ui-resizable-e', -1000, -1000); - equals(widthAfter, 10, "minWidth"); - el.remove(); - - el = $('
      ').dialog({ minWidth: 10 }); - drag('.ui-resizable-w', 1000, 1000); - equals(widthAfter, 10, "minWidth"); - el.remove(); - - el = $('
      ').dialog({ minWidth: 30 }).dialog('option', 'minWidth', 30); - drag('.ui-resizable-w', 1000, 1000); - equals(widthAfter, 30, "minWidth"); - el.remove(); -}); - -test("modal", function() { - ok(false, 'missing test - untested code is broken code'); -}); - -test("position, default center on window", function() { - var el = $('
      ').dialog(); - var offset = el.parent().offset(); - // use .position() instead to avoid replicating center-logic? - same(offset.left, Math.floor($(window).width() / 2 - el.parent().width() / 2)); - same(offset.top, Math.floor($(window).height() / 2 - el.parent().height() / 2)); - el.remove(); -}); - -test("position, others", function() { - ok(false, 'missing test - untested code is broken code'); -}); - -test("resizable", function() { - expect(4); - - el = $('
      ').dialog(); - shouldresize("[default]"); - el.dialog('option', 'resizable', false); - shouldnotresize('disabled after init'); - el.remove(); - - el = $('
      ').dialog({ resizable: false }); - shouldnotresize("disabled in init options"); - el.dialog('option', 'resizable', true); - shouldresize('enabled after init'); - el.remove(); -}); - -test("stack", function() { - ok(false, 'missing test - untested code is broken code'); -}); - -test("title", function() { - expect(5); - - function titleText() { - return dlg().find(".ui-dialog-title").html(); - } - - el = $('
      ').dialog(); - equals(titleText(), " ", "[default]"); - el.remove(); - - el = $('
      ').dialog(); - equals(titleText(), "foo", "title in element attribute"); - el.remove(); - - el = $('
      ').dialog({ title: 'foo' }); - equals(titleText(), "foo", "title in init options"); - el.remove(); - - el = $('
      ').dialog({ title: 'bar' }); - equals(titleText(), "bar", "title in init options should override title in element attribute"); - el.remove(); - - el = $('
      ').dialog().dialog('option', 'title', 'foo'); - equals(titleText(), 'foo', 'title after init'); - el.remove(); -}); - -test("width", function() { - expect(3); - - el = $('
      ').dialog(); - equals(dlg().width(), dialog_defaults.width, "default width"); - el.remove(); - - el = $('
      ').dialog({width: 437 }); - equals(dlg().width(), 437, "explicit width"); - el.dialog('option', 'width', 438); - equals(dlg().width(), 438, 'explicit width after init'); - el.remove(); -}); - -})(jQuery); diff --git a/tests/unit/dialog/dialog_tickets.js b/tests/unit/dialog/dialog_tickets.js deleted file mode 100644 index 296102c9bdc..00000000000 --- a/tests/unit/dialog/dialog_tickets.js +++ /dev/null @@ -1,43 +0,0 @@ -/* - * dialog_tickets.js - */ -(function($) { - -module("dialog: tickets"); - -test("#4826: setting resizable false toggles resizable on dialog", function() { - expect(6); - - el = $('
      ').dialog({ resizable: false }); - shouldnotresize("[default]"); - for (var i=0; i<2; i++) { - el.dialog('close').dialog('open'); - shouldnotresize('initialized with resizable false toggle ('+ (i+1) +')'); - } - el.remove(); - - el = $('
      ').dialog({ resizable: true }); - shouldresize("[default]"); - for (var i=0; i<2; i++) { - el.dialog('close').dialog('option', 'resizable', false).dialog('open'); - shouldnotresize('set option resizable false toggle ('+ (i+1) +')'); - } - el.remove(); - -}); - -test("#5184: isOpen in dialogclose event is true", function() { - expect( 3 ); - - el = $( "
      " ).dialog({ - close: function() { - ok( !el.dialog("isOpen"), "dialog is not open during close" ); - } - }); - ok( el.dialog("isOpen"), "dialog is open after init" ); - el.dialog( "close" ); - ok( !el.dialog("isOpen"), "dialog is not open after close" ); - el.remove(); -}); - -})(jQuery); diff --git a/tests/unit/dialog/events.js b/tests/unit/dialog/events.js new file mode 100644 index 00000000000..eb77de2ff85 --- /dev/null +++ b/tests/unit/dialog/events.js @@ -0,0 +1,374 @@ +define( [ + "qunit", + "jquery", + "./helper", + "ui/widgets/dialog" +], function( QUnit, $, testHelper ) { +"use strict"; + +QUnit.module( "dialog: events", { afterEach: testHelper.moduleAfterEach } ); + +QUnit.test( "open", function( assert ) { + assert.expect( 13 ); + + var element = $( "
      " ); + element.dialog( { + open: function( ev, ui ) { + assert.ok( element.dialog( "instance" )._isOpen, "interal _isOpen flag is set" ); + assert.ok( true, "autoOpen: true fires open callback" ); + assert.equal( this, element[ 0 ], "context of callback" ); + assert.equal( ev.type, "dialogopen", "event type in callback" ); + assert.deepEqual( ui, {}, "ui hash in callback" ); + } + } ); + element.remove(); + + element = $( "
      " ); + element.dialog( { + autoOpen: false, + open: function( ev, ui ) { + assert.ok( true, ".dialog('open') fires open callback" ); + assert.equal( this, element[ 0 ], "context of callback" ); + assert.equal( ev.type, "dialogopen", "event type in callback" ); + assert.deepEqual( ui, {}, "ui hash in callback" ); + } + } ).on( "dialogopen", function( ev, ui ) { + assert.ok( element.dialog( "instance" )._isOpen, "interal _isOpen flag is set" ); + assert.ok( true, "dialog('open') fires open event" ); + assert.equal( this, element[ 0 ], "context of event" ); + assert.deepEqual( ui, {}, "ui hash in event" ); + } ); + element.dialog( "open" ); + element.remove(); +} ); + +QUnit.test( "focus", function( assert ) { + assert.expect( 5 ); + var element, other; + element = $( "#dialog1" ).dialog( { + autoOpen: false + } ); + other = $( "#dialog2" ).dialog( { + autoOpen: false + } ); + + element.one( "dialogopen", function() { + assert.ok( true, "open, just once" ); + } ); + element.one( "dialogfocus", function() { + assert.ok( true, "focus on open" ); + } ); + other.dialog( "open" ); + + element.one( "dialogfocus", function() { + assert.ok( true, "when opening and already open and wasn't on top" ); + } ); + other.dialog( "open" ); + element.dialog( "open" ); + + element.one( "dialogfocus", function() { + assert.ok( true, "when calling moveToTop and wasn't on top" ); + } ); + other.dialog( "moveToTop" ); + element.dialog( "moveToTop" ); + + element.on( "dialogfocus", function() { + assert.ok( true, "when mousedown anywhere on the dialog and it wasn't on top" ); + } ); + other.dialog( "moveToTop" ); + element.trigger( "mousedown" ); + + // Triggers just once when already on top + element.dialog( "open" ); + element.dialog( "moveToTop" ); + element.trigger( "mousedown" ); + + element.add( other ).remove(); +} ); + +QUnit.test( "dragStart", function( assert ) { + assert.expect( 9 ); + + var handle, + element = $( "
      " ).dialog( { + dragStart: function( ev, ui ) { + assert.ok( true, "dragging fires dragStart callback" ); + assert.equal( this, element[ 0 ], "context of callback" ); + assert.equal( ev.type, "dialogdragstart", "event type in callback" ); + assert.ok( ui.position !== undefined, "ui.position in callback" ); + assert.ok( ui.offset !== undefined, "ui.offset in callback" ); + } + } ).on( "dialogdragstart", function( ev, ui ) { + assert.ok( true, "dragging fires dialogdragstart event" ); + assert.equal( this, element[ 0 ], "context of event" ); + assert.ok( ui.position !== undefined, "ui.position in callback" ); + assert.ok( ui.offset !== undefined, "ui.offset in callback" ); + } ); + + handle = $( ".ui-dialog-titlebar", element.dialog( "widget" ) ); + testHelper.drag( element, handle, 50, 50 ); + element.remove(); +} ); + +QUnit.test( "drag", function( assert ) { + assert.expect( 9 ); + var handle, + hasDragged = false, + element = $( "
      " ).dialog( { + drag: function( ev, ui ) { + if ( !hasDragged ) { + assert.ok( true, "dragging fires drag callback" ); + assert.equal( this, element[ 0 ], "context of callback" ); + assert.equal( ev.type, "dialogdrag", "event type in callback" ); + assert.ok( ui.position !== undefined, "ui.position in callback" ); + assert.ok( ui.offset !== undefined, "ui.offset in callback" ); + + hasDragged = true; + } + } + } ).one( "dialogdrag", function( ev, ui ) { + assert.ok( true, "dragging fires dialogdrag event" ); + assert.equal( this, element[ 0 ], "context of event" ); + assert.ok( ui.position !== undefined, "ui.position in callback" ); + assert.ok( ui.offset !== undefined, "ui.offset in callback" ); + } ); + + handle = $( ".ui-dialog-titlebar", element.dialog( "widget" ) ); + testHelper.drag( element, handle, 50, 50 ); + element.remove(); +} ); + +QUnit.test( "dragStop", function( assert ) { + assert.expect( 9 ); + + var handle, + element = $( "
      " ).dialog( { + dragStop: function( ev, ui ) { + assert.ok( true, "dragging fires dragStop callback" ); + assert.equal( this, element[ 0 ], "context of callback" ); + assert.equal( ev.type, "dialogdragstop", "event type in callback" ); + assert.ok( ui.position !== undefined, "ui.position in callback" ); + assert.ok( ui.offset !== undefined, "ui.offset in callback" ); + } + } ).on( "dialogdragstop", function( ev, ui ) { + assert.ok( true, "dragging fires dialogdragstop event" ); + assert.equal( this, element[ 0 ], "context of event" ); + assert.ok( ui.position !== undefined, "ui.position in callback" ); + assert.ok( ui.offset !== undefined, "ui.offset in callback" ); + } ); + + handle = $( ".ui-dialog-titlebar", element.dialog( "widget" ) ); + testHelper.drag( element, handle, 50, 50 ); + element.remove(); +} ); + +QUnit.test( "resizeStart", function( assert ) { + assert.expect( 13 ); + + var handle, + element = $( "
      " ).dialog( { + resizeStart: function( ev, ui ) { + assert.ok( true, "resizing fires resizeStart callback" ); + assert.equal( this, element[ 0 ], "context of callback" ); + assert.equal( ev.type, "dialogresizestart", "event type in callback" ); + assert.ok( ui.originalPosition !== undefined, "ui.originalPosition in callback" ); + assert.ok( ui.originalSize !== undefined, "ui.originalSize in callback" ); + assert.ok( ui.position !== undefined, "ui.position in callback" ); + assert.ok( ui.size !== undefined, "ui.size in callback" ); + } + } ).on( "dialogresizestart", function( ev, ui ) { + assert.ok( true, "resizing fires dialogresizestart event" ); + assert.equal( this, element[ 0 ], "context of event" ); + assert.ok( ui.originalPosition !== undefined, "ui.originalPosition in callback" ); + assert.ok( ui.originalSize !== undefined, "ui.originalSize in callback" ); + assert.ok( ui.position !== undefined, "ui.position in callback" ); + assert.ok( ui.size !== undefined, "ui.size in callback" ); + } ); + + handle = $( ".ui-resizable-se", element.dialog( "widget" ) ); + testHelper.drag( element, handle, 50, 50 ); + element.remove(); +} ); + +QUnit.test( "resize", function( assert ) { + assert.expect( 13 ); + var handle, + hasResized = false, + element = $( "
      " ).dialog( { + resize: function( ev, ui ) { + if ( !hasResized ) { + assert.ok( true, "resizing fires resize callback" ); + assert.equal( this, element[ 0 ], "context of callback" ); + assert.equal( ev.type, "dialogresize", "event type in callback" ); + assert.ok( ui.originalPosition !== undefined, "ui.originalPosition in callback" ); + assert.ok( ui.originalSize !== undefined, "ui.originalSize in callback" ); + assert.ok( ui.position !== undefined, "ui.position in callback" ); + assert.ok( ui.size !== undefined, "ui.size in callback" ); + + hasResized = true; + } + } + } ).one( "dialogresize", function( ev, ui ) { + assert.ok( true, "resizing fires dialogresize event" ); + assert.equal( this, element[ 0 ], "context of event" ); + assert.ok( ui.originalPosition !== undefined, "ui.originalPosition in callback" ); + assert.ok( ui.originalSize !== undefined, "ui.originalSize in callback" ); + assert.ok( ui.position !== undefined, "ui.position in callback" ); + assert.ok( ui.size !== undefined, "ui.size in callback" ); + } ); + + handle = $( ".ui-resizable-se", element.dialog( "widget" ) ); + testHelper.drag( element, handle, 50, 50 ); + element.remove(); +} ); + +QUnit.test( "resizeStop", function( assert ) { + assert.expect( 13 ); + + var handle, + element = $( "
      " ).dialog( { + resizeStop: function( ev, ui ) { + assert.ok( true, "resizing fires resizeStop callback" ); + assert.equal( this, element[ 0 ], "context of callback" ); + assert.equal( ev.type, "dialogresizestop", "event type in callback" ); + assert.ok( ui.originalPosition !== undefined, "ui.originalPosition in callback" ); + assert.ok( ui.originalSize !== undefined, "ui.originalSize in callback" ); + assert.ok( ui.position !== undefined, "ui.position in callback" ); + assert.ok( ui.size !== undefined, "ui.size in callback" ); + } + } ).on( "dialogresizestop", function( ev, ui ) { + assert.ok( true, "resizing fires dialogresizestop event" ); + assert.equal( this, element[ 0 ], "context of event" ); + assert.ok( ui.originalPosition !== undefined, "ui.originalPosition in callback" ); + assert.ok( ui.originalSize !== undefined, "ui.originalSize in callback" ); + assert.ok( ui.position !== undefined, "ui.position in callback" ); + assert.ok( ui.size !== undefined, "ui.size in callback" ); + } ); + + handle = $( ".ui-resizable-se", element.dialog( "widget" ) ); + testHelper.drag( element, handle, 50, 50 ); + element.remove(); +} ); + +QUnit.test( "close", function( assert ) { + var ready = assert.async(); + assert.expect( 14 ); + + var element = $( "
      " ).dialog( { + close: function( ev, ui ) { + assert.ok( true, ".dialog('close') fires close callback" ); + assert.equal( this, element[ 0 ], "context of callback" ); + assert.equal( ev.type, "dialogclose", "event type in callback" ); + assert.deepEqual( ui, {}, "ui hash in callback" ); + } + } ).on( "dialogclose", function( ev, ui ) { + assert.ok( true, ".dialog('close') fires dialogclose event" ); + assert.equal( this, element[ 0 ], "context of event" ); + assert.deepEqual( ui, {}, "ui hash in event" ); + } ); + element.dialog( "close" ); + element.remove(); + + // Close event with an effect + element = $( "
      " ).dialog( { + hide: 10, + close: function( ev, ui ) { + assert.ok( true, ".dialog('close') fires close callback" ); + assert.equal( this, element[ 0 ], "context of callback" ); + assert.equal( ev.type, "dialogclose", "event type in callback" ); + assert.deepEqual( ui, {}, "ui hash in callback" ); + ready(); + } + } ).on( "dialogclose", function( ev, ui ) { + assert.ok( true, ".dialog('close') fires dialogclose event" ); + assert.equal( this, element[ 0 ], "context of event" ); + assert.deepEqual( ui, {}, "ui hash in event" ); + } ); + element.dialog( "close" ); +} ); + +QUnit.test( "beforeClose", function( assert ) { + assert.expect( 14 ); + + var element = $( "
      " ).dialog( { + beforeClose: function( ev, ui ) { + assert.ok( true, ".dialog('close') fires beforeClose callback" ); + assert.equal( this, element[ 0 ], "context of callback" ); + assert.equal( ev.type, "dialogbeforeclose", "event type in callback" ); + assert.deepEqual( ui, {}, "ui hash in callback" ); + return false; + } + } ); + + element.dialog( "close" ); + assert.ok( element.dialog( "widget" ).is( ":visible" ), "beforeClose callback should prevent dialog from closing" ); + element.remove(); + + element = $( "
      " ).dialog(); + element.dialog( "option", "beforeClose", function( ev, ui ) { + assert.ok( true, ".dialog('close') fires beforeClose callback" ); + assert.equal( this, element[ 0 ], "context of callback" ); + assert.equal( ev.type, "dialogbeforeclose", "event type in callback" ); + assert.deepEqual( ui, {}, "ui hash in callback" ); + return false; + } ); + element.dialog( "close" ); + + assert.ok( element.dialog( "widget" ).is( ":visible" ), "beforeClose callback should prevent dialog from closing" ); + element.remove(); + + element = $( "
      " ).dialog().on( "dialogbeforeclose", function( ev, ui ) { + assert.ok( true, ".dialog('close') triggers dialogbeforeclose event" ); + assert.equal( this, element[ 0 ], "context of event" ); + assert.deepEqual( ui, {}, "ui hash in event" ); + return false; + } ); + element.dialog( "close" ); + assert.ok( element.dialog( "widget" ).is( ":visible" ), "dialogbeforeclose event should prevent dialog from closing" ); + element.remove(); +} ); + +// #8789 and #8838 +QUnit.test( "ensure dialog's container doesn't scroll on resize and focus", function( assert ) { + var ready = assert.async(); + assert.expect( 2 ); + + var element = $( "#dialog1" ).dialog(), + initialScroll = $( window ).scrollTop(); + element.dialog( "option", "height", 600 ); + assert.equal( $( window ).scrollTop(), initialScroll, "scroll hasn't moved after height change" ); + setTimeout( function() { + $( ".ui-dialog-titlebar-close" ).simulate( "mousedown" ); + assert.equal( $( window ).scrollTop(), initialScroll, "scroll hasn't moved after focus moved to dialog" ); + element.dialog( "destroy" ); + ready(); + } ); +} ); + +QUnit.test( "#5184: isOpen in dialogclose event is true", function( assert ) { + assert.expect( 3 ); + + var element = $( "
      " ).dialog( { + close: function() { + assert.ok( !element.dialog( "isOpen" ), "dialog is not open during close" ); + } + } ); + assert.ok( element.dialog( "isOpen" ), "dialog is open after init" ); + element.dialog( "close" ); + assert.ok( !element.dialog( "isOpen" ), "dialog is not open after close" ); + element.remove(); +} ); + +QUnit.test( "ensure dialog keeps focus when clicking modal overlay", function( assert ) { + assert.expect( 2 ); + + var element = $( "
      " ).dialog( { + modal: true + } ); + assert.equal( $( document.activeElement ).closest( ".ui-dialog" ).length, 1, "focus is in dialog" ); + $( ".ui-widget-overlay" ).simulate( "mousedown" ); + assert.equal( $( document.activeElement ).closest( ".ui-dialog" ).length, 1, "focus is still in dialog" ); + element.remove(); +} ); + +} ); diff --git a/tests/unit/dialog/helper.js b/tests/unit/dialog/helper.js new file mode 100644 index 00000000000..55555626af9 --- /dev/null +++ b/tests/unit/dialog/helper.js @@ -0,0 +1,60 @@ +define( [ + "qunit", + "jquery", + "lib/helper", + "ui/widgets/dialog" +], function( QUnit, $, helper ) { +"use strict"; + +return $.extend( helper, { + drag: function( element, handle, dx, dy ) { + var d = element.dialog( "widget" ); + + //This mouseover is to work around a limitation in resizable + //TODO: fix resizable so handle doesn't require mouseover in order to be used + $( handle, d ).simulate( "mouseover" ).simulate( "drag", { + dx: dx, + dy: dy + } ); + }, + testDrag: function( assert, element, dx, dy, expectedDX, expectedDY, msg ) { + var actualDX, actualDY, offsetAfter, + d = element.dialog( "widget" ), + handle = $( ".ui-dialog-titlebar", d ), + offsetBefore = d.offset(); + + this.drag( element, handle, dx, dy ); + + offsetAfter = d.offset(); + + msg = msg ? msg + "." : ""; + + actualDX = offsetAfter.left - offsetBefore.left; + actualDY = offsetAfter.top - offsetBefore.top; + assert.ok( expectedDX - actualDX <= 1 && expectedDY - actualDY <= 1, "dragged[" + expectedDX + ", " + expectedDY + "] " + msg ); + }, + + shouldResize: function( assert, element, dw, dh, msg ) { + var actualDH, actualDW, heightAfter, widthAfter, + d = element.dialog( "widget" ), + handle = $( ".ui-resizable-se", d ), + heightBefore = element.height(), + widthBefore = element.width(); + + this.drag( element, handle, 50, 50 ); + + heightAfter = element.height(); + widthAfter = element.width(); + + msg = msg ? msg + "." : ""; + + actualDH = heightAfter - heightBefore; + actualDW = widthAfter - widthBefore; + + // TODO: Switch to assert.close(). + // Also change the testDrag() helper. + assert.ok( Math.abs( actualDH - dh ) <= 1 && Math.abs( actualDW - dw ) <= 1, "resized[50, 50] " + msg ); + } +} ); + +} ); diff --git a/tests/unit/dialog/methods.js b/tests/unit/dialog/methods.js new file mode 100644 index 00000000000..c3f360fb9ed --- /dev/null +++ b/tests/unit/dialog/methods.js @@ -0,0 +1,277 @@ +define( [ + "qunit", + "jquery", + "lib/helper", + "ui/widgets/dialog" +], function( QUnit, $, helper ) { +"use strict"; + +QUnit.module( "dialog: methods", { + afterEach: function() { + $( "body>.ui-dialog" ).remove(); + return helper.moduleAfterEach.apply( this, arguments ); + } +} ); + +QUnit.test( "init", function( assert ) { + assert.expect( 6 ); + + $( "
      " ).appendTo( "body" ).dialog().remove(); + assert.ok( true, ".dialog() called on element" ); + + $( [] ).dialog().remove(); + assert.ok( true, ".dialog() called on empty collection" ); + + $( "
      " ).dialog().remove(); + assert.ok( true, ".dialog() called on disconnected DOMElement - never connected" ); + + $( "
      " ).appendTo( "body" ).remove().dialog().remove(); + assert.ok( true, ".dialog() called on disconnected DOMElement - removed" ); + + var element = $( "
      " ).dialog(); + element.dialog( "option", "foo" ); + element.remove(); + assert.ok( true, "arbitrary option getter after init" ); + + $( "
      " ).dialog().dialog( "option", "foo", "bar" ).remove(); + assert.ok( true, "arbitrary option setter after init" ); +} ); + +QUnit.test( "destroy", function( assert ) { + assert.expect( 17 ); + + var element, element2; + + $( "#dialog1, #form-dialog" ).hide(); + assert.domEqual( "#dialog1", function() { + var dialog = $( "#dialog1" ).dialog().dialog( "destroy" ); + assert.equal( dialog.parent()[ 0 ], $( "#qunit-fixture" )[ 0 ] ); + assert.equal( dialog.index(), 0 ); + } ); + assert.domEqual( "#form-dialog", function() { + var dialog = $( "#form-dialog" ).dialog().dialog( "destroy" ); + assert.equal( dialog.parent()[ 0 ], $( "#qunit-fixture" )[ 0 ] ); + assert.equal( dialog.index(), 2 ); + } ); + + // Ensure dimensions are restored (#8119) + $( "#dialog1" ).show().css( { + width: "400px", + minHeight: "100px", + height: "200px" + } ); + assert.domEqual( "#dialog1", function() { + $( "#dialog1" ).dialog().dialog( "destroy" ); + } ); + + // Don't throw errors when destroying a never opened modal dialog (#9004) + $( "#dialog1" ).dialog( { autoOpen: false, modal: true } ).dialog( "destroy" ); + assert.equal( $( ".ui-widget-overlay" ).length, 0, "overlay does not exist" ); + assert.equal( $( document ).data( "ui-dialog-overlays" ), undefined, "ui-dialog-overlays equals the number of open overlays" ); + + element = $( "#dialog1" ).dialog( { modal: true } ); + element2 = $( "#dialog2" ).dialog( { modal: true } ); + assert.equal( $( ".ui-widget-overlay" ).length, 2, "overlays created when dialogs are open" ); + assert.equal( $( document ).data( "ui-dialog-overlays" ), 2, "ui-dialog-overlays equals the number of open overlays" ); + element.dialog( "close" ); + assert.equal( $( ".ui-widget-overlay" ).length, 1, "overlay remains after closing one dialog" ); + assert.equal( $( document ).data( "ui-dialog-overlays" ), 1, "ui-dialog-overlays equals the number of open overlays" ); + element.dialog( "destroy" ); + assert.equal( $( ".ui-widget-overlay" ).length, 1, "overlay remains after destroying one dialog" ); + assert.equal( $( document ).data( "ui-dialog-overlays" ), 1, "ui-dialog-overlays equals the number of open overlays" ); + element2.dialog( "destroy" ); + assert.equal( $( ".ui-widget-overlay" ).length, 0, "overlays removed when all dialogs are destoryed" ); + assert.equal( $( document ).data( "ui-dialog-overlays" ), undefined, "ui-dialog-overlays equals the number of open overlays" ); +} ); + +QUnit.test( "#9000: Dialog leaves broken event handler after close/destroy in certain cases", function( assert ) { + var ready = assert.async(); + assert.expect( 1 ); + $( "#dialog1" ).dialog( { modal: true } ).dialog( "close" ).dialog( "destroy" ); + setTimeout( function() { + $( "#favorite-animal" ).trigger( "focus" ); + assert.ok( true, "close and destroy modal dialog before its really opened" ); + ready(); + } ); +} ); + +QUnit.test( "#4980: Destroy should place element back in original DOM position", function( assert ) { + assert.expect( 2 ); + var container = $( "
      " ), + modal = container.find( "#modal" ); + modal.dialog(); + assert.ok( !$.contains( container[ 0 ], modal[ 0 ] ), "dialog should move modal element to outside container element" ); + modal.dialog( "destroy" ); + assert.ok( $.contains( container[ 0 ], modal[ 0 ] ), "dialog(destroy) should place element back in original DOM position" ); +} ); + +QUnit.test( "enable/disable disabled", function( assert ) { + assert.expect( 3 ); + var element = $( "
      " ).dialog(); + element.dialog( "disable" ); + assert.equal( element.dialog( "option", "disabled" ), false, "disable method doesn't do anything" ); + assert.lacksClasses( element, "ui-dialog-disabled ui-state-disabled", "disable method doesn't add classes" ); + assert.ok( !element.dialog( "widget" ).attr( "aria-disabled" ), "disable method doesn't add aria-disabled" ); +} ); + +QUnit.test( "close", function( assert ) { + assert.expect( 3 ); + + var element, + expected = $( "
      " ).dialog(), + actual = expected.dialog( "close" ); + assert.equal( actual, expected, "close is chainable" ); + + element = $( "
      " ).dialog(); + assert.ok( element.dialog( "widget" ).is( ":visible" ) && !element.dialog( "widget" ).is( ":hidden" ), "dialog visible before close method called" ); + element.dialog( "close" ); + assert.ok( element.dialog( "widget" ).is( ":hidden" ) && !element.dialog( "widget" ).is( ":visible" ), "dialog hidden after close method called" ); +} ); + +QUnit.test( "isOpen", function( assert ) { + assert.expect( 4 ); + + var element = $( "
      " ).dialog(); + assert.equal( element.dialog( "isOpen" ), true, "dialog is open after init" ); + element.dialog( "close" ); + assert.equal( element.dialog( "isOpen" ), false, "dialog is closed" ); + element.remove(); + + element = $( "
      " ).dialog( { autoOpen: false } ); + assert.equal( element.dialog( "isOpen" ), false, "dialog is closed after init" ); + element.dialog( "open" ); + assert.equal( element.dialog( "isOpen" ), true, "dialog is open" ); + element.remove(); +} ); + +QUnit.test( "moveToTop", function( assert ) { + assert.expect( 5 ); + function order() { + var actual = $( ".ui-dialog" ).map( function() { + return +$( this ).css( "z-index" ); + } ).get(); + assert.deepEqual( actual, $.makeArray( arguments ) ); + } + var dialog1, dialog2, + focusOn = "dialog1"; + dialog1 = $( "#dialog1" ).dialog( { + focus: function() { + assert.equal( focusOn, "dialog1" ); + } + } ); + focusOn = "dialog2"; + dialog2 = $( "#dialog2" ).dialog( { + focus: function() { + assert.equal( focusOn, "dialog2" ); + } + } ); + order( 100, 101 ); + focusOn = "dialog1"; + dialog1.dialog( "moveToTop" ); + order( 102, 101 ); +} ); + +QUnit.test( "moveToTop: content scroll stays intact", function( assert ) { + assert.expect( 2 ); + var otherDialog = $( "#dialog1" ).dialog(), + scrollDialog = $( "#form-dialog" ).dialog( { + height: 200 + } ); + scrollDialog.scrollTop( 50 ); + assert.equal( scrollDialog.scrollTop(), 50 ); + + otherDialog.dialog( "moveToTop" ); + assert.equal( scrollDialog.scrollTop(), 50 ); +} ); + +QUnit.test( "open", function( assert ) { + assert.expect( 3 ); + var element, + expected = $( "
      " ).dialog(), + actual = expected.dialog( "open" ); + assert.equal( actual, expected, "open is chainable" ); + + element = $( "
      " ).dialog( { autoOpen: false } ); + assert.ok( element.dialog( "widget" ).is( ":hidden" ) && !element.dialog( "widget" ).is( ":visible" ), "dialog hidden before open method called" ); + element.dialog( "open" ); + assert.ok( element.dialog( "widget" ).is( ":visible" ) && !element.dialog( "widget" ).is( ":hidden" ), "dialog visible after open method called" ); +} ); + +// https://bugs.jqueryui.com/ticket/6137 +QUnit.test( "Ensure form elements don't reset when opening a dialog", function( assert ) { + assert.expect( 2 ); + + var d1 = $( "
      " + + "b
      " ).appendTo( "body" ).dialog( { autoOpen: false } ); + + d1.find( "#b" ).prop( "checked", true ); + assert.equal( d1.find( "input:checked" ).val(), "b", "checkbox b is checked" ); + + d1.dialog( "open" ); + assert.equal( d1.find( "input:checked" ).val(), "b", "checkbox b is checked" ); + + d1.remove(); +} ); + +QUnit.test( "#8958: dialog can be opened while opening", function( assert ) { + var ready = assert.async( 3 ); + assert.expect( 1 ); + + var element = $( "
      " ).dialog( { + autoOpen: false, + modal: true, + open: function() { + assert.equal( $( ".ui-widget-overlay" ).length, 1 ); + ready(); + } + } ); + + $( "#favorite-animal" ) + + // We focus the input to start the test. Once it receives focus, the + // dialog will open. Opening the dialog, will cause an element inside + // the dialog to gain focus, thus blurring the input. + .on( "focus", function() { + element.dialog( "open" ); + ready(); + } ) + + // When the input blurs, the dialog is in the process of opening. We + // try to open the dialog again, to make sure that dialogs properly + // handle a call to the open() method during the process of the dialog + // being opened. + .on( "blur", function() { + element.dialog( "open" ); + + // Detach the handlers to avoid firing them outside of this + // test logic; this may affect other tests. + $( this ).off( "focus blur" ); + + ready(); + } ) + .trigger( "focus" ); +} ); + +QUnit.test( "#5531: dialog width should be at least minWidth on creation", function( assert ) { + assert.expect( 4 ); + var element = $( "
      " ).dialog( { + width: 200, + minWidth: 300 + } ); + + assert.equal( element.dialog( "option", "width" ), 300, "width is minWidth" ); + element.dialog( "option", "width", 200 ); + assert.equal( element.dialog( "option", "width" ), 300, "width unchanged when set to < minWidth" ); + element.dialog( "option", "width", 320 ); + assert.equal( element.dialog( "option", "width" ), 320, "width changed if set to > minWidth" ); + element.remove(); + + element = $( "
      " ).dialog( { + minWidth: 300 + } ); + assert.ok( element.dialog( "option", "width" ) >= 300, "width is at least 300" ); + element.remove(); + +} ); + +} ); diff --git a/tests/unit/dialog/options.js b/tests/unit/dialog/options.js new file mode 100644 index 00000000000..2de788a4461 --- /dev/null +++ b/tests/unit/dialog/options.js @@ -0,0 +1,572 @@ +define( [ + "qunit", + "jquery", + "lib/helper", + "./helper", + "ui/widgets/dialog", + "ui/effects/effect-blind", + "ui/effects/effect-explode" +], function( QUnit, $, helper, testHelper ) { +"use strict"; + +QUnit.module( "dialog: options", { afterEach: helper.moduleAfterEach } ); + +QUnit.test( "appendTo", function( assert ) { + assert.expect( 16 ); + var detached = $( "
      " ), + element = $( "#dialog1" ).dialog( { + modal: true + } ); + assert.equal( element.dialog( "widget" ).parent()[ 0 ], document.body, "defaults to body" ); + assert.equal( $( ".ui-widget-overlay" ).parent()[ 0 ], document.body, "overlay defaults to body" ); + element.dialog( "destroy" ); + + element.dialog( { + appendTo: ".wrap", + modal: true + } ); + assert.equal( element.dialog( "widget" ).parent()[ 0 ], $( "#wrap1" )[ 0 ], "first found element" ); + assert.equal( $( ".ui-widget-overlay" ).parent()[ 0 ], $( "#wrap1" )[ 0 ], "overlay first found element" ); + assert.equal( $( "#wrap2 .ui-dialog" ).length, 0, "only appends to one element" ); + assert.equal( $( "#wrap2 .ui-widget-overlay" ).length, 0, "overlay only appends to one element" ); + element.dialog( "destroy" ); + + element.dialog( { + appendTo: null, + modal: true + } ); + assert.equal( element.dialog( "widget" ).parent()[ 0 ], document.body, "null" ); + assert.equal( $( ".ui-widget-overlay" ).parent()[ 0 ], document.body, "overlay null" ); + element.dialog( "destroy" ); + + element.dialog( { + autoOpen: false, + modal: true + } ).dialog( "option", "appendTo", "#wrap1" ).dialog( "open" ); + assert.equal( element.dialog( "widget" ).parent()[ 0 ], $( "#wrap1" )[ 0 ], "modified after init" ); + assert.equal( $( ".ui-widget-overlay" ).parent()[ 0 ], $( "#wrap1" )[ 0 ], "overlay modified after init" ); + element.dialog( "destroy" ); + + element.dialog( { + appendTo: detached, + modal: true + } ); + assert.equal( element.dialog( "widget" ).parent()[ 0 ], detached[ 0 ], "detached jQuery object" ); + assert.equal( detached.find( ".ui-widget-overlay" ).parent()[ 0 ], detached[ 0 ], "overlay detached jQuery object" ); + element.dialog( "destroy" ); + + element.dialog( { + appendTo: detached[ 0 ], + modal: true + } ); + assert.equal( element.dialog( "widget" ).parent()[ 0 ], detached[ 0 ], "detached DOM element" ); + assert.equal( detached.find( ".ui-widget-overlay" ).parent()[ 0 ], detached[ 0 ], "overlay detached DOM element" ); + element.dialog( "destroy" ); + + element.dialog( { + autoOpen: false, + modal: true + } ).dialog( "option", "appendTo", detached ); + assert.equal( element.dialog( "widget" ).parent()[ 0 ], detached[ 0 ], "detached DOM element via option()" ); + assert.equal( detached.find( ".ui-widget-overlay" ).length, 0, "overlay detached DOM element via option()" ); + element.dialog( "destroy" ); +} ); + +QUnit.test( "autoOpen", function( assert ) { + assert.expect( 2 ); + + var element = $( "
      " ).dialog( { autoOpen: false } ); + assert.ok( !element.dialog( "widget" ).is( ":visible" ), ".dialog({ autoOpen: false })" ); + element.remove(); + + element = $( "
      " ).dialog( { autoOpen: true } ); + assert.ok( element.dialog( "widget" ).is( ":visible" ), ".dialog({ autoOpen: true })" ); + element.remove(); +} ); + +QUnit.test( "buttons", function( assert ) { + assert.expect( 21 ); + + var btn, i, newButtons, + buttons = { + "Ok": function( ev ) { + assert.ok( true, "button click fires callback" ); + assert.equal( this, element[ 0 ], "context of callback" ); + assert.equal( ev.target, btn[ 0 ], "event target" ); + }, + "Cancel": function( ev ) { + assert.ok( true, "button click fires callback" ); + assert.equal( this, element[ 0 ], "context of callback" ); + assert.equal( ev.target, btn[ 1 ], "event target" ); + } + }, + element = $( "
      " ).dialog( { buttons: buttons } ); + + btn = element.dialog( "widget" ).find( ".ui-dialog-buttonpane button" ); + assert.equal( btn.length, 2, "number of buttons" ); + + i = 0; + $.each( buttons, function( key ) { + assert.equal( btn.eq( i ).text(), key, "text of button " + ( i + 1 ) ); + i++; + } ); + + assert.hasClasses( btn.parent(), "ui-dialog-buttonset" ); + assert.hasClasses( element.parent(), "ui-dialog-buttons" ); + + btn.trigger( "click" ); + + newButtons = { + "Close": function( ev ) { + assert.ok( true, "button click fires callback" ); + assert.equal( this, element[ 0 ], "context of callback" ); + assert.equal( ev.target, btn[ 0 ], "event target" ); + } + }; + + assert.deepEqual( element.dialog( "option", "buttons" ), buttons, ".dialog('option', 'buttons') getter" ); + element.dialog( "option", "buttons", newButtons ); + assert.deepEqual( element.dialog( "option", "buttons" ), newButtons, ".dialog('option', 'buttons', ...) setter" ); + + btn = element.dialog( "widget" ).find( ".ui-dialog-buttonpane button" ); + assert.equal( btn.length, 1, "number of buttons after setter" ); + btn.trigger( "click" ); + + i = 0; + $.each( newButtons, function( key ) { + assert.equal( btn.eq( i ).text(), key, "text of button " + ( i + 1 ) ); + i += 1; + } ); + + element.dialog( "option", "buttons", null ); + btn = element.dialog( "widget" ).find( ".ui-dialog-buttonpane button" ); + assert.equal( btn.length, 0, "all buttons have been removed" ); + assert.equal( element.find( ".ui-dialog-buttonset" ).length, 0, "buttonset has been removed" ); + assert.lacksClasses( element.parent(), "ui-dialog-buttons" ); + element.remove(); +} ); + +QUnit.test( "buttons - advanced", function( assert ) { + assert.expect( 7 ); + + var buttons, + element = $( "
      " ).dialog( { + buttons: [ + { + text: "a button", + "class": "additional-class", + id: "my-button-id", + click: function() { + assert.equal( this, element[ 0 ], "correct context" ); + }, + icon: "ui-icon-cancel", + showLabel: false + } + ] + } ); + + buttons = element.dialog( "widget" ).find( ".ui-dialog-buttonpane button" ); + assert.equal( buttons.length, 1, "correct number of buttons" ); + assert.equal( buttons.attr( "id" ), "my-button-id", "correct id" ); + assert.equal( String.prototype.trim.call( buttons.text() ), "a button", "correct label" ); + assert.hasClasses( buttons, "additional-class" ); + assert.deepEqual( buttons.button( "option", "icon" ), "ui-icon-cancel" ); + assert.equal( buttons.button( "option", "showLabel" ), false ); + buttons.trigger( "click" ); + + element.remove(); +} ); + +QUnit.test( "#9043: buttons with Array.prototype modification", function( assert ) { + assert.expect( 1 ); + Array.prototype.test = $.noop; + var element = $( "
      " ).dialog(); + assert.equal( element.dialog( "widget" ).find( ".ui-dialog-buttonpane" ).length, 0, + "no button pane" ); + element.remove(); + delete Array.prototype.test; +} ); + +QUnit.test( "closeOnEscape", function( assert ) { + assert.expect( 6 ); + var element = $( "
      " ).dialog( { closeOnEscape: false } ); + assert.ok( true, "closeOnEscape: false" ); + assert.ok( element.dialog( "widget" ).is( ":visible" ) && !element.dialog( "widget" ).is( ":hidden" ), "dialog is open before ESC" ); + element.simulate( "keydown", { keyCode: $.ui.keyCode.ESCAPE } ) + .simulate( "keypress", { keyCode: $.ui.keyCode.ESCAPE } ) + .simulate( "keyup", { keyCode: $.ui.keyCode.ESCAPE } ); + assert.ok( element.dialog( "widget" ).is( ":visible" ) && !element.dialog( "widget" ).is( ":hidden" ), "dialog is open after ESC" ); + + element.remove(); + + element = $( "
      " ).dialog( { closeOnEscape: true } ); + assert.ok( true, "closeOnEscape: true" ); + assert.ok( element.dialog( "widget" ).is( ":visible" ) && !element.dialog( "widget" ).is( ":hidden" ), "dialog is open before ESC" ); + element.simulate( "keydown", { keyCode: $.ui.keyCode.ESCAPE } ) + .simulate( "keypress", { keyCode: $.ui.keyCode.ESCAPE } ) + .simulate( "keyup", { keyCode: $.ui.keyCode.ESCAPE } ); + assert.ok( element.dialog( "widget" ).is( ":hidden" ) && !element.dialog( "widget" ).is( ":visible" ), "dialog is closed after ESC" ); +} ); + +QUnit.test( "closeText", function( assert ) { + assert.expect( 4 ); + + var element = $( "
      " ).dialog(); + assert.equal( String.prototype.trim.call( element.dialog( "widget" ).find( ".ui-dialog-titlebar-close" ).text() ), "Close", + "default close text" ); + element.remove(); + + element = $( "
      " ).dialog( { closeText: "foo" } ); + assert.equal( String.prototype.trim.call( element.dialog( "widget" ).find( ".ui-dialog-titlebar-close" ).text() ), "foo", + "closeText on init" ); + element.remove(); + + element = $( "
      " ).dialog().dialog( "option", "closeText", "bar" ); + assert.equal( String.prototype.trim.call( element.dialog( "widget" ).find( ".ui-dialog-titlebar-close" ).text() ), "bar", + "closeText via option method" ); + element.remove(); + + element = $( "
      " ).dialog( { closeText: "foo" } ); + assert.equal( String.prototype.trim.call( element.dialog( "widget" ).find( ".ui-dialog-titlebar-close" ).text() ), "foo", + "closeText is escaped" ); + element.remove(); +} ); + +QUnit.test( "draggable", function( assert ) { + assert.expect( 4 ); + + var element = $( "
      " ).dialog( { draggable: false } ); + + testHelper.testDrag( assert, element, 50, -50, 0, 0 ); + element.dialog( "option", "draggable", true ); + testHelper.testDrag( assert, element, 50, -50, 50, -50 ); + element.remove(); + + element = $( "
      " ).dialog( { draggable: true } ); + testHelper.testDrag( assert, element, 50, -50, 50, -50 ); + element.dialog( "option", "draggable", false ); + testHelper.testDrag( assert, element, 50, -50, 0, 0 ); + element.remove(); +} ); + +QUnit.test( "height", function( assert ) { + assert.expect( 4 ); + + var element = $( "
      " ).dialog(); + assert.ok( Math.abs( element.dialog( "widget" ).outerHeight() - 150 ) < 0.25, + "default height within 0.25 from expected" ); + element.remove(); + + element = $( "
      " ).dialog( { height: 237 } ); + assert.ok( Math.abs( element.dialog( "widget" ).outerHeight() - 237 ) < 0.25, + "explicit height within 0.25 from expected" ); + element.remove(); + + element = $( "
      " ).dialog(); + element.dialog( "option", "height", 238 ); + assert.ok( Math.abs( element.dialog( "widget" ).outerHeight() - 238 ) < 0.25, + "explicit height set after init within 0.25 from expected" ); + element.remove(); + + element = $( "
      " ).css( "padding", "20px" ) + .dialog( { height: 240 } ); + assert.ok( Math.abs( element.dialog( "widget" ).outerHeight() - 240 ) < 0.25, + "explicit height with padding within 0.25 from expected" ); + element.remove(); +} ); + +QUnit.test( "maxHeight", function( assert ) { + assert.expect( 3 ); + + var element = $( "
      " ).dialog( { maxHeight: 200 } ); + testHelper.drag( element, ".ui-resizable-s", 1000, 1000 ); + assert.close( element.dialog( "widget" ).height(), 200, 1, "maxHeight" ); + element.remove(); + + element = $( "
      " ).dialog( { maxHeight: 200 } ); + testHelper.drag( element, ".ui-resizable-n", -1000, -1000 ); + assert.close( element.dialog( "widget" ).height(), 200, 1, "maxHeight" ); + element.remove(); + + element = $( "
      " ).dialog( { maxHeight: 200 } ).dialog( "option", "maxHeight", 300 ); + testHelper.drag( element, ".ui-resizable-s", 1000, 1000 ); + assert.close( element.dialog( "widget" ).height(), 300, 1, "maxHeight" ); + element.remove(); +} ); + +QUnit.test( "maxWidth", function( assert ) { + assert.expect( 3 ); + + var element = $( "
      " ).dialog( { maxWidth: 200 } ); + testHelper.drag( element, ".ui-resizable-e", 1000, 1000 ); + assert.close( element.dialog( "widget" ).width(), 200, 1, "maxWidth" ); + element.remove(); + + element = $( "
      " ).dialog( { maxWidth: 200 } ); + testHelper.drag( element, ".ui-resizable-w", -1000, -1000 ); + assert.close( element.dialog( "widget" ).width(), 200, 1, "maxWidth" ); + element.remove(); + + element = $( "
      " ).dialog( { maxWidth: 200 } ).dialog( "option", "maxWidth", 300 ); + testHelper.drag( element, ".ui-resizable-w", -1000, -1000 ); + assert.close( element.dialog( "widget" ).width(), 300, 1, "maxWidth" ); + element.remove(); +} ); + +QUnit.test( "minHeight", function( assert ) { + assert.expect( 3 ); + + var element = $( "
      " ).dialog( { minHeight: 10 } ); + testHelper.drag( element, ".ui-resizable-s", -1000, -1000 ); + assert.close( element.dialog( "widget" ).height(), 10, 1, "minHeight" ); + element.remove(); + + element = $( "
      " ).dialog( { minHeight: 10 } ); + testHelper.drag( element, ".ui-resizable-n", 1000, 1000 ); + assert.close( element.dialog( "widget" ).height(), 10, 1, "minHeight" ); + element.remove(); + + element = $( "
      " ).dialog( { minHeight: 10 } ).dialog( "option", "minHeight", 30 ); + testHelper.drag( element, ".ui-resizable-n", 1000, 1000 ); + assert.close( element.dialog( "widget" ).height(), 30, 1, "minHeight" ); + element.remove(); +} ); + +QUnit.test( "minWidth", function( assert ) { + assert.expect( 3 ); + + var element = $( "
      " ).dialog( { minWidth: 10 } ); + testHelper.drag( element, ".ui-resizable-e", -1000, -1000 ); + assert.close( element.dialog( "widget" ).width(), 10, 1, "minWidth" ); + element.remove(); + + element = $( "
      " ).dialog( { minWidth: 10 } ); + testHelper.drag( element, ".ui-resizable-w", 1000, 1000 ); + assert.close( element.dialog( "widget" ).width(), 10, 1, "minWidth" ); + element.remove(); + + element = $( "
      " ).dialog( { minWidth: 30 } ).dialog( "option", "minWidth", 30 ); + testHelper.drag( element, ".ui-resizable-w", 1000, 1000 ); + assert.close( element.dialog( "widget" ).width(), 30, 1, "minWidth" ); + element.remove(); +} ); + +QUnit.test( "position, default center on window", function( assert ) { + assert.expect( 2 ); + + // Dialogs alter the window width and height in Firefox + // so we collect that information before creating the dialog + // Support: Firefox + var winWidth = $( window ).width(), + winHeight = $( window ).height(), + element = $( "
      " ).dialog(), + dialog = element.dialog( "widget" ), + offset = dialog.offset(); + assert.close( offset.left, Math.round( winWidth / 2 - dialog.outerWidth() / 2 ) + $( window ).scrollLeft(), 1, "dialog left position of center on window on initilization" ); + assert.close( offset.top, Math.round( winHeight / 2 - dialog.outerHeight() / 2 ) + $( window ).scrollTop(), 1, "dialog top position of center on window on initilization" ); + element.remove(); +} ); + +QUnit.test( "position, right bottom at right bottom via ui.position args", function( assert ) { + assert.expect( 2 ); + + // Dialogs alter the window width and height in Firefox + // so we collect that information before creating the dialog + // Support: Firefox + var winWidth = $( window ).width(), + winHeight = $( window ).height(), + element = $( "
      " ).dialog( { + position: { + my: "right bottom", + at: "right bottom" + } + } ), + dialog = element.dialog( "widget" ), + offset = dialog.offset(); + + assert.close( offset.left, winWidth - dialog.outerWidth() + $( window ).scrollLeft(), 1, "dialog left position of right bottom at right bottom on initilization" ); + assert.close( offset.top, winHeight - dialog.outerHeight() + $( window ).scrollTop(), 1, "dialog top position of right bottom at right bottom on initilization" ); + element.remove(); +} ); + +QUnit.test( "position, at another element", function( assert ) { + assert.expect( 4 ); + var parent = $( "
      " ).css( { + position: "absolute", + top: 400, + left: 600, + height: 10, + width: 10 + } ).appendTo( "body" ), + + element = $( "
      " ).dialog( { + position: { + my: "left top", + at: "left top", + of: parent, + collision: "none" + } + } ), + + dialog = element.dialog( "widget" ), + offset = dialog.offset(); + + assert.close( offset.left, 600, 1, "dialog left position at another element on initilization" ); + assert.close( offset.top, 400, 1, "dialog top position at another element on initilization" ); + + element.dialog( "option", "position", { + my: "left top", + at: "right bottom", + of: parent, + collision: "none" + } ); + + offset = dialog.offset(); + + assert.close( offset.left, 610, 1, "dialog left position at another element via setting option" ); + assert.close( offset.top, 410, 1, "dialog top position at another element via setting option" ); + + element.remove(); + parent.remove(); +} ); + +QUnit.test( "resizable", function( assert ) { + assert.expect( 4 ); + + var element = $( "
      " ).dialog(); + testHelper.shouldResize( assert, element, 50, 50, "[default]" ); + element.dialog( "option", "resizable", false ); + testHelper.shouldResize( assert, element, 0, 0, "disabled after init" ); + element.remove(); + + element = $( "
      " ).dialog( { resizable: false } ); + testHelper.shouldResize( assert, element, 0, 0, "disabled in init options" ); + element.dialog( "option", "resizable", true ); + testHelper.shouldResize( assert, element, 50, 50, "enabled after init" ); + element.remove(); +} ); + +QUnit.test( "title", function( assert ) { + assert.expect( 11 ); + + function titleText() { + return element.dialog( "widget" ).find( ".ui-dialog-title" ).html(); + } + + var element = $( "
      " ).dialog(); + + // Some browsers return a non-breaking space and some return " " + // so we generate a non-breaking space for comparison + assert.equal( titleText(), $( " " ).html(), "[default]" ); + assert.equal( element.dialog( "option", "title" ), null, "option not changed" ); + element.remove(); + + element = $( "
      " ).dialog(); + assert.equal( titleText(), "foo", "title in element attribute" ); + assert.equal( element.dialog( "option", "title" ), "foo", "option updated from attribute" ); + element.remove(); + + element = $( "
      " ).dialog( { title: "foo" } ); + assert.equal( titleText(), "foo", "title in init options" ); + assert.equal( element.dialog( "option", "title" ), "foo", "opiton set from options hash" ); + element.remove(); + + element = $( "
      " ).dialog( { title: "bar" } ); + assert.equal( titleText(), "bar", "title in init options should override title in element attribute" ); + assert.equal( element.dialog( "option", "title" ), "bar", "opiton set from options hash" ); + element.remove(); + + element = $( "
      " ).dialog().dialog( "option", "title", "foo" ); + assert.equal( titleText(), "foo", "title after init" ); + element.remove(); + + // Make sure attroperties are properly ignored - #5742 - .attr() might return a DOMElement + element = $( "
      " ).dialog(); + + // Some browsers return a non-breaking space and some return " " + // so we get the text to normalize to the actual non-breaking space + assert.equal( titleText(), $( " " ).html(), "[default]" ); + assert.equal( element.dialog( "option", "title" ), null, "option not changed" ); + element.remove(); +} ); + +QUnit.test( "width", function( assert ) { + assert.expect( 3 ); + + var element = $( "
      " ).dialog(); + assert.close( element.dialog( "widget" ).width(), 300, 1, "default width" ); + element.remove(); + + element = $( "
      " ).dialog( { width: 437 } ); + assert.close( element.dialog( "widget" ).width(), 437, 1, "explicit width" ); + element.dialog( "option", "width", 438 ); + assert.close( element.dialog( "widget" ).width(), 438, 1, "explicit width after init" ); + element.remove(); +} ); + +QUnit.test( "#4826: setting resizable false toggles resizable on dialog", function( assert ) { + assert.expect( 6 ); + var i, + element = $( "
      " ).dialog( { resizable: false } ); + + testHelper.shouldResize( assert, element, 0, 0, "[default]" ); + for ( i = 0; i < 2; i++ ) { + element.dialog( "close" ).dialog( "open" ); + testHelper.shouldResize( assert, element, 0, 0, "initialized with resizable false toggle (" + ( i + 1 ) + ")" ); + } + element.remove(); + + element = $( "
      " ).dialog( { resizable: true } ); + testHelper.shouldResize( assert, element, 50, 50, "[default]" ); + for ( i = 0; i < 2; i++ ) { + element.dialog( "close" ).dialog( "option", "resizable", false ).dialog( "open" ); + testHelper.shouldResize( assert, element, 0, 0, "set option resizable false toggle (" + ( i + 1 ) + ")" ); + } + element.remove(); + +} ); + +QUnit.test( "#8051 - 'Explode' dialog animation causes crash in IE 6, 7 and 8", function( assert ) { + var ready = assert.async(); + assert.expect( 1 ); + var element = $( "
      " ).dialog( { + show: "explode", + focus: function() { + assert.ok( true, "dialog opened with animation" ); + element.remove(); + ready(); + } + } ); +} ); + +QUnit.test( "#4421 - Focus lost from dialog which uses show-effect", function( assert ) { + var ready = assert.async(); + assert.expect( 1 ); + var element = $( "
      " ).dialog( { + show: "blind", + focus: function() { + assert.equal( element.dialog( "widget" ).find( document.activeElement ).length, 1, "dialog maintains focus" ); + element.remove(); + ready(); + } + } ); +} ); + +QUnit.test( "Open followed by close during show effect", function( assert ) { + var ready = assert.async(); + assert.expect( 1 ); + var element = $( "
      " ).dialog( { + show: "blind", + close: function() { + assert.ok( true, "dialog closed properly during animation" ); + element.remove(); + ready(); + } + } ); + + setTimeout( function() { + element.dialog( "close" ); + }, 100 ); +} ); + +} ); diff --git a/tests/unit/draggable/all.html b/tests/unit/draggable/all.html new file mode 100644 index 00000000000..b785b67ea0d --- /dev/null +++ b/tests/unit/draggable/all.html @@ -0,0 +1,26 @@ + + + + + jQuery UI Draggable Test Suite + + + + + + + + + + + + + +
      +
      + +
      + + diff --git a/tests/unit/draggable/common.js b/tests/unit/draggable/common.js new file mode 100644 index 00000000000..b2a46c7a738 --- /dev/null +++ b/tests/unit/draggable/common.js @@ -0,0 +1,48 @@ +define( [ + "lib/common", + "ui/widgets/draggable" +], function( common ) { + +common.testWidget( "draggable", { + defaults: { + appendTo: "parent", + axis: false, + cancel: "input, textarea, button, select, option", + classes: {}, + connectToSortable: false, + containment: false, + cursor: "auto", + cursorAt: false, + disabled: false, + grid: false, + handle: false, + helper: "original", + opacity: false, + refreshPositions: false, + revert: false, + revertDuration: 500, + scroll: true, + scrollSensitivity: 20, + scrollSpeed: 20, + scope: "default", + snap: false, + snapMode: "both", + snapTolerance: 20, + stack: false, + zIndex: false, + + //Todo: remove the following option checks when interactions are rewritten: + addClasses: true, + delay: 0, + distance: 1, + iframeFix: false, + + // Callbacks + create: null, + drag: null, + start: null, + stop: null + } +} ); + +} ); diff --git a/tests/unit/draggable/core.js b/tests/unit/draggable/core.js new file mode 100644 index 00000000000..d7f786c9376 --- /dev/null +++ b/tests/unit/draggable/core.js @@ -0,0 +1,415 @@ +define( [ + "qunit", + "jquery", + "lib/helper", + "./helper", + "ui/widgets/draggable", + "ui/widgets/droppable", + "ui/widgets/resizable" +], function( QUnit, $, helper, testHelper ) { +"use strict"; + +QUnit.module( "draggable: core", { afterEach: helper.moduleAfterEach } ); + +QUnit.test( "element types", function( assert ) { + var typeNames = ( + "p,h1,h2,h3,h4,h5,h6,blockquote,ol,ul,dl,div,form" + + ",table,fieldset,address,ins,del,em,strong,q,cite,dfn,abbr" + + ",acronym,code,samp,kbd,var,img,hr" + + ",input,button,label,select,iframe" + ).split( "," ); + + assert.expect( typeNames.length * 2 ); + + $.each( typeNames, function( i ) { + var offsetBefore, offsetAfter, + typeName = typeNames[ i ], + el = $( document.createElement( typeName ) ).appendTo( "#qunit-fixture" ); + + if ( typeName === "table" ) { + el.append( "content" ); + } + + el.draggable( { cancel: "" } ); + offsetBefore = el.offset(); + el.simulate( "drag", { + dx: 50, + dy: 50 + } ); + offsetAfter = el.offset(); + + // Support: Firefox, Chrome + // There are some rounding errors, so we can't say equal, we have to settle for close enough + assert.close( offsetBefore.left, offsetAfter.left - 50, 1, "dragged[50, 50] " + "<" + typeName + "> left" ); + assert.close( offsetBefore.top, offsetAfter.top - 50, 1, "dragged[50, 50] " + "<" + typeName + "> top" ); + el.draggable( "destroy" ); + el.remove(); + } ); +} ); + +QUnit.test( "No options, relative", function( assert ) { + assert.expect( 2 ); + testHelper.shouldMove( assert, $( "#draggable1" ).draggable(), "no options, relative" ); +} ); + +QUnit.test( "No options, absolute", function( assert ) { + assert.expect( 2 ); + testHelper.shouldMove( assert, $( "#draggable2" ).draggable(), "no options, absolute" ); +} ); + +QUnit.test( "resizable handle with complex markup (#8756 / #8757)", function( assert ) { + assert.expect( 2 ); + + $( "#draggable1" ) + .append( + $( "
      " ) + .addClass( "ui-resizable-handle ui-resizable-w" ) + .append( $( "
      " ) ) + ); + + var handle = $( ".ui-resizable-w div" ), + target = $( "#draggable1" ).draggable().resizable( { handles: "all" } ); + + // Todo: fix resizable so it doesn't require a mouseover + handle.simulate( "mouseover" ).simulate( "drag", { dx: -50 } ); + assert.equal( target.width(), 250, "compare width" ); + + // Todo: fix resizable so it doesn't require a mouseover + handle.simulate( "mouseover" ).simulate( "drag", { dx: 50 } ); + assert.equal( target.width(), 200, "compare width" ); +} ); + +QUnit.test( "#8269: Removing draggable element on drop", function( assert ) { + assert.expect( 2 ); + + var element = $( "#draggable1" ).wrap( "
      " ).draggable( { + stop: function() { + assert.ok( true, "stop still called despite element being removed from DOM on drop" ); + } + } ), + dropOffset = $( "#droppable" ).offset(); + + $( "#droppable" ).droppable( { + drop: function() { + $( "#wrapper" ).remove(); + assert.ok( true, "element removed from DOM on drop" ); + } + } ); + + element.simulate( "drag", { + handle: "corner", + x: dropOffset.left, + y: dropOffset.top + } ); +} ); + +// https://bugs.jqueryui.com/ticket/7778 +// drag element breaks in IE8 when its content is replaced onmousedown +QUnit.test( "Stray mousemove after mousedown still drags", function( assert ) { + assert.expect( 2 ); + + var element = $( "#draggable1" ).draggable( { scroll: false } ); + + // In IE8, when content is placed under the mouse (e.g. when draggable content is replaced + // on mousedown), mousemove is triggered on those elements even though the mouse hasn't moved. + element.on( "mousedown", function() { + $( document ).simulate( "mousemove", { button: -1 } ); + } ); + + testHelper.shouldMove( assert, element, "element is draggable" ); +} ); + +QUnit.test( "#6258: not following mouse when scrolled and using overflow-y: scroll", function( assert ) { + assert.expect( 2 ); + + var element = $( "#draggable1" ).draggable( { + stop: function( event, ui ) { + assert.equal( ui.position.left, 1, "left position is correct despite overflow on HTML" ); + assert.equal( ui.position.top, 1, "top position is correct despite overflow on HTML" ); + $( "html" ) + .css( "overflow-y", oldOverflowY ) + .css( "overflow-x", oldOverflowX ) + .scrollTop( 0 ) + .scrollLeft( 0 ); + } + } ), + oldOverflowY = $( "html" ).css( "overflow-y" ), + oldOverflowX = $( "html" ).css( "overflow-x" ); + + testHelper.forceScrollableWindow(); + + $( "html" ) + .css( "overflow-y", "scroll" ) + .css( "overflow-x", "scroll" ) + .scrollTop( 300 ) + .scrollLeft( 300 ); + + element.simulate( "drag", { + dx: 1, + dy: 1, + moves: 1 + } ); +} ); + +QUnit.test( "#9315: jumps down with offset of scrollbar", function( assert ) { + assert.expect( 2 ); + + var element = $( "#draggable2" ).draggable( { + stop: function( event, ui ) { + assert.equal( ui.position.left, 11, "left position is correct when position is absolute" ); + assert.equal( ui.position.top, 11, "top position is correct when position is absolute" ); + $( "html" ).scrollTop( 0 ).scrollLeft( 0 ); + } + } ); + + testHelper.forceScrollableWindow(); + + $( "html" ).scrollTop( 300 ).scrollLeft( 300 ); + + element.simulate( "drag", { + dx: 1, + dy: 1, + moves: 1 + } ); +} ); + +QUnit.test( "scroll offset with fixed ancestors", function( assert ) { + assert.expect( 2 ); + + var startValue = 300, + element = $( "#draggable1" ) + + // https://bugs.jqueryui.com/ticket/5009 + // scroll not working with parent's position fixed + .wrap( "
      " ) + + // https://bugs.jqueryui.com/ticket/9612 + // abspos elements inside of fixed elements moving away from the mouse when scrolling + .wrap( "
      " ) + .draggable( { + drag: function() { + startValue += 100; + $( document ).scrollTop( startValue ).scrollLeft( startValue ); + }, + stop: function( event, ui ) { + assert.equal( ui.position.left, 10, "left position is correct when parent position is fixed" ); + assert.equal( ui.position.top, 10, "top position is correct when parent position is fixed" ); + $( document ).scrollTop( 0 ).scrollLeft( 0 ); + } + } ); + + testHelper.forceScrollableWindow(); + + $( "#wrapper" ).css( "position", "fixed" ); + $( "#wrapper2" ).css( "position", "absolute" ); + + element.simulate( "drag", { + dx: 10, + dy: 10, + moves: 3 + } ); +} ); + +$( [ "hidden", "auto", "scroll" ] ).each( function() { + var overflow = this; + + // https://bugs.jqueryui.com/ticket/9379 - position bug in scrollable div + // https://bugs.jqueryui.com/ticket/10147 - Wrong position in a parent with "overflow: hidden" + QUnit.test( "position in scrollable parent with overflow: " + overflow, function( assert ) { + assert.expect( 2 ); + + $( "#qunit-fixture" ).html( "
      a
      " ); + $( "#inner" ).css( { position: "absolute", width: "500px", height: "500px" } ); + $( "#outer" ).css( { position: "absolute", width: "300px", height: "300px" } ); + $( "#dragged" ).css( { width: "10px", height: "10px" } ); + + var moves = 3, + startValue = 0, + dragDelta = 20, + delta = 100, + + // We scroll after each drag event, so subtract 1 from number of moves for expected + expected = delta + ( ( moves - 1 ) * dragDelta ), + element = $( "#dragged" ).draggable( { + drag: function() { + startValue += dragDelta; + $( "#outer" ).scrollTop( startValue ).scrollLeft( startValue ); + }, + stop: function( event, ui ) { + assert.equal( ui.position.left, expected, "left position is correct when grandparent is scrolled" ); + assert.equal( ui.position.top, expected, "top position is correct when grandparent is scrolled" ); + } + } ); + + $( "#outer" ).css( "overflow", overflow ); + + element.simulate( "drag", { + dy: delta, + dx: delta, + moves: moves + } ); + } ); +} ); + +QUnit.test( "#5727: draggable from iframe", function( assert ) { + assert.expect( 1 ); + + var iframeBody, draggable1, + iframe = $( "" ) + .append( " +
      + +
      +

      a bunch of content

      +
      + +
      Just another dialog to test stacking
      + + + diff --git a/tests/visual/draggable/draggable.html b/tests/visual/draggable/draggable.html deleted file mode 100644 index 394d5475bb3..00000000000 --- a/tests/visual/draggable/draggable.html +++ /dev/null @@ -1,24 +0,0 @@ - - - - - Draggable Visual Test : Default - - - - - - - - - - -
      -

      Draggable

      -
      - - diff --git a/tests/visual/draggable/draggable.scroll.html b/tests/visual/draggable/draggable.scroll.html deleted file mode 100644 index e0311c4c12e..00000000000 --- a/tests/visual/draggable/draggable.scroll.html +++ /dev/null @@ -1,152 +0,0 @@ - - - - - Draggable Scroll Tests - - - - - - - - - - - - - -
      Simple draggable
      -
      - - -
      -
      (Broken in IE)
      -
      -
      - -
      -
      -
      -
      - -
      -
      Absolute
      -
      -
      - -
      -
      Absolute
      -
      -
      - -
      -
      Fixed
      -
      -
      - -
      -
      Fixed
      -
      -
      - - - -
      -
      -
      Relative
      -
      -
      - -
      - -
      -
      -
      Relative
      -
      -
      -
      - -
      -
      -
      Relative (Broken in IE)
      -
      -
      - -
      - -
      -
      -
      Relative
      -
      -
      -
      - - - -
      -
      -
      Absolute
      -
      -
      - -
      - -
      -
      -
      Absolute
      -
      -
      -
      - -
      -
      -
      Absolute
      -
      -
      - -
      - -
      -
      -
      Absolute
      -
      -
      -
      - - - diff --git a/tests/visual/draggable/draggable_option_containment_array.html b/tests/visual/draggable/draggable_option_containment_array.html deleted file mode 100644 index 03e5288b5af..00000000000 --- a/tests/visual/draggable/draggable_option_containment_array.html +++ /dev/null @@ -1,26 +0,0 @@ - - - - - Draggable Visual Test : Draggable option containment array - - - - - - - - - - -
      -

      Draggable

      -
      - - diff --git a/tests/visual/draggable/draggable_option_cursorAt_object.html b/tests/visual/draggable/draggable_option_cursorAt_object.html deleted file mode 100644 index d51d29d1e60..00000000000 --- a/tests/visual/draggable/draggable_option_cursorAt_object.html +++ /dev/null @@ -1,26 +0,0 @@ - - - - - Draggable Visual Test : Draggable option cursorAt object - - - - - - - - - - -
      -

      Draggable

      -
      - - diff --git a/tests/visual/draggable/draggable_option_handle_selector.html b/tests/visual/draggable/draggable_option_handle_selector.html deleted file mode 100644 index 84d6609c888..00000000000 --- a/tests/visual/draggable/draggable_option_handle_selector.html +++ /dev/null @@ -1,28 +0,0 @@ - - - - - Draggable Visual Test : Draggable option handle selector - - - - - - - - - - -
      -

      Draggable

      -

      Handle

      -

      Not handle

      -
      - - diff --git a/tests/visual/draggable/draggable_option_iframeFix_false.html b/tests/visual/draggable/draggable_option_iframeFix_false.html deleted file mode 100644 index 1fbad89249f..00000000000 --- a/tests/visual/draggable/draggable_option_iframeFix_false.html +++ /dev/null @@ -1,30 +0,0 @@ - - - - - Draggable Visual Test : Draggable option iframeFix false - - - - - - - - - - -
      -

      Draggable

      -
      - - - - - diff --git a/tests/visual/draggable/draggable_option_iframeFix_selector.html b/tests/visual/draggable/draggable_option_iframeFix_selector.html deleted file mode 100644 index 5670148c0f0..00000000000 --- a/tests/visual/draggable/draggable_option_iframeFix_selector.html +++ /dev/null @@ -1,30 +0,0 @@ - - - - - Draggable Visual Test : Draggable option iframeFix selector - - - - - - - - - - -
      -

      Draggable

      -
      - - - - - diff --git a/tests/visual/draggable/draggable_option_iframeFix_true.html b/tests/visual/draggable/draggable_option_iframeFix_true.html deleted file mode 100644 index 917b71827de..00000000000 --- a/tests/visual/draggable/draggable_option_iframeFix_true.html +++ /dev/null @@ -1,30 +0,0 @@ - - - - - Draggable Visual Test : Draggable option iframeFix true - - - - - - - - - - -
      -

      Draggable

      -
      - - - - - diff --git a/tests/visual/draggable/replaced.html b/tests/visual/draggable/replaced.html new file mode 100644 index 00000000000..38931f34576 --- /dev/null +++ b/tests/visual/draggable/replaced.html @@ -0,0 +1,32 @@ + + + + + Draggable Visual Test + + + + + + + + +

      WHAT: A draggable, whose content is replaced onmousedown.

      +

      EXPECTED: In IE8, the draggable can actually be dragged.

      + +
      content
      + + + diff --git a/tests/visual/droppable/droppable.css b/tests/visual/droppable/droppable.css deleted file mode 100644 index cfe663ecead..00000000000 --- a/tests/visual/droppable/droppable.css +++ /dev/null @@ -1,3 +0,0 @@ -#draggables * { width: 100px; height: 20px; display: block; margin-bottom: 1em; background: #abc; } -#droppable { width: 200px; } -#droppable * { margin: 0.8em; padding: 0.4em; } diff --git a/tests/visual/droppable/droppable.html b/tests/visual/droppable/droppable.html deleted file mode 100644 index 0d306f70911..00000000000 --- a/tests/visual/droppable/droppable.html +++ /dev/null @@ -1,33 +0,0 @@ - - - - - Droppable Visual Test : Default - - - - - - - - - - - -
      -

      Draggable

      -
      -
      -

      Droppable

      -
      - - diff --git a/tests/visual/droppable/droppable_option_accept_default.html b/tests/visual/droppable/droppable_option_accept_default.html deleted file mode 100644 index ce3ff9a04e2..00000000000 --- a/tests/visual/droppable/droppable_option_accept_default.html +++ /dev/null @@ -1,40 +0,0 @@ - - - - - Droppable Visual Test : Draggable option accept default - - - - - - - - - - - - - -
      -
      Draggable div
      -

      Draggable p

      - Draggable span
      -
      - -
      -

      Droppable

      -
      - - diff --git a/tests/visual/droppable/droppable_option_accept_function.html b/tests/visual/droppable/droppable_option_accept_function.html deleted file mode 100644 index ee6f4395cce..00000000000 --- a/tests/visual/droppable/droppable_option_accept_function.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - - Droppable Visual Test : Draggable option accept function - - - - - - - - - - - - - -
      -
      Draggable div
      -

      Draggable p

      - Draggable span
      -
      - -
      -

      Droppable

      -
      - - diff --git a/tests/visual/droppable/droppable_option_accept_selector.html b/tests/visual/droppable/droppable_option_accept_selector.html deleted file mode 100644 index 7a71cf88b84..00000000000 --- a/tests/visual/droppable/droppable_option_accept_selector.html +++ /dev/null @@ -1,41 +0,0 @@ - - - - - Droppable Visual Test : Draggable option accept selector - - - - - - - - - - - - - -
      -
      Draggable div
      -

      Draggable p

      - Draggable span
      -
      - -
      -

      Droppable

      -
      - - diff --git a/tests/visual/droppable/droppable_ticket_4087.html b/tests/visual/droppable/droppable_ticket_4087.html deleted file mode 100644 index f18922a77af..00000000000 --- a/tests/visual/droppable/droppable_ticket_4087.html +++ /dev/null @@ -1,51 +0,0 @@ - - - - - Droppable Visual Test - Droppable ticket 4087 - - - - - - - - - - - - - -

      -Ticket #4087 - Removing ui.draggable immediately after the drop callback raises an error. -

      -

      -TEST: Drag 'Drag me' to the div labelled 'Drop here' -

      - -
      -

      Drag me

      -
      - -
      -

      Drop here

      -
      - -

      -ASSERT: No exception '$(this).data("draggable") is undefined' -

      - - - diff --git a/tests/visual/droppable/droppable_ticket_4088.html b/tests/visual/droppable/droppable_ticket_4088.html deleted file mode 100644 index 9eb1128e5b5..00000000000 --- a/tests/visual/droppable/droppable_ticket_4088.html +++ /dev/null @@ -1,69 +0,0 @@ - - - - - Droppable Visual Test - Droppable ticket 4088 - - - - - - - - - - - - - -

      -Ticket #4088 - Unable to remove() ui.draggable (sortable item) immediately after the drop callback. -

      -

      -TEST: Drag 'Special Item' to the div labelled 'Drop here' -

      -

      -TEST: Drag a 'Normal Item' to the div labelled 'Drop here' -

      - -
        -
      • Special Item
      • -
      • Normal Item 1
      • -
      • Normal Item 2
      • -
      • Normal Item 3
      • -
      - -
      -

      Trash Drop here

      -
      - -

      -ASSERT: The dropped item is removed from the original list and the following text does not appear: "I was dropped and removed, but still here I am!" -

      - - - diff --git a/tests/visual/effects.all.css b/tests/visual/effects.all.css deleted file mode 100644 index d2ed9402675..00000000000 --- a/tests/visual/effects.all.css +++ /dev/null @@ -1,54 +0,0 @@ - -body,html { - margin: 0; - padding: 0; - font-size: 12px; - font-family: Arial; - background: #191919; -} -body { margin: 1em; } - -ul.effects { - list-style-type: none; - margin: 0; - padding: 0; -} - -ul.effects li { - list-style-type: none; - margin: 0; - padding: 0; - width: 120px; - height: 100px; - float: left; - margin-top: 20px; - margin-left: 20px; -} - -div.effect { - width: 120px; - height: 100px; - background: #ccc; - border: 5px outset #aaa; - float: left; - cursor: pointer; - cursor: hand; -} - -div.current { - border: 5px outset #FF9C08; - background: #FF9C08; -} - -div.effect p { - color: #191919; - font-weight: bold; - margin: 0px; - padding: 10px; -} - -.ui-effects-transfer { - border: 1px dotted #fff; - background: #666; - opacity: 0.5; -} diff --git a/tests/visual/effects.all.html b/tests/visual/effects.all.html deleted file mode 100644 index c132381cb37..00000000000 --- a/tests/visual/effects.all.html +++ /dev/null @@ -1,180 +0,0 @@ - - - - - jQuery UI Effects Test Suite - - - - - - - - - - - - - - - - - - - -
        - -
      • -
        -

        Blind horizontally

        -
        -
      • - -
      • -
        -

        Blind vertically

        -
        -
      • - -
      • -
        -

        Bounce 3 times

        -
        -
      • - -
      • -
        -

        Clip horizontally

        -
        -
      • - -
      • -
        -

        Clip vertically

        -
        -
      • - -
      • - -
      • - -
      • -
        -

        Drop up

        -
        -
      • - -
      • -
        -

        Drop left

        -
        -
      • - -
      • -
        -

        Drop right

        -
        -
      • - -
      • -
        -

        Explode in 9 pieces

        -
        -
      • - -
      • -
        -

        Explode in 36 pieces

        -
        -
      • - -
      • -
        -

        Fold

        -
        -
      • - -
      • -
        -

        Highlight

        -
        -
      • - -
      • -
        -

        Pulsate 2 times

        -
        -
      • - -
      • -
        -

        Puff

        -
        -
      • - -
      • -
        -

        Scale

        -
        -
      • - -
      • -
        -

        Shake

        -
        -
      • - -
      • -
        -

        Slide down

        -
        -
      • - -
      • -
        -

        Slide up

        -
        -
      • - -
      • -
        -

        Slide left

        -
        -
      • - -
      • -
        -

        Slide right

        -
        -
      • - -
      • -
        -

        Transfer to first element

        -
        -
      • - -
      • -
        -

        addClass

        -
        -
      • - -
      • -
        -

        removeClass

        -
        -
      • - -
      • -
        -

        toggleClass

        -
        -
      • - -
      - - - diff --git a/tests/visual/effects.all.js b/tests/visual/effects.all.js deleted file mode 100644 index 0479c47ac7c..00000000000 --- a/tests/visual/effects.all.js +++ /dev/null @@ -1,80 +0,0 @@ - -$(function() { - - $("div.effect") - .hover(function() { $(this).addClass("hover"); }, - function() { $(this).removeClass("hover"); }); - - var effect = function(el, n, o) { - - $.extend(o, { - easing: "easeOutQuint" - }); - - $(el).bind("click", function() { - - $(this).addClass("current").hide(n, o, 1000, function() { - var self = this; - window.setTimeout(function() { - $(self).show(n, o, 1000, function() { $(this).removeClass("current"); }); - },500); - }); - }); - - }; - - effect("#blindHorizontally", "blind", { direction: "horizontal" }); - effect("#blindVertically", "blind", { direction: "vertical" }); - - effect("#bounce3times", "bounce", { times: 3 }); - - effect("#clipHorizontally", "clip", { direction: "horizontal" }); - effect("#clipVertically", "clip", { direction: "vertical" }); - - effect("#dropDown", "drop", { direction: "down" }); - effect("#dropUp", "drop", { direction: "up" }); - effect("#dropLeft", "drop", { direction: "left" }); - effect("#dropRight", "drop", { direction: "right" }); - - effect("#explode9", "explode", {}); - effect("#explode36", "explode", { pieces: 36 }); - - effect("#fold", "fold", { size: 50 }); - - effect("#highlight", "highlight", {}); - - effect("#pulsate", "pulsate", { times: 2 }); - - effect("#puff", "puff", { times: 2 }); - effect("#scale", "scale", {}); - - $("#shake").bind("click", function() { $(this).addClass("current").effect("shake", {}, 100, function() { $(this).removeClass("current"); }); }); - - effect("#slideDown", "slide", { direction: "down" }); - effect("#slideUp", "slide", { direction: "up" }); - effect("#slideLeft", "slide", { direction: "left" }); - effect("#slideRight", "slide", { direction: "right" }); - - $("#transfer").bind("click", function() { $(this).addClass("current").effect("transfer", { to: "div:eq(0)" }, 1000, function() { $(this).removeClass("current"); }); }); - - $("#addClass").click(function() { - $(this).addClass(function() { - window.console && console.log(arguments); - return "current"; - }, 1000, function() { - $(this).removeClass("current"); - }); - }); - $("#removeClass").click(function() { - $(this).addClass("current").removeClass(function() { - window.console && console.log(arguments); - return "current" - }, 1000); - }); - $("#toggleClass").click(function() { - $(this).toggleClass(function() { - window.console && console.log(arguments); - return "current" - }, 1000); - }); -}); diff --git a/tests/visual/effects/all.html b/tests/visual/effects/all.html new file mode 100644 index 00000000000..f4f9c270eba --- /dev/null +++ b/tests/visual/effects/all.html @@ -0,0 +1,199 @@ + + + + + jQuery UI Effects Test Suite + + + + + + +
        + +
      • +
        +

        Blind up

        +
        +
      • + +
      • +
        +

        Blind down

        +
        +
      • + +
      • +
        +

        Blind left

        +
        +
      • + +
      • +
        +

        Blind right

        +
        +
      • + +
      • +
        +

        Bounce 3 times

        +
        +
      • + +
      • +
        +

        Clip horizontally

        +
        +
      • + +
      • +
        +

        Clip vertically

        +
        +
      • + +
      • + +
      • + +
      • +
        +

        Drop up

        +
        +
      • + +
      • +
        +

        Drop left

        +
        +
      • + +
      • +
        +

        Drop right

        +
        +
      • + +
      • +
        +

        Explode in 9 pieces

        +
        +
      • + +
      • +
        +

        Explode in 36 pieces

        +
        +
      • + +
      • +
        +

        Fade

        +
        +
      • + +
      • +
        +

        Fold

        +
        +
      • + +
      • +
        +

        Highlight

        +
        +
      • + +
      • +
        +

        Pulsate 2 times

        +
        +
      • + +
      • +
        +

        Puff

        +
        +
      • + +
      • +
        +

        Scale

        +
        +
      • + +
      • +
        +

        Shake

        +
        +
      • + +
      • +
        +

        Size Default Show/Hide

        +
        +
      • + +
      • +
        +

        Size Toggle

        +
        +
      • + +
      • +
        +

        Slide down

        +
        +
      • + +
      • +
        +

        Slide up

        +
        +
      • + +
      • +
        +

        Slide left

        +
        +
      • + +
      • +
        +

        Slide right

        +
        +
      • + +
      • +
        +

        addClass

        +
        +
      • + +
      • +
        +

        removeClass

        +
        +
      • + +
      • +
        +

        toggleClass

        +
        +
      • + +
      • +
        +

        hide/show (jQuery)

        +
        +
      • + +
      + + + diff --git a/tests/visual/effects/clip.html b/tests/visual/effects/clip.html new file mode 100644 index 00000000000..c20e6506a3a --- /dev/null +++ b/tests/visual/effects/clip.html @@ -0,0 +1,90 @@ + + + + + jQuery UI Effects Test Suite + + + + + + + +

      WHAT: A set of elements with various positions and clips, using the clip effect.

      +

      EXPECTED: When clicking "Toggle" or "Effect Toggle", to observe the same behavior; All elements should not change position, aside from the expected clip animation. At the end of the animation, the animated elements should hide. Layout (i.e. the position of other elements) should not change until the animated elements are hidden.

      +

      EXPECTED: Clicking "Toggle" or "Effect Toggle" a second time reverses the animation, first showing all elements at their original dimensions, and restoring them to their original state.

      +

      EXPECTED: Clicking "Effect Default" should always perform a "hide" animation.

      +

      EXPECTED: Clicking any of the buttons in quick succession should queue the relevant animations.

      +

      EXPECTED CANTFIX: In IE8, the clip animation jumps due to a bug that causes .css('clip') to return undefined unless the clip property is an inline style.

      + +
      + + + +

      Bacon ipsum dolor sit amet chuck cow ground round, ham hock short loin tail jowl sausage flank. Venison andouille turducken sausage. Boudin filet mignon shoulder, prosciutto sirloin tail cow pastrami. Salami jerky flank rump, sirloin spare ribs pork belly. Biltong brisket boudin ground round, venison chicken shankle short ribs meatball corned beef. Swine short ribs shoulder, short loin turducken biltong prosciutto ball tip. Biltong beef bresaola sausage prosciutto spare ribs, short loin swine pork chop cow flank pork turkey shankle.

      + jQuery Logo +

      Jerky corned beef short loin fatback jowl tail. Rump spare ribs shoulder pork belly. Sausage cow ground round bacon. Bresaola kielbasa pastrami brisket ham hock. Andouille kielbasa ham, pork beef tenderloin ground round beef ribs flank turkey pancetta tri-tip.

      +
      +

      Shankle filet mignon ribeye chicken, bacon jowl drumstick frankfurter swine short loin capicola leberkas tenderloin pig. Shankle bacon shank pork loin, shoulder ham drumstick biltong. Shankle ham pastrami ball tip turkey leberkas pork loin ground round. Chicken strip steak venison shoulder biltong ham. Bacon pork loin tenderloin kielbasa, prosciutto sausage leberkas jowl ribeye turducken. Flank short loin venison tenderloin spare ribs boudin, tongue pork chop shank sirloin. Ground round ham pork belly, corned beef jowl strip steak short ribs prosciutto pig bresaola spare ribs.

      + jQuery Logo +

      Pork loin biltong ball tip tail jerky beef ribs prosciutto short loin turducken. Turkey chicken jowl pork loin shank tri-tip swine brisket. Doner prosciutto leberkas venison ground round, short loin capicola hamburger pork bacon. Spare ribs beef pork tenderloin rump shoulder pork belly turducken cow beef ribs pastrami tail flank. Spare ribs tri-tip shank, pork beef ribs ribeye chicken bacon boudin shoulder venison. Sirloin beef ribs boudin, andouille doner tail ball tip biltong prosciutto chicken beef turkey tongue hamburger tri-tip.

      +
      +

      Doner salami jowl beef ribs. Pork chop beef short loin pork, kielbasa tail andouille salami sausage meatball short ribs t-bone tri-tip ham. Meatball short ribs prosciutto flank chicken fatback frankfurter brisket turducken. Corned beef hamburger swine short ribs pancetta. Jerky bresaola pork chuck spare ribs pastrami shoulder flank chicken leberkas beef.

      +

      Doner salami jowl beef ribs. Pork chop beef short loin pork, kielbasa tail andouille salami sausage meatball short ribs t-bone tri-tip ham. Meatball short ribs prosciutto flank chicken fatback frankfurter brisket turducken. Corned beef hamburger swine short ribs pancetta. Jerky bresaola pork chuck spare ribs pastrami shoulder flank chicken leberkas beef.

      +

      Doner salami jowl beef ribs. Pork chop beef short loin pork, kielbasa tail andouille salami sausage meatball short ribs t-bone tri-tip ham. Meatball short ribs prosciutto flank chicken fatback frankfurter brisket turducken. Corned beef hamburger swine short ribs pancetta. Jerky bresaola pork chuck spare ribs pastrami shoulder flank chicken leberkas beef.

      +
      + + + diff --git a/tests/visual/effects/effects.css b/tests/visual/effects/effects.css new file mode 100644 index 00000000000..8e9ee0ffdea --- /dev/null +++ b/tests/visual/effects/effects.css @@ -0,0 +1,49 @@ +body { + margin: 1em; + padding: 0; + background: #fff; + color: #000; +} + +ul.effects { + list-style-type: none; + margin: 0; + padding: 0; +} + +ul.effects li { + padding: 0; + width: 120px; + height: 100px; + float: left; + margin-top: 20px; + margin-left: 20px; +} + +div.effect { + width: 120px; + height: 100px; + background: #ccc; + border: 5px outset #aaa; + float: left; + cursor: pointer; + cursor: hand; +} + +div.current { + border: 5px outset #FF9C08; + background: #FF9C08; +} + +div.effect p { + color: #191919; + font-weight: bold; + margin: 0; + padding: 10px; +} + +.ui-effects-transfer { + border: 1px dotted #fff; + background: #666; + opacity: 0.5; +} diff --git a/tests/visual/effects/effects.js b/tests/visual/effects/effects.js new file mode 100644 index 00000000000..5e8390abe12 --- /dev/null +++ b/tests/visual/effects/effects.js @@ -0,0 +1,96 @@ +var duration = 1000, + wait = 500; + +function effect( elem, name, options ) { + $.extend( options, { + easing: "easeOutQuint" + } ); + + $( elem ).on( "click", function() { + $( this ) + .addClass( "current" ) + + // delaying the initial animation makes sure that the queue stays in tact + .delay( 10 ) + .hide( name, options, duration ) + .delay( wait ) + .show( name, options, duration, function() { + $( this ).removeClass( "current" ); + } ); + } ); +} + +$( "#hide" ).on( "click", function() { + $( this ) + .addClass( "current" ) + .hide( duration ) + .delay( wait ) + .show( duration, function() { + $( this ).removeClass( "current" ); + } ); +} ); + +effect( "#blindLeft", "blind", { direction: "left" } ); +effect( "#blindUp", "blind", { direction: "up" } ); +effect( "#blindRight", "blind", { direction: "right" } ); +effect( "#blindDown", "blind", { direction: "down" } ); + +effect( "#bounce3times", "bounce", { times: 3 } ); + +effect( "#clipHorizontally", "clip", { direction: "horizontal" } ); +effect( "#clipVertically", "clip", { direction: "vertical" } ); + +effect( "#dropDown", "drop", { direction: "down" } ); +effect( "#dropUp", "drop", { direction: "up" } ); +effect( "#dropLeft", "drop", { direction: "left" } ); +effect( "#dropRight", "drop", { direction: "right" } ); + +effect( "#explode9", "explode", {} ); +effect( "#explode36", "explode", { pieces: 36 } ); + +effect( "#fade", "fade", {} ); + +effect( "#fold", "fold", { size: 50 } ); + +effect( "#highlight", "highlight", {} ); + +effect( "#pulsate", "pulsate", { times: 2 } ); + +effect( "#puff", "puff", {} ); +effect( "#scale", "scale", {} ); +effect( "#size", "size", {} ); +$( "#sizeToggle" ).on( "click", function() { + var options = { to: { width: 300, height: 300 } }; + $( this ) + .addClass( "current" ) + .toggle( "size", options, duration ) + .delay( wait ) + .toggle( "size", options, duration, function() { + $( this ).removeClass( "current" ); + } ); +} ); + +$( "#shake" ).on( "click", function() { + $( this ) + .addClass( "current" ) + .effect( "shake", {}, 100, function() { + $( this ).removeClass( "current" ); + } ); +} ); + +effect( "#slideDown", "slide", { direction: "down" } ); +effect( "#slideUp", "slide", { direction: "up" } ); +effect( "#slideLeft", "slide", { direction: "left" } ); +effect( "#slideRight", "slide", { direction: "right" } ); + +$( "#addClass" ).on( "click", function() { + $( this ).addClass( "current", duration, function() { + $( this ).removeClass( "current" ); + } ); +} ); +$( "#removeClass" ).on( "click", function() { + $( this ).addClass( "current" ).removeClass( "current", duration ); +} ); +$( "#toggleClass" ).on( "click", function() { + $( this ).toggleClass( "current", duration ); +} ); diff --git a/tests/visual/effects/image.png b/tests/visual/effects/image.png new file mode 100644 index 00000000000..030f1bc2684 Binary files /dev/null and b/tests/visual/effects/image.png differ diff --git a/tests/visual/effects/scale.html b/tests/visual/effects/scale.html new file mode 100644 index 00000000000..1d5a5bbfa9e --- /dev/null +++ b/tests/visual/effects/scale.html @@ -0,0 +1,163 @@ + + + + + jQuery UI Effects Test Suite + + + + + + + +
      +
      +
      +
      +
      + + + + +
      + + + + +
      + + + diff --git a/tests/visual/effects/shake.html b/tests/visual/effects/shake.html new file mode 100644 index 00000000000..c93f0eb5733 --- /dev/null +++ b/tests/visual/effects/shake.html @@ -0,0 +1,94 @@ + + + + + jQuery UI Effects Test Suite + + + + + + + +

      WHAT: A set of elements with various box-model properties, using the shake effect to toggle.

      +

      EXPECTED: When clicking "Toggle", all elements should not change dimension nor position, aside from the expected shake animation, which should take the number of milliseconds specified to complete. At the end of the animation, all elements should hide.

      +

      EXPECTED: Clicking "Toggle" a second time reverses the animation, first showing all elements at their original dimensions, and restoring them to their original state.

      + + + +
      +
      test
      +
      test
      +
      test
      +
      +
      +
      test
      +
      test
      +
      test
      + +
      +
      +
      test
      +
      test
      +
      test
      + +
      +
      +
      test
      +
      test
      +
      test
      + +
      +
      +
      test
      +
      test
      +
      test
      +
      + + + diff --git a/tests/visual/index.html b/tests/visual/index.html index 05f6fd49a43..f848cfa1a35 100644 --- a/tests/visual/index.html +++ b/tests/visual/index.html @@ -1,50 +1,99 @@ - + - + jQuery UI Visual Tests - - + + + + + + - -

      jQuery UI Visual Tests

      - -

      Composites

      - - - -

      Interactions

      - - -

      Widgets

      - + +
      +

      jQuery UI Visual Tests

      +
      +

      Accordion

      + + +

      addClass

      + + +

      Checkboxradio

      + + +

      Dialog

      + + +

      Draggable

      + + +

      Effects

      + + +

      Menu

      + + +

      Position

      + + +

      Selectmenu

      + + +

      Slider

      + + +

      Tooltip

      + + +

      Compound

      + +
      +
      diff --git a/tests/visual/menu/contextmenu.html b/tests/visual/menu/contextmenu.html deleted file mode 100644 index 6e9b8520052..00000000000 --- a/tests/visual/menu/contextmenu.html +++ /dev/null @@ -1,175 +0,0 @@ - - - - Menu Visual Test: Default - - - - - - - - - - - - - - - - - - - -
      - Log: -
      -
      - - - - - diff --git a/tests/visual/menu/drilldown.html b/tests/visual/menu/drilldown.html deleted file mode 100644 index 1539045f050..00000000000 --- a/tests/visual/menu/drilldown.html +++ /dev/null @@ -1,259 +0,0 @@ - - - - Menu Visual Test: Default - - - - - - - - - - - - - -
      -

      Make a selection...

      - - Go back -
      - -
      - Log: -
      -
      - - - diff --git a/tests/visual/menu/menu.html b/tests/visual/menu/menu.html index 93c33d4e297..97ecdb4dfbb 100644 --- a/tests/visual/menu/menu.html +++ b/tests/visual/menu/menu.html @@ -1,117 +1,342 @@ - + + Menu Visual Test: Default - - - - - - - - + - - -
      ') - .css({ - position: 'absolute', - visibility: 'visible', - left: -j*(width/cells), - top: -i*(height/rows) - }) - .parent() - .addClass('ui-effects-explode') - .css({ - position: 'absolute', - overflow: 'hidden', - width: width/cells, - height: height/rows, - left: offset.left + j*(width/cells) + (o.options.mode == 'show' ? (j-Math.floor(cells/2))*(width/cells) : 0), - top: offset.top + i*(height/rows) + (o.options.mode == 'show' ? (i-Math.floor(rows/2))*(height/rows) : 0), - opacity: o.options.mode == 'show' ? 0 : 1 - }).animate({ - left: offset.left + j*(width/cells) + (o.options.mode == 'show' ? 0 : (j-Math.floor(cells/2))*(width/cells)), - top: offset.top + i*(height/rows) + (o.options.mode == 'show' ? 0 : (i-Math.floor(rows/2))*(height/rows)), - opacity: o.options.mode == 'show' ? 1 : 0 - }, o.duration || 500); - } - } - - // Set a timeout, to call the callback approx. when the other animations have finished - setTimeout(function() { - - o.options.mode == 'show' ? el.css({ visibility: 'visible' }) : el.css({ visibility: 'visible' }).hide(); - if(o.callback) o.callback.apply(el[0]); // Callback - el.dequeue(); - - $('div.ui-effects-explode').remove(); - - }, o.duration || 500); - - - }); - -}; - -})(jQuery); diff --git a/ui/jquery.effects.fade.js b/ui/jquery.effects.fade.js deleted file mode 100644 index c42a9f565ab..00000000000 --- a/ui/jquery.effects.fade.js +++ /dev/null @@ -1,32 +0,0 @@ -/* - * jQuery UI Effects Fade @VERSION - * - * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT (MIT-LICENSE.txt) - * and GPL (GPL-LICENSE.txt) licenses. - * - * http://docs.jquery.com/UI/Effects/Fade - * - * Depends: - * jquery.effects.core.js - */ -(function($) { - -$.effects.fade = function(o) { - return this.queue(function() { - var elem = $(this), - mode = $.effects.setMode(elem, o.options.mode || 'hide'); - - elem.animate({ opacity: mode }, { - queue: false, - duration: o.duration, - easing: o.options.easing, - complete: function() { - (o.callback && o.callback.apply(this, arguments)); - elem.dequeue(); - } - }); - }); -}; - -})(jQuery); diff --git a/ui/jquery.effects.fold.js b/ui/jquery.effects.fold.js deleted file mode 100644 index 1098ee4208b..00000000000 --- a/ui/jquery.effects.fold.js +++ /dev/null @@ -1,56 +0,0 @@ -/* - * jQuery UI Effects Fold @VERSION - * - * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT (MIT-LICENSE.txt) - * and GPL (GPL-LICENSE.txt) licenses. - * - * http://docs.jquery.com/UI/Effects/Fold - * - * Depends: - * jquery.effects.core.js - */ -(function($) { - -$.effects.fold = function(o) { - - return this.queue(function() { - - // Create element - var el = $(this), props = ['position','top','left']; - - // Set options - var mode = $.effects.setMode(el, o.options.mode || 'hide'); // Set Mode - var size = o.options.size || 15; // Default fold size - var horizFirst = !(!o.options.horizFirst); // Ensure a boolean value - var duration = o.duration ? o.duration / 2 : $.fx.speeds._default / 2; - - // Adjust - $.effects.save(el, props); el.show(); // Save & Show - var wrapper = $.effects.createWrapper(el).css({overflow:'hidden'}); // Create Wrapper - var widthFirst = ((mode == 'show') != horizFirst); - var ref = widthFirst ? ['width', 'height'] : ['height', 'width']; - var distance = widthFirst ? [wrapper.width(), wrapper.height()] : [wrapper.height(), wrapper.width()]; - var percent = /([0-9]+)%/.exec(size); - if(percent) size = parseInt(percent[1],10) / 100 * distance[mode == 'hide' ? 0 : 1]; - if(mode == 'show') wrapper.css(horizFirst ? {height: 0, width: size} : {height: size, width: 0}); // Shift - - // Animation - var animation1 = {}, animation2 = {}; - animation1[ref[0]] = mode == 'show' ? distance[0] : size; - animation2[ref[1]] = mode == 'show' ? distance[1] : 0; - - // Animate - wrapper.animate(animation1, duration, o.options.easing) - .animate(animation2, duration, o.options.easing, function() { - if(mode == 'hide') el.hide(); // Hide - $.effects.restore(el, props); $.effects.removeWrapper(el); // Restore - if(o.callback) o.callback.apply(el[0], arguments); // Callback - el.dequeue(); - }); - - }); - -}; - -})(jQuery); diff --git a/ui/jquery.effects.highlight.js b/ui/jquery.effects.highlight.js deleted file mode 100644 index 4719abed980..00000000000 --- a/ui/jquery.effects.highlight.js +++ /dev/null @@ -1,50 +0,0 @@ -/* - * jQuery UI Effects Highlight @VERSION - * - * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT (MIT-LICENSE.txt) - * and GPL (GPL-LICENSE.txt) licenses. - * - * http://docs.jquery.com/UI/Effects/Highlight - * - * Depends: - * jquery.effects.core.js - */ -(function($) { - -$.effects.highlight = function(o) { - return this.queue(function() { - var elem = $(this), - props = ['backgroundImage', 'backgroundColor', 'opacity'], - mode = $.effects.setMode(elem, o.options.mode || 'show'), - animation = { - backgroundColor: elem.css('backgroundColor') - }; - - if (mode == 'hide') { - animation.opacity = 0; - } - - $.effects.save(elem, props); - elem - .show() - .css({ - backgroundImage: 'none', - backgroundColor: o.options.color || '#ffff99' - }) - .animate(animation, { - queue: false, - duration: o.duration, - easing: o.options.easing, - complete: function() { - (mode == 'hide' && elem.hide()); - $.effects.restore(elem, props); - (mode == 'show' && !$.support.opacity && this.style.removeAttribute('filter')); - (o.callback && o.callback.apply(this, arguments)); - elem.dequeue(); - } - }); - }); -}; - -})(jQuery); diff --git a/ui/jquery.effects.pulsate.js b/ui/jquery.effects.pulsate.js deleted file mode 100644 index ca1af19fd5a..00000000000 --- a/ui/jquery.effects.pulsate.js +++ /dev/null @@ -1,51 +0,0 @@ -/* - * jQuery UI Effects Pulsate @VERSION - * - * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT (MIT-LICENSE.txt) - * and GPL (GPL-LICENSE.txt) licenses. - * - * http://docs.jquery.com/UI/Effects/Pulsate - * - * Depends: - * jquery.effects.core.js - */ -(function($) { - -$.effects.pulsate = function(o) { - return this.queue(function() { - var elem = $(this), - mode = $.effects.setMode(elem, o.options.mode || 'show'); - times = ((o.options.times || 5) * 2) - 1; - duration = o.duration ? o.duration / 2 : $.fx.speeds._default / 2, - isVisible = elem.is(':visible'), - animateTo = 0; - - if (!isVisible) { - elem.css('opacity', 0).show(); - animateTo = 1; - } - - if ((mode == 'hide' && isVisible) || (mode == 'show' && !isVisible)) { - times--; - } - - for (var i = 0; i < times; i++) { - elem.animate({ opacity: animateTo }, duration, o.options.easing); - animateTo = (animateTo + 1) % 2; - } - - elem.animate({ opacity: animateTo }, duration, o.options.easing, function() { - if (animateTo == 0) { - elem.hide(); - } - (o.callback && o.callback.apply(this, arguments)); - }); - - elem - .queue('fx', function() { elem.dequeue(); }) - .dequeue(); - }); -}; - -})(jQuery); diff --git a/ui/jquery.effects.scale.js b/ui/jquery.effects.scale.js deleted file mode 100644 index ee430e7b8ea..00000000000 --- a/ui/jquery.effects.scale.js +++ /dev/null @@ -1,178 +0,0 @@ -/* - * jQuery UI Effects Scale @VERSION - * - * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT (MIT-LICENSE.txt) - * and GPL (GPL-LICENSE.txt) licenses. - * - * http://docs.jquery.com/UI/Effects/Scale - * - * Depends: - * jquery.effects.core.js - */ -(function($) { - -$.effects.puff = function(o) { - return this.queue(function() { - var elem = $(this), - mode = $.effects.setMode(elem, o.options.mode || 'hide'), - percent = parseInt(o.options.percent, 10) || 150, - factor = percent / 100, - original = { height: elem.height(), width: elem.width() }; - - $.extend(o.options, { - fade: true, - mode: mode, - percent: mode == 'hide' ? percent : 100, - from: mode == 'hide' - ? original - : { - height: original.height * factor, - width: original.width * factor - } - }); - - elem.effect('scale', o.options, o.duration, o.callback); - elem.dequeue(); - }); -}; - -$.effects.scale = function(o) { - - return this.queue(function() { - - // Create element - var el = $(this); - - // Set options - var options = $.extend(true, {}, o.options); - var mode = $.effects.setMode(el, o.options.mode || 'effect'); // Set Mode - var percent = parseInt(o.options.percent,10) || (parseInt(o.options.percent,10) == 0 ? 0 : (mode == 'hide' ? 0 : 100)); // Set default scaling percent - var direction = o.options.direction || 'both'; // Set default axis - var origin = o.options.origin; // The origin of the scaling - if (mode != 'effect') { // Set default origin and restore for show/hide - options.origin = origin || ['middle','center']; - options.restore = true; - } - var original = {height: el.height(), width: el.width()}; // Save original - el.from = o.options.from || (mode == 'show' ? {height: 0, width: 0} : original); // Default from state - - // Adjust - var factor = { // Set scaling factor - y: direction != 'horizontal' ? (percent / 100) : 1, - x: direction != 'vertical' ? (percent / 100) : 1 - }; - el.to = {height: original.height * factor.y, width: original.width * factor.x}; // Set to state - - if (o.options.fade) { // Fade option to support puff - if (mode == 'show') {el.from.opacity = 0; el.to.opacity = 1;}; - if (mode == 'hide') {el.from.opacity = 1; el.to.opacity = 0;}; - }; - - // Animation - options.from = el.from; options.to = el.to; options.mode = mode; - - // Animate - el.effect('size', options, o.duration, o.callback); - el.dequeue(); - }); - -}; - -$.effects.size = function(o) { - - return this.queue(function() { - - // Create element - var el = $(this), props = ['position','top','left','width','height','overflow','opacity']; - var props1 = ['position','top','left','overflow','opacity']; // Always restore - var props2 = ['width','height','overflow']; // Copy for children - var cProps = ['fontSize']; - var vProps = ['borderTopWidth', 'borderBottomWidth', 'paddingTop', 'paddingBottom']; - var hProps = ['borderLeftWidth', 'borderRightWidth', 'paddingLeft', 'paddingRight']; - - // Set options - var mode = $.effects.setMode(el, o.options.mode || 'effect'); // Set Mode - var restore = o.options.restore || false; // Default restore - var scale = o.options.scale || 'both'; // Default scale mode - var origin = o.options.origin; // The origin of the sizing - var original = {height: el.height(), width: el.width()}; // Save original - el.from = o.options.from || original; // Default from state - el.to = o.options.to || original; // Default to state - // Adjust - if (origin) { // Calculate baseline shifts - var baseline = $.effects.getBaseline(origin, original); - el.from.top = (original.height - el.from.height) * baseline.y; - el.from.left = (original.width - el.from.width) * baseline.x; - el.to.top = (original.height - el.to.height) * baseline.y; - el.to.left = (original.width - el.to.width) * baseline.x; - }; - var factor = { // Set scaling factor - from: {y: el.from.height / original.height, x: el.from.width / original.width}, - to: {y: el.to.height / original.height, x: el.to.width / original.width} - }; - if (scale == 'box' || scale == 'both') { // Scale the css box - if (factor.from.y != factor.to.y) { // Vertical props scaling - props = props.concat(vProps); - el.from = $.effects.setTransition(el, vProps, factor.from.y, el.from); - el.to = $.effects.setTransition(el, vProps, factor.to.y, el.to); - }; - if (factor.from.x != factor.to.x) { // Horizontal props scaling - props = props.concat(hProps); - el.from = $.effects.setTransition(el, hProps, factor.from.x, el.from); - el.to = $.effects.setTransition(el, hProps, factor.to.x, el.to); - }; - }; - if (scale == 'content' || scale == 'both') { // Scale the content - if (factor.from.y != factor.to.y) { // Vertical props scaling - props = props.concat(cProps); - el.from = $.effects.setTransition(el, cProps, factor.from.y, el.from); - el.to = $.effects.setTransition(el, cProps, factor.to.y, el.to); - }; - }; - $.effects.save(el, restore ? props : props1); el.show(); // Save & Show - $.effects.createWrapper(el); // Create Wrapper - el.css('overflow','hidden').css(el.from); // Shift - - // Animate - if (scale == 'content' || scale == 'both') { // Scale the children - vProps = vProps.concat(['marginTop','marginBottom']).concat(cProps); // Add margins/font-size - hProps = hProps.concat(['marginLeft','marginRight']); // Add margins - props2 = props.concat(vProps).concat(hProps); // Concat - el.find("*[width]").each(function(){ - child = $(this); - if (restore) $.effects.save(child, props2); - var c_original = {height: child.height(), width: child.width()}; // Save original - child.from = {height: c_original.height * factor.from.y, width: c_original.width * factor.from.x}; - child.to = {height: c_original.height * factor.to.y, width: c_original.width * factor.to.x}; - if (factor.from.y != factor.to.y) { // Vertical props scaling - child.from = $.effects.setTransition(child, vProps, factor.from.y, child.from); - child.to = $.effects.setTransition(child, vProps, factor.to.y, child.to); - }; - if (factor.from.x != factor.to.x) { // Horizontal props scaling - child.from = $.effects.setTransition(child, hProps, factor.from.x, child.from); - child.to = $.effects.setTransition(child, hProps, factor.to.x, child.to); - }; - child.css(child.from); // Shift children - child.animate(child.to, o.duration, o.options.easing, function(){ - if (restore) $.effects.restore(child, props2); // Restore children - }); // Animate children - }); - }; - - // Animate - el.animate(el.to, { queue: false, duration: o.duration, easing: o.options.easing, complete: function() { - if (el.to.opacity === 0) { - el.css('opacity', el.from.opacity); - } - if(mode == 'hide') el.hide(); // Hide - $.effects.restore(el, restore ? props : props1); $.effects.removeWrapper(el); // Restore - if(o.callback) o.callback.apply(this, arguments); // Callback - el.dequeue(); - }}); - - }); - -}; - -})(jQuery); diff --git a/ui/jquery.effects.shake.js b/ui/jquery.effects.shake.js deleted file mode 100644 index dd3e1cb615d..00000000000 --- a/ui/jquery.effects.shake.js +++ /dev/null @@ -1,57 +0,0 @@ -/* - * jQuery UI Effects Shake @VERSION - * - * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT (MIT-LICENSE.txt) - * and GPL (GPL-LICENSE.txt) licenses. - * - * http://docs.jquery.com/UI/Effects/Shake - * - * Depends: - * jquery.effects.core.js - */ -(function($) { - -$.effects.shake = function(o) { - - return this.queue(function() { - - // Create element - var el = $(this), props = ['position','top','left']; - - // Set options - var mode = $.effects.setMode(el, o.options.mode || 'effect'); // Set Mode - var direction = o.options.direction || 'left'; // Default direction - var distance = o.options.distance || 20; // Default distance - var times = o.options.times || 3; // Default # of times - var speed = o.duration || o.options.duration || 140; // Default speed per shake - - // Adjust - $.effects.save(el, props); el.show(); // Save & Show - $.effects.createWrapper(el); // Create Wrapper - var ref = (direction == 'up' || direction == 'down') ? 'top' : 'left'; - var motion = (direction == 'up' || direction == 'left') ? 'pos' : 'neg'; - - // Animation - var animation = {}, animation1 = {}, animation2 = {}; - animation[ref] = (motion == 'pos' ? '-=' : '+=') + distance; - animation1[ref] = (motion == 'pos' ? '+=' : '-=') + distance * 2; - animation2[ref] = (motion == 'pos' ? '-=' : '+=') + distance * 2; - - // Animate - el.animate(animation, speed, o.options.easing); - for (var i = 1; i < times; i++) { // Shakes - el.animate(animation1, speed, o.options.easing).animate(animation2, speed, o.options.easing); - }; - el.animate(animation1, speed, o.options.easing). - animate(animation, speed / 2, o.options.easing, function(){ // Last shake - $.effects.restore(el, props); $.effects.removeWrapper(el); // Restore - if(o.callback) o.callback.apply(this, arguments); // Callback - }); - el.queue('fx', function() { el.dequeue(); }); - el.dequeue(); - }); - -}; - -})(jQuery); diff --git a/ui/jquery.effects.slide.js b/ui/jquery.effects.slide.js deleted file mode 100644 index d84447d135a..00000000000 --- a/ui/jquery.effects.slide.js +++ /dev/null @@ -1,50 +0,0 @@ -/* - * jQuery UI Effects Slide @VERSION - * - * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT (MIT-LICENSE.txt) - * and GPL (GPL-LICENSE.txt) licenses. - * - * http://docs.jquery.com/UI/Effects/Slide - * - * Depends: - * jquery.effects.core.js - */ -(function($) { - -$.effects.slide = function(o) { - - return this.queue(function() { - - // Create element - var el = $(this), props = ['position','top','left']; - - // Set options - var mode = $.effects.setMode(el, o.options.mode || 'show'); // Set Mode - var direction = o.options.direction || 'left'; // Default Direction - - // Adjust - $.effects.save(el, props); el.show(); // Save & Show - $.effects.createWrapper(el).css({overflow:'hidden'}); // Create Wrapper - var ref = (direction == 'up' || direction == 'down') ? 'top' : 'left'; - var motion = (direction == 'up' || direction == 'left') ? 'pos' : 'neg'; - var distance = o.options.distance || (ref == 'top' ? el.outerHeight({margin:true}) : el.outerWidth({margin:true})); - if (mode == 'show') el.css(ref, motion == 'pos' ? -distance : distance); // Shift - - // Animation - var animation = {}; - animation[ref] = (mode == 'show' ? (motion == 'pos' ? '+=' : '-=') : (motion == 'pos' ? '-=' : '+=')) + distance; - - // Animate - el.animate(animation, { queue: false, duration: o.duration, easing: o.options.easing, complete: function() { - if(mode == 'hide') el.hide(); // Hide - $.effects.restore(el, props); $.effects.removeWrapper(el); // Restore - if(o.callback) o.callback.apply(this, arguments); // Callback - el.dequeue(); - }}); - - }); - -}; - -})(jQuery); diff --git a/ui/jquery.effects.transfer.js b/ui/jquery.effects.transfer.js deleted file mode 100644 index f597d4b4323..00000000000 --- a/ui/jquery.effects.transfer.js +++ /dev/null @@ -1,45 +0,0 @@ -/* - * jQuery UI Effects Transfer @VERSION - * - * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT (MIT-LICENSE.txt) - * and GPL (GPL-LICENSE.txt) licenses. - * - * http://docs.jquery.com/UI/Effects/Transfer - * - * Depends: - * jquery.effects.core.js - */ -(function($) { - -$.effects.transfer = function(o) { - return this.queue(function() { - var elem = $(this), - target = $(o.options.to), - endPosition = target.offset(), - animation = { - top: endPosition.top, - left: endPosition.left, - height: target.innerHeight(), - width: target.innerWidth() - }, - startPosition = elem.offset(), - transfer = $('
      ') - .appendTo(document.body) - .addClass(o.options.className) - .css({ - top: startPosition.top, - left: startPosition.left, - height: elem.innerHeight(), - width: elem.innerWidth(), - position: 'absolute' - }) - .animate(animation, o.duration, o.options.easing, function() { - transfer.remove(); - (o.callback && o.callback.apply(elem[0], arguments)); - elem.dequeue(); - }); - }); -}; - -})(jQuery); diff --git a/ui/jquery.ui.accordion.js b/ui/jquery.ui.accordion.js deleted file mode 100644 index 1a8825dacdf..00000000000 --- a/ui/jquery.ui.accordion.js +++ /dev/null @@ -1,504 +0,0 @@ -/* - * jQuery UI Accordion @VERSION - * - * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT (MIT-LICENSE.txt) - * and GPL (GPL-LICENSE.txt) licenses. - * - * http://docs.jquery.com/UI/Accordion - * - * Depends: - * jquery.ui.core.js - * jquery.ui.widget.js - */ -(function($) { - -$.widget("ui.accordion", { - options: { - active: 0, - animated: 'slide', - autoHeight: true, - clearStyle: false, - collapsible: false, - event: "click", - fillSpace: false, - header: "> li > :first-child,> :not(li):even", - icons: { - header: "ui-icon-triangle-1-e", - headerSelected: "ui-icon-triangle-1-s" - }, - navigation: false, - navigationFilter: function() { - return this.href.toLowerCase() == location.href.toLowerCase(); - } - }, - _create: function() { - - var o = this.options, self = this; - this.running = 0; - - this.element.addClass("ui-accordion ui-widget ui-helper-reset"); - - // in lack of child-selectors in CSS we need to mark top-LIs in a UL-accordion for some IE-fix - this.element.children("li").addClass("ui-accordion-li-fix"); - - this.headers = this.element.find(o.header).addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all") - .bind("mouseenter.accordion", function(){ $(this).addClass('ui-state-hover'); }) - .bind("mouseleave.accordion", function(){ $(this).removeClass('ui-state-hover'); }) - .bind("focus.accordion", function(){ $(this).addClass('ui-state-focus'); }) - .bind("blur.accordion", function(){ $(this).removeClass('ui-state-focus'); }); - - this.headers - .next() - .addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom"); - - if ( o.navigation ) { - var current = this.element.find("a").filter(o.navigationFilter); - if ( current.length ) { - var header = current.closest(".ui-accordion-header"); - if ( header.length ) { - // anchor within header - this.active = header; - } else { - // anchor within content - this.active = current.closest(".ui-accordion-content").prev(); - } - } - } - - this.active = this._findActive(this.active || o.active).toggleClass("ui-state-default").toggleClass("ui-state-active").toggleClass("ui-corner-all").toggleClass("ui-corner-top"); - this.active.next().addClass('ui-accordion-content-active'); - - //Append icon elements - this._createIcons(); - - this.resize(); - - //ARIA - this.element.attr('role','tablist'); - - this.headers - .attr('role','tab') - .bind('keydown', function(event) { return self._keydown(event); }) - .next() - .attr('role','tabpanel'); - - this.headers - .not(this.active || "") - .attr('aria-expanded','false') - .attr("tabIndex", "-1") - .next() - .hide(); - - // make sure at least one header is in the tab order - if (!this.active.length) { - this.headers.eq(0).attr('tabIndex','0'); - } else { - this.active - .attr('aria-expanded','true') - .attr('tabIndex', '0'); - } - - // only need links in taborder for Safari - if (!$.browser.safari) - this.headers.find('a').attr('tabIndex','-1'); - - if (o.event) { - this.headers.bind((o.event) + ".accordion", function(event) { - self._clickHandler.call(self, event, this); - event.preventDefault(); - }); - } - - }, - - _createIcons: function() { - var o = this.options; - if (o.icons) { - $("").addClass("ui-icon " + o.icons.header).prependTo(this.headers); - this.active.find(".ui-icon").toggleClass(o.icons.header).toggleClass(o.icons.headerSelected); - this.element.addClass("ui-accordion-icons"); - } - }, - - _destroyIcons: function() { - this.headers.children(".ui-icon").remove(); - this.element.removeClass("ui-accordion-icons"); - }, - - destroy: function() { - var o = this.options; - - this.element - .removeClass("ui-accordion ui-widget ui-helper-reset") - .removeAttr("role") - .unbind('.accordion') - .removeData('accordion'); - - this.headers - .unbind(".accordion") - .removeClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-corner-top") - .removeAttr("role").removeAttr("aria-expanded").removeAttr("tabIndex"); - - this.headers.find("a").removeAttr("tabIndex"); - this._destroyIcons(); - var contents = this.headers.next().css("display", "").removeAttr("role").removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active"); - if (o.autoHeight || o.fillHeight) { - contents.css("height", ""); - } - - return this; - }, - - _setOption: function(key, value) { - $.Widget.prototype._setOption.apply(this, arguments); - - if (key == "active") { - this.activate(value); - } - if (key == "icons") { - this._destroyIcons(); - if (value) { - this._createIcons(); - } - } - - }, - - _keydown: function(event) { - - var o = this.options, keyCode = $.ui.keyCode; - - if (o.disabled || event.altKey || event.ctrlKey) - return; - - var length = this.headers.length; - var currentIndex = this.headers.index(event.target); - var toFocus = false; - - switch(event.keyCode) { - case keyCode.RIGHT: - case keyCode.DOWN: - toFocus = this.headers[(currentIndex + 1) % length]; - break; - case keyCode.LEFT: - case keyCode.UP: - toFocus = this.headers[(currentIndex - 1 + length) % length]; - break; - case keyCode.SPACE: - case keyCode.ENTER: - this._clickHandler({ target: event.target }, event.target); - event.preventDefault(); - } - - if (toFocus) { - $(event.target).attr('tabIndex','-1'); - $(toFocus).attr('tabIndex','0'); - toFocus.focus(); - return false; - } - - return true; - - }, - - resize: function() { - - var o = this.options, maxHeight; - - if (o.fillSpace) { - - if($.browser.msie) { var defOverflow = this.element.parent().css('overflow'); this.element.parent().css('overflow', 'hidden'); } - maxHeight = this.element.parent().height(); - if($.browser.msie) { this.element.parent().css('overflow', defOverflow); } - - this.headers.each(function() { - maxHeight -= $(this).outerHeight(true); - }); - - this.headers.next().each(function() { - $(this).height(Math.max(0, maxHeight - $(this).innerHeight() + $(this).height())); - }).css('overflow', 'auto'); - - } else if ( o.autoHeight ) { - maxHeight = 0; - this.headers.next().each(function() { - maxHeight = Math.max(maxHeight, $(this).height()); - }).height(maxHeight); - } - - return this; - }, - - activate: function(index) { - // TODO this gets called on init, changing the option without an explicit call for that - this.options.active = index; - // call clickHandler with custom event - var active = this._findActive(index)[0]; - this._clickHandler({ target: active }, active); - - return this; - }, - - _findActive: function(selector) { - return selector - ? typeof selector == "number" - ? this.headers.filter(":eq(" + selector + ")") - : this.headers.not(this.headers.not(selector)) - : selector === false - ? $([]) - : this.headers.filter(":eq(0)"); - }, - - // TODO isn't event.target enough? why the seperate target argument? - _clickHandler: function(event, target) { - - var o = this.options; - if (o.disabled) - return; - - // called only when using activate(false) to close all parts programmatically - if (!event.target) { - if (!o.collapsible) - return; - this.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all") - .find(".ui-icon").removeClass(o.icons.headerSelected).addClass(o.icons.header); - this.active.next().addClass('ui-accordion-content-active'); - var toHide = this.active.next(), - data = { - options: o, - newHeader: $([]), - oldHeader: o.active, - newContent: $([]), - oldContent: toHide - }, - toShow = (this.active = $([])); - this._toggle(toShow, toHide, data); - return; - } - - // get the click target - var clicked = $(event.currentTarget || target); - var clickedIsActive = clicked[0] == this.active[0]; - - // TODO the option is changed, is that correct? - // TODO if it is correct, shouldn't that happen after determining that the click is valid? - o.active = o.collapsible && clickedIsActive ? false : $('.ui-accordion-header', this.element).index(clicked); - - // if animations are still active, or the active header is the target, ignore click - if (this.running || (!o.collapsible && clickedIsActive)) { - return; - } - - // switch classes - this.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all") - .find(".ui-icon").removeClass(o.icons.headerSelected).addClass(o.icons.header); - if (!clickedIsActive) { - clicked.removeClass("ui-state-default ui-corner-all").addClass("ui-state-active ui-corner-top") - .find(".ui-icon").removeClass(o.icons.header).addClass(o.icons.headerSelected); - clicked.next().addClass('ui-accordion-content-active'); - } - - // find elements to show and hide - var toShow = clicked.next(), - toHide = this.active.next(), - data = { - options: o, - newHeader: clickedIsActive && o.collapsible ? $([]) : clicked, - oldHeader: this.active, - newContent: clickedIsActive && o.collapsible ? $([]) : toShow, - oldContent: toHide - }, - down = this.headers.index( this.active[0] ) > this.headers.index( clicked[0] ); - - this.active = clickedIsActive ? $([]) : clicked; - this._toggle(toShow, toHide, data, clickedIsActive, down); - - return; - - }, - - _toggle: function(toShow, toHide, data, clickedIsActive, down) { - - var o = this.options, self = this; - - this.toShow = toShow; - this.toHide = toHide; - this.data = data; - - var complete = function() { if(!self) return; return self._completed.apply(self, arguments); }; - - // trigger changestart event - this._trigger("changestart", null, this.data); - - // count elements to animate - this.running = toHide.size() === 0 ? toShow.size() : toHide.size(); - - if (o.animated) { - - var animOptions = {}; - - if ( o.collapsible && clickedIsActive ) { - animOptions = { - toShow: $([]), - toHide: toHide, - complete: complete, - down: down, - autoHeight: o.autoHeight || o.fillSpace - }; - } else { - animOptions = { - toShow: toShow, - toHide: toHide, - complete: complete, - down: down, - autoHeight: o.autoHeight || o.fillSpace - }; - } - - if (!o.proxied) { - o.proxied = o.animated; - } - - if (!o.proxiedDuration) { - o.proxiedDuration = o.duration; - } - - o.animated = $.isFunction(o.proxied) ? - o.proxied(animOptions) : o.proxied; - - o.duration = $.isFunction(o.proxiedDuration) ? - o.proxiedDuration(animOptions) : o.proxiedDuration; - - var animations = $.ui.accordion.animations, - duration = o.duration, - easing = o.animated; - - if (easing && !animations[easing] && !$.easing[easing]) { - easing = 'slide'; - } - if (!animations[easing]) { - animations[easing] = function(options) { - this.slide(options, { - easing: easing, - duration: duration || 700 - }); - }; - } - - animations[easing](animOptions); - - } else { - - if (o.collapsible && clickedIsActive) { - toShow.toggle(); - } else { - toHide.hide(); - toShow.show(); - } - - complete(true); - - } - - // TODO assert that the blur and focus triggers are really necessary, remove otherwise - toHide.prev().attr('aria-expanded','false').attr("tabIndex", "-1").blur(); - toShow.prev().attr('aria-expanded','true').attr("tabIndex", "0").focus(); - - }, - - _completed: function(cancel) { - - var o = this.options; - - this.running = cancel ? 0 : --this.running; - if (this.running) return; - - if (o.clearStyle) { - this.toShow.add(this.toHide).css({ - height: "", - overflow: "" - }); - } - - // other classes are removed before the animation; this one needs to stay until completed - this.toHide.removeClass("ui-accordion-content-active"); - - this._trigger('change', null, this.data); - } - -}); - - -$.extend($.ui.accordion, { - version: "@VERSION", - animations: { - slide: function(options, additions) { - options = $.extend({ - easing: "swing", - duration: 300 - }, options, additions); - if ( !options.toHide.size() ) { - options.toShow.animate({height: "show"}, options); - return; - } - if ( !options.toShow.size() ) { - options.toHide.animate({height: "hide"}, options); - return; - } - var overflow = options.toShow.css('overflow'), - percentDone = 0, - showProps = {}, - hideProps = {}, - fxAttrs = [ "height", "paddingTop", "paddingBottom" ], - originalWidth; - // fix width before calculating height of hidden element - var s = options.toShow; - originalWidth = s[0].style.width; - s.width( parseInt(s.parent().width(),10) - parseInt(s.css("paddingLeft"),10) - parseInt(s.css("paddingRight"),10) - (parseInt(s.css("borderLeftWidth"),10) || 0) - (parseInt(s.css("borderRightWidth"),10) || 0) ); - - $.each(fxAttrs, function(i, prop) { - hideProps[prop] = 'hide'; - - var parts = ('' + $.css(options.toShow[0], prop)).match(/^([\d+-.]+)(.*)$/); - showProps[prop] = { - value: parts[1], - unit: parts[2] || 'px' - }; - }); - options.toShow.css({ height: 0, overflow: 'hidden' }).show(); - options.toHide.filter(":hidden").each(options.complete).end().filter(":visible").animate(hideProps,{ - step: function(now, settings) { - // only calculate the percent when animating height - // IE gets very inconsistent results when animating elements - // with small values, which is common for padding - if (settings.prop == 'height') { - percentDone = ( settings.end - settings.start === 0 ) ? 0 : - (settings.now - settings.start) / (settings.end - settings.start); - } - - options.toShow[0].style[settings.prop] = - (percentDone * showProps[settings.prop].value) + showProps[settings.prop].unit; - }, - duration: options.duration, - easing: options.easing, - complete: function() { - if ( !options.autoHeight ) { - options.toShow.css("height", ""); - } - options.toShow.css("width", originalWidth); - options.toShow.css({overflow: overflow}); - options.complete(); - } - }); - }, - bounceslide: function(options) { - this.slide(options, { - easing: options.down ? "easeOutBounce" : "swing", - duration: options.down ? 1000 : 200 - }); - } - } -}); - -})(jQuery); diff --git a/ui/jquery.ui.autocomplete.js b/ui/jquery.ui.autocomplete.js deleted file mode 100644 index bd7420df8d0..00000000000 --- a/ui/jquery.ui.autocomplete.js +++ /dev/null @@ -1,511 +0,0 @@ -/* - * jQuery UI Autocomplete @VERSION - * - * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT (MIT-LICENSE.txt) - * and GPL (GPL-LICENSE.txt) licenses. - * - * http://docs.jquery.com/UI/Autocomplete - * - * Depends: - * jquery.ui.core.js - * jquery.ui.widget.js - * jquery.ui.position.js - */ -(function( $ ) { - -$.widget( "ui.autocomplete", { - options: { - minLength: 1, - delay: 300 - }, - _create: function() { - var self = this, - doc = this.element[ 0 ].ownerDocument; - this.element - .addClass( "ui-autocomplete-input" ) - .attr( "autocomplete", "off" ) - // TODO verify these actually work as intended - .attr({ - role: "textbox", - "aria-autocomplete": "list", - "aria-haspopup": "true" - }) - .bind( "keydown.autocomplete", function( event ) { - var keyCode = $.ui.keyCode; - switch( event.keyCode ) { - case keyCode.PAGE_UP: - self._move( "previousPage", event ); - break; - case keyCode.PAGE_DOWN: - self._move( "nextPage", event ); - break; - case keyCode.UP: - self._move( "previous", event ); - // prevent moving cursor to beginning of text field in some browsers - event.preventDefault(); - break; - case keyCode.DOWN: - self._move( "next", event ); - // prevent moving cursor to end of text field in some browsers - event.preventDefault(); - break; - case keyCode.ENTER: - case keyCode.NUMPAD_ENTER: - // when menu is open or has focus - if ( self.menu.active ) { - event.preventDefault(); - } - //passthrough - ENTER and TAB both select the current element - case keyCode.TAB: - if ( !self.menu.active ) { - return; - } - self.menu.select( event ); - break; - case keyCode.ESCAPE: - self.element.val( self.term ); - self.close( event ); - break; - case keyCode.LEFT: - case keyCode.RIGHT: - case keyCode.SHIFT: - case keyCode.CONTROL: - case keyCode.ALT: - case keyCode.COMMAND: - case keyCode.COMMAND_RIGHT: - case keyCode.INSERT: - case keyCode.CAPS_LOCK: - case keyCode.END: - case keyCode.HOME: - // ignore metakeys (shift, ctrl, alt) - break; - default: - // keypress is triggered before the input value is changed - clearTimeout( self.searching ); - self.searching = setTimeout(function() { - self.search( null, event ); - }, self.options.delay ); - break; - } - }) - .bind( "focus.autocomplete", function() { - self.selectedItem = null; - self.previous = self.element.val(); - }) - .bind( "blur.autocomplete", function( event ) { - clearTimeout( self.searching ); - // clicks on the menu (or a button to trigger a search) will cause a blur event - self.closing = setTimeout(function() { - self.close( event ); - self._change( event ); - }, 150 ); - }); - this._initSource(); - this.response = function() { - return self._response.apply( self, arguments ); - }; - this.menu = $( "
        " ) - .addClass( "ui-autocomplete" ) - .appendTo( "body", doc ) - // prevent the close-on-blur in case of a "slow" click on the menu (long mousedown) - .mousedown(function() { - // use another timeout to make sure the blur-event-handler on the input was already triggered - setTimeout(function() { - clearTimeout( self.closing ); - }, 13); - }) - .menu({ - focus: function( event, ui ) { - var item = ui.item.data( "item.autocomplete" ); - if ( false !== self._trigger( "focus", null, { item: item } ) ) { - // use value to match what will end up in the input, if it was a key event - if ( /^key/.test(event.originalEvent.type) ) { - self.element.val( item.value ); - } - } - }, - selected: function( event, ui ) { - var item = ui.item.data( "item.autocomplete" ); - if ( false !== self._trigger( "select", event, { item: item } ) ) { - self.element.val( item.value ); - } - self.close( event ); - // only trigger when focus was lost (click on menu) - var previous = self.previous; - if ( self.element[0] !== doc.activeElement ) { - self.element.focus(); - self.previous = previous; - } - self.selectedItem = item; - }, - blur: function( event, ui ) { - if ( self.menu.element.is(":visible") ) { - self.element.val( self.term ); - } - } - }) - .zIndex( this.element.zIndex() + 1 ) - // workaround for jQuery bug #5781 http://dev.jquery.com/ticket/5781 - .css({ top: 0, left: 0 }) - .hide() - .data( "menu" ); - if ( $.fn.bgiframe ) { - this.menu.element.bgiframe(); - } - }, - - destroy: function() { - this.element - .removeClass( "ui-autocomplete-input" ) - .removeAttr( "autocomplete" ) - .removeAttr( "role" ) - .removeAttr( "aria-autocomplete" ) - .removeAttr( "aria-haspopup" ); - this.menu.element.remove(); - $.Widget.prototype.destroy.call( this ); - }, - - _setOption: function( key ) { - $.Widget.prototype._setOption.apply( this, arguments ); - if ( key === "source" ) { - this._initSource(); - } - }, - - _initSource: function() { - var array, - url; - if ( $.isArray(this.options.source) ) { - array = this.options.source; - this.source = function( request, response ) { - response( $.ui.autocomplete.filter(array, request.term) ); - }; - } else if ( typeof this.options.source === "string" ) { - url = this.options.source; - this.source = function( request, response ) { - $.getJSON( url, request, response ); - }; - } else { - this.source = this.options.source; - } - }, - - search: function( value, event ) { - value = value != null ? value : this.element.val(); - if ( value.length < this.options.minLength ) { - return this.close( event ); - } - - clearTimeout( this.closing ); - if ( this._trigger("search") === false ) { - return; - } - - return this._search( value ); - }, - - _search: function( value ) { - this.term = this.element - .addClass( "ui-autocomplete-loading" ) - // always save the actual value, not the one passed as an argument - .val(); - - this.source( { term: value }, this.response ); - }, - - _response: function( content ) { - if ( content.length ) { - content = this._normalize( content ); - this._suggest( content ); - this._trigger( "open" ); - } else { - this.close(); - } - this.element.removeClass( "ui-autocomplete-loading" ); - }, - - close: function( event ) { - clearTimeout( this.closing ); - if ( this.menu.element.is(":visible") ) { - this._trigger( "close", event ); - this.menu.element.hide(); - this.menu.deactivate(); - } - }, - - _change: function( event ) { - if ( this.previous !== this.element.val() ) { - this._trigger( "change", event, { item: this.selectedItem } ); - } - }, - - _normalize: function( items ) { - // assume all items have the right format when the first item is complete - if ( items.length && items[0].label && items[0].value ) { - return items; - } - return $.map( items, function(item) { - if ( typeof item === "string" ) { - return { - label: item, - value: item - }; - } - return $.extend({ - label: item.label || item.value, - value: item.value || item.label - }, item ); - }); - }, - - _suggest: function( items ) { - var ul = this.menu.element - .empty() - .zIndex( this.element.zIndex() + 1 ), - menuWidth, - textWidth; - this._renderMenu( ul, items ); - // TODO refresh should check if the active item is still in the dom, removing the need for a manual deactivate - this.menu.deactivate(); - this.menu.refresh(); - this.menu.element.show().position({ - my: "left top", - at: "left bottom", - of: this.element, - collision: "none" - }); - - menuWidth = ul.width( "" ).width(); - textWidth = this.element.width(); - ul.width( Math.max( menuWidth, textWidth ) ); - }, - - _renderMenu: function( ul, items ) { - var self = this; - $.each( items, function( index, item ) { - self._renderItem( ul, item ); - }); - }, - - _renderItem: function( ul, item) { - return $( "
      • " ) - .data( "item.autocomplete", item ) - .append( "" + item.label + "" ) - .appendTo( ul ); - }, - - _move: function( direction, event ) { - if ( !this.menu.element.is(":visible") ) { - this.search( null, event ); - return; - } - if ( this.menu.first() && /^previous/.test(direction) || - this.menu.last() && /^next/.test(direction) ) { - this.element.val( this.term ); - this.menu.deactivate(); - return; - } - this.menu[ direction ]( event ); - }, - - widget: function() { - return this.menu.element; - } -}); - -$.extend( $.ui.autocomplete, { - escapeRegex: function( value ) { - return value.replace( /([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi, "\\$1" ); - }, - filter: function(array, term) { - var matcher = new RegExp( $.ui.autocomplete.escapeRegex(term), "i" ); - return $.grep( array, function(value) { - return matcher.test( value.label || value.value || value ); - }); - } -}); - -}( jQuery )); - -/* - * jQuery UI Menu (not officially released) - * - * This widget isn't yet finished and the API is subject to change. We plan to finish - * it for the next release. You're welcome to give it a try anyway and give us feedback, - * as long as you're okay with migrating your code later on. We can help with that, too. - * - * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT (MIT-LICENSE.txt) - * and GPL (GPL-LICENSE.txt) licenses. - * - * http://docs.jquery.com/UI/Menu - * - * Depends: - * jquery.ui.core.js - * jquery.ui.widget.js - */ -(function($) { - -$.widget("ui.menu", { - _create: function() { - var self = this; - this.element - .addClass("ui-menu ui-widget ui-widget-content ui-corner-all") - .attr({ - role: "listbox", - "aria-activedescendant": "ui-active-menuitem" - }) - .click(function( event ) { - if ( !$( event.target ).closest( ".ui-menu-item a" ).length ) { - return; - } - // temporary - event.preventDefault(); - self.select( event ); - }); - this.refresh(); - }, - - refresh: function() { - var self = this; - - // don't refresh list items that are already adapted - var items = this.element.children("li:not(.ui-menu-item):has(a)") - .addClass("ui-menu-item") - .attr("role", "menuitem"); - - items.children("a") - .addClass("ui-corner-all") - .attr("tabindex", -1) - // mouseenter doesn't work with event delegation - .mouseenter(function( event ) { - self.activate( event, $(this).parent() ); - }) - .mouseleave(function() { - self.deactivate(); - }); - }, - - activate: function( event, item ) { - this.deactivate(); - if (this.hasScroll()) { - var offset = item.offset().top - this.element.offset().top, - scroll = this.element.attr("scrollTop"), - elementHeight = this.element.height(); - if (offset < 0) { - this.element.attr("scrollTop", scroll + offset); - } else if (offset > elementHeight) { - this.element.attr("scrollTop", scroll + offset - elementHeight + item.height()); - } - } - this.active = item.eq(0) - .children("a") - .addClass("ui-state-hover") - .attr("id", "ui-active-menuitem") - .end(); - this._trigger("focus", event, { item: item }); - }, - - deactivate: function() { - if (!this.active) { return; } - - this.active.children("a") - .removeClass("ui-state-hover") - .removeAttr("id"); - this._trigger("blur"); - this.active = null; - }, - - next: function(event) { - this.move("next", ".ui-menu-item:first", event); - }, - - previous: function(event) { - this.move("prev", ".ui-menu-item:last", event); - }, - - first: function() { - return this.active && !this.active.prev().length; - }, - - last: function() { - return this.active && !this.active.next().length; - }, - - move: function(direction, edge, event) { - if (!this.active) { - this.activate(event, this.element.children(edge)); - return; - } - var next = this.active[direction + "All"](".ui-menu-item").eq(0); - if (next.length) { - this.activate(event, next); - } else { - this.activate(event, this.element.children(edge)); - } - }, - - // TODO merge with previousPage - nextPage: function(event) { - if (this.hasScroll()) { - // TODO merge with no-scroll-else - if (!this.active || this.last()) { - this.activate(event, this.element.children(":first")); - return; - } - var base = this.active.offset().top, - height = this.element.height(), - result = this.element.children("li").filter(function() { - var close = $(this).offset().top - base - height + $(this).height(); - // TODO improve approximation - return close < 10 && close > -10; - }); - - // TODO try to catch this earlier when scrollTop indicates the last page anyway - if (!result.length) { - result = this.element.children(":last"); - } - this.activate(event, result); - } else { - this.activate(event, this.element.children(!this.active || this.last() ? ":first" : ":last")); - } - }, - - // TODO merge with nextPage - previousPage: function(event) { - if (this.hasScroll()) { - // TODO merge with no-scroll-else - if (!this.active || this.first()) { - this.activate(event, this.element.children(":last")); - return; - } - - var base = this.active.offset().top, - height = this.element.height(); - result = this.element.children("li").filter(function() { - var close = $(this).offset().top - base + height - $(this).height(); - // TODO improve approximation - return close < 10 && close > -10; - }); - - // TODO try to catch this earlier when scrollTop indicates the last page anyway - if (!result.length) { - result = this.element.children(":first"); - } - this.activate(event, result); - } else { - this.activate(event, this.element.children(!this.active || this.first() ? ":last" : ":first")); - } - }, - - hasScroll: function() { - return this.element.height() < this.element.attr("scrollHeight"); - }, - - select: function( event ) { - this._trigger("selected", event, { item: this.active }); - } -}); - -}(jQuery)); diff --git a/ui/jquery.ui.button.js b/ui/jquery.ui.button.js deleted file mode 100644 index 8176c332190..00000000000 --- a/ui/jquery.ui.button.js +++ /dev/null @@ -1,365 +0,0 @@ -/* - * jQuery UI Button @VERSION - * - * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT (MIT-LICENSE.txt) - * and GPL (GPL-LICENSE.txt) licenses. - * - * http://docs.jquery.com/UI/Button - * - * Depends: - * jquery.ui.core.js - * jquery.ui.widget.js - */ -(function( $ ) { - -var lastActive, - baseClasses = "ui-button ui-widget ui-state-default ui-corner-all", - stateClasses = "ui-state-hover ui-state-active ", - typeClasses = "ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only", - formResetHandler = function( event ) { - $( ":ui-button", event.target.form ).each(function() { - var inst = $( this ).data( "button" ); - setTimeout(function() { - inst.refresh(); - }, 1 ); - }); - }, - radioGroup = function( radio ) { - var name = radio.name, - form = radio.form, - radios = $( [] ); - if ( name ) { - if ( form ) { - radios = $( form ).find( "[name='" + name + "']" ); - } else { - radios = $( "[name='" + name + "']", radio.ownerDocument ) - .filter(function() { - return !this.form; - }); - } - } - return radios; - }; - -$.widget( "ui.button", { - options: { - text: true, - label: null, - icons: { - primary: null, - secondary: null - } - }, - _create: function() { - this.element.closest( "form" ) - .unbind( "reset.button" ) - .bind( "reset.button", formResetHandler ); - - this._determineButtonType(); - this.hasTitle = !!this.buttonElement.attr( "title" ); - - var self = this, - options = this.options, - toggleButton = this.type === "checkbox" || this.type === "radio", - hoverClass = "ui-state-hover" + ( !toggleButton ? " ui-state-active" : "" ), - focusClass = "ui-state-focus"; - - if ( options.label === null ) { - options.label = this.buttonElement.html(); - } - - if ( this.element.is( ":disabled" ) ) { - options.disabled = true; - } - - this.buttonElement - .addClass( baseClasses ) - .attr( "role", "button" ) - .bind( "mouseenter.button", function() { - if ( options.disabled ) { - return; - } - $( this ).addClass( "ui-state-hover" ); - if ( this === lastActive ) { - $( this ).addClass( "ui-state-active" ); - } - }) - .bind( "mouseleave.button", function() { - if ( options.disabled ) { - return; - } - $( this ).removeClass( hoverClass ); - }) - .bind( "focus.button", function() { - // no need to check disabled, focus won't be triggered anyway - $( this ).addClass( focusClass ); - }) - .bind( "blur.button", function() { - $( this ).removeClass( focusClass ); - }); - - if ( toggleButton ) { - this.element.bind( "change.button", function() { - self.refresh(); - }); - } - - if ( this.type === "checkbox" ) { - this.buttonElement.bind( "click.button", function() { - if ( options.disabled ) { - return false; - } - $( this ).toggleClass( "ui-state-active" ); - self.buttonElement.attr( "aria-pressed", self.element[0].checked ); - }); - } else if ( this.type === "radio" ) { - this.buttonElement.bind( "click.button", function() { - if ( options.disabled ) { - return false; - } - $( this ).addClass( "ui-state-active" ); - self.buttonElement.attr( "aria-pressed", true ); - - var radio = self.element[ 0 ]; - radioGroup( radio ) - .not( radio ) - .map(function() { - return $( this ).button( "widget" )[ 0 ]; - }) - .removeClass( "ui-state-active" ) - .attr( "aria-pressed", false ); - }); - } else { - this.buttonElement - .bind( "mousedown.button", function() { - if ( options.disabled ) { - return false; - } - $( this ).addClass( "ui-state-active" ); - lastActive = this; - $( document ).one( "mouseup", function() { - lastActive = null; - }); - }) - .bind( "mouseup.button", function() { - if ( options.disabled ) { - return false; - } - $( this ).removeClass( "ui-state-active" ); - }) - .bind( "keydown.button", function(event) { - if ( options.disabled ) { - return false; - } - if ( event.keyCode == $.ui.keyCode.SPACE || event.keyCode == $.ui.keyCode.ENTER ) { - $( this ).addClass( "ui-state-active" ); - } - }) - .bind( "keyup.button", function() { - $( this ).removeClass( "ui-state-active" ); - }); - - if ( this.buttonElement.is("a") ) { - this.buttonElement.keyup(function(event) { - if ( event.keyCode === $.ui.keyCode.SPACE ) { - // TODO pass through original event correctly (just as 2nd argument doesn't work) - $( this ).click(); - } - }); - } - } - - // TODO: pull out $.Widget's handling for the disabled option into - // $.Widget.prototype._setOptionDisabled so it's easy to proxy and can - // be overridden by individual plugins - this._setOption( "disabled", options.disabled ); - }, - - _determineButtonType: function() { - - if ( this.element.is(":checkbox") ) { - this.type = "checkbox"; - } else { - if ( this.element.is(":radio") ) { - this.type = "radio"; - } else { - if ( this.element.is("input") ) { - this.type = "input"; - } else { - this.type = "button"; - } - } - } - - if ( this.type === "checkbox" || this.type === "radio" ) { - // we don't search against the document in case the element - // is disconnected from the DOM - this.buttonElement = this.element.parents().last() - .find( "[for=" + this.element.attr("id") + "]" ); - this.element.addClass( "ui-helper-hidden-accessible" ); - - var checked = this.element.is( ":checked" ); - if ( checked ) { - this.buttonElement.addClass( "ui-state-active" ); - } - this.buttonElement.attr( "aria-pressed", checked ); - } else { - this.buttonElement = this.element; - } - }, - - widget: function() { - return this.buttonElement; - }, - - destroy: function() { - this.element - .removeClass( "ui-helper-hidden-accessible" ); - this.buttonElement - .removeClass( baseClasses + " " + stateClasses + " " + typeClasses ) - .removeAttr( "role" ) - .removeAttr( "aria-pressed" ) - .html( this.buttonElement.find(".ui-button-text").html() ); - - if ( !this.hasTitle ) { - this.buttonElement.removeAttr( "title" ); - } - - $.Widget.prototype.destroy.call( this ); - }, - - _setOption: function( key, value ) { - $.Widget.prototype._setOption.apply( this, arguments ); - if ( key === "disabled" ) { - if ( value ) { - this.element.attr( "disabled", true ); - } else { - this.element.removeAttr( "disabled" ); - } - } - this._resetButton(); - }, - - refresh: function() { - var isDisabled = this.element.is( ":disabled" ); - if ( isDisabled !== this.options.disabled ) { - this._setOption( "disabled", isDisabled ); - } - if ( this.type === "radio" ) { - radioGroup( this.element[0] ).each(function() { - if ( $( this ).is( ":checked" ) ) { - $( this ).button( "widget" ) - .addClass( "ui-state-active" ) - .attr( "aria-pressed", true ); - } else { - $( this ).button( "widget" ) - .removeClass( "ui-state-active" ) - .attr( "aria-pressed", false ); - } - }); - } else if ( this.type === "checkbox" ) { - if ( this.element.is( ":checked" ) ) { - this.buttonElement - .addClass( "ui-state-active" ) - .attr( "aria-pressed", true ); - } else { - this.buttonElement - .removeClass( "ui-state-active" ) - .attr( "aria-pressed", false ); - } - } - }, - - _resetButton: function() { - if ( this.type === "input" ) { - if ( this.options.label ) { - this.element.val( this.options.label ); - } - return; - } - var buttonElement = this.buttonElement.removeClass( typeClasses ), - buttonText = $( "" ) - .addClass( "ui-button-text" ) - .html( this.options.label ) - .appendTo( buttonElement.empty() ) - .text(), - icons = this.options.icons, - multipleIcons = icons.primary && icons.secondary; - if ( icons.primary || icons.secondary ) { - buttonElement.addClass( "ui-button-text-icon" + - ( multipleIcons ? "s" : ( icons.primary ? "-primary" : "-secondary" ) ) ); - if ( icons.primary ) { - buttonElement.prepend( "" ); - } - if ( icons.secondary ) { - buttonElement.append( "" ); - } - if ( !this.options.text ) { - buttonElement - .addClass( multipleIcons ? "ui-button-icons-only" : "ui-button-icon-only" ) - .removeClass( "ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary" ); - if ( !this.hasTitle ) { - buttonElement.attr( "title", buttonText ); - } - } - } else { - buttonElement.addClass( "ui-button-text-only" ); - } - } -}); - -$.widget( "ui.buttonset", { - _create: function() { - this.element.addClass( "ui-buttonset" ); - this._init(); - }, - - _init: function() { - this.refresh(); - }, - - _setOption: function( key, value ) { - if ( key === "disabled" ) { - this.buttons.button( "option", key, value ); - } - - $.Widget.prototype._setOption.apply( this, arguments ); - }, - - refresh: function() { - this.buttons = this.element.find( ":button, :submit, :reset, :checkbox, :radio, a, :data(button)" ) - .filter( ":ui-button" ) - .button( "refresh" ) - .end() - .not( ":ui-button" ) - .button() - .end() - .map(function() { - return $( this ).button( "widget" )[ 0 ]; - }) - .removeClass( "ui-corner-all ui-corner-left ui-corner-right" ) - .filter( ":first" ) - .addClass( "ui-corner-left" ) - .end() - .filter( ":last" ) - .addClass( "ui-corner-right" ) - .end() - .end(); - }, - - destroy: function() { - this.element.removeClass( "ui-buttonset" ); - this.buttons - .map(function() { - return $( this ).button( "widget" )[ 0 ]; - }) - .removeClass( "ui-corner-left ui-corner-right" ) - .end() - .button( "destroy" ); - - $.Widget.prototype.destroy.call( this ); - } -}); - -}( jQuery ) ); diff --git a/ui/jquery.ui.core.js b/ui/jquery.ui.core.js deleted file mode 100644 index 9b32e8d1e0d..00000000000 --- a/ui/jquery.ui.core.js +++ /dev/null @@ -1,216 +0,0 @@ -/*! - * jQuery UI @VERSION - * - * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT (MIT-LICENSE.txt) - * and GPL (GPL-LICENSE.txt) licenses. - * - * http://docs.jquery.com/UI - */ - -(function($) { - -// prevent duplicate loading -// this is only a problem because we proxy existing functions -// and we don't want to double proxy them -$.ui = $.ui || {}; -if ($.ui.version) { - return; -} - -//Helper functions and ui object -$.extend($.ui, { - version: "@VERSION", - - // $.ui.plugin is deprecated. Use the proxy pattern instead. - plugin: { - add: function(module, option, set) { - var proto = $.ui[module].prototype; - for(var i in set) { - proto.plugins[i] = proto.plugins[i] || []; - proto.plugins[i].push([option, set[i]]); - } - }, - call: function(instance, name, args) { - var set = instance.plugins[name]; - if(!set || !instance.element[0].parentNode) { return; } - - for (var i = 0; i < set.length; i++) { - if (instance.options[set[i][0]]) { - set[i][1].apply(instance.element, args); - } - } - } - }, - - contains: function(a, b) { - return document.compareDocumentPosition - ? a.compareDocumentPosition(b) & 16 - : a !== b && a.contains(b); - }, - - hasScroll: function(el, a) { - - //If overflow is hidden, the element might have extra content, but the user wants to hide it - if ($(el).css('overflow') == 'hidden') { return false; } - - var scroll = (a && a == 'left') ? 'scrollLeft' : 'scrollTop', - has = false; - - if (el[scroll] > 0) { return true; } - - // TODO: determine which cases actually cause this to happen - // if the element doesn't have the scroll set, see if it's possible to - // set the scroll - el[scroll] = 1; - has = (el[scroll] > 0); - el[scroll] = 0; - return has; - }, - - isOverAxis: function(x, reference, size) { - //Determines when x coordinate is over "b" element axis - return (x > reference) && (x < (reference + size)); - }, - - isOver: function(y, x, top, left, height, width) { - //Determines when x, y coordinates is over "b" element - return $.ui.isOverAxis(y, top, height) && $.ui.isOverAxis(x, left, width); - }, - - keyCode: { - ALT: 18, - BACKSPACE: 8, - CAPS_LOCK: 20, - COMMA: 188, - COMMAND: 91, - COMMAND_LEFT: 91, // COMMAND - COMMAND_RIGHT: 93, - CONTROL: 17, - DELETE: 46, - DOWN: 40, - END: 35, - ENTER: 13, - ESCAPE: 27, - HOME: 36, - INSERT: 45, - LEFT: 37, - MENU: 93, // COMMAND_RIGHT - NUMPAD_ADD: 107, - NUMPAD_DECIMAL: 110, - NUMPAD_DIVIDE: 111, - NUMPAD_ENTER: 108, - NUMPAD_MULTIPLY: 106, - NUMPAD_SUBTRACT: 109, - PAGE_DOWN: 34, - PAGE_UP: 33, - PERIOD: 190, - RIGHT: 39, - SHIFT: 16, - SPACE: 32, - TAB: 9, - UP: 38, - WINDOWS: 91 // COMMAND - } -}); - -//jQuery plugins -$.fn.extend({ - _focus: $.fn.focus, - focus: function(delay, fn) { - return typeof delay === 'number' - ? this.each(function() { - var elem = this; - setTimeout(function() { - $(elem).focus(); - (fn && fn.call(elem)); - }, delay); - }) - : this._focus.apply(this, arguments); - }, - - enableSelection: function() { - return this - .attr('unselectable', 'off') - .css('MozUserSelect', ''); - }, - - disableSelection: function() { - return this - .attr('unselectable', 'on') - .css('MozUserSelect', 'none'); - }, - - scrollParent: function() { - var scrollParent; - if(($.browser.msie && (/(static|relative)/).test(this.css('position'))) || (/absolute/).test(this.css('position'))) { - scrollParent = this.parents().filter(function() { - return (/(relative|absolute|fixed)/).test($.curCSS(this,'position',1)) && (/(auto|scroll)/).test($.curCSS(this,'overflow',1)+$.curCSS(this,'overflow-y',1)+$.curCSS(this,'overflow-x',1)); - }).eq(0); - } else { - scrollParent = this.parents().filter(function() { - return (/(auto|scroll)/).test($.curCSS(this,'overflow',1)+$.curCSS(this,'overflow-y',1)+$.curCSS(this,'overflow-x',1)); - }).eq(0); - } - - return (/fixed/).test(this.css('position')) || !scrollParent.length ? $(document) : scrollParent; - }, - - zIndex: function(zIndex) { - if (zIndex !== undefined) { - return this.css('zIndex', zIndex); - } - - if (this.length) { - var elem = $(this[0]), position, value; - while (elem.length && elem[0] !== document) { - // Ignore z-index if position is set to a value where z-index is ignored by the browser - // This makes behavior of this function consistent across browsers - // WebKit always returns auto if the element is positioned - position = elem.css('position'); - if (position == 'absolute' || position == 'relative' || position == 'fixed') - { - // IE returns 0 when zIndex is not specified - // other browsers return a string - // we ignore the case of nested elements with an explicit value of 0 - //
        - value = parseInt(elem.css('zIndex')); - if (!isNaN(value) && value != 0) { - return value; - } - } - elem = elem.parent(); - } - } - - return 0; - } -}); - - -//Additional selectors -$.extend($.expr[':'], { - data: function(elem, i, match) { - return !!$.data(elem, match[3]); - }, - - focusable: function(element) { - var nodeName = element.nodeName.toLowerCase(), - tabIndex = $.attr(element, 'tabindex'); - return (/input|select|textarea|button|object/.test(nodeName) - ? !element.disabled - : 'a' == nodeName || 'area' == nodeName - ? element.href || !isNaN(tabIndex) - : !isNaN(tabIndex)) - // the element and all of its ancestors must be visible - // the browser may report that the area is hidden - && !$(element)['area' == nodeName ? 'parents' : 'closest'](':hidden').length; - }, - - tabbable: function(element) { - var tabIndex = $.attr(element, 'tabindex'); - return (isNaN(tabIndex) || tabIndex >= 0) && $(element).is(':focusable'); - } -}); - -})(jQuery); diff --git a/ui/jquery.ui.datepicker.js b/ui/jquery.ui.datepicker.js deleted file mode 100644 index 255fcc904f1..00000000000 --- a/ui/jquery.ui.datepicker.js +++ /dev/null @@ -1,1730 +0,0 @@ -/* - * jQuery UI Datepicker @VERSION - * - * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT (MIT-LICENSE.txt) - * and GPL (GPL-LICENSE.txt) licenses. - * - * http://docs.jquery.com/UI/Datepicker - * - * Depends: - * jquery.ui.core.js - */ - -(function($) { // hide the namespace - -$.extend($.ui, { datepicker: { version: "@VERSION" } }); - -var PROP_NAME = 'datepicker'; -var dpuuid = new Date().getTime(); - -/* Date picker manager. - Use the singleton instance of this class, $.datepicker, to interact with the date picker. - Settings for (groups of) date pickers are maintained in an instance object, - allowing multiple different settings on the same page. */ - -function Datepicker() { - this.debug = false; // Change this to true to start debugging - this._curInst = null; // The current instance in use - this._keyEvent = false; // If the last event was a key event - this._disabledInputs = []; // List of date picker inputs that have been disabled - this._datepickerShowing = false; // True if the popup picker is showing , false if not - this._inDialog = false; // True if showing within a "dialog", false if not - this._mainDivId = 'ui-datepicker-div'; // The ID of the main datepicker division - this._inlineClass = 'ui-datepicker-inline'; // The name of the inline marker class - this._appendClass = 'ui-datepicker-append'; // The name of the append marker class - this._triggerClass = 'ui-datepicker-trigger'; // The name of the trigger marker class - this._dialogClass = 'ui-datepicker-dialog'; // The name of the dialog marker class - this._disableClass = 'ui-datepicker-disabled'; // The name of the disabled covering marker class - this._unselectableClass = 'ui-datepicker-unselectable'; // The name of the unselectable cell marker class - this._currentClass = 'ui-datepicker-current-day'; // The name of the current day marker class - this._dayOverClass = 'ui-datepicker-days-cell-over'; // The name of the day hover marker class - this.regional = []; // Available regional settings, indexed by language code - this.regional[''] = { // Default regional settings - closeText: 'Done', // Display text for close link - prevText: 'Prev', // Display text for previous month link - nextText: 'Next', // Display text for next month link - currentText: 'Today', // Display text for current month link - monthNames: ['January','February','March','April','May','June', - 'July','August','September','October','November','December'], // Names of months for drop-down and formatting - monthNamesShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], // For formatting - dayNames: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], // For formatting - dayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], // For formatting - dayNamesMin: ['Su','Mo','Tu','We','Th','Fr','Sa'], // Column headings for days starting at Sunday - weekHeader: 'Wk', // Column header for week of the year - dateFormat: 'mm/dd/yy', // See format options on parseDate - firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ... - isRTL: false, // True if right-to-left language, false if left-to-right - showMonthAfterYear: false, // True if the year select precedes month, false for month then year - yearSuffix: '' // Additional text to append to the year in the month headers - }; - this._defaults = { // Global defaults for all the date picker instances - showOn: 'focus', // 'focus' for popup on focus, - // 'button' for trigger button, or 'both' for either - showAnim: 'fadeIn', // Name of jQuery animation for popup - showOptions: {}, // Options for enhanced animations - defaultDate: null, // Used when field is blank: actual date, - // +/-number for offset from today, null for today - appendText: '', // Display text following the input box, e.g. showing the format - buttonText: '...', // Text for trigger button - buttonImage: '', // URL for trigger button image - buttonImageOnly: false, // True if the image appears alone, false if it appears on a button - hideIfNoPrevNext: false, // True to hide next/previous month links - // if not applicable, false to just disable them - navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links - gotoCurrent: false, // True if today link goes back to current selection instead - changeMonth: false, // True if month can be selected directly, false if only prev/next - changeYear: false, // True if year can be selected directly, false if only prev/next - yearRange: 'c-10:c+10', // Range of years to display in drop-down, - // either relative to today's year (-nn:+nn), relative to currently displayed year - // (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n) - showOtherMonths: false, // True to show dates in other months, false to leave blank - selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable - showWeek: false, // True to show week of the year, false to not show it - calculateWeek: this.iso8601Week, // How to calculate the week of the year, - // takes a Date and returns the number of the week for it - shortYearCutoff: '+10', // Short year values < this are in the current century, - // > this are in the previous century, - // string value starting with '+' for current year + value - minDate: null, // The earliest selectable date, or null for no limit - maxDate: null, // The latest selectable date, or null for no limit - duration: 'fast', // Duration of display/closure - beforeShowDay: null, // Function that takes a date and returns an array with - // [0] = true if selectable, false if not, [1] = custom CSS class name(s) or '', - // [2] = cell title (optional), e.g. $.datepicker.noWeekends - beforeShow: null, // Function that takes an input field and - // returns a set of custom settings for the date picker - onSelect: null, // Define a callback function when a date is selected - onChangeMonthYear: null, // Define a callback function when the month or year is changed - onClose: null, // Define a callback function when the datepicker is closed - numberOfMonths: 1, // Number of months to show at a time - showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0) - stepMonths: 1, // Number of months to step back/forward - stepBigMonths: 12, // Number of months to step back/forward for the big links - altField: '', // Selector for an alternate field to store selected dates into - altFormat: '', // The date format to use for the alternate field - constrainInput: true, // The input is constrained by the current date format - showButtonPanel: false, // True to show button panel, false to not show it - autoSize: false // True to size the input for the date format, false to leave as is - }; - $.extend(this._defaults, this.regional['']); - this.dpDiv = $('
        '); -} - -$.extend(Datepicker.prototype, { - /* Class name added to elements to indicate already configured with a date picker. */ - markerClassName: 'hasDatepicker', - - /* Debug logging (if enabled). */ - log: function () { - if (this.debug) - console.log.apply('', arguments); - }, - - // TODO rename to "widget" when switching to widget factory - _widgetDatepicker: function() { - return this.dpDiv; - }, - - /* Override the default settings for all instances of the date picker. - @param settings object - the new settings to use as defaults (anonymous object) - @return the manager object */ - setDefaults: function(settings) { - extendRemove(this._defaults, settings || {}); - return this; - }, - - /* Attach the date picker to a jQuery selection. - @param target element - the target input field or division or span - @param settings object - the new settings to use for this date picker instance (anonymous) */ - _attachDatepicker: function(target, settings) { - // check for settings on the control itself - in namespace 'date:' - var inlineSettings = null; - for (var attrName in this._defaults) { - var attrValue = target.getAttribute('date:' + attrName); - if (attrValue) { - inlineSettings = inlineSettings || {}; - try { - inlineSettings[attrName] = eval(attrValue); - } catch (err) { - inlineSettings[attrName] = attrValue; - } - } - } - var nodeName = target.nodeName.toLowerCase(); - var inline = (nodeName == 'div' || nodeName == 'span'); - if (!target.id) { - this.uuid += 1; - target.id = 'dp' + this.uuid; - } - var inst = this._newInst($(target), inline); - inst.settings = $.extend({}, settings || {}, inlineSettings || {}); - if (nodeName == 'input') { - this._connectDatepicker(target, inst); - } else if (inline) { - this._inlineDatepicker(target, inst); - } - }, - - /* Create a new instance object. */ - _newInst: function(target, inline) { - var id = target[0].id.replace(/([^A-Za-z0-9_])/g, '\\\\$1'); // escape jQuery meta chars - return {id: id, input: target, // associated target - selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection - drawMonth: 0, drawYear: 0, // month being drawn - inline: inline, // is datepicker inline or not - dpDiv: (!inline ? this.dpDiv : // presentation div - $('
        '))}; - }, - - /* Attach the date picker to an input field. */ - _connectDatepicker: function(target, inst) { - var input = $(target); - inst.append = $([]); - inst.trigger = $([]); - if (input.hasClass(this.markerClassName)) - return; - this._attachments(input, inst); - input.addClass(this.markerClassName).keydown(this._doKeyDown). - keypress(this._doKeyPress).keyup(this._doKeyUp). - bind("setData.datepicker", function(event, key, value) { - inst.settings[key] = value; - }).bind("getData.datepicker", function(event, key) { - return this._get(inst, key); - }); - this._autoSize(inst); - $.data(target, PROP_NAME, inst); - }, - - /* Make attachments based on settings. */ - _attachments: function(input, inst) { - var appendText = this._get(inst, 'appendText'); - var isRTL = this._get(inst, 'isRTL'); - if (inst.append) - inst.append.remove(); - if (appendText) { - inst.append = $('' + appendText + ''); - input[isRTL ? 'before' : 'after'](inst.append); - } - input.unbind('focus', this._showDatepicker); - if (inst.trigger) - inst.trigger.remove(); - var showOn = this._get(inst, 'showOn'); - if (showOn == 'focus' || showOn == 'both') // pop-up date picker when in the marked field - input.focus(this._showDatepicker); - if (showOn == 'button' || showOn == 'both') { // pop-up date picker when button clicked - var buttonText = this._get(inst, 'buttonText'); - var buttonImage = this._get(inst, 'buttonImage'); - inst.trigger = $(this._get(inst, 'buttonImageOnly') ? - $('').addClass(this._triggerClass). - attr({ src: buttonImage, alt: buttonText, title: buttonText }) : - $('').addClass(this._triggerClass). - html(buttonImage == '' ? buttonText : $('').attr( - { src:buttonImage, alt:buttonText, title:buttonText }))); - input[isRTL ? 'before' : 'after'](inst.trigger); - inst.trigger.click(function() { - if ($.datepicker._datepickerShowing && $.datepicker._lastInput == input[0]) - $.datepicker._hideDatepicker(); - else - $.datepicker._showDatepicker(input[0]); - return false; - }); - } - }, - - /* Apply the maximum length for the date format. */ - _autoSize: function(inst) { - if (this._get(inst, 'autoSize') && !inst.inline) { - var date = new Date(2009, 12 - 1, 20); // Ensure double digits - var dateFormat = this._get(inst, 'dateFormat'); - if (dateFormat.match(/[DM]/)) { - var findMax = function(names) { - var max = 0; - var maxI = 0; - for (var i = 0; i < names.length; i++) { - if (names[i].length > max) { - max = names[i].length; - maxI = i; - } - } - return maxI; - }; - date.setMonth(findMax(this._get(inst, (dateFormat.match(/MM/) ? - 'monthNames' : 'monthNamesShort')))); - date.setDate(findMax(this._get(inst, (dateFormat.match(/DD/) ? - 'dayNames' : 'dayNamesShort'))) + 20 - date.getDay()); - } - inst.input.attr('size', this._formatDate(inst, date).length); - } - }, - - /* Attach an inline date picker to a div. */ - _inlineDatepicker: function(target, inst) { - var divSpan = $(target); - if (divSpan.hasClass(this.markerClassName)) - return; - divSpan.addClass(this.markerClassName).append(inst.dpDiv). - bind("setData.datepicker", function(event, key, value){ - inst.settings[key] = value; - }).bind("getData.datepicker", function(event, key){ - return this._get(inst, key); - }); - $.data(target, PROP_NAME, inst); - this._setDate(inst, this._getDefaultDate(inst), true); - this._updateDatepicker(inst); - this._updateAlternate(inst); - }, - - /* Pop-up the date picker in a "dialog" box. - @param input element - ignored - @param date string or Date - the initial date to display - @param onSelect function - the function to call when a date is selected - @param settings object - update the dialog date picker instance's settings (anonymous object) - @param pos int[2] - coordinates for the dialog's position within the screen or - event - with x/y coordinates or - leave empty for default (screen centre) - @return the manager object */ - _dialogDatepicker: function(input, date, onSelect, settings, pos) { - var inst = this._dialogInst; // internal instance - if (!inst) { - this.uuid += 1; - var id = 'dp' + this.uuid; - this._dialogInput = $(''); - this._dialogInput.keydown(this._doKeyDown); - $('body').append(this._dialogInput); - inst = this._dialogInst = this._newInst(this._dialogInput, false); - inst.settings = {}; - $.data(this._dialogInput[0], PROP_NAME, inst); - } - extendRemove(inst.settings, settings || {}); - date = (date && date.constructor == Date ? this._formatDate(inst, date) : date); - this._dialogInput.val(date); - - this._pos = (pos ? (pos.length ? pos : [pos.pageX, pos.pageY]) : null); - if (!this._pos) { - var browserWidth = document.documentElement.clientWidth; - var browserHeight = document.documentElement.clientHeight; - var scrollX = document.documentElement.scrollLeft || document.body.scrollLeft; - var scrollY = document.documentElement.scrollTop || document.body.scrollTop; - this._pos = // should use actual width/height below - [(browserWidth / 2) - 100 + scrollX, (browserHeight / 2) - 150 + scrollY]; - } - - // move input on screen for focus, but hidden behind dialog - this._dialogInput.css('left', (this._pos[0] + 20) + 'px').css('top', this._pos[1] + 'px'); - inst.settings.onSelect = onSelect; - this._inDialog = true; - this.dpDiv.addClass(this._dialogClass); - this._showDatepicker(this._dialogInput[0]); - if ($.blockUI) - $.blockUI(this.dpDiv); - $.data(this._dialogInput[0], PROP_NAME, inst); - return this; - }, - - /* Detach a datepicker from its control. - @param target element - the target input field or division or span */ - _destroyDatepicker: function(target) { - var $target = $(target); - var inst = $.data(target, PROP_NAME); - if (!$target.hasClass(this.markerClassName)) { - return; - } - var nodeName = target.nodeName.toLowerCase(); - $.removeData(target, PROP_NAME); - if (nodeName == 'input') { - inst.append.remove(); - inst.trigger.remove(); - $target.removeClass(this.markerClassName). - unbind('focus', this._showDatepicker). - unbind('keydown', this._doKeyDown). - unbind('keypress', this._doKeyPress). - unbind('keyup', this._doKeyUp); - } else if (nodeName == 'div' || nodeName == 'span') - $target.removeClass(this.markerClassName).empty(); - }, - - /* Enable the date picker to a jQuery selection. - @param target element - the target input field or division or span */ - _enableDatepicker: function(target) { - var $target = $(target); - var inst = $.data(target, PROP_NAME); - if (!$target.hasClass(this.markerClassName)) { - return; - } - var nodeName = target.nodeName.toLowerCase(); - if (nodeName == 'input') { - target.disabled = false; - inst.trigger.filter('button'). - each(function() { this.disabled = false; }).end(). - filter('img').css({opacity: '1.0', cursor: ''}); - } - else if (nodeName == 'div' || nodeName == 'span') { - var inline = $target.children('.' + this._inlineClass); - inline.children().removeClass('ui-state-disabled'); - } - this._disabledInputs = $.map(this._disabledInputs, - function(value) { return (value == target ? null : value); }); // delete entry - }, - - /* Disable the date picker to a jQuery selection. - @param target element - the target input field or division or span */ - _disableDatepicker: function(target) { - var $target = $(target); - var inst = $.data(target, PROP_NAME); - if (!$target.hasClass(this.markerClassName)) { - return; - } - var nodeName = target.nodeName.toLowerCase(); - if (nodeName == 'input') { - target.disabled = true; - inst.trigger.filter('button'). - each(function() { this.disabled = true; }).end(). - filter('img').css({opacity: '0.5', cursor: 'default'}); - } - else if (nodeName == 'div' || nodeName == 'span') { - var inline = $target.children('.' + this._inlineClass); - inline.children().addClass('ui-state-disabled'); - } - this._disabledInputs = $.map(this._disabledInputs, - function(value) { return (value == target ? null : value); }); // delete entry - this._disabledInputs[this._disabledInputs.length] = target; - }, - - /* Is the first field in a jQuery collection disabled as a datepicker? - @param target element - the target input field or division or span - @return boolean - true if disabled, false if enabled */ - _isDisabledDatepicker: function(target) { - if (!target) { - return false; - } - for (var i = 0; i < this._disabledInputs.length; i++) { - if (this._disabledInputs[i] == target) - return true; - } - return false; - }, - - /* Retrieve the instance data for the target control. - @param target element - the target input field or division or span - @return object - the associated instance data - @throws error if a jQuery problem getting data */ - _getInst: function(target) { - try { - return $.data(target, PROP_NAME); - } - catch (err) { - throw 'Missing instance data for this datepicker'; - } - }, - - /* Update or retrieve the settings for a date picker attached to an input field or division. - @param target element - the target input field or division or span - @param name object - the new settings to update or - string - the name of the setting to change or retrieve, - when retrieving also 'all' for all instance settings or - 'defaults' for all global defaults - @param value any - the new value for the setting - (omit if above is an object or to retrieve a value) */ - _optionDatepicker: function(target, name, value) { - var inst = this._getInst(target); - if (arguments.length == 2 && typeof name == 'string') { - return (name == 'defaults' ? $.extend({}, $.datepicker._defaults) : - (inst ? (name == 'all' ? $.extend({}, inst.settings) : - this._get(inst, name)) : null)); - } - var settings = name || {}; - if (typeof name == 'string') { - settings = {}; - settings[name] = value; - } - if (inst) { - if (this._curInst == inst) { - this._hideDatepicker(); - } - var date = this._getDateDatepicker(target, true); - extendRemove(inst.settings, settings); - this._attachments($(target), inst); - this._autoSize(inst); - this._setDateDatepicker(target, date); - this._updateDatepicker(inst); - } - }, - - // change method deprecated - _changeDatepicker: function(target, name, value) { - this._optionDatepicker(target, name, value); - }, - - /* Redraw the date picker attached to an input field or division. - @param target element - the target input field or division or span */ - _refreshDatepicker: function(target) { - var inst = this._getInst(target); - if (inst) { - this._updateDatepicker(inst); - } - }, - - /* Set the dates for a jQuery selection. - @param target element - the target input field or division or span - @param date Date - the new date */ - _setDateDatepicker: function(target, date) { - var inst = this._getInst(target); - if (inst) { - this._setDate(inst, date); - this._updateDatepicker(inst); - this._updateAlternate(inst); - } - }, - - /* Get the date(s) for the first entry in a jQuery selection. - @param target element - the target input field or division or span - @param noDefault boolean - true if no default date is to be used - @return Date - the current date */ - _getDateDatepicker: function(target, noDefault) { - var inst = this._getInst(target); - if (inst && !inst.inline) - this._setDateFromField(inst, noDefault); - return (inst ? this._getDate(inst) : null); - }, - - /* Handle keystrokes. */ - _doKeyDown: function(event) { - var inst = $.datepicker._getInst(event.target); - var handled = true; - var isRTL = inst.dpDiv.is('.ui-datepicker-rtl'); - inst._keyEvent = true; - if ($.datepicker._datepickerShowing) - switch (event.keyCode) { - case 9: $.datepicker._hideDatepicker(); - handled = false; - break; // hide on tab out - case 13: var sel = $('td.' + $.datepicker._dayOverClass, inst.dpDiv). - add($('td.' + $.datepicker._currentClass, inst.dpDiv)); - if (sel[0]) - $.datepicker._selectDay(event.target, inst.selectedMonth, inst.selectedYear, sel[0]); - else - $.datepicker._hideDatepicker(); - return false; // don't submit the form - break; // select the value on enter - case 27: $.datepicker._hideDatepicker(); - break; // hide on escape - case 33: $.datepicker._adjustDate(event.target, (event.ctrlKey ? - -$.datepicker._get(inst, 'stepBigMonths') : - -$.datepicker._get(inst, 'stepMonths')), 'M'); - break; // previous month/year on page up/+ ctrl - case 34: $.datepicker._adjustDate(event.target, (event.ctrlKey ? - +$.datepicker._get(inst, 'stepBigMonths') : - +$.datepicker._get(inst, 'stepMonths')), 'M'); - break; // next month/year on page down/+ ctrl - case 35: if (event.ctrlKey || event.metaKey) $.datepicker._clearDate(event.target); - handled = event.ctrlKey || event.metaKey; - break; // clear on ctrl or command +end - case 36: if (event.ctrlKey || event.metaKey) $.datepicker._gotoToday(event.target); - handled = event.ctrlKey || event.metaKey; - break; // current on ctrl or command +home - case 37: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, (isRTL ? +1 : -1), 'D'); - handled = event.ctrlKey || event.metaKey; - // -1 day on ctrl or command +left - if (event.originalEvent.altKey) $.datepicker._adjustDate(event.target, (event.ctrlKey ? - -$.datepicker._get(inst, 'stepBigMonths') : - -$.datepicker._get(inst, 'stepMonths')), 'M'); - // next month/year on alt +left on Mac - break; - case 38: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, -7, 'D'); - handled = event.ctrlKey || event.metaKey; - break; // -1 week on ctrl or command +up - case 39: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, (isRTL ? -1 : +1), 'D'); - handled = event.ctrlKey || event.metaKey; - // +1 day on ctrl or command +right - if (event.originalEvent.altKey) $.datepicker._adjustDate(event.target, (event.ctrlKey ? - +$.datepicker._get(inst, 'stepBigMonths') : - +$.datepicker._get(inst, 'stepMonths')), 'M'); - // next month/year on alt +right - break; - case 40: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, +7, 'D'); - handled = event.ctrlKey || event.metaKey; - break; // +1 week on ctrl or command +down - default: handled = false; - } - else if (event.keyCode == 36 && event.ctrlKey) // display the date picker on ctrl+home - $.datepicker._showDatepicker(this); - else { - handled = false; - } - if (handled) { - event.preventDefault(); - event.stopPropagation(); - } - }, - - /* Filter entered characters - based on date format. */ - _doKeyPress: function(event) { - var inst = $.datepicker._getInst(event.target); - if ($.datepicker._get(inst, 'constrainInput')) { - var chars = $.datepicker._possibleChars($.datepicker._get(inst, 'dateFormat')); - var chr = String.fromCharCode(event.charCode == undefined ? event.keyCode : event.charCode); - return event.ctrlKey || (chr < ' ' || !chars || chars.indexOf(chr) > -1); - } - }, - - /* Synchronise manual entry and field/alternate field. */ - _doKeyUp: function(event) { - var inst = $.datepicker._getInst(event.target); - if (inst.input.val() != inst.lastVal) { - try { - var date = $.datepicker.parseDate($.datepicker._get(inst, 'dateFormat'), - (inst.input ? inst.input.val() : null), - $.datepicker._getFormatConfig(inst)); - if (date) { // only if valid - $.datepicker._setDateFromField(inst); - $.datepicker._updateAlternate(inst); - $.datepicker._updateDatepicker(inst); - } - } - catch (event) { - $.datepicker.log(event); - } - } - return true; - }, - - /* Pop-up the date picker for a given input field. - @param input element - the input field attached to the date picker or - event - if triggered by focus */ - _showDatepicker: function(input) { - input = input.target || input; - if (input.nodeName.toLowerCase() != 'input') // find from button/image trigger - input = $('input', input.parentNode)[0]; - if ($.datepicker._isDisabledDatepicker(input) || $.datepicker._lastInput == input) // already here - return; - var inst = $.datepicker._getInst(input); - if ($.datepicker._curInst && $.datepicker._curInst != inst) { - $.datepicker._curInst.dpDiv.stop(true, true); - } - var beforeShow = $.datepicker._get(inst, 'beforeShow'); - extendRemove(inst.settings, (beforeShow ? beforeShow.apply(input, [input, inst]) : {})); - inst.lastVal = null; - $.datepicker._lastInput = input; - $.datepicker._setDateFromField(inst); - if ($.datepicker._inDialog) // hide cursor - input.value = ''; - if (!$.datepicker._pos) { // position below input - $.datepicker._pos = $.datepicker._findPos(input); - $.datepicker._pos[1] += input.offsetHeight; // add the height - } - var isFixed = false; - $(input).parents().each(function() { - isFixed |= $(this).css('position') == 'fixed'; - return !isFixed; - }); - if (isFixed && $.browser.opera) { // correction for Opera when fixed and scrolled - $.datepicker._pos[0] -= document.documentElement.scrollLeft; - $.datepicker._pos[1] -= document.documentElement.scrollTop; - } - var offset = {left: $.datepicker._pos[0], top: $.datepicker._pos[1]}; - $.datepicker._pos = null; - // determine sizing offscreen - inst.dpDiv.css({position: 'absolute', display: 'block', top: '-1000px'}); - $.datepicker._updateDatepicker(inst); - // fix width for dynamic number of date pickers - // and adjust position before showing - offset = $.datepicker._checkOffset(inst, offset, isFixed); - inst.dpDiv.css({position: ($.datepicker._inDialog && $.blockUI ? - 'static' : (isFixed ? 'fixed' : 'absolute')), display: 'none', - left: offset.left + 'px', top: offset.top + 'px'}); - if (!inst.inline) { - var showAnim = $.datepicker._get(inst, 'showAnim'); - var duration = $.datepicker._get(inst, 'duration'); - var postProcess = function() { - $.datepicker._datepickerShowing = true; - var borders = $.datepicker._getBorders(inst.dpDiv); - inst.dpDiv.find('iframe.ui-datepicker-cover'). // IE6- only - css({left: -borders[0], top: -borders[1], - width: inst.dpDiv.outerWidth(), height: inst.dpDiv.outerHeight()}); - }; - inst.dpDiv.zIndex($(input).zIndex()+1); - if ($.effects && $.effects[showAnim]) - inst.dpDiv.show(showAnim, $.datepicker._get(inst, 'showOptions'), duration, postProcess); - else - inst.dpDiv[showAnim || 'show']((showAnim ? duration : null), postProcess); - if (!showAnim || !duration) - postProcess(); - if (inst.input.is(':visible') && !inst.input.is(':disabled')) - inst.input.focus(); - $.datepicker._curInst = inst; - } - }, - - /* Generate the date picker content. */ - _updateDatepicker: function(inst) { - var self = this; - var borders = $.datepicker._getBorders(inst.dpDiv); - inst.dpDiv.empty().append(this._generateHTML(inst)) - .find('iframe.ui-datepicker-cover') // IE6- only - .css({left: -borders[0], top: -borders[1], - width: inst.dpDiv.outerWidth(), height: inst.dpDiv.outerHeight()}) - .end() - .find('button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a') - .bind('mouseout', function(){ - $(this).removeClass('ui-state-hover'); - if(this.className.indexOf('ui-datepicker-prev') != -1) $(this).removeClass('ui-datepicker-prev-hover'); - if(this.className.indexOf('ui-datepicker-next') != -1) $(this).removeClass('ui-datepicker-next-hover'); - }) - .bind('mouseover', function(){ - if (!self._isDisabledDatepicker( inst.inline ? inst.dpDiv.parent()[0] : inst.input[0])) { - $(this).parents('.ui-datepicker-calendar').find('a').removeClass('ui-state-hover'); - $(this).addClass('ui-state-hover'); - if(this.className.indexOf('ui-datepicker-prev') != -1) $(this).addClass('ui-datepicker-prev-hover'); - if(this.className.indexOf('ui-datepicker-next') != -1) $(this).addClass('ui-datepicker-next-hover'); - } - }) - .end() - .find('.' + this._dayOverClass + ' a') - .trigger('mouseover') - .end(); - var numMonths = this._getNumberOfMonths(inst); - var cols = numMonths[1]; - var width = 17; - if (cols > 1) - inst.dpDiv.addClass('ui-datepicker-multi-' + cols).css('width', (width * cols) + 'em'); - else - inst.dpDiv.removeClass('ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4').width(''); - inst.dpDiv[(numMonths[0] != 1 || numMonths[1] != 1 ? 'add' : 'remove') + - 'Class']('ui-datepicker-multi'); - inst.dpDiv[(this._get(inst, 'isRTL') ? 'add' : 'remove') + - 'Class']('ui-datepicker-rtl'); - if (inst == $.datepicker._curInst && $.datepicker._datepickerShowing && inst.input && - inst.input.is(':visible') && !inst.input.is(':disabled')) - inst.input.focus(); - }, - - /* Retrieve the size of left and top borders for an element. - @param elem (jQuery object) the element of interest - @return (number[2]) the left and top borders */ - _getBorders: function(elem) { - var convert = function(value) { - return {thin: 1, medium: 2, thick: 3}[value] || value; - }; - return [parseFloat(convert(elem.css('border-left-width'))), - parseFloat(convert(elem.css('border-top-width')))]; - }, - - /* Check positioning to remain on screen. */ - _checkOffset: function(inst, offset, isFixed) { - var dpWidth = inst.dpDiv.outerWidth(); - var dpHeight = inst.dpDiv.outerHeight(); - var inputWidth = inst.input ? inst.input.outerWidth() : 0; - var inputHeight = inst.input ? inst.input.outerHeight() : 0; - var viewWidth = document.documentElement.clientWidth + $(document).scrollLeft(); - var viewHeight = document.documentElement.clientHeight + $(document).scrollTop(); - - offset.left -= (this._get(inst, 'isRTL') ? (dpWidth - inputWidth) : 0); - offset.left -= (isFixed && offset.left == inst.input.offset().left) ? $(document).scrollLeft() : 0; - offset.top -= (isFixed && offset.top == (inst.input.offset().top + inputHeight)) ? $(document).scrollTop() : 0; - - // now check if datepicker is showing outside window viewport - move to a better place if so. - offset.left -= Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ? - Math.abs(offset.left + dpWidth - viewWidth) : 0); - offset.top -= Math.min(offset.top, (offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ? - Math.abs(dpHeight + inputHeight) : 0); - - return offset; - }, - - /* Find an object's position on the screen. */ - _findPos: function(obj) { - var inst = this._getInst(obj); - var isRTL = this._get(inst, 'isRTL'); - while (obj && (obj.type == 'hidden' || obj.nodeType != 1)) { - obj = obj[isRTL ? 'previousSibling' : 'nextSibling']; - } - var position = $(obj).offset(); - return [position.left, position.top]; - }, - - /* Hide the date picker from view. - @param input element - the input field attached to the date picker */ - _hideDatepicker: function(input) { - var inst = this._curInst; - if (!inst || (input && inst != $.data(input, PROP_NAME))) - return; - if (this._datepickerShowing) { - var showAnim = this._get(inst, 'showAnim'); - var duration = this._get(inst, 'duration'); - var postProcess = function() { - $.datepicker._tidyDialog(inst); - this._curInst = null; - }; - if ($.effects && $.effects[showAnim]) - inst.dpDiv.hide(showAnim, $.datepicker._get(inst, 'showOptions'), duration, postProcess); - else - inst.dpDiv[(showAnim == 'slideDown' ? 'slideUp' : - (showAnim == 'fadeIn' ? 'fadeOut' : 'hide'))]((showAnim ? duration : null), postProcess); - if (!showAnim) - postProcess(); - var onClose = this._get(inst, 'onClose'); - if (onClose) - onClose.apply((inst.input ? inst.input[0] : null), - [(inst.input ? inst.input.val() : ''), inst]); // trigger custom callback - this._datepickerShowing = false; - this._lastInput = null; - if (this._inDialog) { - this._dialogInput.css({ position: 'absolute', left: '0', top: '-100px' }); - if ($.blockUI) { - $.unblockUI(); - $('body').append(this.dpDiv); - } - } - this._inDialog = false; - } - }, - - /* Tidy up after a dialog display. */ - _tidyDialog: function(inst) { - inst.dpDiv.removeClass(this._dialogClass).unbind('.ui-datepicker-calendar'); - }, - - /* Close date picker if clicked elsewhere. */ - _checkExternalClick: function(event) { - if (!$.datepicker._curInst) - return; - var $target = $(event.target); - if ($target[0].id != $.datepicker._mainDivId && - $target.parents('#' + $.datepicker._mainDivId).length == 0 && - !$target.hasClass($.datepicker.markerClassName) && - !$target.hasClass($.datepicker._triggerClass) && - $.datepicker._datepickerShowing && !($.datepicker._inDialog && $.blockUI)) - $.datepicker._hideDatepicker(); - }, - - /* Adjust one of the date sub-fields. */ - _adjustDate: function(id, offset, period) { - var target = $(id); - var inst = this._getInst(target[0]); - if (this._isDisabledDatepicker(target[0])) { - return; - } - this._adjustInstDate(inst, offset + - (period == 'M' ? this._get(inst, 'showCurrentAtPos') : 0), // undo positioning - period); - this._updateDatepicker(inst); - }, - - /* Action for current link. */ - _gotoToday: function(id) { - var target = $(id); - var inst = this._getInst(target[0]); - if (this._get(inst, 'gotoCurrent') && inst.currentDay) { - inst.selectedDay = inst.currentDay; - inst.drawMonth = inst.selectedMonth = inst.currentMonth; - inst.drawYear = inst.selectedYear = inst.currentYear; - } - else { - var date = new Date(); - inst.selectedDay = date.getDate(); - inst.drawMonth = inst.selectedMonth = date.getMonth(); - inst.drawYear = inst.selectedYear = date.getFullYear(); - } - this._notifyChange(inst); - this._adjustDate(target); - }, - - /* Action for selecting a new month/year. */ - _selectMonthYear: function(id, select, period) { - var target = $(id); - var inst = this._getInst(target[0]); - inst._selectingMonthYear = false; - inst['selected' + (period == 'M' ? 'Month' : 'Year')] = - inst['draw' + (period == 'M' ? 'Month' : 'Year')] = - parseInt(select.options[select.selectedIndex].value,10); - this._notifyChange(inst); - this._adjustDate(target); - }, - - /* Restore input focus after not changing month/year. */ - _clickMonthYear: function(id) { - var target = $(id); - var inst = this._getInst(target[0]); - if (inst.input && inst._selectingMonthYear && !$.browser.msie) - inst.input.focus(); - inst._selectingMonthYear = !inst._selectingMonthYear; - }, - - /* Action for selecting a day. */ - _selectDay: function(id, month, year, td) { - var target = $(id); - if ($(td).hasClass(this._unselectableClass) || this._isDisabledDatepicker(target[0])) { - return; - } - var inst = this._getInst(target[0]); - inst.selectedDay = inst.currentDay = $('a', td).html(); - inst.selectedMonth = inst.currentMonth = month; - inst.selectedYear = inst.currentYear = year; - this._selectDate(id, this._formatDate(inst, - inst.currentDay, inst.currentMonth, inst.currentYear)); - }, - - /* Erase the input field and hide the date picker. */ - _clearDate: function(id) { - var target = $(id); - var inst = this._getInst(target[0]); - this._selectDate(target, ''); - }, - - /* Update the input field with the selected date. */ - _selectDate: function(id, dateStr) { - var target = $(id); - var inst = this._getInst(target[0]); - dateStr = (dateStr != null ? dateStr : this._formatDate(inst)); - if (inst.input) - inst.input.val(dateStr); - this._updateAlternate(inst); - var onSelect = this._get(inst, 'onSelect'); - if (onSelect) - onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); // trigger custom callback - else if (inst.input) - inst.input.trigger('change'); // fire the change event - if (inst.inline) - this._updateDatepicker(inst); - else { - this._hideDatepicker(); - this._lastInput = inst.input[0]; - if (typeof(inst.input[0]) != 'object') - inst.input.focus(); // restore focus - this._lastInput = null; - } - }, - - /* Update any alternate field to synchronise with the main field. */ - _updateAlternate: function(inst) { - var altField = this._get(inst, 'altField'); - if (altField) { // update alternate field too - var altFormat = this._get(inst, 'altFormat') || this._get(inst, 'dateFormat'); - var date = this._getDate(inst); - var dateStr = this.formatDate(altFormat, date, this._getFormatConfig(inst)); - $(altField).each(function() { $(this).val(dateStr); }); - } - }, - - /* Set as beforeShowDay function to prevent selection of weekends. - @param date Date - the date to customise - @return [boolean, string] - is this date selectable?, what is its CSS class? */ - noWeekends: function(date) { - var day = date.getDay(); - return [(day > 0 && day < 6), '']; - }, - - /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition. - @param date Date - the date to get the week for - @return number - the number of the week within the year that contains this date */ - iso8601Week: function(date) { - var checkDate = new Date(date.getTime()); - // Find Thursday of this week starting on Monday - checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7)); - var time = checkDate.getTime(); - checkDate.setMonth(0); // Compare with Jan 1 - checkDate.setDate(1); - return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1; - }, - - /* Parse a string value into a date object. - See formatDate below for the possible formats. - - @param format string - the expected format of the date - @param value string - the date in the above format - @param settings Object - attributes include: - shortYearCutoff number - the cutoff year for determining the century (optional) - dayNamesShort string[7] - abbreviated names of the days from Sunday (optional) - dayNames string[7] - names of the days from Sunday (optional) - monthNamesShort string[12] - abbreviated names of the months (optional) - monthNames string[12] - names of the months (optional) - @return Date - the extracted date value or null if value is blank */ - parseDate: function (format, value, settings) { - if (format == null || value == null) - throw 'Invalid arguments'; - value = (typeof value == 'object' ? value.toString() : value + ''); - if (value == '') - return null; - var shortYearCutoff = (settings ? settings.shortYearCutoff : null) || this._defaults.shortYearCutoff; - var dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort; - var dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames; - var monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort; - var monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames; - var year = -1; - var month = -1; - var day = -1; - var doy = -1; - var literal = false; - // Check whether a format character is doubled - var lookAhead = function(match) { - var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match); - if (matches) - iFormat++; - return matches; - }; - // Extract a number from the string value - var getNumber = function(match) { - lookAhead(match); - var size = (match == '@' ? 14 : (match == '!' ? 20 : - (match == 'y' ? 4 : (match == 'o' ? 3 : 2)))); - var digits = new RegExp('^\\d{1,' + size + '}'); - var num = value.substring(iValue).match(digits); - if (!num) - throw 'Missing number at position ' + iValue; - iValue += num[0].length; - return parseInt(num[0], 10); - }; - // Extract a name from the string value and convert to an index - var getName = function(match, shortNames, longNames) { - var names = (lookAhead(match) ? longNames : shortNames); - for (var i = 0; i < names.length; i++) { - if (value.substr(iValue, names[i].length) == names[i]) { - iValue += names[i].length; - return i + 1; - } - } - throw 'Unknown name at position ' + iValue; - }; - // Confirm that a literal character matches the string value - var checkLiteral = function() { - if (value.charAt(iValue) != format.charAt(iFormat)) - throw 'Unexpected literal at position ' + iValue; - iValue++; - }; - var iValue = 0; - for (var iFormat = 0; iFormat < format.length; iFormat++) { - if (literal) - if (format.charAt(iFormat) == "'" && !lookAhead("'")) - literal = false; - else - checkLiteral(); - else - switch (format.charAt(iFormat)) { - case 'd': - day = getNumber('d'); - break; - case 'D': - getName('D', dayNamesShort, dayNames); - break; - case 'o': - doy = getNumber('o'); - break; - case 'm': - month = getNumber('m'); - break; - case 'M': - month = getName('M', monthNamesShort, monthNames); - break; - case 'y': - year = getNumber('y'); - break; - case '@': - var date = new Date(getNumber('@')); - year = date.getFullYear(); - month = date.getMonth() + 1; - day = date.getDate(); - break; - case '!': - var date = new Date((getNumber('!') - this._ticksTo1970) / 10000); - year = date.getFullYear(); - month = date.getMonth() + 1; - day = date.getDate(); - break; - case "'": - if (lookAhead("'")) - checkLiteral(); - else - literal = true; - break; - default: - checkLiteral(); - } - } - if (year == -1) - year = new Date().getFullYear(); - else if (year < 100) - year += new Date().getFullYear() - new Date().getFullYear() % 100 + - (year <= shortYearCutoff ? 0 : -100); - if (doy > -1) { - month = 1; - day = doy; - do { - var dim = this._getDaysInMonth(year, month - 1); - if (day <= dim) - break; - month++; - day -= dim; - } while (true); - } - var date = this._daylightSavingAdjust(new Date(year, month - 1, day)); - if (date.getFullYear() != year || date.getMonth() + 1 != month || date.getDate() != day) - throw 'Invalid date'; // E.g. 31/02/* - return date; - }, - - /* Standard date formats. */ - ATOM: 'yy-mm-dd', // RFC 3339 (ISO 8601) - COOKIE: 'D, dd M yy', - ISO_8601: 'yy-mm-dd', - RFC_822: 'D, d M y', - RFC_850: 'DD, dd-M-y', - RFC_1036: 'D, d M y', - RFC_1123: 'D, d M yy', - RFC_2822: 'D, d M yy', - RSS: 'D, d M y', // RFC 822 - TICKS: '!', - TIMESTAMP: '@', - W3C: 'yy-mm-dd', // ISO 8601 - - _ticksTo1970: (((1970 - 1) * 365 + Math.floor(1970 / 4) - Math.floor(1970 / 100) + - Math.floor(1970 / 400)) * 24 * 60 * 60 * 10000000), - - /* Format a date object into a string value. - The format can be combinations of the following: - d - day of month (no leading zero) - dd - day of month (two digit) - o - day of year (no leading zeros) - oo - day of year (three digit) - D - day name short - DD - day name long - m - month of year (no leading zero) - mm - month of year (two digit) - M - month name short - MM - month name long - y - year (two digit) - yy - year (four digit) - @ - Unix timestamp (ms since 01/01/1970) - ! - Windows ticks (100ns since 01/01/0001) - '...' - literal text - '' - single quote - - @param format string - the desired format of the date - @param date Date - the date value to format - @param settings Object - attributes include: - dayNamesShort string[7] - abbreviated names of the days from Sunday (optional) - dayNames string[7] - names of the days from Sunday (optional) - monthNamesShort string[12] - abbreviated names of the months (optional) - monthNames string[12] - names of the months (optional) - @return string - the date in the above format */ - formatDate: function (format, date, settings) { - if (!date) - return ''; - var dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort; - var dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames; - var monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort; - var monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames; - // Check whether a format character is doubled - var lookAhead = function(match) { - var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match); - if (matches) - iFormat++; - return matches; - }; - // Format a number, with leading zero if necessary - var formatNumber = function(match, value, len) { - var num = '' + value; - if (lookAhead(match)) - while (num.length < len) - num = '0' + num; - return num; - }; - // Format a name, short or long as requested - var formatName = function(match, value, shortNames, longNames) { - return (lookAhead(match) ? longNames[value] : shortNames[value]); - }; - var output = ''; - var literal = false; - if (date) - for (var iFormat = 0; iFormat < format.length; iFormat++) { - if (literal) - if (format.charAt(iFormat) == "'" && !lookAhead("'")) - literal = false; - else - output += format.charAt(iFormat); - else - switch (format.charAt(iFormat)) { - case 'd': - output += formatNumber('d', date.getDate(), 2); - break; - case 'D': - output += formatName('D', date.getDay(), dayNamesShort, dayNames); - break; - case 'o': - output += formatNumber('o', - (date.getTime() - new Date(date.getFullYear(), 0, 0).getTime()) / 86400000, 3); - break; - case 'm': - output += formatNumber('m', date.getMonth() + 1, 2); - break; - case 'M': - output += formatName('M', date.getMonth(), monthNamesShort, monthNames); - break; - case 'y': - output += (lookAhead('y') ? date.getFullYear() : - (date.getYear() % 100 < 10 ? '0' : '') + date.getYear() % 100); - break; - case '@': - output += date.getTime(); - break; - case '!': - output += date.getTime() * 10000 + this._ticksTo1970; - break; - case "'": - if (lookAhead("'")) - output += "'"; - else - literal = true; - break; - default: - output += format.charAt(iFormat); - } - } - return output; - }, - - /* Extract all possible characters from the date format. */ - _possibleChars: function (format) { - var chars = ''; - var literal = false; - // Check whether a format character is doubled - var lookAhead = function(match) { - var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match); - if (matches) - iFormat++; - return matches; - }; - for (var iFormat = 0; iFormat < format.length; iFormat++) - if (literal) - if (format.charAt(iFormat) == "'" && !lookAhead("'")) - literal = false; - else - chars += format.charAt(iFormat); - else - switch (format.charAt(iFormat)) { - case 'd': case 'm': case 'y': case '@': - chars += '0123456789'; - break; - case 'D': case 'M': - return null; // Accept anything - case "'": - if (lookAhead("'")) - chars += "'"; - else - literal = true; - break; - default: - chars += format.charAt(iFormat); - } - return chars; - }, - - /* Get a setting value, defaulting if necessary. */ - _get: function(inst, name) { - return inst.settings[name] !== undefined ? - inst.settings[name] : this._defaults[name]; - }, - - /* Parse existing date and initialise date picker. */ - _setDateFromField: function(inst, noDefault) { - if (inst.input.val() == inst.lastVal) { - return; - } - var dateFormat = this._get(inst, 'dateFormat'); - var dates = inst.lastVal = inst.input ? inst.input.val() : null; - var date, defaultDate; - date = defaultDate = this._getDefaultDate(inst); - var settings = this._getFormatConfig(inst); - try { - date = this.parseDate(dateFormat, dates, settings) || defaultDate; - } catch (event) { - this.log(event); - dates = (noDefault ? '' : dates); - } - inst.selectedDay = date.getDate(); - inst.drawMonth = inst.selectedMonth = date.getMonth(); - inst.drawYear = inst.selectedYear = date.getFullYear(); - inst.currentDay = (dates ? date.getDate() : 0); - inst.currentMonth = (dates ? date.getMonth() : 0); - inst.currentYear = (dates ? date.getFullYear() : 0); - this._adjustInstDate(inst); - }, - - /* Retrieve the default date shown on opening. */ - _getDefaultDate: function(inst) { - return this._restrictMinMax(inst, - this._determineDate(inst, this._get(inst, 'defaultDate'), new Date())); - }, - - /* A date may be specified as an exact value or a relative one. */ - _determineDate: function(inst, date, defaultDate) { - var offsetNumeric = function(offset) { - var date = new Date(); - date.setDate(date.getDate() + offset); - return date; - }; - var offsetString = function(offset) { - try { - return $.datepicker.parseDate($.datepicker._get(inst, 'dateFormat'), - offset, $.datepicker._getFormatConfig(inst)); - } - catch (e) { - // Ignore - } - var date = (offset.toLowerCase().match(/^c/) ? - $.datepicker._getDate(inst) : null) || new Date(); - var year = date.getFullYear(); - var month = date.getMonth(); - var day = date.getDate(); - var pattern = /([+-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g; - var matches = pattern.exec(offset); - while (matches) { - switch (matches[2] || 'd') { - case 'd' : case 'D' : - day += parseInt(matches[1],10); break; - case 'w' : case 'W' : - day += parseInt(matches[1],10) * 7; break; - case 'm' : case 'M' : - month += parseInt(matches[1],10); - day = Math.min(day, $.datepicker._getDaysInMonth(year, month)); - break; - case 'y': case 'Y' : - year += parseInt(matches[1],10); - day = Math.min(day, $.datepicker._getDaysInMonth(year, month)); - break; - } - matches = pattern.exec(offset); - } - return new Date(year, month, day); - }; - date = (date == null ? defaultDate : (typeof date == 'string' ? offsetString(date) : - (typeof date == 'number' ? (isNaN(date) ? defaultDate : offsetNumeric(date)) : date))); - date = (date && date.toString() == 'Invalid Date' ? defaultDate : date); - if (date) { - date.setHours(0); - date.setMinutes(0); - date.setSeconds(0); - date.setMilliseconds(0); - } - return this._daylightSavingAdjust(date); - }, - - /* Handle switch to/from daylight saving. - Hours may be non-zero on daylight saving cut-over: - > 12 when midnight changeover, but then cannot generate - midnight datetime, so jump to 1AM, otherwise reset. - @param date (Date) the date to check - @return (Date) the corrected date */ - _daylightSavingAdjust: function(date) { - if (!date) return null; - date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0); - return date; - }, - - /* Set the date(s) directly. */ - _setDate: function(inst, date, noChange) { - var clear = !(date); - var origMonth = inst.selectedMonth; - var origYear = inst.selectedYear; - date = this._restrictMinMax(inst, this._determineDate(inst, date, new Date())); - inst.selectedDay = inst.currentDay = date.getDate(); - inst.drawMonth = inst.selectedMonth = inst.currentMonth = date.getMonth(); - inst.drawYear = inst.selectedYear = inst.currentYear = date.getFullYear(); - if ((origMonth != inst.selectedMonth || origYear != inst.selectedYear) && !noChange) - this._notifyChange(inst); - this._adjustInstDate(inst); - if (inst.input) { - inst.input.val(clear ? '' : this._formatDate(inst)); - } - }, - - /* Retrieve the date(s) directly. */ - _getDate: function(inst) { - var startDate = (!inst.currentYear || (inst.input && inst.input.val() == '') ? null : - this._daylightSavingAdjust(new Date( - inst.currentYear, inst.currentMonth, inst.currentDay))); - return startDate; - }, - - /* Generate the HTML for the current state of the date picker. */ - _generateHTML: function(inst) { - var today = new Date(); - today = this._daylightSavingAdjust( - new Date(today.getFullYear(), today.getMonth(), today.getDate())); // clear time - var isRTL = this._get(inst, 'isRTL'); - var showButtonPanel = this._get(inst, 'showButtonPanel'); - var hideIfNoPrevNext = this._get(inst, 'hideIfNoPrevNext'); - var navigationAsDateFormat = this._get(inst, 'navigationAsDateFormat'); - var numMonths = this._getNumberOfMonths(inst); - var showCurrentAtPos = this._get(inst, 'showCurrentAtPos'); - var stepMonths = this._get(inst, 'stepMonths'); - var isMultiMonth = (numMonths[0] != 1 || numMonths[1] != 1); - var currentDate = this._daylightSavingAdjust((!inst.currentDay ? new Date(9999, 9, 9) : - new Date(inst.currentYear, inst.currentMonth, inst.currentDay))); - var minDate = this._getMinMaxDate(inst, 'min'); - var maxDate = this._getMinMaxDate(inst, 'max'); - var drawMonth = inst.drawMonth - showCurrentAtPos; - var drawYear = inst.drawYear; - if (drawMonth < 0) { - drawMonth += 12; - drawYear--; - } - if (maxDate) { - var maxDraw = this._daylightSavingAdjust(new Date(maxDate.getFullYear(), - maxDate.getMonth() - (numMonths[0] * numMonths[1]) + 1, maxDate.getDate())); - maxDraw = (minDate && maxDraw < minDate ? minDate : maxDraw); - while (this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1)) > maxDraw) { - drawMonth--; - if (drawMonth < 0) { - drawMonth = 11; - drawYear--; - } - } - } - inst.drawMonth = drawMonth; - inst.drawYear = drawYear; - var prevText = this._get(inst, 'prevText'); - prevText = (!navigationAsDateFormat ? prevText : this.formatDate(prevText, - this._daylightSavingAdjust(new Date(drawYear, drawMonth - stepMonths, 1)), - this._getFormatConfig(inst))); - var prev = (this._canAdjustMonth(inst, -1, drawYear, drawMonth) ? - '' + prevText + '' : - (hideIfNoPrevNext ? '' : '' + prevText + '')); - var nextText = this._get(inst, 'nextText'); - nextText = (!navigationAsDateFormat ? nextText : this.formatDate(nextText, - this._daylightSavingAdjust(new Date(drawYear, drawMonth + stepMonths, 1)), - this._getFormatConfig(inst))); - var next = (this._canAdjustMonth(inst, +1, drawYear, drawMonth) ? - '' + nextText + '' : - (hideIfNoPrevNext ? '' : '' + nextText + '')); - var currentText = this._get(inst, 'currentText'); - var gotoDate = (this._get(inst, 'gotoCurrent') && inst.currentDay ? currentDate : today); - currentText = (!navigationAsDateFormat ? currentText : - this.formatDate(currentText, gotoDate, this._getFormatConfig(inst))); - var controls = (!inst.inline ? '' : ''); - var buttonPanel = (showButtonPanel) ? '
        ' + (isRTL ? controls : '') + - (this._isInRange(inst, gotoDate) ? '' : '') + (isRTL ? '' : controls) + '
        ' : ''; - var firstDay = parseInt(this._get(inst, 'firstDay'),10); - firstDay = (isNaN(firstDay) ? 0 : firstDay); - var showWeek = this._get(inst, 'showWeek'); - var dayNames = this._get(inst, 'dayNames'); - var dayNamesShort = this._get(inst, 'dayNamesShort'); - var dayNamesMin = this._get(inst, 'dayNamesMin'); - var monthNames = this._get(inst, 'monthNames'); - var monthNamesShort = this._get(inst, 'monthNamesShort'); - var beforeShowDay = this._get(inst, 'beforeShowDay'); - var showOtherMonths = this._get(inst, 'showOtherMonths'); - var selectOtherMonths = this._get(inst, 'selectOtherMonths'); - var calculateWeek = this._get(inst, 'calculateWeek') || this.iso8601Week; - var defaultDate = this._getDefaultDate(inst); - var html = ''; - for (var row = 0; row < numMonths[0]; row++) { - var group = ''; - for (var col = 0; col < numMonths[1]; col++) { - var selectedDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, inst.selectedDay)); - var cornerClass = ' ui-corner-all'; - var calender = ''; - if (isMultiMonth) { - calender += '
        '; - } - calender += '
        ' + - (/all|left/.test(cornerClass) && row == 0 ? (isRTL ? next : prev) : '') + - (/all|right/.test(cornerClass) && row == 0 ? (isRTL ? prev : next) : '') + - this._generateMonthYearHeader(inst, drawMonth, drawYear, minDate, maxDate, - row > 0 || col > 0, monthNames, monthNamesShort) + // draw month headers - '
        ' + - ''; - var thead = (showWeek ? '' : ''); - for (var dow = 0; dow < 7; dow++) { // days of the week - var day = (dow + firstDay) % 7; - thead += '= 5 ? ' class="ui-datepicker-week-end"' : '') + '>' + - '' + dayNamesMin[day] + ''; - } - calender += thead + ''; - var daysInMonth = this._getDaysInMonth(drawYear, drawMonth); - if (drawYear == inst.selectedYear && drawMonth == inst.selectedMonth) - inst.selectedDay = Math.min(inst.selectedDay, daysInMonth); - var leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7; - var numRows = (isMultiMonth ? 6 : Math.ceil((leadDays + daysInMonth) / 7)); // calculate the number of rows to generate - var printDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1 - leadDays)); - for (var dRow = 0; dRow < numRows; dRow++) { // create date picker rows - calender += ''; - var tbody = (!showWeek ? '' : ''); - for (var dow = 0; dow < 7; dow++) { // create date picker days - var daySettings = (beforeShowDay ? - beforeShowDay.apply((inst.input ? inst.input[0] : null), [printDate]) : [true, '']); - var otherMonth = (printDate.getMonth() != drawMonth); - var unselectable = (otherMonth && !selectOtherMonths) || !daySettings[0] || - (minDate && printDate < minDate) || (maxDate && printDate > maxDate); - tbody += ''; // display selectable date - printDate.setDate(printDate.getDate() + 1); - printDate = this._daylightSavingAdjust(printDate); - } - calender += tbody + ''; - } - drawMonth++; - if (drawMonth > 11) { - drawMonth = 0; - drawYear++; - } - calender += '
        ' + this._get(inst, 'weekHeader') + '
        ' + - this._get(inst, 'calculateWeek')(printDate) + '' + // actions - (otherMonth && !showOtherMonths ? ' ' : // display for other months - (unselectable ? '' + printDate.getDate() + '' : '' + printDate.getDate() + '')) + '
        ' + (isMultiMonth ? '
        ' + - ((numMonths[0] > 0 && col == numMonths[1]-1) ? '
        ' : '') : ''); - group += calender; - } - html += group; - } - html += buttonPanel + ($.browser.msie && parseInt($.browser.version,10) < 7 && !inst.inline ? - '' : ''); - inst._keyEvent = false; - return html; - }, - - /* Generate the month and year header. */ - _generateMonthYearHeader: function(inst, drawMonth, drawYear, minDate, maxDate, - secondary, monthNames, monthNamesShort) { - var changeMonth = this._get(inst, 'changeMonth'); - var changeYear = this._get(inst, 'changeYear'); - var showMonthAfterYear = this._get(inst, 'showMonthAfterYear'); - var html = '
        '; - var monthHtml = ''; - // month selection - if (secondary || !changeMonth) - monthHtml += '' + monthNames[drawMonth] + ''; - else { - var inMinYear = (minDate && minDate.getFullYear() == drawYear); - var inMaxYear = (maxDate && maxDate.getFullYear() == drawYear); - monthHtml += ''; - } - if (!showMonthAfterYear) - html += monthHtml + (secondary || !(changeMonth && changeYear) ? ' ' : ''); - // year selection - if (secondary || !changeYear) - html += '' + drawYear + ''; - else { - // determine range of years to display - var years = this._get(inst, 'yearRange').split(':'); - var thisYear = new Date().getFullYear(); - var determineYear = function(value) { - var year = (value.match(/c[+-].*/) ? drawYear + parseInt(value.substring(1), 10) : - (value.match(/[+-].*/) ? thisYear + parseInt(value, 10) : - parseInt(value, 10))); - return (isNaN(year) ? thisYear : year); - }; - var year = determineYear(years[0]); - var endYear = Math.max(year, determineYear(years[1] || '')); - year = (minDate ? Math.max(year, minDate.getFullYear()) : year); - endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear); - html += ''; - } - html += this._get(inst, 'yearSuffix'); - if (showMonthAfterYear) - html += (secondary || !(changeMonth && changeYear) ? ' ' : '') + monthHtml; - html += '
        '; // Close datepicker_header - return html; - }, - - /* Adjust one of the date sub-fields. */ - _adjustInstDate: function(inst, offset, period) { - var year = inst.drawYear + (period == 'Y' ? offset : 0); - var month = inst.drawMonth + (period == 'M' ? offset : 0); - var day = Math.min(inst.selectedDay, this._getDaysInMonth(year, month)) + - (period == 'D' ? offset : 0); - var date = this._restrictMinMax(inst, - this._daylightSavingAdjust(new Date(year, month, day))); - inst.selectedDay = date.getDate(); - inst.drawMonth = inst.selectedMonth = date.getMonth(); - inst.drawYear = inst.selectedYear = date.getFullYear(); - if (period == 'M' || period == 'Y') - this._notifyChange(inst); - }, - - /* Ensure a date is within any min/max bounds. */ - _restrictMinMax: function(inst, date) { - var minDate = this._getMinMaxDate(inst, 'min'); - var maxDate = this._getMinMaxDate(inst, 'max'); - date = (minDate && date < minDate ? minDate : date); - date = (maxDate && date > maxDate ? maxDate : date); - return date; - }, - - /* Notify change of month/year. */ - _notifyChange: function(inst) { - var onChange = this._get(inst, 'onChangeMonthYear'); - if (onChange) - onChange.apply((inst.input ? inst.input[0] : null), - [inst.selectedYear, inst.selectedMonth + 1, inst]); - }, - - /* Determine the number of months to show. */ - _getNumberOfMonths: function(inst) { - var numMonths = this._get(inst, 'numberOfMonths'); - return (numMonths == null ? [1, 1] : (typeof numMonths == 'number' ? [1, numMonths] : numMonths)); - }, - - /* Determine the current maximum date - ensure no time components are set. */ - _getMinMaxDate: function(inst, minMax) { - return this._determineDate(inst, this._get(inst, minMax + 'Date'), null); - }, - - /* Find the number of days in a given month. */ - _getDaysInMonth: function(year, month) { - return 32 - new Date(year, month, 32).getDate(); - }, - - /* Find the day of the week of the first of a month. */ - _getFirstDayOfMonth: function(year, month) { - return new Date(year, month, 1).getDay(); - }, - - /* Determines if we should allow a "next/prev" month display change. */ - _canAdjustMonth: function(inst, offset, curYear, curMonth) { - var numMonths = this._getNumberOfMonths(inst); - var date = this._daylightSavingAdjust(new Date(curYear, - curMonth + (offset < 0 ? offset : numMonths[0] * numMonths[1]), 1)); - if (offset < 0) - date.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth())); - return this._isInRange(inst, date); - }, - - /* Is the given date in the accepted range? */ - _isInRange: function(inst, date) { - var minDate = this._getMinMaxDate(inst, 'min'); - var maxDate = this._getMinMaxDate(inst, 'max'); - return ((!minDate || date.getTime() >= minDate.getTime()) && - (!maxDate || date.getTime() <= maxDate.getTime())); - }, - - /* Provide the configuration settings for formatting/parsing. */ - _getFormatConfig: function(inst) { - var shortYearCutoff = this._get(inst, 'shortYearCutoff'); - shortYearCutoff = (typeof shortYearCutoff != 'string' ? shortYearCutoff : - new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10)); - return {shortYearCutoff: shortYearCutoff, - dayNamesShort: this._get(inst, 'dayNamesShort'), dayNames: this._get(inst, 'dayNames'), - monthNamesShort: this._get(inst, 'monthNamesShort'), monthNames: this._get(inst, 'monthNames')}; - }, - - /* Format the given date for display. */ - _formatDate: function(inst, day, month, year) { - if (!day) { - inst.currentDay = inst.selectedDay; - inst.currentMonth = inst.selectedMonth; - inst.currentYear = inst.selectedYear; - } - var date = (day ? (typeof day == 'object' ? day : - this._daylightSavingAdjust(new Date(year, month, day))) : - this._daylightSavingAdjust(new Date(inst.currentYear, inst.currentMonth, inst.currentDay))); - return this.formatDate(this._get(inst, 'dateFormat'), date, this._getFormatConfig(inst)); - } -}); - -/* jQuery extend now ignores nulls! */ -function extendRemove(target, props) { - $.extend(target, props); - for (var name in props) - if (props[name] == null || props[name] == undefined) - target[name] = props[name]; - return target; -}; - -/* Determine whether an object is an array. */ -function isArray(a) { - return (a && (($.browser.safari && typeof a == 'object' && a.length) || - (a.constructor && a.constructor.toString().match(/\Array\(\)/)))); -}; - -/* Invoke the datepicker functionality. - @param options string - a command, optionally followed by additional parameters or - Object - settings for attaching new datepicker functionality - @return jQuery object */ -$.fn.datepicker = function(options){ - - /* Initialise the date picker. */ - if (!$.datepicker.initialized) { - $(document).mousedown($.datepicker._checkExternalClick). - find('body').append($.datepicker.dpDiv); - $.datepicker.initialized = true; - } - - var otherArgs = Array.prototype.slice.call(arguments, 1); - if (typeof options == 'string' && (options == 'isDisabled' || options == 'getDate' || options == 'widget')) - return $.datepicker['_' + options + 'Datepicker']. - apply($.datepicker, [this[0]].concat(otherArgs)); - if (options == 'option' && arguments.length == 2 && typeof arguments[1] == 'string') - return $.datepicker['_' + options + 'Datepicker']. - apply($.datepicker, [this[0]].concat(otherArgs)); - return this.each(function() { - typeof options == 'string' ? - $.datepicker['_' + options + 'Datepicker']. - apply($.datepicker, [this].concat(otherArgs)) : - $.datepicker._attachDatepicker(this, options); - }); -}; - -$.datepicker = new Datepicker(); // singleton instance -$.datepicker.initialized = false; -$.datepicker.uuid = new Date().getTime(); -$.datepicker.version = "@VERSION"; - -// Workaround for #4055 -// Add another global to avoid noConflict issues with inline event handlers -window['DP_jQuery_' + dpuuid] = $; - -})(jQuery); diff --git a/ui/jquery.ui.dialog.js b/ui/jquery.ui.dialog.js deleted file mode 100644 index 6e538b6e58a..00000000000 --- a/ui/jquery.ui.dialog.js +++ /dev/null @@ -1,823 +0,0 @@ -/* - * jQuery UI Dialog @VERSION - * - * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT (MIT-LICENSE.txt) - * and GPL (GPL-LICENSE.txt) licenses. - * - * http://docs.jquery.com/UI/Dialog - * - * Depends: - * jquery.ui.core.js - * jquery.ui.widget.js - * jquery.ui.button.js - * jquery.ui.draggable.js - * jquery.ui.mouse.js - * jquery.ui.position.js - * jquery.ui.resizable.js - */ -(function($) { - -var uiDialogClasses = - 'ui-dialog ' + - 'ui-widget ' + - 'ui-widget-content ' + - 'ui-corner-all '; - -$.widget("ui.dialog", { - options: { - autoOpen: true, - buttons: {}, - closeOnEscape: true, - closeText: 'close', - dialogClass: '', - draggable: true, - hide: null, - height: 'auto', - maxHeight: false, - maxWidth: false, - minHeight: 150, - minWidth: 150, - modal: false, - position: 'center', - resizable: true, - show: null, - stack: true, - title: '', - width: 300, - zIndex: 1000 - }, - _create: function() { - this.originalTitle = this.element.attr('title'); - - var self = this, - options = self.options, - - title = options.title || self.originalTitle || ' ', - titleId = $.ui.dialog.getTitleId(self.element), - - uiDialog = (self.uiDialog = $('
        ')) - .appendTo(document.body) - .hide() - .addClass(uiDialogClasses + options.dialogClass) - .css({ - zIndex: options.zIndex - }) - // setting tabIndex makes the div focusable - // setting outline to 0 prevents a border on focus in Mozilla - .attr('tabIndex', -1).css('outline', 0).keydown(function(event) { - if (options.closeOnEscape && event.keyCode && - event.keyCode === $.ui.keyCode.ESCAPE) { - - self.close(event); - event.preventDefault(); - } - }) - .attr({ - role: 'dialog', - 'aria-labelledby': titleId - }) - .mousedown(function(event) { - self.moveToTop(false, event); - }), - - uiDialogContent = self.element - .show() - .removeAttr('title') - .addClass( - 'ui-dialog-content ' + - 'ui-widget-content') - .appendTo(uiDialog), - - uiDialogTitlebar = (self.uiDialogTitlebar = $('
        ')) - .addClass( - 'ui-dialog-titlebar ' + - 'ui-widget-header ' + - 'ui-corner-all ' + - 'ui-helper-clearfix' - ) - .prependTo(uiDialog), - - uiDialogTitlebarClose = $('') - .addClass( - 'ui-dialog-titlebar-close ' + - 'ui-corner-all' - ) - .attr('role', 'button') - .hover( - function() { - uiDialogTitlebarClose.addClass('ui-state-hover'); - }, - function() { - uiDialogTitlebarClose.removeClass('ui-state-hover'); - } - ) - .focus(function() { - uiDialogTitlebarClose.addClass('ui-state-focus'); - }) - .blur(function() { - uiDialogTitlebarClose.removeClass('ui-state-focus'); - }) - .click(function(event) { - self.close(event); - return false; - }) - .appendTo(uiDialogTitlebar), - - uiDialogTitlebarCloseText = (self.uiDialogTitlebarCloseText = $('')) - .addClass( - 'ui-icon ' + - 'ui-icon-closethick' - ) - .text(options.closeText) - .appendTo(uiDialogTitlebarClose), - - uiDialogTitle = $('') - .addClass('ui-dialog-title') - .attr('id', titleId) - .html(title) - .prependTo(uiDialogTitlebar); - - //handling of deprecated beforeclose (vs beforeClose) option - //Ticket #4669 http://dev.jqueryui.com/ticket/4669 - //TODO: remove in 1.9pre - if ($.isFunction(options.beforeclose) && !$.isFunction(options.beforeClose)) { - options.beforeClose = options.beforeclose; - } - - uiDialogTitlebar.find("*").add(uiDialogTitlebar).disableSelection(); - - if (options.draggable && $.fn.draggable) { - self._makeDraggable(); - } - if (options.resizable && $.fn.resizable) { - self._makeResizable(); - } - - self._createButtons(options.buttons); - self._isOpen = false; - - if ($.fn.bgiframe) { - uiDialog.bgiframe(); - } - }, - _init: function() { - if ( this.options.autoOpen ) { - this.open(); - } - }, - - destroy: function() { - var self = this; - - if (self.overlay) { - self.overlay.destroy(); - } - self.uiDialog.hide(); - self.element - .unbind('.dialog') - .removeData('dialog') - .removeClass('ui-dialog-content ui-widget-content') - .hide().appendTo('body'); - self.uiDialog.remove(); - - if (self.originalTitle) { - self.element.attr('title', self.originalTitle); - } - - return self; - }, - - widget: function() { - return this.uiDialog; - }, - - close: function(event) { - var self = this, - maxZ; - - if (false === self._trigger('beforeClose', event)) { - return; - } - - if (self.overlay) { - self.overlay.destroy(); - } - self.uiDialog.unbind('keypress.ui-dialog'); - - self._isOpen = false; - - if (self.options.hide) { - self.uiDialog.hide(self.options.hide, function() { - self._trigger('close', event); - }); - } else { - self.uiDialog.hide(); - self._trigger('close', event); - } - - $.ui.dialog.overlay.resize(); - - // adjust the maxZ to allow other modal dialogs to continue to work (see #4309) - if (self.options.modal) { - maxZ = 0; - $('.ui-dialog').each(function() { - if (this !== self.uiDialog[0]) { - maxZ = Math.max(maxZ, $(this).css('z-index')); - } - }); - $.ui.dialog.maxZ = maxZ; - } - - return self; - }, - - isOpen: function() { - return this._isOpen; - }, - - // the force parameter allows us to move modal dialogs to their correct - // position on open - moveToTop: function(force, event) { - var self = this, - options = self.options, - saveScroll; - - if ((options.modal && !force) || - (!options.stack && !options.modal)) { - return self._trigger('focus', event); - } - - if (options.zIndex > $.ui.dialog.maxZ) { - $.ui.dialog.maxZ = options.zIndex; - } - if (self.overlay) { - $.ui.dialog.maxZ += 1; - self.overlay.$el.css('z-index', $.ui.dialog.overlay.maxZ = $.ui.dialog.maxZ); - } - - //Save and then restore scroll since Opera 9.5+ resets when parent z-Index is changed. - // http://ui.jquery.com/bugs/ticket/3193 - saveScroll = { scrollTop: self.element.attr('scrollTop'), scrollLeft: self.element.attr('scrollLeft') }; - $.ui.dialog.maxZ += 1; - self.uiDialog.css('z-index', $.ui.dialog.maxZ); - self.element.attr(saveScroll); - self._trigger('focus', event); - - return self; - }, - - open: function() { - if (this._isOpen) { return; } - - var self = this, - options = self.options, - uiDialog = self.uiDialog; - - self.overlay = options.modal ? new $.ui.dialog.overlay(self) : null; - if (uiDialog.next().length) { - uiDialog.appendTo('body'); - } - self._size(); - self._position(options.position); - uiDialog.show(options.show); - self.moveToTop(true); - - // prevent tabbing out of modal dialogs - if (options.modal) { - uiDialog.bind('keypress.ui-dialog', function(event) { - if (event.keyCode !== $.ui.keyCode.TAB) { - return; - } - - var tabbables = $(':tabbable', this), - first = tabbables.filter(':first'), - last = tabbables.filter(':last'); - - if (event.target === last[0] && !event.shiftKey) { - first.focus(1); - return false; - } else if (event.target === first[0] && event.shiftKey) { - last.focus(1); - return false; - } - }); - } - - // set focus to the first tabbable element in the content area or the first button - // if there are no tabbable elements, set focus on the dialog itself - $([]) - .add(uiDialog.find('.ui-dialog-content :tabbable:first')) - .add(uiDialog.find('.ui-dialog-buttonpane :tabbable:first')) - .add(uiDialog) - .filter(':first') - .focus(); - - self._trigger('open'); - self._isOpen = true; - - return self; - }, - - _createButtons: function(buttons) { - var self = this, - hasButtons = false, - uiDialogButtonPane = $('
        ') - .addClass( - 'ui-dialog-buttonpane ' + - 'ui-widget-content ' + - 'ui-helper-clearfix' - ); - - // if we already have a button pane, remove it - self.uiDialog.find('.ui-dialog-buttonpane').remove(); - - if (typeof buttons === 'object' && buttons !== null) { - $.each(buttons, function() { - return !(hasButtons = true); - }); - } - if (hasButtons) { - $.each(buttons, function(name, fn) { - var button = $('') - .text(name) - .click(function() { fn.apply(self.element[0], arguments); }) - .appendTo(uiDialogButtonPane); - if ($.fn.button) { - button.button(); - } - }); - uiDialogButtonPane.appendTo(self.uiDialog); - } - }, - - _makeDraggable: function() { - var self = this, - options = self.options, - doc = $(document), - heightBeforeDrag; - - function filteredUi(ui) { - return { - position: ui.position, - offset: ui.offset - }; - } - - self.uiDialog.draggable({ - cancel: '.ui-dialog-content, .ui-dialog-titlebar-close', - handle: '.ui-dialog-titlebar', - containment: 'document', - start: function(event, ui) { - heightBeforeDrag = options.height === "auto" ? "auto" : $(this).height(); - $(this).height($(this).height()).addClass("ui-dialog-dragging"); - self._trigger('dragStart', event, filteredUi(ui)); - }, - drag: function(event, ui) { - self._trigger('drag', event, filteredUi(ui)); - }, - stop: function(event, ui) { - options.position = [ui.position.left - doc.scrollLeft(), - ui.position.top - doc.scrollTop()]; - $(this).removeClass("ui-dialog-dragging").height(heightBeforeDrag); - self._trigger('dragStop', event, filteredUi(ui)); - $.ui.dialog.overlay.resize(); - } - }); - }, - - _makeResizable: function(handles) { - handles = (handles === undefined ? this.options.resizable : handles); - var self = this, - options = self.options, - // .ui-resizable has position: relative defined in the stylesheet - // but dialogs have to use absolute or fixed positioning - position = self.uiDialog.css('position'), - resizeHandles = (typeof handles === 'string' ? - handles : - 'n,e,s,w,se,sw,ne,nw' - ); - - function filteredUi(ui) { - return { - originalPosition: ui.originalPosition, - originalSize: ui.originalSize, - position: ui.position, - size: ui.size - }; - } - - self.uiDialog.resizable({ - cancel: '.ui-dialog-content', - containment: 'document', - alsoResize: self.element, - maxWidth: options.maxWidth, - maxHeight: options.maxHeight, - minWidth: options.minWidth, - minHeight: self._minHeight(), - handles: resizeHandles, - start: function(event, ui) { - $(this).addClass("ui-dialog-resizing"); - self._trigger('resizeStart', event, filteredUi(ui)); - }, - resize: function(event, ui) { - self._trigger('resize', event, filteredUi(ui)); - }, - stop: function(event, ui) { - $(this).removeClass("ui-dialog-resizing"); - options.height = $(this).height(); - options.width = $(this).width(); - self._trigger('resizeStop', event, filteredUi(ui)); - $.ui.dialog.overlay.resize(); - } - }) - .css('position', position) - .find('.ui-resizable-se').addClass('ui-icon ui-icon-grip-diagonal-se'); - }, - - _minHeight: function() { - var options = this.options; - - if (options.height === 'auto') { - return options.minHeight; - } else { - return Math.min(options.minHeight, options.height); - } - }, - - _position: function(position) { - var myAt = [], - offset = [0, 0], - isVisible; - - position = position || $.ui.dialog.prototype.options.position; - - // deep extending converts arrays to objects in jQuery <= 1.3.2 :-( -// if (typeof position == 'string' || $.isArray(position)) { -// myAt = $.isArray(position) ? position : position.split(' '); - - if (typeof position === 'string' || (typeof position === 'object' && '0' in position)) { - myAt = position.split ? position.split(' ') : [position[0], position[1]]; - if (myAt.length === 1) { - myAt[1] = myAt[0]; - } - - $.each(['left', 'top'], function(i, offsetPosition) { - if (+myAt[i] === myAt[i]) { - offset[i] = myAt[i]; - myAt[i] = offsetPosition; - } - }); - } else if (typeof position === 'object') { - if ('left' in position) { - myAt[0] = 'left'; - offset[0] = position.left; - } else if ('right' in position) { - myAt[0] = 'right'; - offset[0] = -position.right; - } - - if ('top' in position) { - myAt[1] = 'top'; - offset[1] = position.top; - } else if ('bottom' in position) { - myAt[1] = 'bottom'; - offset[1] = -position.bottom; - } - } - - // need to show the dialog to get the actual offset in the position plugin - isVisible = this.uiDialog.is(':visible'); - if (!isVisible) { - this.uiDialog.show(); - } - this.uiDialog - // workaround for jQuery bug #5781 http://dev.jquery.com/ticket/5781 - .css({ top: 0, left: 0 }) - .position({ - my: myAt.join(' '), - at: myAt.join(' '), - offset: offset.join(' '), - of: window, - collision: 'fit', - // ensure that the titlebar is never outside the document - using: function(pos) { - var topOffset = $(this).css(pos).offset().top; - if (topOffset < 0) { - $(this).css('top', pos.top - topOffset); - } - } - }); - if (!isVisible) { - this.uiDialog.hide(); - } - }, - - _setOption: function(key, value){ - var self = this, - uiDialog = self.uiDialog, - isResizable = uiDialog.is(':data(resizable)'), - resize = false; - - switch (key) { - //handling of deprecated beforeclose (vs beforeClose) option - //Ticket #4669 http://dev.jqueryui.com/ticket/4669 - //TODO: remove in 1.9pre - case "beforeclose": - key = "beforeClose"; - break; - case "buttons": - self._createButtons(value); - break; - case "closeText": - // convert whatever was passed in to a string, for text() to not throw up - self.uiDialogTitlebarCloseText.text("" + value); - break; - case "dialogClass": - uiDialog - .removeClass(self.options.dialogClass) - .addClass(uiDialogClasses + value); - break; - case "disabled": - if (value) { - uiDialog.addClass('ui-dialog-disabled'); - } else { - uiDialog.removeClass('ui-dialog-disabled'); - } - break; - case "draggable": - if (value) { - self._makeDraggable(); - } else { - uiDialog.draggable('destroy'); - } - break; - case "height": - resize = true; - break; - case "maxHeight": - if (isResizable) { - uiDialog.resizable('option', 'maxHeight', value); - } - resize = true; - break; - case "maxWidth": - if (isResizable) { - uiDialog.resizable('option', 'maxWidth', value); - } - resize = true; - break; - case "minHeight": - if (isResizable) { - uiDialog.resizable('option', 'minHeight', value); - } - resize = true; - break; - case "minWidth": - if (isResizable) { - uiDialog.resizable('option', 'minWidth', value); - } - resize = true; - break; - case "position": - self._position(value); - break; - case "resizable": - // currently resizable, becoming non-resizable - if (isResizable && !value) { - uiDialog.resizable('destroy'); - } - - // currently resizable, changing handles - if (isResizable && typeof value === 'string') { - uiDialog.resizable('option', 'handles', value); - } - - // currently non-resizable, becoming resizable - if (!isResizable && value !== false) { - self._makeResizable(value); - } - break; - case "title": - // convert whatever was passed in o a string, for html() to not throw up - $(".ui-dialog-title", self.uiDialogTitlebar).html("" + (value || ' ')); - break; - case "width": - resize = true; - break; - } - - $.Widget.prototype._setOption.apply(self, arguments); - if (resize) { - self._size(); - } - }, - - _size: function() { - /* If the user has resized the dialog, the .ui-dialog and .ui-dialog-content - * divs will both have width and height set, so we need to reset them - */ - var options = this.options, - nonContentHeight; - - // reset content sizing - // hide for non content measurement because height: 0 doesn't work in IE quirks mode (see #4350) - this.element.css({ - width: 'auto', - minHeight: 0, - height: 0 - }); - - // reset wrapper sizing - // determine the height of all the non-content elements - nonContentHeight = this.uiDialog.css({ - height: 'auto', - width: options.width - }) - .height(); - - this.element - .css(options.height === 'auto' ? { - minHeight: Math.max(options.minHeight - nonContentHeight, 0), - height: 'auto' - } : { - minHeight: 0, - height: Math.max(options.height - nonContentHeight, 0) - }) - .show(); - - if (this.uiDialog.is(':data(resizable)')) { - this.uiDialog.resizable('option', 'minHeight', this._minHeight()); - } - } -}); - -$.extend($.ui.dialog, { - version: "@VERSION", - - uuid: 0, - maxZ: 0, - - getTitleId: function($el) { - var id = $el.attr('id'); - if (!id) { - this.uuid += 1; - id = this.uuid; - } - return 'ui-dialog-title-' + id; - }, - - overlay: function(dialog) { - this.$el = $.ui.dialog.overlay.create(dialog); - } -}); - -$.extend($.ui.dialog.overlay, { - instances: [], - // reuse old instances due to IE memory leak with alpha transparency (see #5185) - oldInstances: [], - maxZ: 0, - events: $.map('focus,mousedown,mouseup,keydown,keypress,click'.split(','), - function(event) { return event + '.dialog-overlay'; }).join(' '), - create: function(dialog) { - if (this.instances.length === 0) { - // prevent use of anchors and inputs - // we use a setTimeout in case the overlay is created from an - // event that we're going to be cancelling (see #2804) - setTimeout(function() { - // handle $(el).dialog().dialog('close') (see #4065) - if ($.ui.dialog.overlay.instances.length) { - $(document).bind($.ui.dialog.overlay.events, function(event) { - // stop events if the z-index of the target is < the z-index of the overlay - return ($(event.target).zIndex() >= $.ui.dialog.overlay.maxZ); - }); - } - }, 1); - - // allow closing by pressing the escape key - $(document).bind('keydown.dialog-overlay', function(event) { - if (dialog.options.closeOnEscape && event.keyCode && - event.keyCode === $.ui.keyCode.ESCAPE) { - - dialog.close(event); - event.preventDefault(); - } - }); - - // handle window resize - $(window).bind('resize.dialog-overlay', $.ui.dialog.overlay.resize); - } - - var $el = (this.oldInstances.pop() || $('
        ').addClass('ui-widget-overlay')) - .appendTo(document.body) - .css({ - width: this.width(), - height: this.height() - }); - - if ($.fn.bgiframe) { - $el.bgiframe(); - } - - this.instances.push($el); - return $el; - }, - - destroy: function($el) { - this.oldInstances.push(this.instances.splice($.inArray($el, this.instances), 1)[0]); - - if (this.instances.length === 0) { - $([document, window]).unbind('.dialog-overlay'); - } - - $el.remove(); - - // adjust the maxZ to allow other modal dialogs to continue to work (see #4309) - var maxZ = 0; - $.each(this.instances, function() { - maxZ = Math.max(maxZ, this.css('z-index')); - }); - this.maxZ = maxZ; - }, - - height: function() { - var scrollHeight, - offsetHeight; - // handle IE 6 - if ($.browser.msie && $.browser.version < 7) { - scrollHeight = Math.max( - document.documentElement.scrollHeight, - document.body.scrollHeight - ); - offsetHeight = Math.max( - document.documentElement.offsetHeight, - document.body.offsetHeight - ); - - if (scrollHeight < offsetHeight) { - return $(window).height() + 'px'; - } else { - return scrollHeight + 'px'; - } - // handle "good" browsers - } else { - return $(document).height() + 'px'; - } - }, - - width: function() { - var scrollWidth, - offsetWidth; - // handle IE 6 - if ($.browser.msie && $.browser.version < 7) { - scrollWidth = Math.max( - document.documentElement.scrollWidth, - document.body.scrollWidth - ); - offsetWidth = Math.max( - document.documentElement.offsetWidth, - document.body.offsetWidth - ); - - if (scrollWidth < offsetWidth) { - return $(window).width() + 'px'; - } else { - return scrollWidth + 'px'; - } - // handle "good" browsers - } else { - return $(document).width() + 'px'; - } - }, - - resize: function() { - /* If the dialog is draggable and the user drags it past the - * right edge of the window, the document becomes wider so we - * need to stretch the overlay. If the user then drags the - * dialog back to the left, the document will become narrower, - * so we need to shrink the overlay to the appropriate size. - * This is handled by shrinking the overlay before setting it - * to the full document size. - */ - var $overlays = $([]); - $.each($.ui.dialog.overlay.instances, function() { - $overlays = $overlays.add(this); - }); - - $overlays.css({ - width: 0, - height: 0 - }).css({ - width: $.ui.dialog.overlay.width(), - height: $.ui.dialog.overlay.height() - }); - } -}); - -$.extend($.ui.dialog.overlay.prototype, { - destroy: function() { - $.ui.dialog.overlay.destroy(this.$el); - } -}); - -}(jQuery)); diff --git a/ui/jquery.ui.draggable.js b/ui/jquery.ui.draggable.js deleted file mode 100644 index 9496ce3f549..00000000000 --- a/ui/jquery.ui.draggable.js +++ /dev/null @@ -1,797 +0,0 @@ -/* - * jQuery UI Draggable @VERSION - * - * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT (MIT-LICENSE.txt) - * and GPL (GPL-LICENSE.txt) licenses. - * - * http://docs.jquery.com/UI/Draggables - * - * Depends: - * jquery.ui.core.js - * jquery.ui.mouse.js - * jquery.ui.widget.js - */ -(function($) { - -$.widget("ui.draggable", $.ui.mouse, { - widgetEventPrefix: "drag", - options: { - addClasses: true, - appendTo: "parent", - axis: false, - connectToSortable: false, - containment: false, - cursor: "auto", - cursorAt: false, - grid: false, - handle: false, - helper: "original", - iframeFix: false, - opacity: false, - refreshPositions: false, - revert: false, - revertDuration: 500, - scope: "default", - scroll: true, - scrollSensitivity: 20, - scrollSpeed: 20, - snap: false, - snapMode: "both", - snapTolerance: 20, - stack: false, - zIndex: false - }, - _create: function() { - - if (this.options.helper == 'original' && !(/^(?:r|a|f)/).test(this.element.css("position"))) - this.element[0].style.position = 'relative'; - - (this.options.addClasses && this.element.addClass("ui-draggable")); - (this.options.disabled && this.element.addClass("ui-draggable-disabled")); - - this._mouseInit(); - - }, - - destroy: function() { - if(!this.element.data('draggable')) return; - this.element - .removeData("draggable") - .unbind(".draggable") - .removeClass("ui-draggable" - + " ui-draggable-dragging" - + " ui-draggable-disabled"); - this._mouseDestroy(); - - return this; - }, - - _mouseCapture: function(event) { - - var o = this.options; - - // among others, prevent a drag on a resizable-handle - if (this.helper || o.disabled || $(event.target).is('.ui-resizable-handle')) - return false; - - //Quit if we're not on a valid handle - this.handle = this._getHandle(event); - if (!this.handle) - return false; - - return true; - - }, - - _mouseStart: function(event) { - - var o = this.options; - - //Create and append the visible helper - this.helper = this._createHelper(event); - - //Cache the helper size - this._cacheHelperProportions(); - - //If ddmanager is used for droppables, set the global draggable - if($.ui.ddmanager) - $.ui.ddmanager.current = this; - - /* - * - Position generation - - * This block generates everything position related - it's the core of draggables. - */ - - //Cache the margins of the original element - this._cacheMargins(); - - //Store the helper's css position - this.cssPosition = this.helper.css("position"); - this.scrollParent = this.helper.scrollParent(); - - //The element's absolute position on the page minus margins - this.offset = this.positionAbs = this.element.offset(); - this.offset = { - top: this.offset.top - this.margins.top, - left: this.offset.left - this.margins.left - }; - - $.extend(this.offset, { - click: { //Where the click happened, relative to the element - left: event.pageX - this.offset.left, - top: event.pageY - this.offset.top - }, - parent: this._getParentOffset(), - relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper - }); - - //Generate the original position - this.originalPosition = this.position = this._generatePosition(event); - this.originalPageX = event.pageX; - this.originalPageY = event.pageY; - - //Adjust the mouse offset relative to the helper if 'cursorAt' is supplied - (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt)); - - //Set a containment if given in the options - if(o.containment) - this._setContainment(); - - //Trigger event + callbacks - if(this._trigger("start", event) === false) { - this._clear(); - return false; - } - - //Recache the helper size - this._cacheHelperProportions(); - - //Prepare the droppable offsets - if ($.ui.ddmanager && !o.dropBehaviour) - $.ui.ddmanager.prepareOffsets(this, event); - - this.helper.addClass("ui-draggable-dragging"); - this._mouseDrag(event, true); //Execute the drag once - this causes the helper not to be visible before getting its correct position - return true; - }, - - _mouseDrag: function(event, noPropagation) { - - //Compute the helpers position - this.position = this._generatePosition(event); - this.positionAbs = this._convertPositionTo("absolute"); - - //Call plugins and callbacks and use the resulting position if something is returned - if (!noPropagation) { - var ui = this._uiHash(); - if(this._trigger('drag', event, ui) === false) { - this._mouseUp({}); - return false; - } - this.position = ui.position; - } - - if(!this.options.axis || this.options.axis != "y") this.helper[0].style.left = this.position.left+'px'; - if(!this.options.axis || this.options.axis != "x") this.helper[0].style.top = this.position.top+'px'; - if($.ui.ddmanager) $.ui.ddmanager.drag(this, event); - - return false; - }, - - _mouseStop: function(event) { - - //If we are using droppables, inform the manager about the drop - var dropped = false; - if ($.ui.ddmanager && !this.options.dropBehaviour) - dropped = $.ui.ddmanager.drop(this, event); - - //if a drop comes from outside (a sortable) - if(this.dropped) { - dropped = this.dropped; - this.dropped = false; - } - - //if the original element is removed, don't bother to continue - if(!this.element[0] || !this.element[0].parentNode) - return false; - - if((this.options.revert == "invalid" && !dropped) || (this.options.revert == "valid" && dropped) || this.options.revert === true || ($.isFunction(this.options.revert) && this.options.revert.call(this.element, dropped))) { - var self = this; - $(this.helper).animate(this.originalPosition, parseInt(this.options.revertDuration, 10), function() { - if(self._trigger("stop", event) !== false) { - self._clear(); - } - }); - } else { - if(this._trigger("stop", event) !== false) { - this._clear(); - } - } - - return false; - }, - - cancel: function() { - - if(this.helper.is(".ui-draggable-dragging")) { - this._mouseUp({}); - } else { - this._clear(); - } - - return this; - - }, - - _getHandle: function(event) { - - var handle = !this.options.handle || !$(this.options.handle, this.element).length ? true : false; - $(this.options.handle, this.element) - .find("*") - .andSelf() - .each(function() { - if(this == event.target) handle = true; - }); - - return handle; - - }, - - _createHelper: function(event) { - - var o = this.options; - var helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event])) : (o.helper == 'clone' ? this.element.clone() : this.element); - - if(!helper.parents('body').length) - helper.appendTo((o.appendTo == 'parent' ? this.element[0].parentNode : o.appendTo)); - - if(helper[0] != this.element[0] && !(/(fixed|absolute)/).test(helper.css("position"))) - helper.css("position", "absolute"); - - return helper; - - }, - - _adjustOffsetFromHelper: function(obj) { - if (typeof obj == 'string') { - obj = obj.split(' '); - } - if ($.isArray(obj)) { - obj = {left: +obj[0], top: +obj[1] || 0}; - } - if ('left' in obj) { - this.offset.click.left = obj.left + this.margins.left; - } - if ('right' in obj) { - this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left; - } - if ('top' in obj) { - this.offset.click.top = obj.top + this.margins.top; - } - if ('bottom' in obj) { - this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top; - } - }, - - _getParentOffset: function() { - - //Get the offsetParent and cache its position - this.offsetParent = this.helper.offsetParent(); - var po = this.offsetParent.offset(); - - // This is a special case where we need to modify a offset calculated on start, since the following happened: - // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent - // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that - // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag - if(this.cssPosition == 'absolute' && this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) { - po.left += this.scrollParent.scrollLeft(); - po.top += this.scrollParent.scrollTop(); - } - - if((this.offsetParent[0] == document.body) //This needs to be actually done for all browsers, since pageX/pageY includes this information - || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() == 'html' && $.browser.msie)) //Ugly IE fix - po = { top: 0, left: 0 }; - - return { - top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0), - left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0) - }; - - }, - - _getRelativeOffset: function() { - - if(this.cssPosition == "relative") { - var p = this.element.position(); - return { - top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(), - left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft() - }; - } else { - return { top: 0, left: 0 }; - } - - }, - - _cacheMargins: function() { - this.margins = { - left: (parseInt(this.element.css("marginLeft"),10) || 0), - top: (parseInt(this.element.css("marginTop"),10) || 0) - }; - }, - - _cacheHelperProportions: function() { - this.helperProportions = { - width: this.helper.outerWidth(), - height: this.helper.outerHeight() - }; - }, - - _setContainment: function() { - - var o = this.options; - if(o.containment == 'parent') o.containment = this.helper[0].parentNode; - if(o.containment == 'document' || o.containment == 'window') this.containment = [ - 0 - this.offset.relative.left - this.offset.parent.left, - 0 - this.offset.relative.top - this.offset.parent.top, - $(o.containment == 'document' ? document : window).width() - this.helperProportions.width - this.margins.left, - ($(o.containment == 'document' ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top - ]; - - if(!(/^(document|window|parent)$/).test(o.containment) && o.containment.constructor != Array) { - var ce = $(o.containment)[0]; if(!ce) return; - var co = $(o.containment).offset(); - var over = ($(ce).css("overflow") != 'hidden'); - - this.containment = [ - co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0) - this.margins.left, - co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0) - this.margins.top, - co.left+(over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css("borderLeftWidth"),10) || 0) - (parseInt($(ce).css("paddingRight"),10) || 0) - this.helperProportions.width - this.margins.left, - co.top+(over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css("borderTopWidth"),10) || 0) - (parseInt($(ce).css("paddingBottom"),10) || 0) - this.helperProportions.height - this.margins.top - ]; - } else if(o.containment.constructor == Array) { - this.containment = o.containment; - } - - }, - - _convertPositionTo: function(d, pos) { - - if(!pos) pos = this.position; - var mod = d == "absolute" ? 1 : -1; - var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); - - return { - top: ( - pos.top // The absolute mouse position - + this.offset.relative.top * mod // Only for relative positioned nodes: Relative offset from element to offset parent - + this.offset.parent.top * mod // The offsetParent's offset without borders (offset + border) - - ($.browser.safari && $.browser.version < 526 && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod) - ), - left: ( - pos.left // The absolute mouse position - + this.offset.relative.left * mod // Only for relative positioned nodes: Relative offset from element to offset parent - + this.offset.parent.left * mod // The offsetParent's offset without borders (offset + border) - - ($.browser.safari && $.browser.version < 526 && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod) - ) - }; - - }, - - _generatePosition: function(event) { - - var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); - var pageX = event.pageX; - var pageY = event.pageY; - - /* - * - Position constraining - - * Constrain the position to a mix of grid, containment. - */ - - if(this.originalPosition) { //If we are not dragging yet, we won't check for options - - if(this.containment) { - if(event.pageX - this.offset.click.left < this.containment[0]) pageX = this.containment[0] + this.offset.click.left; - if(event.pageY - this.offset.click.top < this.containment[1]) pageY = this.containment[1] + this.offset.click.top; - if(event.pageX - this.offset.click.left > this.containment[2]) pageX = this.containment[2] + this.offset.click.left; - if(event.pageY - this.offset.click.top > this.containment[3]) pageY = this.containment[3] + this.offset.click.top; - } - - if(o.grid) { - var top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1]; - pageY = this.containment ? (!(top - this.offset.click.top < this.containment[1] || top - this.offset.click.top > this.containment[3]) ? top : (!(top - this.offset.click.top < this.containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top; - - var left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0]; - pageX = this.containment ? (!(left - this.offset.click.left < this.containment[0] || left - this.offset.click.left > this.containment[2]) ? left : (!(left - this.offset.click.left < this.containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left; - } - - } - - return { - top: ( - pageY // The absolute mouse position - - this.offset.click.top // Click offset (relative to the element) - - this.offset.relative.top // Only for relative positioned nodes: Relative offset from element to offset parent - - this.offset.parent.top // The offsetParent's offset without borders (offset + border) - + ($.browser.safari && $.browser.version < 526 && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) )) - ), - left: ( - pageX // The absolute mouse position - - this.offset.click.left // Click offset (relative to the element) - - this.offset.relative.left // Only for relative positioned nodes: Relative offset from element to offset parent - - this.offset.parent.left // The offsetParent's offset without borders (offset + border) - + ($.browser.safari && $.browser.version < 526 && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() )) - ) - }; - - }, - - _clear: function() { - this.helper.removeClass("ui-draggable-dragging"); - if(this.helper[0] != this.element[0] && !this.cancelHelperRemoval) this.helper.remove(); - //if($.ui.ddmanager) $.ui.ddmanager.current = null; - this.helper = null; - this.cancelHelperRemoval = false; - }, - - // From now on bulk stuff - mainly helpers - - _trigger: function(type, event, ui) { - ui = ui || this._uiHash(); - $.ui.plugin.call(this, type, [event, ui]); - if(type == "drag") this.positionAbs = this._convertPositionTo("absolute"); //The absolute position has to be recalculated after plugins - return $.Widget.prototype._trigger.call(this, type, event, ui); - }, - - plugins: {}, - - _uiHash: function(event) { - return { - helper: this.helper, - position: this.position, - originalPosition: this.originalPosition, - offset: this.positionAbs - }; - } - -}); - -$.extend($.ui.draggable, { - version: "@VERSION" -}); - -$.ui.plugin.add("draggable", "connectToSortable", { - start: function(event, ui) { - - var inst = $(this).data("draggable"), o = inst.options, - uiSortable = $.extend({}, ui, { item: inst.element }); - inst.sortables = []; - $(o.connectToSortable).each(function() { - var sortable = $.data(this, 'sortable'); - if (sortable && !sortable.options.disabled) { - inst.sortables.push({ - instance: sortable, - shouldRevert: sortable.options.revert - }); - sortable._refreshItems(); //Do a one-time refresh at start to refresh the containerCache - sortable._trigger("activate", event, uiSortable); - } - }); - - }, - stop: function(event, ui) { - - //If we are still over the sortable, we fake the stop event of the sortable, but also remove helper - var inst = $(this).data("draggable"), - uiSortable = $.extend({}, ui, { item: inst.element }); - - $.each(inst.sortables, function() { - if(this.instance.isOver) { - - this.instance.isOver = 0; - - inst.cancelHelperRemoval = true; //Don't remove the helper in the draggable instance - this.instance.cancelHelperRemoval = false; //Remove it in the sortable instance (so sortable plugins like revert still work) - - //The sortable revert is supported, and we have to set a temporary dropped variable on the draggable to support revert: 'valid/invalid' - if(this.shouldRevert) this.instance.options.revert = true; - - //Trigger the stop of the sortable - this.instance._mouseStop(event); - - this.instance.options.helper = this.instance.options._helper; - - //If the helper has been the original item, restore properties in the sortable - if(inst.options.helper == 'original') - this.instance.currentItem.css({ top: 'auto', left: 'auto' }); - - } else { - this.instance.cancelHelperRemoval = false; //Remove the helper in the sortable instance - this.instance._trigger("deactivate", event, uiSortable); - } - - }); - - }, - drag: function(event, ui) { - - var inst = $(this).data("draggable"), self = this; - - var checkPos = function(o) { - var dyClick = this.offset.click.top, dxClick = this.offset.click.left; - var helperTop = this.positionAbs.top, helperLeft = this.positionAbs.left; - var itemHeight = o.height, itemWidth = o.width; - var itemTop = o.top, itemLeft = o.left; - - return $.ui.isOver(helperTop + dyClick, helperLeft + dxClick, itemTop, itemLeft, itemHeight, itemWidth); - }; - - $.each(inst.sortables, function(i) { - - //Copy over some variables to allow calling the sortable's native _intersectsWith - this.instance.positionAbs = inst.positionAbs; - this.instance.helperProportions = inst.helperProportions; - this.instance.offset.click = inst.offset.click; - - if(this.instance._intersectsWith(this.instance.containerCache)) { - - //If it intersects, we use a little isOver variable and set it once, so our move-in stuff gets fired only once - if(!this.instance.isOver) { - - this.instance.isOver = 1; - //Now we fake the start of dragging for the sortable instance, - //by cloning the list group item, appending it to the sortable and using it as inst.currentItem - //We can then fire the start event of the sortable with our passed browser event, and our own helper (so it doesn't create a new one) - this.instance.currentItem = $(self).clone().appendTo(this.instance.element).data("sortable-item", true); - this.instance.options._helper = this.instance.options.helper; //Store helper option to later restore it - this.instance.options.helper = function() { return ui.helper[0]; }; - - event.target = this.instance.currentItem[0]; - this.instance._mouseCapture(event, true); - this.instance._mouseStart(event, true, true); - - //Because the browser event is way off the new appended portlet, we modify a couple of variables to reflect the changes - this.instance.offset.click.top = inst.offset.click.top; - this.instance.offset.click.left = inst.offset.click.left; - this.instance.offset.parent.left -= inst.offset.parent.left - this.instance.offset.parent.left; - this.instance.offset.parent.top -= inst.offset.parent.top - this.instance.offset.parent.top; - - inst._trigger("toSortable", event); - inst.dropped = this.instance.element; //draggable revert needs that - //hack so receive/update callbacks work (mostly) - inst.currentItem = inst.element; - this.instance.fromOutside = inst; - - } - - //Provided we did all the previous steps, we can fire the drag event of the sortable on every draggable drag, when it intersects with the sortable - if(this.instance.currentItem) this.instance._mouseDrag(event); - - } else { - - //If it doesn't intersect with the sortable, and it intersected before, - //we fake the drag stop of the sortable, but make sure it doesn't remove the helper by using cancelHelperRemoval - if(this.instance.isOver) { - - this.instance.isOver = 0; - this.instance.cancelHelperRemoval = true; - - //Prevent reverting on this forced stop - this.instance.options.revert = false; - - // The out event needs to be triggered independently - this.instance._trigger('out', event, this.instance._uiHash(this.instance)); - - this.instance._mouseStop(event, true); - this.instance.options.helper = this.instance.options._helper; - - //Now we remove our currentItem, the list group clone again, and the placeholder, and animate the helper back to it's original size - this.instance.currentItem.remove(); - if(this.instance.placeholder) this.instance.placeholder.remove(); - - inst._trigger("fromSortable", event); - inst.dropped = false; //draggable revert needs that - } - - }; - - }); - - } -}); - -$.ui.plugin.add("draggable", "cursor", { - start: function(event, ui) { - var t = $('body'), o = $(this).data('draggable').options; - if (t.css("cursor")) o._cursor = t.css("cursor"); - t.css("cursor", o.cursor); - }, - stop: function(event, ui) { - var o = $(this).data('draggable').options; - if (o._cursor) $('body').css("cursor", o._cursor); - } -}); - -$.ui.plugin.add("draggable", "iframeFix", { - start: function(event, ui) { - var o = $(this).data('draggable').options; - $(o.iframeFix === true ? "iframe" : o.iframeFix).each(function() { - $('
        ') - .css({ - width: this.offsetWidth+"px", height: this.offsetHeight+"px", - position: "absolute", opacity: "0.001", zIndex: 1000 - }) - .css($(this).offset()) - .appendTo("body"); - }); - }, - stop: function(event, ui) { - $("div.ui-draggable-iframeFix").each(function() { this.parentNode.removeChild(this); }); //Remove frame helpers - } -}); - -$.ui.plugin.add("draggable", "opacity", { - start: function(event, ui) { - var t = $(ui.helper), o = $(this).data('draggable').options; - if(t.css("opacity")) o._opacity = t.css("opacity"); - t.css('opacity', o.opacity); - }, - stop: function(event, ui) { - var o = $(this).data('draggable').options; - if(o._opacity) $(ui.helper).css('opacity', o._opacity); - } -}); - -$.ui.plugin.add("draggable", "scroll", { - start: function(event, ui) { - var i = $(this).data("draggable"); - if(i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') i.overflowOffset = i.scrollParent.offset(); - }, - drag: function(event, ui) { - - var i = $(this).data("draggable"), o = i.options, scrolled = false; - - if(i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') { - - if(!o.axis || o.axis != 'x') { - if((i.overflowOffset.top + i.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) - i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop + o.scrollSpeed; - else if(event.pageY - i.overflowOffset.top < o.scrollSensitivity) - i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop - o.scrollSpeed; - } - - if(!o.axis || o.axis != 'y') { - if((i.overflowOffset.left + i.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) - i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft + o.scrollSpeed; - else if(event.pageX - i.overflowOffset.left < o.scrollSensitivity) - i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft - o.scrollSpeed; - } - - } else { - - if(!o.axis || o.axis != 'x') { - if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) - scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed); - else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) - scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed); - } - - if(!o.axis || o.axis != 'y') { - if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) - scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed); - else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) - scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed); - } - - } - - if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) - $.ui.ddmanager.prepareOffsets(i, event); - - } -}); - -$.ui.plugin.add("draggable", "snap", { - start: function(event, ui) { - - var i = $(this).data("draggable"), o = i.options; - i.snapElements = []; - - $(o.snap.constructor != String ? ( o.snap.items || ':data(draggable)' ) : o.snap).each(function() { - var $t = $(this); var $o = $t.offset(); - if(this != i.element[0]) i.snapElements.push({ - item: this, - width: $t.outerWidth(), height: $t.outerHeight(), - top: $o.top, left: $o.left - }); - }); - - }, - drag: function(event, ui) { - - var inst = $(this).data("draggable"), o = inst.options; - var d = o.snapTolerance; - - var x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width, - y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height; - - for (var i = inst.snapElements.length - 1; i >= 0; i--){ - - var l = inst.snapElements[i].left, r = l + inst.snapElements[i].width, - t = inst.snapElements[i].top, b = t + inst.snapElements[i].height; - - //Yes, I know, this is insane ;) - if(!((l-d < x1 && x1 < r+d && t-d < y1 && y1 < b+d) || (l-d < x1 && x1 < r+d && t-d < y2 && y2 < b+d) || (l-d < x2 && x2 < r+d && t-d < y1 && y1 < b+d) || (l-d < x2 && x2 < r+d && t-d < y2 && y2 < b+d))) { - if(inst.snapElements[i].snapping) (inst.options.snap.release && inst.options.snap.release.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item }))); - inst.snapElements[i].snapping = false; - continue; - } - - if(o.snapMode != 'inner') { - var ts = Math.abs(t - y2) <= d; - var bs = Math.abs(b - y1) <= d; - var ls = Math.abs(l - x2) <= d; - var rs = Math.abs(r - x1) <= d; - if(ts) ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top - inst.margins.top; - if(bs) ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top - inst.margins.top; - if(ls) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left - inst.margins.left; - if(rs) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left - inst.margins.left; - } - - var first = (ts || bs || ls || rs); - - if(o.snapMode != 'outer') { - var ts = Math.abs(t - y1) <= d; - var bs = Math.abs(b - y2) <= d; - var ls = Math.abs(l - x1) <= d; - var rs = Math.abs(r - x2) <= d; - if(ts) ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top - inst.margins.top; - if(bs) ui.position.top = inst._convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top - inst.margins.top; - if(ls) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left - inst.margins.left; - if(rs) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left - inst.margins.left; - } - - if(!inst.snapElements[i].snapping && (ts || bs || ls || rs || first)) - (inst.options.snap.snap && inst.options.snap.snap.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item }))); - inst.snapElements[i].snapping = (ts || bs || ls || rs || first); - - }; - - } -}); - -$.ui.plugin.add("draggable", "stack", { - start: function(event, ui) { - - var o = $(this).data("draggable").options; - - var group = $.makeArray($(o.stack)).sort(function(a,b) { - return (parseInt($(a).css("zIndex"),10) || 0) - (parseInt($(b).css("zIndex"),10) || 0); - }); - if (!group.length) { return; } - - var min = parseInt(group[0].style.zIndex) || 0; - $(group).each(function(i) { - this.style.zIndex = min + i; - }); - - this[0].style.zIndex = min + group.length; - - } -}); - -$.ui.plugin.add("draggable", "zIndex", { - start: function(event, ui) { - var t = $(ui.helper), o = $(this).data("draggable").options; - if(t.css("zIndex")) o._zIndex = t.css("zIndex"); - t.css('zIndex', o.zIndex); - }, - stop: function(event, ui) { - var o = $(this).data("draggable").options; - if(o._zIndex) $(ui.helper).css('zIndex', o._zIndex); - } -}); - -})(jQuery); diff --git a/ui/jquery.ui.droppable.js b/ui/jquery.ui.droppable.js deleted file mode 100644 index 4cd7f56e264..00000000000 --- a/ui/jquery.ui.droppable.js +++ /dev/null @@ -1,285 +0,0 @@ -/* - * jQuery UI Droppable @VERSION - * - * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT (MIT-LICENSE.txt) - * and GPL (GPL-LICENSE.txt) licenses. - * - * http://docs.jquery.com/UI/Droppables - * - * Depends: - * jquery.ui.core.js - * jquery.ui.widget.js - * jquery.ui.mouse.js - * jquery.ui.draggable.js - */ -(function($) { - -$.widget("ui.droppable", { - widgetEventPrefix: "drop", - options: { - accept: '*', - activeClass: false, - addClasses: true, - greedy: false, - hoverClass: false, - scope: 'default', - tolerance: 'intersect' - }, - _create: function() { - - var o = this.options, accept = o.accept; - this.isover = 0; this.isout = 1; - - this.accept = $.isFunction(accept) ? accept : function(d) { - return d.is(accept); - }; - - //Store the droppable's proportions - this.proportions = { width: this.element[0].offsetWidth, height: this.element[0].offsetHeight }; - - // Add the reference and positions to the manager - $.ui.ddmanager.droppables[o.scope] = $.ui.ddmanager.droppables[o.scope] || []; - $.ui.ddmanager.droppables[o.scope].push(this); - - (o.addClasses && this.element.addClass("ui-droppable")); - - }, - - destroy: function() { - var drop = $.ui.ddmanager.droppables[this.options.scope]; - for ( var i = 0; i < drop.length; i++ ) - if ( drop[i] == this ) - drop.splice(i, 1); - - this.element - .removeClass("ui-droppable ui-droppable-disabled") - .removeData("droppable") - .unbind(".droppable"); - - return this; - }, - - _setOption: function(key, value) { - - if(key == 'accept') { - this.accept = $.isFunction(value) ? value : function(d) { - return d.is(value); - }; - } - $.Widget.prototype._setOption.apply(this, arguments); - }, - - _activate: function(event) { - var draggable = $.ui.ddmanager.current; - if(this.options.activeClass) this.element.addClass(this.options.activeClass); - (draggable && this._trigger('activate', event, this.ui(draggable))); - }, - - _deactivate: function(event) { - var draggable = $.ui.ddmanager.current; - if(this.options.activeClass) this.element.removeClass(this.options.activeClass); - (draggable && this._trigger('deactivate', event, this.ui(draggable))); - }, - - _over: function(event) { - - var draggable = $.ui.ddmanager.current; - if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return; // Bail if draggable and droppable are same element - - if (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) { - if(this.options.hoverClass) this.element.addClass(this.options.hoverClass); - this._trigger('over', event, this.ui(draggable)); - } - - }, - - _out: function(event) { - - var draggable = $.ui.ddmanager.current; - if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return; // Bail if draggable and droppable are same element - - if (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) { - if(this.options.hoverClass) this.element.removeClass(this.options.hoverClass); - this._trigger('out', event, this.ui(draggable)); - } - - }, - - _drop: function(event,custom) { - - var draggable = custom || $.ui.ddmanager.current; - if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return false; // Bail if draggable and droppable are same element - - var childrenIntersection = false; - this.element.find(":data(droppable)").not(".ui-draggable-dragging").each(function() { - var inst = $.data(this, 'droppable'); - if( - inst.options.greedy - && !inst.options.disabled - && inst.options.scope == draggable.options.scope - && inst.accept.call(inst.element[0], (draggable.currentItem || draggable.element)) - && $.ui.intersect(draggable, $.extend(inst, { offset: inst.element.offset() }), inst.options.tolerance) - ) { childrenIntersection = true; return false; } - }); - if(childrenIntersection) return false; - - if(this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) { - if(this.options.activeClass) this.element.removeClass(this.options.activeClass); - if(this.options.hoverClass) this.element.removeClass(this.options.hoverClass); - this._trigger('drop', event, this.ui(draggable)); - return this.element; - } - - return false; - - }, - - ui: function(c) { - return { - draggable: (c.currentItem || c.element), - helper: c.helper, - position: c.position, - offset: c.positionAbs - }; - } - -}); - -$.extend($.ui.droppable, { - version: "@VERSION" -}); - -$.ui.intersect = function(draggable, droppable, toleranceMode) { - - if (!droppable.offset) return false; - - var x1 = (draggable.positionAbs || draggable.position.absolute).left, x2 = x1 + draggable.helperProportions.width, - y1 = (draggable.positionAbs || draggable.position.absolute).top, y2 = y1 + draggable.helperProportions.height; - var l = droppable.offset.left, r = l + droppable.proportions.width, - t = droppable.offset.top, b = t + droppable.proportions.height; - - switch (toleranceMode) { - case 'fit': - return (l < x1 && x2 < r - && t < y1 && y2 < b); - break; - case 'intersect': - return (l < x1 + (draggable.helperProportions.width / 2) // Right Half - && x2 - (draggable.helperProportions.width / 2) < r // Left Half - && t < y1 + (draggable.helperProportions.height / 2) // Bottom Half - && y2 - (draggable.helperProportions.height / 2) < b ); // Top Half - break; - case 'pointer': - var draggableLeft = ((draggable.positionAbs || draggable.position.absolute).left + (draggable.clickOffset || draggable.offset.click).left), - draggableTop = ((draggable.positionAbs || draggable.position.absolute).top + (draggable.clickOffset || draggable.offset.click).top), - isOver = $.ui.isOver(draggableTop, draggableLeft, t, l, droppable.proportions.height, droppable.proportions.width); - return isOver; - break; - case 'touch': - return ( - (y1 >= t && y1 <= b) || // Top edge touching - (y2 >= t && y2 <= b) || // Bottom edge touching - (y1 < t && y2 > b) // Surrounded vertically - ) && ( - (x1 >= l && x1 <= r) || // Left edge touching - (x2 >= l && x2 <= r) || // Right edge touching - (x1 < l && x2 > r) // Surrounded horizontally - ); - break; - default: - return false; - break; - } - -}; - -/* - This manager tracks offsets of draggables and droppables -*/ -$.ui.ddmanager = { - current: null, - droppables: { 'default': [] }, - prepareOffsets: function(t, event) { - - var m = $.ui.ddmanager.droppables[t.options.scope] || []; - var type = event ? event.type : null; // workaround for #2317 - var list = (t.currentItem || t.element).find(":data(droppable)").andSelf(); - - droppablesLoop: for (var i = 0; i < m.length; i++) { - - if(m[i].options.disabled || (t && !m[i].accept.call(m[i].element[0],(t.currentItem || t.element)))) continue; //No disabled and non-accepted - for (var j=0; j < list.length; j++) { if(list[j] == m[i].element[0]) { m[i].proportions.height = 0; continue droppablesLoop; } }; //Filter out elements in the current dragged item - m[i].visible = m[i].element.css("display") != "none"; if(!m[i].visible) continue; //If the element is not visible, continue - - m[i].offset = m[i].element.offset(); - m[i].proportions = { width: m[i].element[0].offsetWidth, height: m[i].element[0].offsetHeight }; - - if(type == "mousedown") m[i]._activate.call(m[i], event); //Activate the droppable if used directly from draggables - - } - - }, - drop: function(draggable, event) { - - var dropped = false; - $.each($.ui.ddmanager.droppables[draggable.options.scope] || [], function() { - - if(!this.options) return; - if (!this.options.disabled && this.visible && $.ui.intersect(draggable, this, this.options.tolerance)) - dropped = dropped || this._drop.call(this, event); - - if (!this.options.disabled && this.visible && this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) { - this.isout = 1; this.isover = 0; - this._deactivate.call(this, event); - } - - }); - return dropped; - - }, - drag: function(draggable, event) { - - //If you have a highly dynamic page, you might try this option. It renders positions every time you move the mouse. - if(draggable.options.refreshPositions) $.ui.ddmanager.prepareOffsets(draggable, event); - - //Run through all droppables and check their positions based on specific tolerance options - $.each($.ui.ddmanager.droppables[draggable.options.scope] || [], function() { - - if(this.options.disabled || this.greedyChild || !this.visible) return; - var intersects = $.ui.intersect(draggable, this, this.options.tolerance); - - var c = !intersects && this.isover == 1 ? 'isout' : (intersects && this.isover == 0 ? 'isover' : null); - if(!c) return; - - var parentInstance; - if (this.options.greedy) { - var parent = this.element.parents(':data(droppable):eq(0)'); - if (parent.length) { - parentInstance = $.data(parent[0], 'droppable'); - parentInstance.greedyChild = (c == 'isover' ? 1 : 0); - } - } - - // we just moved into a greedy child - if (parentInstance && c == 'isover') { - parentInstance['isover'] = 0; - parentInstance['isout'] = 1; - parentInstance._out.call(parentInstance, event); - } - - this[c] = 1; this[c == 'isout' ? 'isover' : 'isout'] = 0; - this[c == "isover" ? "_over" : "_out"].call(this, event); - - // we just moved out of a greedy child - if (parentInstance && c == 'isout') { - parentInstance['isout'] = 0; - parentInstance['isover'] = 1; - parentInstance._over.call(parentInstance, event); - } - }); - - } -}; - -})(jQuery); diff --git a/ui/jquery.ui.mouse.js b/ui/jquery.ui.mouse.js deleted file mode 100644 index 30c5f14a25c..00000000000 --- a/ui/jquery.ui.mouse.js +++ /dev/null @@ -1,151 +0,0 @@ -/*! - * jQuery UI Mouse @VERSION - * - * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT (MIT-LICENSE.txt) - * and GPL (GPL-LICENSE.txt) licenses. - * - * http://docs.jquery.com/UI/Mouse - * - * Depends: - * jquery.ui.widget.js - */ -(function($) { - -$.widget("ui.mouse", { - options: { - cancel: ':input,option', - distance: 1, - delay: 0 - }, - _mouseInit: function() { - var self = this; - - this.element - .bind('mousedown.'+this.widgetName, function(event) { - return self._mouseDown(event); - }) - .bind('click.'+this.widgetName, function(event) { - if(self._preventClickEvent) { - self._preventClickEvent = false; - event.stopImmediatePropagation(); - return false; - } - }); - - this.started = false; - }, - - // TODO: make sure destroying one instance of mouse doesn't mess with - // other instances of mouse - _mouseDestroy: function() { - this.element.unbind('.'+this.widgetName); - }, - - _mouseDown: function(event) { - // don't let more than one widget handle mouseStart - // TODO: figure out why we have to use originalEvent - event.originalEvent = event.originalEvent || {}; - if (event.originalEvent.mouseHandled) { return; } - - // we may have missed mouseup (out of window) - (this._mouseStarted && this._mouseUp(event)); - - this._mouseDownEvent = event; - - var self = this, - btnIsLeft = (event.which == 1), - elIsCancel = (typeof this.options.cancel == "string" ? $(event.target).parents().add(event.target).filter(this.options.cancel).length : false); - if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) { - return true; - } - - this.mouseDelayMet = !this.options.delay; - if (!this.mouseDelayMet) { - this._mouseDelayTimer = setTimeout(function() { - self.mouseDelayMet = true; - }, this.options.delay); - } - - if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) { - this._mouseStarted = (this._mouseStart(event) !== false); - if (!this._mouseStarted) { - event.preventDefault(); - return true; - } - } - - // these delegates are required to keep context - this._mouseMoveDelegate = function(event) { - return self._mouseMove(event); - }; - this._mouseUpDelegate = function(event) { - return self._mouseUp(event); - }; - $(document) - .bind('mousemove.'+this.widgetName, this._mouseMoveDelegate) - .bind('mouseup.'+this.widgetName, this._mouseUpDelegate); - - // preventDefault() is used to prevent the selection of text here - - // however, in Safari, this causes select boxes not to be selectable - // anymore, so this fix is needed - ($.browser.safari || event.preventDefault()); - - event.originalEvent.mouseHandled = true; - return true; - }, - - _mouseMove: function(event) { - // IE mouseup check - mouseup happened when mouse was out of window - if ($.browser.msie && !event.button) { - return this._mouseUp(event); - } - - if (this._mouseStarted) { - this._mouseDrag(event); - return event.preventDefault(); - } - - if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) { - this._mouseStarted = - (this._mouseStart(this._mouseDownEvent, event) !== false); - (this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event)); - } - - return !this._mouseStarted; - }, - - _mouseUp: function(event) { - $(document) - .unbind('mousemove.'+this.widgetName, this._mouseMoveDelegate) - .unbind('mouseup.'+this.widgetName, this._mouseUpDelegate); - - if (this._mouseStarted) { - this._mouseStarted = false; - this._preventClickEvent = (event.target == this._mouseDownEvent.target); - this._mouseStop(event); - } - - return false; - }, - - _mouseDistanceMet: function(event) { - return (Math.max( - Math.abs(this._mouseDownEvent.pageX - event.pageX), - Math.abs(this._mouseDownEvent.pageY - event.pageY) - ) >= this.options.distance - ); - }, - - _mouseDelayMet: function(event) { - return this.mouseDelayMet; - }, - - // These are placeholder methods, to be overriden by extending plugin - _mouseStart: function(event) {}, - _mouseDrag: function(event) {}, - _mouseStop: function(event) {}, - _mouseCapture: function(event) { return true; } -}); - -})(jQuery); diff --git a/ui/jquery.ui.position.js b/ui/jquery.ui.position.js deleted file mode 100644 index 11f8baa0638..00000000000 --- a/ui/jquery.ui.position.js +++ /dev/null @@ -1,233 +0,0 @@ -/* - * jQuery UI Position @VERSION - * - * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT (MIT-LICENSE.txt) - * and GPL (GPL-LICENSE.txt) licenses. - * - * http://docs.jquery.com/UI/Position - */ -(function( $ ) { - -$.ui = $.ui || {}; - -var horizontalPositions = /left|center|right/, - horizontalDefault = "center", - verticalPositions = /top|center|bottom/, - verticalDefault = "center", - _position = $.fn.position, - _offset = $.fn.offset; - -$.fn.position = function( options ) { - if ( !options || !options.of ) { - return _position.apply( this, arguments ); - } - - // make a copy, we don't want to modify arguments - options = $.extend( {}, options ); - - var target = $( options.of ), - collision = ( options.collision || "flip" ).split( " " ), - offset = options.offset ? options.offset.split( " " ) : [ 0, 0 ], - targetWidth, - targetHeight, - basePosition; - - if ( options.of.nodeType === 9 ) { - targetWidth = target.width(); - targetHeight = target.height(); - basePosition = { top: 0, left: 0 }; - } else if ( options.of.scrollTo && options.of.document ) { - targetWidth = target.width(); - targetHeight = target.height(); - basePosition = { top: target.scrollTop(), left: target.scrollLeft() }; - } else if ( options.of.preventDefault ) { - // force left top to allow flipping - options.at = "left top"; - targetWidth = targetHeight = 0; - basePosition = { top: options.of.pageY, left: options.of.pageX }; - } else { - targetWidth = target.outerWidth(); - targetHeight = target.outerHeight(); - basePosition = target.offset(); - } - - // force my and at to have valid horizontal and veritcal positions - // if a value is missing or invalid, it will be converted to center - $.each( [ "my", "at" ], function() { - var pos = ( options[this] || "" ).split( " " ); - if ( pos.length === 1) { - pos = horizontalPositions.test( pos[0] ) ? - pos.concat( [verticalDefault] ) : - verticalPositions.test( pos[0] ) ? - [ horizontalDefault ].concat( pos ) : - [ horizontalDefault, verticalDefault ]; - } - pos[ 0 ] = horizontalPositions.test( pos[0] ) ? pos[ 0 ] : horizontalDefault; - pos[ 1 ] = verticalPositions.test( pos[1] ) ? pos[ 1 ] : verticalDefault; - options[ this ] = pos; - }); - - // normalize collision option - if ( collision.length === 1 ) { - collision[ 1 ] = collision[ 0 ]; - } - - // normalize offset option - offset[ 0 ] = parseInt( offset[0], 10 ) || 0; - if ( offset.length === 1 ) { - offset[ 1 ] = offset[ 0 ]; - } - offset[ 1 ] = parseInt( offset[1], 10 ) || 0; - - if ( options.at[0] === "right" ) { - basePosition.left += targetWidth; - } else if (options.at[0] === horizontalDefault ) { - basePosition.left += targetWidth / 2; - } - - if ( options.at[1] === "bottom" ) { - basePosition.top += targetHeight; - } else if ( options.at[1] === verticalDefault ) { - basePosition.top += targetHeight / 2; - } - - basePosition.left += offset[ 0 ]; - basePosition.top += offset[ 1 ]; - - return this.each(function() { - var elem = $( this ), - elemWidth = elem.outerWidth(), - elemHeight = elem.outerHeight(), - position = $.extend( {}, basePosition ); - - if ( options.my[0] === "right" ) { - position.left -= elemWidth; - } else if ( options.my[0] === horizontalDefault ) { - position.left -= elemWidth / 2; - } - - if ( options.my[1] === "bottom" ) { - position.top -= elemHeight; - } else if ( options.my[1] === verticalDefault ) { - position.top -= elemHeight / 2; - } - - // prevent fractions (see #5280) - position.left = parseInt( position.left ); - position.top = parseInt( position.top ); - - $.each( [ "left", "top" ], function( i, dir ) { - if ( $.ui.position[ collision[i] ] ) { - $.ui.position[ collision[i] ][ dir ]( position, { - targetWidth: targetWidth, - targetHeight: targetHeight, - elemWidth: elemWidth, - elemHeight: elemHeight, - offset: offset, - my: options.my, - at: options.at - }); - } - }); - - if ( $.fn.bgiframe ) { - elem.bgiframe(); - } - elem.offset( $.extend( position, { using: options.using } ) ); - }); -}; - -$.ui.position = { - fit: { - left: function( position, data ) { - var win = $( window ), - over = position.left + data.elemWidth - win.width() - win.scrollLeft(); - position.left = over > 0 ? position.left - over : Math.max( 0, position.left ); - }, - top: function( position, data ) { - var win = $( window ), - over = position.top + data.elemHeight - win.height() - win.scrollTop(); - position.top = over > 0 ? position.top - over : Math.max( 0, position.top ); - } - }, - - flip: { - left: function( position, data ) { - if ( data.at[0] === "center" ) { - return; - } - var win = $( window ), - over = position.left + data.elemWidth - win.width() - win.scrollLeft(), - myOffset = data.my[ 0 ] === "left" ? - -data.elemWidth : - data.my[ 0 ] === "right" ? - data.elemWidth : - 0, - offset = -2 * data.offset[ 0 ]; - position.left += position.left < 0 ? - myOffset + data.targetWidth + offset : - over > 0 ? - myOffset - data.targetWidth + offset : - 0; - }, - top: function( position, data ) { - if ( data.at[1] === "center" ) { - return; - } - var win = $( window ), - over = position.top + data.elemHeight - win.height() - win.scrollTop(), - myOffset = data.my[ 1 ] === "top" ? - -data.elemHeight : - data.my[ 1 ] === "bottom" ? - data.elemHeight : - 0, - atOffset = data.at[ 1 ] === "top" ? - data.targetHeight : - -data.targetHeight, - offset = -2 * data.offset[ 1 ]; - position.top += position.top < 0 ? - myOffset + data.targetHeight + offset : - over > 0 ? - myOffset + atOffset + offset : - 0; - } - } -}; - -// offset setter from jQuery 1.4 -if ( !$.offset.setOffset ) { - $.offset.setOffset = function( elem, options ) { - // set position first, in-case top/left are set even on static elem - if ( /static/.test( $.curCSS( elem, "position" ) ) ) { - elem.style.position = "relative"; - } - var curElem = $( elem ), - curOffset = curElem.offset(), - curTop = parseInt( $.curCSS( elem, "top", true ), 10 ) || 0, - curLeft = parseInt( $.curCSS( elem, "left", true ), 10) || 0, - props = { - top: (options.top - curOffset.top) + curTop, - left: (options.left - curOffset.left) + curLeft - }; - - if ( 'using' in options ) { - options.using.call( elem, props ); - } else { - curElem.css( props ); - } - }; - - $.fn.offset = function( options ) { - var elem = this[ 0 ]; - if ( !elem || !elem.ownerDocument ) { return null; } - if ( options ) { - return this.each(function() { - $.offset.setOffset( this, options ); - }); - } - return _offset.call( this ); - }; -} - -}( jQuery )); diff --git a/ui/jquery.ui.progressbar.js b/ui/jquery.ui.progressbar.js deleted file mode 100644 index b38d826f0cd..00000000000 --- a/ui/jquery.ui.progressbar.js +++ /dev/null @@ -1,107 +0,0 @@ -/* - * jQuery UI Progressbar @VERSION - * - * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT (MIT-LICENSE.txt) - * and GPL (GPL-LICENSE.txt) licenses. - * - * http://docs.jquery.com/UI/Progressbar - * - * Depends: - * jquery.ui.core.js - * jquery.ui.widget.js - */ -(function( $ ) { - -$.widget( "ui.progressbar", { - options: { - value: 0 - }, - _create: function() { - this.element - .addClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" ) - .attr({ - role: "progressbar", - "aria-valuemin": this._valueMin(), - "aria-valuemax": this._valueMax(), - "aria-valuenow": this._value() - }); - - this.valueDiv = $( "
        " ) - .appendTo( this.element ); - - this._refreshValue(); - }, - - destroy: function() { - this.element - .removeClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" ) - .removeAttr( "role" ) - .removeAttr( "aria-valuemin" ) - .removeAttr( "aria-valuemax" ) - .removeAttr( "aria-valuenow" ); - - this.valueDiv.remove(); - - $.Widget.prototype.destroy.apply( this, arguments ); - }, - - value: function( newValue ) { - if ( newValue === undefined ) { - return this._value(); - } - - this._setOption( "value", newValue ); - return this; - }, - - _setOption: function( key, value ) { - switch ( key ) { - case "value": - this.options.value = value; - this._refreshValue(); - this._trigger( "change" ); - break; - } - - $.Widget.prototype._setOption.apply( this, arguments ); - }, - - _value: function() { - var val = this.options.value; - // normalize invalid value - if ( typeof val !== "number" ) { - val = 0; - } - if ( val < this._valueMin() ) { - val = this._valueMin(); - } - if ( val > this._valueMax() ) { - val = this._valueMax(); - } - - return val; - }, - - _valueMin: function() { - return 0; - }, - - _valueMax: function() { - return 100; - }, - - _refreshValue: function() { - var value = this.value(); - this.valueDiv - [ value === this._valueMax() ? "addClass" : "removeClass"]( "ui-corner-right" ) - .width( value + "%" ); - this.element.attr( "aria-valuenow", value ); - } -}); - -$.extend( $.ui.progressbar, { - version: "@VERSION" -}); - -})( jQuery ); diff --git a/ui/jquery.ui.resizable.js b/ui/jquery.ui.resizable.js deleted file mode 100644 index 1f7215e2cac..00000000000 --- a/ui/jquery.ui.resizable.js +++ /dev/null @@ -1,812 +0,0 @@ -/* - * jQuery UI Resizable @VERSION - * - * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT (MIT-LICENSE.txt) - * and GPL (GPL-LICENSE.txt) licenses. - * - * http://docs.jquery.com/UI/Resizables - * - * Depends: - * jquery.ui.core.js - * jquery.ui.mouse.js - * jquery.ui.widget.js - */ -(function($) { - -$.widget("ui.resizable", $.ui.mouse, { - widgetEventPrefix: "resize", - options: { - alsoResize: false, - animate: false, - animateDuration: "slow", - animateEasing: "swing", - aspectRatio: false, - autoHide: false, - containment: false, - ghost: false, - grid: false, - handles: "e,s,se", - helper: false, - maxHeight: null, - maxWidth: null, - minHeight: 10, - minWidth: 10, - zIndex: 1000 - }, - _create: function() { - - var self = this, o = this.options; - this.element.addClass("ui-resizable"); - - $.extend(this, { - _aspectRatio: !!(o.aspectRatio), - aspectRatio: o.aspectRatio, - originalElement: this.element, - _proportionallyResizeElements: [], - _helper: o.helper || o.ghost || o.animate ? o.helper || 'ui-resizable-helper' : null - }); - - //Wrap the element if it cannot hold child nodes - if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)) { - - //Opera fix for relative positioning - if (/relative/.test(this.element.css('position')) && $.browser.opera) - this.element.css({ position: 'relative', top: 'auto', left: 'auto' }); - - //Create a wrapper element and set the wrapper to the new current internal element - this.element.wrap( - $('
        ').css({ - position: this.element.css('position'), - width: this.element.outerWidth(), - height: this.element.outerHeight(), - top: this.element.css('top'), - left: this.element.css('left') - }) - ); - - //Overwrite the original this.element - this.element = this.element.parent().data( - "resizable", this.element.data('resizable') - ); - - this.elementIsWrapper = true; - - //Move margins to the wrapper - this.element.css({ marginLeft: this.originalElement.css("marginLeft"), marginTop: this.originalElement.css("marginTop"), marginRight: this.originalElement.css("marginRight"), marginBottom: this.originalElement.css("marginBottom") }); - this.originalElement.css({ marginLeft: 0, marginTop: 0, marginRight: 0, marginBottom: 0}); - - //Prevent Safari textarea resize - this.originalResizeStyle = this.originalElement.css('resize'); - this.originalElement.css('resize', 'none'); - - //Push the actual element to our proportionallyResize internal array - this._proportionallyResizeElements.push(this.originalElement.css({ position: 'static', zoom: 1, display: 'block' })); - - // avoid IE jump (hard set the margin) - this.originalElement.css({ margin: this.originalElement.css('margin') }); - - // fix handlers offset - this._proportionallyResize(); - - } - - this.handles = o.handles || (!$('.ui-resizable-handle', this.element).length ? "e,s,se" : { n: '.ui-resizable-n', e: '.ui-resizable-e', s: '.ui-resizable-s', w: '.ui-resizable-w', se: '.ui-resizable-se', sw: '.ui-resizable-sw', ne: '.ui-resizable-ne', nw: '.ui-resizable-nw' }); - if(this.handles.constructor == String) { - - if(this.handles == 'all') this.handles = 'n,e,s,w,se,sw,ne,nw'; - var n = this.handles.split(","); this.handles = {}; - - for(var i = 0; i < n.length; i++) { - - var handle = $.trim(n[i]), hname = 'ui-resizable-'+handle; - var axis = $('
        '); - - // increase zIndex of sw, se, ne, nw axis - //TODO : this modifies original option - if(/sw|se|ne|nw/.test(handle)) axis.css({ zIndex: ++o.zIndex }); - - //TODO : What's going on here? - if ('se' == handle) { - axis.addClass('ui-icon ui-icon-gripsmall-diagonal-se'); - }; - - //Insert into internal handles object and append to element - this.handles[handle] = '.ui-resizable-'+handle; - this.element.append(axis); - } - - } - - this._renderAxis = function(target) { - - target = target || this.element; - - for(var i in this.handles) { - - if(this.handles[i].constructor == String) - this.handles[i] = $(this.handles[i], this.element).show(); - - //Apply pad to wrapper element, needed to fix axis position (textarea, inputs, scrolls) - if (this.elementIsWrapper && this.originalElement[0].nodeName.match(/textarea|input|select|button/i)) { - - var axis = $(this.handles[i], this.element), padWrapper = 0; - - //Checking the correct pad and border - padWrapper = /sw|ne|nw|se|n|s/.test(i) ? axis.outerHeight() : axis.outerWidth(); - - //The padding type i have to apply... - var padPos = [ 'padding', - /ne|nw|n/.test(i) ? 'Top' : - /se|sw|s/.test(i) ? 'Bottom' : - /^e$/.test(i) ? 'Right' : 'Left' ].join(""); - - target.css(padPos, padWrapper); - - this._proportionallyResize(); - - } - - //TODO: What's that good for? There's not anything to be executed left - if(!$(this.handles[i]).length) - continue; - - } - }; - - //TODO: make renderAxis a prototype function - this._renderAxis(this.element); - - this._handles = $('.ui-resizable-handle', this.element) - .disableSelection(); - - //Matching axis name - this._handles.mouseover(function() { - if (!self.resizing) { - if (this.className) - var axis = this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i); - //Axis, default = se - self.axis = axis && axis[1] ? axis[1] : 'se'; - } - }); - - //If we want to auto hide the elements - if (o.autoHide) { - this._handles.hide(); - $(this.element) - .addClass("ui-resizable-autohide") - .hover(function() { - $(this).removeClass("ui-resizable-autohide"); - self._handles.show(); - }, - function(){ - if (!self.resizing) { - $(this).addClass("ui-resizable-autohide"); - self._handles.hide(); - } - }); - } - - //Initialize the mouse interaction - this._mouseInit(); - - }, - - destroy: function() { - - this._mouseDestroy(); - - var _destroy = function(exp) { - $(exp).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing") - .removeData("resizable").unbind(".resizable").find('.ui-resizable-handle').remove(); - }; - - //TODO: Unwrap at same DOM position - if (this.elementIsWrapper) { - _destroy(this.element); - var wrapper = this.element; - wrapper.after( - this.originalElement.css({ - position: wrapper.css('position'), - width: wrapper.outerWidth(), - height: wrapper.outerHeight(), - top: wrapper.css('top'), - left: wrapper.css('left') - }) - ).remove(); - } - - this.originalElement.css('resize', this.originalResizeStyle); - _destroy(this.originalElement); - - return this; - }, - - _mouseCapture: function(event) { - var handle = false; - for (var i in this.handles) { - if ($(this.handles[i])[0] == event.target) { - handle = true; - } - } - - return !this.options.disabled && handle; - }, - - _mouseStart: function(event) { - - var o = this.options, iniPos = this.element.position(), el = this.element; - - this.resizing = true; - this.documentScroll = { top: $(document).scrollTop(), left: $(document).scrollLeft() }; - - // bugfix for http://dev.jquery.com/ticket/1749 - if (el.is('.ui-draggable') || (/absolute/).test(el.css('position'))) { - el.css({ position: 'absolute', top: iniPos.top, left: iniPos.left }); - } - - //Opera fixing relative position - if ($.browser.opera && (/relative/).test(el.css('position'))) - el.css({ position: 'relative', top: 'auto', left: 'auto' }); - - this._renderProxy(); - - var curleft = num(this.helper.css('left')), curtop = num(this.helper.css('top')); - - if (o.containment) { - curleft += $(o.containment).scrollLeft() || 0; - curtop += $(o.containment).scrollTop() || 0; - } - - //Store needed variables - this.offset = this.helper.offset(); - this.position = { left: curleft, top: curtop }; - this.size = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() }; - this.originalSize = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() }; - this.originalPosition = { left: curleft, top: curtop }; - this.sizeDiff = { width: el.outerWidth() - el.width(), height: el.outerHeight() - el.height() }; - this.originalMousePosition = { left: event.pageX, top: event.pageY }; - - //Aspect Ratio - this.aspectRatio = (typeof o.aspectRatio == 'number') ? o.aspectRatio : ((this.originalSize.width / this.originalSize.height) || 1); - - var cursor = $('.ui-resizable-' + this.axis).css('cursor'); - $('body').css('cursor', cursor == 'auto' ? this.axis + '-resize' : cursor); - - el.addClass("ui-resizable-resizing"); - this._propagate("start", event); - return true; - }, - - _mouseDrag: function(event) { - - //Increase performance, avoid regex - var el = this.helper, o = this.options, props = {}, - self = this, smp = this.originalMousePosition, a = this.axis; - - var dx = (event.pageX-smp.left)||0, dy = (event.pageY-smp.top)||0; - var trigger = this._change[a]; - if (!trigger) return false; - - // Calculate the attrs that will be change - var data = trigger.apply(this, [event, dx, dy]), ie6 = $.browser.msie && $.browser.version < 7, csdif = this.sizeDiff; - - if (this._aspectRatio || event.shiftKey) - data = this._updateRatio(data, event); - - data = this._respectSize(data, event); - - // plugins callbacks need to be called first - this._propagate("resize", event); - - el.css({ - top: this.position.top + "px", left: this.position.left + "px", - width: this.size.width + "px", height: this.size.height + "px" - }); - - if (!this._helper && this._proportionallyResizeElements.length) - this._proportionallyResize(); - - this._updateCache(data); - - // calling the user callback at the end - this._trigger('resize', event, this.ui()); - - return false; - }, - - _mouseStop: function(event) { - - this.resizing = false; - var o = this.options, self = this; - - if(this._helper) { - var pr = this._proportionallyResizeElements, ista = pr.length && (/textarea/i).test(pr[0].nodeName), - soffseth = ista && $.ui.hasScroll(pr[0], 'left') /* TODO - jump height */ ? 0 : self.sizeDiff.height, - soffsetw = ista ? 0 : self.sizeDiff.width; - - var s = { width: (self.size.width - soffsetw), height: (self.size.height - soffseth) }, - left = (parseInt(self.element.css('left'), 10) + (self.position.left - self.originalPosition.left)) || null, - top = (parseInt(self.element.css('top'), 10) + (self.position.top - self.originalPosition.top)) || null; - - if (!o.animate) - this.element.css($.extend(s, { top: top, left: left })); - - self.helper.height(self.size.height); - self.helper.width(self.size.width); - - if (this._helper && !o.animate) this._proportionallyResize(); - } - - $('body').css('cursor', 'auto'); - - this.element.removeClass("ui-resizable-resizing"); - - this._propagate("stop", event); - - if (this._helper) this.helper.remove(); - return false; - - }, - - _updateCache: function(data) { - var o = this.options; - this.offset = this.helper.offset(); - if (isNumber(data.left)) this.position.left = data.left; - if (isNumber(data.top)) this.position.top = data.top; - if (isNumber(data.height)) this.size.height = data.height; - if (isNumber(data.width)) this.size.width = data.width; - }, - - _updateRatio: function(data, event) { - - var o = this.options, cpos = this.position, csize = this.size, a = this.axis; - - if (data.height) data.width = (csize.height * this.aspectRatio); - else if (data.width) data.height = (csize.width / this.aspectRatio); - - if (a == 'sw') { - data.left = cpos.left + (csize.width - data.width); - data.top = null; - } - if (a == 'nw') { - data.top = cpos.top + (csize.height - data.height); - data.left = cpos.left + (csize.width - data.width); - } - - return data; - }, - - _respectSize: function(data, event) { - - var el = this.helper, o = this.options, pRatio = this._aspectRatio || event.shiftKey, a = this.axis, - ismaxw = isNumber(data.width) && o.maxWidth && (o.maxWidth < data.width), ismaxh = isNumber(data.height) && o.maxHeight && (o.maxHeight < data.height), - isminw = isNumber(data.width) && o.minWidth && (o.minWidth > data.width), isminh = isNumber(data.height) && o.minHeight && (o.minHeight > data.height); - - if (isminw) data.width = o.minWidth; - if (isminh) data.height = o.minHeight; - if (ismaxw) data.width = o.maxWidth; - if (ismaxh) data.height = o.maxHeight; - - var dw = this.originalPosition.left + this.originalSize.width, dh = this.position.top + this.size.height; - var cw = /sw|nw|w/.test(a), ch = /nw|ne|n/.test(a); - - if (isminw && cw) data.left = dw - o.minWidth; - if (ismaxw && cw) data.left = dw - o.maxWidth; - if (isminh && ch) data.top = dh - o.minHeight; - if (ismaxh && ch) data.top = dh - o.maxHeight; - - // fixing jump error on top/left - bug #2330 - var isNotwh = !data.width && !data.height; - if (isNotwh && !data.left && data.top) data.top = null; - else if (isNotwh && !data.top && data.left) data.left = null; - - return data; - }, - - _proportionallyResize: function() { - - var o = this.options; - if (!this._proportionallyResizeElements.length) return; - var element = this.helper || this.element; - - for (var i=0; i < this._proportionallyResizeElements.length; i++) { - - var prel = this._proportionallyResizeElements[i]; - - if (!this.borderDif) { - var b = [prel.css('borderTopWidth'), prel.css('borderRightWidth'), prel.css('borderBottomWidth'), prel.css('borderLeftWidth')], - p = [prel.css('paddingTop'), prel.css('paddingRight'), prel.css('paddingBottom'), prel.css('paddingLeft')]; - - this.borderDif = $.map(b, function(v, i) { - var border = parseInt(v,10)||0, padding = parseInt(p[i],10)||0; - return border + padding; - }); - } - - if ($.browser.msie && !(!($(element).is(':hidden') || $(element).parents(':hidden').length))) - continue; - - prel.css({ - height: (element.height() - this.borderDif[0] - this.borderDif[2]) || 0, - width: (element.width() - this.borderDif[1] - this.borderDif[3]) || 0 - }); - - }; - - }, - - _renderProxy: function() { - - var el = this.element, o = this.options; - this.elementOffset = el.offset(); - - if(this._helper) { - - this.helper = this.helper || $('
        '); - - // fix ie6 offset TODO: This seems broken - var ie6 = $.browser.msie && $.browser.version < 7, ie6offset = (ie6 ? 1 : 0), - pxyoffset = ( ie6 ? 2 : -1 ); - - this.helper.addClass(this._helper).css({ - width: this.element.outerWidth() + pxyoffset, - height: this.element.outerHeight() + pxyoffset, - position: 'absolute', - left: this.elementOffset.left - ie6offset +'px', - top: this.elementOffset.top - ie6offset +'px', - zIndex: ++o.zIndex //TODO: Don't modify option - }); - - this.helper - .appendTo("body") - .disableSelection(); - - } else { - this.helper = this.element; - } - - }, - - _change: { - e: function(event, dx, dy) { - return { width: this.originalSize.width + dx }; - }, - w: function(event, dx, dy) { - var o = this.options, cs = this.originalSize, sp = this.originalPosition; - return { left: sp.left + dx, width: cs.width - dx }; - }, - n: function(event, dx, dy) { - var o = this.options, cs = this.originalSize, sp = this.originalPosition; - return { top: sp.top + dy, height: cs.height - dy }; - }, - s: function(event, dx, dy) { - return { height: this.originalSize.height + dy }; - }, - se: function(event, dx, dy) { - return $.extend(this._change.s.apply(this, arguments), this._change.e.apply(this, [event, dx, dy])); - }, - sw: function(event, dx, dy) { - return $.extend(this._change.s.apply(this, arguments), this._change.w.apply(this, [event, dx, dy])); - }, - ne: function(event, dx, dy) { - return $.extend(this._change.n.apply(this, arguments), this._change.e.apply(this, [event, dx, dy])); - }, - nw: function(event, dx, dy) { - return $.extend(this._change.n.apply(this, arguments), this._change.w.apply(this, [event, dx, dy])); - } - }, - - _propagate: function(n, event) { - $.ui.plugin.call(this, n, [event, this.ui()]); - (n != "resize" && this._trigger(n, event, this.ui())); - }, - - plugins: {}, - - ui: function() { - return { - originalElement: this.originalElement, - element: this.element, - helper: this.helper, - position: this.position, - size: this.size, - originalSize: this.originalSize, - originalPosition: this.originalPosition - }; - } - -}); - -$.extend($.ui.resizable, { - version: "@VERSION" -}); - -/* - * Resizable Extensions - */ - -$.ui.plugin.add("resizable", "alsoResize", { - - start: function (event, ui) { - var self = $(this).data("resizable"), o = self.options; - - var _store = function (exp) { - $(exp).each(function() { - var el = $(this); - el.data("resizable-alsoresize", { - width: parseInt(el.width(), 10), height: parseInt(el.height(), 10), - left: parseInt(el.css('left'), 10), top: parseInt(el.css('top'), 10), - position: el.css('position') // to reset Opera on stop() - }); - }); - }; - - if (typeof(o.alsoResize) == 'object' && !o.alsoResize.parentNode) { - if (o.alsoResize.length) { o.alsoResize = o.alsoResize[0]; _store(o.alsoResize); } - else { $.each(o.alsoResize, function (exp) { _store(exp); }); } - }else{ - _store(o.alsoResize); - } - }, - - resize: function (event, ui) { - var self = $(this).data("resizable"), o = self.options, os = self.originalSize, op = self.originalPosition; - - var delta = { - height: (self.size.height - os.height) || 0, width: (self.size.width - os.width) || 0, - top: (self.position.top - op.top) || 0, left: (self.position.left - op.left) || 0 - }, - - _alsoResize = function (exp, c) { - $(exp).each(function() { - var el = $(this), start = $(this).data("resizable-alsoresize"), style = {}, - css = c && c.length ? c : el.parents(ui.originalElement[0]).length ? ['width', 'height'] : ['width', 'height', 'top', 'left']; - - $.each(css, function (i, prop) { - var sum = (start[prop]||0) + (delta[prop]||0); - if (sum && sum >= 0) - style[prop] = sum || null; - }); - - // Opera fixing relative position - if ($.browser.opera && /relative/.test(el.css('position'))) { - self._revertToRelativePosition = true; - el.css({ position: 'absolute', top: 'auto', left: 'auto' }); - } - - el.css(style); - }); - }; - - if (typeof(o.alsoResize) == 'object' && !o.alsoResize.nodeType) { - $.each(o.alsoResize, function (exp, c) { _alsoResize(exp, c); }); - }else{ - _alsoResize(o.alsoResize); - } - }, - - stop: function (event, ui) { - var self = $(this).data("resizable"); - - var _reset = function (exp) { - $(exp).each(function() { - var el = $(this); - // reset position for Opera - no need to verify it was changed - el.css({ position: el.data("resizable-alsoresize").position }); - }); - } - - if (self._revertToRelativePosition) { - self._revertToRelativePosition = false; - if (typeof(o.alsoResize) == 'object' && !o.alsoResize.nodeType) { - $.each(o.alsoResize, function (exp) { _reset(exp); }); - }else{ - _reset(o.alsoResize); - } - } - - $(this).removeData("resizable-alsoresize"); - } -}); - -$.ui.plugin.add("resizable", "animate", { - - stop: function(event, ui) { - var self = $(this).data("resizable"), o = self.options; - - var pr = self._proportionallyResizeElements, ista = pr.length && (/textarea/i).test(pr[0].nodeName), - soffseth = ista && $.ui.hasScroll(pr[0], 'left') /* TODO - jump height */ ? 0 : self.sizeDiff.height, - soffsetw = ista ? 0 : self.sizeDiff.width; - - var style = { width: (self.size.width - soffsetw), height: (self.size.height - soffseth) }, - left = (parseInt(self.element.css('left'), 10) + (self.position.left - self.originalPosition.left)) || null, - top = (parseInt(self.element.css('top'), 10) + (self.position.top - self.originalPosition.top)) || null; - - self.element.animate( - $.extend(style, top && left ? { top: top, left: left } : {}), { - duration: o.animateDuration, - easing: o.animateEasing, - step: function() { - - var data = { - width: parseInt(self.element.css('width'), 10), - height: parseInt(self.element.css('height'), 10), - top: parseInt(self.element.css('top'), 10), - left: parseInt(self.element.css('left'), 10) - }; - - if (pr && pr.length) $(pr[0]).css({ width: data.width, height: data.height }); - - // propagating resize, and updating values for each animation step - self._updateCache(data); - self._propagate("resize", event); - - } - } - ); - } - -}); - -$.ui.plugin.add("resizable", "containment", { - - start: function(event, ui) { - var self = $(this).data("resizable"), o = self.options, el = self.element; - var oc = o.containment, ce = (oc instanceof $) ? oc.get(0) : (/parent/.test(oc)) ? el.parent().get(0) : oc; - if (!ce) return; - - self.containerElement = $(ce); - - if (/document/.test(oc) || oc == document) { - self.containerOffset = { left: 0, top: 0 }; - self.containerPosition = { left: 0, top: 0 }; - - self.parentData = { - element: $(document), left: 0, top: 0, - width: $(document).width(), height: $(document).height() || document.body.parentNode.scrollHeight - }; - } - - // i'm a node, so compute top, left, right, bottom - else { - var element = $(ce), p = []; - $([ "Top", "Right", "Left", "Bottom" ]).each(function(i, name) { p[i] = num(element.css("padding" + name)); }); - - self.containerOffset = element.offset(); - self.containerPosition = element.position(); - self.containerSize = { height: (element.innerHeight() - p[3]), width: (element.innerWidth() - p[1]) }; - - var co = self.containerOffset, ch = self.containerSize.height, cw = self.containerSize.width, - width = ($.ui.hasScroll(ce, "left") ? ce.scrollWidth : cw ), height = ($.ui.hasScroll(ce) ? ce.scrollHeight : ch); - - self.parentData = { - element: ce, left: co.left, top: co.top, width: width, height: height - }; - } - }, - - resize: function(event, ui) { - var self = $(this).data("resizable"), o = self.options, - ps = self.containerSize, co = self.containerOffset, cs = self.size, cp = self.position, - pRatio = self._aspectRatio || event.shiftKey, cop = { top:0, left:0 }, ce = self.containerElement; - - if (ce[0] != document && (/static/).test(ce.css('position'))) cop = co; - - if (cp.left < (self._helper ? co.left : 0)) { - self.size.width = self.size.width + (self._helper ? (self.position.left - co.left) : (self.position.left - cop.left)); - if (pRatio) self.size.height = self.size.width / o.aspectRatio; - self.position.left = o.helper ? co.left : 0; - } - - if (cp.top < (self._helper ? co.top : 0)) { - self.size.height = self.size.height + (self._helper ? (self.position.top - co.top) : self.position.top); - if (pRatio) self.size.width = self.size.height * o.aspectRatio; - self.position.top = self._helper ? co.top : 0; - } - - self.offset.left = self.parentData.left+self.position.left; - self.offset.top = self.parentData.top+self.position.top; - - var woset = Math.abs( (self._helper ? self.offset.left - cop.left : (self.offset.left - cop.left)) + self.sizeDiff.width ), - hoset = Math.abs( (self._helper ? self.offset.top - cop.top : (self.offset.top - co.top)) + self.sizeDiff.height ); - - var isParent = self.containerElement.get(0) == self.element.parent().get(0), - isOffsetRelative = /relative|absolute/.test(self.containerElement.css('position')); - - if(isParent && isOffsetRelative) woset -= self.parentData.left; - - if (woset + self.size.width >= self.parentData.width) { - self.size.width = self.parentData.width - woset; - if (pRatio) self.size.height = self.size.width / self.aspectRatio; - } - - if (hoset + self.size.height >= self.parentData.height) { - self.size.height = self.parentData.height - hoset; - if (pRatio) self.size.width = self.size.height * self.aspectRatio; - } - }, - - stop: function(event, ui){ - var self = $(this).data("resizable"), o = self.options, cp = self.position, - co = self.containerOffset, cop = self.containerPosition, ce = self.containerElement; - - var helper = $(self.helper), ho = helper.offset(), w = helper.outerWidth() - self.sizeDiff.width, h = helper.outerHeight() - self.sizeDiff.height; - - if (self._helper && !o.animate && (/relative/).test(ce.css('position'))) - $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h }); - - if (self._helper && !o.animate && (/static/).test(ce.css('position'))) - $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h }); - - } -}); - -$.ui.plugin.add("resizable", "ghost", { - - start: function(event, ui) { - - var self = $(this).data("resizable"), o = self.options, cs = self.size; - - self.ghost = self.originalElement.clone(); - self.ghost - .css({ opacity: .25, display: 'block', position: 'relative', height: cs.height, width: cs.width, margin: 0, left: 0, top: 0 }) - .addClass('ui-resizable-ghost') - .addClass(typeof o.ghost == 'string' ? o.ghost : ''); - - self.ghost.appendTo(self.helper); - - }, - - resize: function(event, ui){ - var self = $(this).data("resizable"), o = self.options; - if (self.ghost) self.ghost.css({ position: 'relative', height: self.size.height, width: self.size.width }); - }, - - stop: function(event, ui){ - var self = $(this).data("resizable"), o = self.options; - if (self.ghost && self.helper) self.helper.get(0).removeChild(self.ghost.get(0)); - } - -}); - -$.ui.plugin.add("resizable", "grid", { - - resize: function(event, ui) { - var self = $(this).data("resizable"), o = self.options, cs = self.size, os = self.originalSize, op = self.originalPosition, a = self.axis, ratio = o._aspectRatio || event.shiftKey; - o.grid = typeof o.grid == "number" ? [o.grid, o.grid] : o.grid; - var ox = Math.round((cs.width - os.width) / (o.grid[0]||1)) * (o.grid[0]||1), oy = Math.round((cs.height - os.height) / (o.grid[1]||1)) * (o.grid[1]||1); - - if (/^(se|s|e)$/.test(a)) { - self.size.width = os.width + ox; - self.size.height = os.height + oy; - } - else if (/^(ne)$/.test(a)) { - self.size.width = os.width + ox; - self.size.height = os.height + oy; - self.position.top = op.top - oy; - } - else if (/^(sw)$/.test(a)) { - self.size.width = os.width + ox; - self.size.height = os.height + oy; - self.position.left = op.left - ox; - } - else { - self.size.width = os.width + ox; - self.size.height = os.height + oy; - self.position.top = op.top - oy; - self.position.left = op.left - ox; - } - } - -}); - -var num = function(v) { - return parseInt(v, 10) || 0; -}; - -var isNumber = function(value) { - return !isNaN(parseInt(value, 10)); -}; - -})(jQuery); diff --git a/ui/jquery.ui.selectable.js b/ui/jquery.ui.selectable.js deleted file mode 100644 index 04c27e35305..00000000000 --- a/ui/jquery.ui.selectable.js +++ /dev/null @@ -1,267 +0,0 @@ - -/* - * jQuery UI Selectable @VERSION - * - * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT (MIT-LICENSE.txt) - * and GPL (GPL-LICENSE.txt) licenses. - * - * http://docs.jquery.com/UI/Selectables - * - * Depends: - * jquery.ui.core.js - * jquery.ui.mouse.js - * jquery.ui.widget.js - */ -(function($) { - -$.widget("ui.selectable", $.ui.mouse, { - options: { - appendTo: 'body', - autoRefresh: true, - distance: 0, - filter: '*', - tolerance: 'touch' - }, - _create: function() { - var self = this; - - this.element.addClass("ui-selectable"); - - this.dragged = false; - - // cache selectee children based on filter - var selectees; - this.refresh = function() { - selectees = $(self.options.filter, self.element[0]); - selectees.each(function() { - var $this = $(this); - var pos = $this.offset(); - $.data(this, "selectable-item", { - element: this, - $element: $this, - left: pos.left, - top: pos.top, - right: pos.left + $this.outerWidth(), - bottom: pos.top + $this.outerHeight(), - startselected: false, - selected: $this.hasClass('ui-selected'), - selecting: $this.hasClass('ui-selecting'), - unselecting: $this.hasClass('ui-unselecting') - }); - }); - }; - this.refresh(); - - this.selectees = selectees.addClass("ui-selectee"); - - this._mouseInit(); - - this.helper = $("
        "); - }, - - destroy: function() { - this.selectees - .removeClass("ui-selectee") - .removeData("selectable-item"); - this.element - .removeClass("ui-selectable ui-selectable-disabled") - .removeData("selectable") - .unbind(".selectable"); - this._mouseDestroy(); - - return this; - }, - - _mouseStart: function(event) { - var self = this; - - this.opos = [event.pageX, event.pageY]; - - if (this.options.disabled) - return; - - var options = this.options; - - this.selectees = $(options.filter, this.element[0]); - - this._trigger("start", event); - - $(options.appendTo).append(this.helper); - // position helper (lasso) - this.helper.css({ - "left": event.clientX, - "top": event.clientY, - "width": 0, - "height": 0 - }); - - if (options.autoRefresh) { - this.refresh(); - } - - this.selectees.filter('.ui-selected').each(function() { - var selectee = $.data(this, "selectable-item"); - selectee.startselected = true; - if (!event.metaKey) { - selectee.$element.removeClass('ui-selected'); - selectee.selected = false; - selectee.$element.addClass('ui-unselecting'); - selectee.unselecting = true; - // selectable UNSELECTING callback - self._trigger("unselecting", event, { - unselecting: selectee.element - }); - } - }); - - $(event.target).parents().andSelf().each(function() { - var selectee = $.data(this, "selectable-item"); - if (selectee) { - var doSelect = !event.metaKey || !selectee.$element.hasClass('ui-selected'); - selectee.$element - .removeClass(doSelect ? "ui-unselecting" : "ui-selected") - .addClass(doSelect ? "ui-selecting" : "ui-unselecting"); - selectee.unselecting = !doSelect; - selectee.selecting = doSelect; - selectee.selected = doSelect; - // selectable (UN)SELECTING callback - if (doSelect) { - self._trigger("selecting", event, { - selecting: selectee.element - }); - } else { - self._trigger("unselecting", event, { - unselecting: selectee.element - }); - } - return false; - } - }); - - }, - - _mouseDrag: function(event) { - var self = this; - this.dragged = true; - - if (this.options.disabled) - return; - - var options = this.options; - - var x1 = this.opos[0], y1 = this.opos[1], x2 = event.pageX, y2 = event.pageY; - if (x1 > x2) { var tmp = x2; x2 = x1; x1 = tmp; } - if (y1 > y2) { var tmp = y2; y2 = y1; y1 = tmp; } - this.helper.css({left: x1, top: y1, width: x2-x1, height: y2-y1}); - - this.selectees.each(function() { - var selectee = $.data(this, "selectable-item"); - //prevent helper from being selected if appendTo: selectable - if (!selectee || selectee.element == self.element[0]) - return; - var hit = false; - if (options.tolerance == 'touch') { - hit = ( !(selectee.left > x2 || selectee.right < x1 || selectee.top > y2 || selectee.bottom < y1) ); - } else if (options.tolerance == 'fit') { - hit = (selectee.left > x1 && selectee.right < x2 && selectee.top > y1 && selectee.bottom < y2); - } - - if (hit) { - // SELECT - if (selectee.selected) { - selectee.$element.removeClass('ui-selected'); - selectee.selected = false; - } - if (selectee.unselecting) { - selectee.$element.removeClass('ui-unselecting'); - selectee.unselecting = false; - } - if (!selectee.selecting) { - selectee.$element.addClass('ui-selecting'); - selectee.selecting = true; - // selectable SELECTING callback - self._trigger("selecting", event, { - selecting: selectee.element - }); - } - } else { - // UNSELECT - if (selectee.selecting) { - if (event.metaKey && selectee.startselected) { - selectee.$element.removeClass('ui-selecting'); - selectee.selecting = false; - selectee.$element.addClass('ui-selected'); - selectee.selected = true; - } else { - selectee.$element.removeClass('ui-selecting'); - selectee.selecting = false; - if (selectee.startselected) { - selectee.$element.addClass('ui-unselecting'); - selectee.unselecting = true; - } - // selectable UNSELECTING callback - self._trigger("unselecting", event, { - unselecting: selectee.element - }); - } - } - if (selectee.selected) { - if (!event.metaKey && !selectee.startselected) { - selectee.$element.removeClass('ui-selected'); - selectee.selected = false; - - selectee.$element.addClass('ui-unselecting'); - selectee.unselecting = true; - // selectable UNSELECTING callback - self._trigger("unselecting", event, { - unselecting: selectee.element - }); - } - } - } - }); - - return false; - }, - - _mouseStop: function(event) { - var self = this; - - this.dragged = false; - - var options = this.options; - - $('.ui-unselecting', this.element[0]).each(function() { - var selectee = $.data(this, "selectable-item"); - selectee.$element.removeClass('ui-unselecting'); - selectee.unselecting = false; - selectee.startselected = false; - self._trigger("unselected", event, { - unselected: selectee.element - }); - }); - $('.ui-selecting', this.element[0]).each(function() { - var selectee = $.data(this, "selectable-item"); - selectee.$element.removeClass('ui-selecting').addClass('ui-selected'); - selectee.selecting = false; - selectee.selected = true; - selectee.startselected = true; - self._trigger("selected", event, { - selected: selectee.element - }); - }); - this._trigger("stop", event); - - this.helper.remove(); - - return false; - } - -}); - -$.extend($.ui.selectable, { - version: "@VERSION" -}); - -})(jQuery); diff --git a/ui/jquery.ui.slider.js b/ui/jquery.ui.slider.js deleted file mode 100644 index 71b52ce37d7..00000000000 --- a/ui/jquery.ui.slider.js +++ /dev/null @@ -1,682 +0,0 @@ -/* - * jQuery UI Slider @VERSION - * - * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT (MIT-LICENSE.txt) - * and GPL (GPL-LICENSE.txt) licenses. - * - * http://docs.jquery.com/UI/Slider - * - * Depends: - * jquery.ui.core.js - * jquery.ui.mouse.js - * jquery.ui.widget.js - */ - -(function( $ ) { - -// number of pages in a slider -// (how many times can you page up/down to go through the whole range) -var numPages = 5; - -$.widget( "ui.slider", $.ui.mouse, { - - widgetEventPrefix: "slide", - - options: { - animate: false, - distance: 0, - max: 100, - min: 0, - orientation: "horizontal", - range: false, - step: 1, - value: 0, - values: null - }, - - _create: function() { - var self = this, - o = this.options; - - this._keySliding = false; - this._mouseSliding = false; - this._animateOff = true; - this._handleIndex = null; - this._detectOrientation(); - this._mouseInit(); - - this.element - .addClass( "ui-slider" + - " ui-slider-" + this.orientation + - " ui-widget" + - " ui-widget-content" + - " ui-corner-all" ); - - if ( o.disabled ) { - this.element.addClass( "ui-slider-disabled ui-disabled" ); - } - - this.range = $([]); - - if ( o.range ) { - if ( o.range === true ) { - this.range = $( "
        " ); - if ( !o.values ) { - o.values = [ this._valueMin(), this._valueMin() ]; - } - if ( o.values.length && o.values.length !== 2 ) { - o.values = [ o.values[0], o.values[0] ]; - } - } else { - this.range = $( "
        " ); - } - - this.range - .appendTo( this.element ) - .addClass( "ui-slider-range" ); - - if ( o.range === "min" || o.range === "max" ) { - this.range.addClass( "ui-slider-range-" + o.range ); - } - - // note: this isn't the most fittingly semantic framework class for this element, - // but worked best visually with a variety of themes - this.range.addClass( "ui-widget-header" ); - } - - if ( $( ".ui-slider-handle", this.element ).length === 0 ) { - $( "" ) - .appendTo( this.element ) - .addClass( "ui-slider-handle" ); - } - - if ( o.values && o.values.length ) { - while ( $(".ui-slider-handle", this.element).length < o.values.length ) { - $( "" ) - .appendTo( this.element ) - .addClass( "ui-slider-handle" ); - } - } - - this.handles = $( ".ui-slider-handle", this.element ) - .addClass( "ui-state-default" + - " ui-corner-all" ); - - this.handle = this.handles.eq( 0 ); - - this.handles.add( this.range ).filter( "a" ) - .click(function( event ) { - event.preventDefault(); - }) - .hover(function() { - if ( !o.disabled ) { - $( this ).addClass( "ui-state-hover" ); - } - }, function() { - $( this ).removeClass( "ui-state-hover" ); - }) - .focus(function() { - if ( !o.disabled ) { - $( ".ui-slider .ui-state-focus" ).removeClass( "ui-state-focus" ); - $( this ).addClass( "ui-state-focus" ); - } else { - $( this ).blur(); - } - }) - .blur(function() { - $( this ).removeClass( "ui-state-focus" ); - }); - - this.handles.each(function( i ) { - $( this ).data( "index.ui-slider-handle", i ); - }); - - this.handles - .keydown(function( event ) { - var ret = true, - index = $( this ).data( "index.ui-slider-handle" ), - allowed, - curVal, - newVal, - step; - - if ( self.options.disabled ) { - return; - } - - switch ( event.keyCode ) { - case $.ui.keyCode.HOME: - case $.ui.keyCode.END: - case $.ui.keyCode.PAGE_UP: - case $.ui.keyCode.PAGE_DOWN: - case $.ui.keyCode.UP: - case $.ui.keyCode.RIGHT: - case $.ui.keyCode.DOWN: - case $.ui.keyCode.LEFT: - ret = false; - if ( !self._keySliding ) { - self._keySliding = true; - $( this ).addClass( "ui-state-active" ); - allowed = self._start( event, index ); - if ( allowed === false ) { - return; - } - } - break; - } - - step = self.options.step; - if ( self.options.values && self.options.values.length ) { - curVal = newVal = self.values( index ); - } else { - curVal = newVal = self.value(); - } - - switch ( event.keyCode ) { - case $.ui.keyCode.HOME: - newVal = self._valueMin(); - break; - case $.ui.keyCode.END: - newVal = self._valueMax(); - break; - case $.ui.keyCode.PAGE_UP: - newVal = self._trimAlignValue( curVal + ( (self._valueMax() - self._valueMin()) / numPages ) ); - break; - case $.ui.keyCode.PAGE_DOWN: - newVal = self._trimAlignValue( curVal - ( (self._valueMax() - self._valueMin()) / numPages ) ); - break; - case $.ui.keyCode.UP: - case $.ui.keyCode.RIGHT: - if ( curVal === self._valueMax() ) { - return; - } - newVal = self._trimAlignValue( curVal + step ); - break; - case $.ui.keyCode.DOWN: - case $.ui.keyCode.LEFT: - if ( curVal === self._valueMin() ) { - return; - } - newVal = self._trimAlignValue( curVal - step ); - break; - } - - self._slide( event, index, newVal ); - - return ret; - - }) - .keyup(function( event ) { - var index = $( this ).data( "index.ui-slider-handle" ); - - if ( self._keySliding ) { - self._keySliding = false; - self._stop( event, index ); - self._change( event, index ); - $( this ).removeClass( "ui-state-active" ); - } - - }); - - this._refreshValue(); - - this._animateOff = false; - }, - - destroy: function() { - this.handles.remove(); - this.range.remove(); - - this.element - .removeClass( "ui-slider" + - " ui-slider-horizontal" + - " ui-slider-vertical" + - " ui-slider-disabled" + - " ui-widget" + - " ui-widget-content" + - " ui-corner-all" ) - .removeData( "slider" ) - .unbind( ".slider" ); - - this._mouseDestroy(); - - return this; - }, - - _mouseCapture: function( event ) { - var o = this.options, - position, - normValue, - distance, - closestHandle, - self, - index, - allowed, - offset, - mouseOverHandle; - - if ( o.disabled ) { - return false; - } - - this.elementSize = { - width: this.element.outerWidth(), - height: this.element.outerHeight() - }; - this.elementOffset = this.element.offset(); - - position = { x: event.pageX, y: event.pageY }; - normValue = this._normValueFromMouse( position ); - distance = this._valueMax() - this._valueMin() + 1; - self = this; - this.handles.each(function( i ) { - var thisDistance = Math.abs( normValue - self.values(i) ); - if ( distance > thisDistance ) { - distance = thisDistance; - closestHandle = $( this ); - index = i; - } - }); - - // workaround for bug #3736 (if both handles of a range are at 0, - // the first is always used as the one with least distance, - // and moving it is obviously prevented by preventing negative ranges) - if( o.range === true && this.values(1) === o.min ) { - index += 1; - closestHandle = $( this.handles[index] ); - } - - allowed = this._start( event, index ); - if ( allowed === false ) { - return false; - } - this._mouseSliding = true; - - self._handleIndex = index; - - closestHandle - .addClass( "ui-state-active" ) - .focus(); - - offset = closestHandle.offset(); - mouseOverHandle = !$( event.target ).parents().andSelf().is( ".ui-slider-handle" ); - this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : { - left: event.pageX - offset.left - ( closestHandle.width() / 2 ), - top: event.pageY - offset.top - - ( closestHandle.height() / 2 ) - - ( parseInt( closestHandle.css("borderTopWidth"), 10 ) || 0 ) - - ( parseInt( closestHandle.css("borderBottomWidth"), 10 ) || 0) + - ( parseInt( closestHandle.css("marginTop"), 10 ) || 0) - }; - - normValue = this._normValueFromMouse( position ); - this._slide( event, index, normValue ); - this._animateOff = true; - return true; - }, - - _mouseStart: function( event ) { - return true; - }, - - _mouseDrag: function( event ) { - var position = { x: event.pageX, y: event.pageY }, - normValue = this._normValueFromMouse( position ); - - this._slide( event, this._handleIndex, normValue ); - - return false; - }, - - _mouseStop: function( event ) { - this.handles.removeClass( "ui-state-active" ); - this._mouseSliding = false; - - this._stop( event, this._handleIndex ); - this._change( event, this._handleIndex ); - - this._handleIndex = null; - this._clickOffset = null; - this._animateOff = false; - - return false; - }, - - _detectOrientation: function() { - this.orientation = ( this.options.orientation === "vertical" ) ? "vertical" : "horizontal"; - }, - - _normValueFromMouse: function( position ) { - var pixelTotal, - pixelMouse, - percentMouse, - valueTotal, - valueMouse; - - if ( this.orientation === "horizontal" ) { - pixelTotal = this.elementSize.width; - pixelMouse = position.x - this.elementOffset.left - ( this._clickOffset ? this._clickOffset.left : 0 ); - } else { - pixelTotal = this.elementSize.height; - pixelMouse = position.y - this.elementOffset.top - ( this._clickOffset ? this._clickOffset.top : 0 ); - } - - percentMouse = ( pixelMouse / pixelTotal ); - if ( percentMouse > 1 ) { - percentMouse = 1; - } - if ( percentMouse < 0 ) { - percentMouse = 0; - } - if ( this.orientation === "vertical" ) { - percentMouse = 1 - percentMouse; - } - - valueTotal = this._valueMax() - this._valueMin(); - valueMouse = this._valueMin() + percentMouse * valueTotal; - - return this._trimAlignValue( valueMouse ); - }, - - _start: function( event, index ) { - var uiHash = { - handle: this.handles[ index ], - value: this.value() - }; - if ( this.options.values && this.options.values.length ) { - uiHash.value = this.values( index ); - uiHash.values = this.values(); - } - return this._trigger( "start", event, uiHash ); - }, - - _slide: function( event, index, newVal ) { - var otherVal, - newValues, - allowed; - - if ( this.options.values && this.options.values.length ) { - otherVal = this.values( index ? 0 : 1 ); - - if ( ( this.options.values.length === 2 && this.options.range === true ) && - ( ( index === 0 && newVal > otherVal) || ( index === 1 && newVal < otherVal ) ) - ) { - newVal = otherVal; - } - - if ( newVal !== this.values( index ) ) { - newValues = this.values(); - newValues[ index ] = newVal; - // A slide can be canceled by returning false from the slide callback - allowed = this._trigger( "slide", event, { - handle: this.handles[ index ], - value: newVal, - values: newValues - } ); - otherVal = this.values( index ? 0 : 1 ); - if ( allowed !== false ) { - this.values( index, newVal, true ); - } - } - } else { - if ( newVal !== this.value() ) { - // A slide can be canceled by returning false from the slide callback - allowed = this._trigger( "slide", event, { - handle: this.handles[ index ], - value: newVal - } ); - if ( allowed !== false ) { - this.value( newVal ); - } - } - } - }, - - _stop: function( event, index ) { - var uiHash = { - handle: this.handles[ index ], - value: this.value() - }; - if ( this.options.values && this.options.values.length ) { - uiHash.value = this.values( index ); - uiHash.values = this.values(); - } - - this._trigger( "stop", event, uiHash ); - }, - - _change: function( event, index ) { - if ( !this._keySliding && !this._mouseSliding ) { - var uiHash = { - handle: this.handles[ index ], - value: this.value() - }; - if ( this.options.values && this.options.values.length ) { - uiHash.value = this.values( index ); - uiHash.values = this.values(); - } - - this._trigger( "change", event, uiHash ); - } - }, - - value: function( newValue ) { - if ( arguments.length ) { - this.options.value = this._trimAlignValue( newValue ); - this._refreshValue(); - this._change( null, 0 ); - } - - return this._value(); - }, - - values: function( index, newValue ) { - var vals, - newValues, - i; - - if ( arguments.length > 1 ) { - this.options.values[ index ] = this._trimAlignValue( newValue ); - this._refreshValue(); - this._change( null, index ); - } - - if ( arguments.length ) { - if ( $.isArray( arguments[ 0 ] ) ) { - vals = this.options.values; - newValues = arguments[ 0 ]; - for ( i = 0; i < vals.length; i += 1 ) { - vals[ i ] = this._trimAlignValue( newValues[ i ] ); - this._change( null, i ); - } - this._refreshValue(); - } else { - if ( this.options.values && this.options.values.length ) { - return this._values( index ); - } else { - return this.value(); - } - } - } else { - return this._values(); - } - }, - - _setOption: function( key, value ) { - var i, - valsLength = 0; - - if ( $.isArray( this.options.values ) ) { - valsLength = this.options.values.length; - } - - $.Widget.prototype._setOption.apply( this, arguments ); - - switch ( key ) { - case "disabled": - if ( value ) { - this.handles.filter( ".ui-state-focus" ).blur(); - this.handles.removeClass( "ui-state-hover" ); - this.handles.attr( "disabled", "disabled" ); - this.element.addClass( "ui-disabled" ); - } else { - this.handles.removeAttr( "disabled" ); - this.element.removeClass( "ui-disabled" ); - } - break; - case "orientation": - this._detectOrientation(); - this.element - .removeClass( "ui-slider-horizontal ui-slider-vertical" ) - .addClass( "ui-slider-" + this.orientation ); - this._refreshValue(); - break; - case "value": - this._animateOff = true; - this._refreshValue(); - this._change( null, 0 ); - this._animateOff = false; - break; - case "values": - this._animateOff = true; - this._refreshValue(); - for ( i = 0; i < valsLength; i += 1 ) { - this._change( null, i ); - } - this._animateOff = false; - break; - } - }, - - //internal value getter - // _value() returns value trimmed by min and max, aligned by step - _value: function() { - var val = this.options.value; - val = this._trimAlignValue( val ); - - return val; - }, - - //internal values getter - // _values() returns array of values trimmed by min and max, aligned by step - // _values( index ) returns single value trimmed by min and max, aligned by step - _values: function( index ) { - var val, - vals, - i; - - if ( arguments.length ) { - val = this.options.values[ index ]; - val = this._trimAlignValue( val ); - - return val; - } else { - // .slice() creates a copy of the array - // this copy gets trimmed by min and max and then returned - vals = this.options.values.slice(); - for ( i = 0; i < vals.length; i+= 1) { - vals[ i ] = this._trimAlignValue( vals[ i ] ); - } - - return vals; - } - }, - - // returns the step-aligned value that val is closest to, between (inclusive) min and max - _trimAlignValue: function( val ) { - if ( val < this._valueMin() ) { - return this._valueMin(); - } - if ( val > this._valueMax() ) { - return this._valueMax(); - } - var step = ( this.options.step > 0 ) ? this.options.step : 1, - valModStep = val % step, - alignValue = val - valModStep; - - if ( Math.abs(valModStep) * 2 >= step ) { - alignValue += ( valModStep > 0 ) ? step : ( -step ); - } - - // Since JavaScript has problems with large floats, round - // the final value to 5 digits after the decimal point (see #4124) - return parseFloat( alignValue.toFixed(5) ); - }, - - _valueMin: function() { - return this.options.min; - }, - - _valueMax: function() { - return this.options.max; - }, - - _refreshValue: function() { - var oRange = this.options.range, - o = this.options, - self = this, - animate = ( !this._animateOff ) ? o.animate : false, - valPercent, - _set = {}, - lastValPercent, - value, - valueMin, - valueMax; - - if ( this.options.values && this.options.values.length ) { - this.handles.each(function( i, j ) { - valPercent = ( self.values(i) - self._valueMin() ) / ( self._valueMax() - self._valueMin() ) * 100; - _set[ self.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%"; - $( this ).stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate ); - if ( self.options.range === true ) { - if ( self.orientation === "horizontal" ) { - if ( i === 0 ) { - self.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { left: valPercent + "%" }, o.animate ); - } - if ( i === 1 ) { - self.range[ animate ? "animate" : "css" ]( { width: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } ); - } - } else { - if ( i === 0 ) { - self.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { bottom: ( valPercent ) + "%" }, o.animate ); - } - if ( i === 1 ) { - self.range[ animate ? "animate" : "css" ]( { height: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } ); - } - } - } - lastValPercent = valPercent; - }); - } else { - value = this.value(); - valueMin = this._valueMin(); - valueMax = this._valueMax(); - valPercent = ( valueMax !== valueMin ) ? - ( value - valueMin ) / ( valueMax - valueMin ) * 100 : - 0; - _set[ self.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%"; - this.handle.stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate ); - - if ( oRange === "min" && this.orientation === "horizontal" ) { - this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { width: valPercent + "%" }, o.animate ); - } - if ( oRange === "max" && this.orientation === "horizontal" ) { - this.range[ animate ? "animate" : "css" ]( { width: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } ); - } - if ( oRange === "min" && this.orientation === "vertical" ) { - this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { height: valPercent + "%" }, o.animate ); - } - if ( oRange === "max" && this.orientation === "vertical" ) { - this.range[ animate ? "animate" : "css" ]( { height: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } ); - } - } - } - -}); - -$.extend( $.ui.slider, { - version: "@VERSION" -}); - -}(jQuery)); diff --git a/ui/jquery.ui.sortable.js b/ui/jquery.ui.sortable.js deleted file mode 100644 index ba0b283933f..00000000000 --- a/ui/jquery.ui.sortable.js +++ /dev/null @@ -1,1067 +0,0 @@ -/* - * jQuery UI Sortable @VERSION - * - * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT (MIT-LICENSE.txt) - * and GPL (GPL-LICENSE.txt) licenses. - * - * http://docs.jquery.com/UI/Sortables - * - * Depends: - * jquery.ui.core.js - * jquery.ui.mouse.js - * jquery.ui.widget.js - */ -(function($) { - -$.widget("ui.sortable", $.ui.mouse, { - widgetEventPrefix: "sort", - options: { - appendTo: "parent", - axis: false, - connectWith: false, - containment: false, - cursor: 'auto', - cursorAt: false, - dropOnEmpty: true, - forcePlaceholderSize: false, - forceHelperSize: false, - grid: false, - handle: false, - helper: "original", - items: '> *', - opacity: false, - placeholder: false, - revert: false, - scroll: true, - scrollSensitivity: 20, - scrollSpeed: 20, - scope: "default", - tolerance: "intersect", - zIndex: 1000 - }, - _create: function() { - - var o = this.options; - this.containerCache = {}; - this.element.addClass("ui-sortable"); - - //Get the items - this.refresh(); - - //Let's determine if the items are floating - this.floating = this.items.length ? (/left|right/).test(this.items[0].item.css('float')) : false; - - //Let's determine the parent's offset - this.offset = this.element.offset(); - - //Initialize mouse events for interaction - this._mouseInit(); - - }, - - destroy: function() { - this.element - .removeClass("ui-sortable ui-sortable-disabled") - .removeData("sortable") - .unbind(".sortable"); - this._mouseDestroy(); - - for ( var i = this.items.length - 1; i >= 0; i-- ) - this.items[i].item.removeData("sortable-item"); - - return this; - }, - - _setOption: function(key, value){ - if ( key === "disabled" ) { - this.options[ key ] = value; - - this.widget() - [ value ? "addClass" : "removeClass"]( "ui-sortable-disabled" ); - } else { - // Don't call widget base _setOption for disable as it adds ui-state-disabled class - $.Widget.prototype._setOption.apply(this, arguments); - } - }, - - _mouseCapture: function(event, overrideHandle) { - - if (this.reverting) { - return false; - } - - if(this.options.disabled || this.options.type == 'static') return false; - - //We have to refresh the items data once first - this._refreshItems(event); - - //Find out if the clicked node (or one of its parents) is a actual item in this.items - var currentItem = null, self = this, nodes = $(event.target).parents().each(function() { - if($.data(this, 'sortable-item') == self) { - currentItem = $(this); - return false; - } - }); - if($.data(event.target, 'sortable-item') == self) currentItem = $(event.target); - - if(!currentItem) return false; - if(this.options.handle && !overrideHandle) { - var validHandle = false; - - $(this.options.handle, currentItem).find("*").andSelf().each(function() { if(this == event.target) validHandle = true; }); - if(!validHandle) return false; - } - - this.currentItem = currentItem; - this._removeCurrentsFromItems(); - return true; - - }, - - _mouseStart: function(event, overrideHandle, noActivation) { - - var o = this.options, self = this; - this.currentContainer = this; - - //We only need to call refreshPositions, because the refreshItems call has been moved to mouseCapture - this.refreshPositions(); - - //Create and append the visible helper - this.helper = this._createHelper(event); - - //Cache the helper size - this._cacheHelperProportions(); - - /* - * - Position generation - - * This block generates everything position related - it's the core of draggables. - */ - - //Cache the margins of the original element - this._cacheMargins(); - - //Get the next scrolling parent - this.scrollParent = this.helper.scrollParent(); - - //The element's absolute position on the page minus margins - this.offset = this.currentItem.offset(); - this.offset = { - top: this.offset.top - this.margins.top, - left: this.offset.left - this.margins.left - }; - - // Only after we got the offset, we can change the helper's position to absolute - // TODO: Still need to figure out a way to make relative sorting possible - this.helper.css("position", "absolute"); - this.cssPosition = this.helper.css("position"); - - $.extend(this.offset, { - click: { //Where the click happened, relative to the element - left: event.pageX - this.offset.left, - top: event.pageY - this.offset.top - }, - parent: this._getParentOffset(), - relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper - }); - - //Generate the original position - this.originalPosition = this._generatePosition(event); - this.originalPageX = event.pageX; - this.originalPageY = event.pageY; - - //Adjust the mouse offset relative to the helper if 'cursorAt' is supplied - (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt)); - - //Cache the former DOM position - this.domPosition = { prev: this.currentItem.prev()[0], parent: this.currentItem.parent()[0] }; - - //If the helper is not the original, hide the original so it's not playing any role during the drag, won't cause anything bad this way - if(this.helper[0] != this.currentItem[0]) { - this.currentItem.hide(); - } - - //Create the placeholder - this._createPlaceholder(); - - //Set a containment if given in the options - if(o.containment) - this._setContainment(); - - if(o.cursor) { // cursor option - if ($('body').css("cursor")) this._storedCursor = $('body').css("cursor"); - $('body').css("cursor", o.cursor); - } - - if(o.opacity) { // opacity option - if (this.helper.css("opacity")) this._storedOpacity = this.helper.css("opacity"); - this.helper.css("opacity", o.opacity); - } - - if(o.zIndex) { // zIndex option - if (this.helper.css("zIndex")) this._storedZIndex = this.helper.css("zIndex"); - this.helper.css("zIndex", o.zIndex); - } - - //Prepare scrolling - if(this.scrollParent[0] != document && this.scrollParent[0].tagName != 'HTML') - this.overflowOffset = this.scrollParent.offset(); - - //Call callbacks - this._trigger("start", event, this._uiHash()); - - //Recache the helper size - if(!this._preserveHelperProportions) - this._cacheHelperProportions(); - - - //Post 'activate' events to possible containers - if(!noActivation) { - for (var i = this.containers.length - 1; i >= 0; i--) { this.containers[i]._trigger("activate", event, self._uiHash(this)); } - } - - //Prepare possible droppables - if($.ui.ddmanager) - $.ui.ddmanager.current = this; - - if ($.ui.ddmanager && !o.dropBehaviour) - $.ui.ddmanager.prepareOffsets(this, event); - - this.dragging = true; - - this.helper.addClass("ui-sortable-helper"); - this._mouseDrag(event); //Execute the drag once - this causes the helper not to be visible before getting its correct position - return true; - - }, - - _mouseDrag: function(event) { - - //Compute the helpers position - this.position = this._generatePosition(event); - this.positionAbs = this._convertPositionTo("absolute"); - - if (!this.lastPositionAbs) { - this.lastPositionAbs = this.positionAbs; - } - - //Do scrolling - if(this.options.scroll) { - var o = this.options, scrolled = false; - if(this.scrollParent[0] != document && this.scrollParent[0].tagName != 'HTML') { - - if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) - this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed; - else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity) - this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed; - - if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) - this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed; - else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity) - this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed; - - } else { - - if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) - scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed); - else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) - scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed); - - if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) - scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed); - else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) - scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed); - - } - - if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) - $.ui.ddmanager.prepareOffsets(this, event); - } - - //Regenerate the absolute position used for position checks - this.positionAbs = this._convertPositionTo("absolute"); - - //Set the helper position - if(!this.options.axis || this.options.axis != "y") this.helper[0].style.left = this.position.left+'px'; - if(!this.options.axis || this.options.axis != "x") this.helper[0].style.top = this.position.top+'px'; - - //Rearrange - for (var i = this.items.length - 1; i >= 0; i--) { - - //Cache variables and intersection, continue if no intersection - var item = this.items[i], itemElement = item.item[0], intersection = this._intersectsWithPointer(item); - if (!intersection) continue; - - if(itemElement != this.currentItem[0] //cannot intersect with itself - && this.placeholder[intersection == 1 ? "next" : "prev"]()[0] != itemElement //no useless actions that have been done before - && !$.ui.contains(this.placeholder[0], itemElement) //no action if the item moved is the parent of the item checked - && (this.options.type == 'semi-dynamic' ? !$.ui.contains(this.element[0], itemElement) : true) - //&& itemElement.parentNode == this.placeholder[0].parentNode // only rearrange items within the same container - ) { - - this.direction = intersection == 1 ? "down" : "up"; - - if (this.options.tolerance == "pointer" || this._intersectsWithSides(item)) { - this._rearrange(event, item); - } else { - break; - } - - this._trigger("change", event, this._uiHash()); - break; - } - } - - //Post events to containers - this._contactContainers(event); - - //Interconnect with droppables - if($.ui.ddmanager) $.ui.ddmanager.drag(this, event); - - //Call callbacks - this._trigger('sort', event, this._uiHash()); - - this.lastPositionAbs = this.positionAbs; - return false; - - }, - - _mouseStop: function(event, noPropagation) { - - if(!event) return; - - //If we are using droppables, inform the manager about the drop - if ($.ui.ddmanager && !this.options.dropBehaviour) - $.ui.ddmanager.drop(this, event); - - if(this.options.revert) { - var self = this; - var cur = self.placeholder.offset(); - - self.reverting = true; - - $(this.helper).animate({ - left: cur.left - this.offset.parent.left - self.margins.left + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollLeft), - top: cur.top - this.offset.parent.top - self.margins.top + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollTop) - }, parseInt(this.options.revert, 10) || 500, function() { - self._clear(event); - }); - } else { - this._clear(event, noPropagation); - } - - return false; - - }, - - cancel: function() { - - var self = this; - - if(this.dragging) { - - this._mouseUp(); - - if(this.options.helper == "original") - this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"); - else - this.currentItem.show(); - - //Post deactivating events to containers - for (var i = this.containers.length - 1; i >= 0; i--){ - this.containers[i]._trigger("deactivate", null, self._uiHash(this)); - if(this.containers[i].containerCache.over) { - this.containers[i]._trigger("out", null, self._uiHash(this)); - this.containers[i].containerCache.over = 0; - } - } - - } - - //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node! - if(this.placeholder[0].parentNode) this.placeholder[0].parentNode.removeChild(this.placeholder[0]); - if(this.options.helper != "original" && this.helper && this.helper[0].parentNode) this.helper.remove(); - - $.extend(this, { - helper: null, - dragging: false, - reverting: false, - _noFinalSort: null - }); - - if(this.domPosition.prev) { - $(this.domPosition.prev).after(this.currentItem); - } else { - $(this.domPosition.parent).prepend(this.currentItem); - } - - return this; - - }, - - serialize: function(o) { - - var items = this._getItemsAsjQuery(o && o.connected); - var str = []; o = o || {}; - - $(items).each(function() { - var res = ($(o.item || this).attr(o.attribute || 'id') || '').match(o.expression || (/(.+)[-=_](.+)/)); - if(res) str.push((o.key || res[1]+'[]')+'='+(o.key && o.expression ? res[1] : res[2])); - }); - - return str.join('&'); - - }, - - toArray: function(o) { - - var items = this._getItemsAsjQuery(o && o.connected); - var ret = []; o = o || {}; - - items.each(function() { ret.push($(o.item || this).attr(o.attribute || 'id') || ''); }); - return ret; - - }, - - /* Be careful with the following core functions */ - _intersectsWith: function(item) { - - var x1 = this.positionAbs.left, - x2 = x1 + this.helperProportions.width, - y1 = this.positionAbs.top, - y2 = y1 + this.helperProportions.height; - - var l = item.left, - r = l + item.width, - t = item.top, - b = t + item.height; - - var dyClick = this.offset.click.top, - dxClick = this.offset.click.left; - - var isOverElement = (y1 + dyClick) > t && (y1 + dyClick) < b && (x1 + dxClick) > l && (x1 + dxClick) < r; - - if( this.options.tolerance == "pointer" - || this.options.forcePointerForContainers - || (this.options.tolerance != "pointer" && this.helperProportions[this.floating ? 'width' : 'height'] > item[this.floating ? 'width' : 'height']) - ) { - return isOverElement; - } else { - - return (l < x1 + (this.helperProportions.width / 2) // Right Half - && x2 - (this.helperProportions.width / 2) < r // Left Half - && t < y1 + (this.helperProportions.height / 2) // Bottom Half - && y2 - (this.helperProportions.height / 2) < b ); // Top Half - - } - }, - - _intersectsWithPointer: function(item) { - - var isOverElementHeight = $.ui.isOverAxis(this.positionAbs.top + this.offset.click.top, item.top, item.height), - isOverElementWidth = $.ui.isOverAxis(this.positionAbs.left + this.offset.click.left, item.left, item.width), - isOverElement = isOverElementHeight && isOverElementWidth, - verticalDirection = this._getDragVerticalDirection(), - horizontalDirection = this._getDragHorizontalDirection(); - - if (!isOverElement) - return false; - - return this.floating ? - ( ((horizontalDirection && horizontalDirection == "right") || verticalDirection == "down") ? 2 : 1 ) - : ( verticalDirection && (verticalDirection == "down" ? 2 : 1) ); - - }, - - _intersectsWithSides: function(item) { - - var isOverBottomHalf = $.ui.isOverAxis(this.positionAbs.top + this.offset.click.top, item.top + (item.height/2), item.height), - isOverRightHalf = $.ui.isOverAxis(this.positionAbs.left + this.offset.click.left, item.left + (item.width/2), item.width), - verticalDirection = this._getDragVerticalDirection(), - horizontalDirection = this._getDragHorizontalDirection(); - - if (this.floating && horizontalDirection) { - return ((horizontalDirection == "right" && isOverRightHalf) || (horizontalDirection == "left" && !isOverRightHalf)); - } else { - return verticalDirection && ((verticalDirection == "down" && isOverBottomHalf) || (verticalDirection == "up" && !isOverBottomHalf)); - } - - }, - - _getDragVerticalDirection: function() { - var delta = this.positionAbs.top - this.lastPositionAbs.top; - return delta != 0 && (delta > 0 ? "down" : "up"); - }, - - _getDragHorizontalDirection: function() { - var delta = this.positionAbs.left - this.lastPositionAbs.left; - return delta != 0 && (delta > 0 ? "right" : "left"); - }, - - refresh: function(event) { - this._refreshItems(event); - this.refreshPositions(); - return this; - }, - - _connectWith: function() { - var options = this.options; - return options.connectWith.constructor == String - ? [options.connectWith] - : options.connectWith; - }, - - _getItemsAsjQuery: function(connected) { - - var self = this; - var items = []; - var queries = []; - var connectWith = this._connectWith(); - - if(connectWith && connected) { - for (var i = connectWith.length - 1; i >= 0; i--){ - var cur = $(connectWith[i]); - for (var j = cur.length - 1; j >= 0; j--){ - var inst = $.data(cur[j], 'sortable'); - if(inst && inst != this && !inst.options.disabled) { - queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element) : $(inst.options.items, inst.element).not(".ui-sortable-helper").not('.ui-sortable-placeholder'), inst]); - } - }; - }; - } - - queries.push([$.isFunction(this.options.items) ? this.options.items.call(this.element, null, { options: this.options, item: this.currentItem }) : $(this.options.items, this.element).not(".ui-sortable-helper").not('.ui-sortable-placeholder'), this]); - - for (var i = queries.length - 1; i >= 0; i--){ - queries[i][0].each(function() { - items.push(this); - }); - }; - - return $(items); - - }, - - _removeCurrentsFromItems: function() { - - var list = this.currentItem.find(":data(sortable-item)"); - - for (var i=0; i < this.items.length; i++) { - - for (var j=0; j < list.length; j++) { - if(list[j] == this.items[i].item[0]) - this.items.splice(i,1); - }; - - }; - - }, - - _refreshItems: function(event) { - - this.items = []; - this.containers = [this]; - var items = this.items; - var self = this; - var queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]]; - var connectWith = this._connectWith(); - - if(connectWith) { - for (var i = connectWith.length - 1; i >= 0; i--){ - var cur = $(connectWith[i]); - for (var j = cur.length - 1; j >= 0; j--){ - var inst = $.data(cur[j], 'sortable'); - if(inst && inst != this && !inst.options.disabled) { - queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element[0], event, { item: this.currentItem }) : $(inst.options.items, inst.element), inst]); - this.containers.push(inst); - } - }; - }; - } - - for (var i = queries.length - 1; i >= 0; i--) { - var targetData = queries[i][1]; - var _queries = queries[i][0]; - - for (var j=0, queriesLength = _queries.length; j < queriesLength; j++) { - var item = $(_queries[j]); - - item.data('sortable-item', targetData); // Data for target checking (mouse manager) - - items.push({ - item: item, - instance: targetData, - width: 0, height: 0, - left: 0, top: 0 - }); - }; - }; - - }, - - refreshPositions: function(fast) { - - //This has to be redone because due to the item being moved out/into the offsetParent, the offsetParent's position will change - if(this.offsetParent && this.helper) { - this.offset.parent = this._getParentOffset(); - } - - for (var i = this.items.length - 1; i >= 0; i--){ - var item = this.items[i]; - - var t = this.options.toleranceElement ? $(this.options.toleranceElement, item.item) : item.item; - - if (!fast) { - item.width = t.outerWidth(); - item.height = t.outerHeight(); - } - - var p = t.offset(); - item.left = p.left; - item.top = p.top; - }; - - if(this.options.custom && this.options.custom.refreshContainers) { - this.options.custom.refreshContainers.call(this); - } else { - for (var i = this.containers.length - 1; i >= 0; i--){ - var p = this.containers[i].element.offset(); - this.containers[i].containerCache.left = p.left; - this.containers[i].containerCache.top = p.top; - this.containers[i].containerCache.width = this.containers[i].element.outerWidth(); - this.containers[i].containerCache.height = this.containers[i].element.outerHeight(); - }; - } - - return this; - }, - - _createPlaceholder: function(that) { - - var self = that || this, o = self.options; - - if(!o.placeholder || o.placeholder.constructor == String) { - var className = o.placeholder; - o.placeholder = { - element: function() { - - var el = $(document.createElement(self.currentItem[0].nodeName)) - .addClass(className || self.currentItem[0].className+" ui-sortable-placeholder") - .removeClass("ui-sortable-helper")[0]; - - if(!className) - el.style.visibility = "hidden"; - - return el; - }, - update: function(container, p) { - - // 1. If a className is set as 'placeholder option, we don't force sizes - the class is responsible for that - // 2. The option 'forcePlaceholderSize can be enabled to force it even if a class name is specified - if(className && !o.forcePlaceholderSize) return; - - //If the element doesn't have a actual height by itself (without styles coming from a stylesheet), it receives the inline height from the dragged item - if(!p.height()) { p.height(self.currentItem.innerHeight() - parseInt(self.currentItem.css('paddingTop')||0, 10) - parseInt(self.currentItem.css('paddingBottom')||0, 10)); }; - if(!p.width()) { p.width(self.currentItem.innerWidth() - parseInt(self.currentItem.css('paddingLeft')||0, 10) - parseInt(self.currentItem.css('paddingRight')||0, 10)); }; - } - }; - } - - //Create the placeholder - self.placeholder = $(o.placeholder.element.call(self.element, self.currentItem)); - - //Append it after the actual current item - self.currentItem.after(self.placeholder); - - //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317) - o.placeholder.update(self, self.placeholder); - - }, - - _contactContainers: function(event) { - - // get innermost container that intersects with item - var innermostContainer = null, innermostIndex = null; - - - for (var i = this.containers.length - 1; i >= 0; i--){ - - // never consider a container that's located within the item itself - if($.ui.contains(this.currentItem[0], this.containers[i].element[0])) - continue; - - if(this._intersectsWith(this.containers[i].containerCache)) { - - // if we've already found a container and it's more "inner" than this, then continue - if(innermostContainer && $.ui.contains(this.containers[i].element[0], innermostContainer.element[0])) - continue; - - innermostContainer = this.containers[i]; - innermostIndex = i; - - } else { - // container doesn't intersect. trigger "out" event if necessary - if(this.containers[i].containerCache.over) { - this.containers[i]._trigger("out", event, this._uiHash(this)); - this.containers[i].containerCache.over = 0; - } - } - - } - - // if no intersecting containers found, return - if(!innermostContainer) return; - - // move the item into the container if it's not there already - if(this.containers.length === 1) { - this.containers[innermostIndex]._trigger("over", event, this._uiHash(this)); - this.containers[innermostIndex].containerCache.over = 1; - } else if(this.currentContainer != this.containers[innermostIndex]) { - - //When entering a new container, we will find the item with the least distance and append our item near it - var dist = 10000; var itemWithLeastDistance = null; var base = this.positionAbs[this.containers[innermostIndex].floating ? 'left' : 'top']; - for (var j = this.items.length - 1; j >= 0; j--) { - if(!$.ui.contains(this.containers[innermostIndex].element[0], this.items[j].item[0])) continue; - var cur = this.items[j][this.containers[innermostIndex].floating ? 'left' : 'top']; - if(Math.abs(cur - base) < dist) { - dist = Math.abs(cur - base); itemWithLeastDistance = this.items[j]; - } - } - - if(!itemWithLeastDistance && !this.options.dropOnEmpty) //Check if dropOnEmpty is enabled - return; - - this.currentContainer = this.containers[innermostIndex]; - itemWithLeastDistance ? this._rearrange(event, itemWithLeastDistance, null, true) : this._rearrange(event, null, this.containers[innermostIndex].element, true); - this._trigger("change", event, this._uiHash()); - this.containers[innermostIndex]._trigger("change", event, this._uiHash(this)); - - //Update the placeholder - this.options.placeholder.update(this.currentContainer, this.placeholder); - - this.containers[innermostIndex]._trigger("over", event, this._uiHash(this)); - this.containers[innermostIndex].containerCache.over = 1; - } - - - }, - - _createHelper: function(event) { - - var o = this.options; - var helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event, this.currentItem])) : (o.helper == 'clone' ? this.currentItem.clone() : this.currentItem); - - if(!helper.parents('body').length) //Add the helper to the DOM if that didn't happen already - $(o.appendTo != 'parent' ? o.appendTo : this.currentItem[0].parentNode)[0].appendChild(helper[0]); - - if(helper[0] == this.currentItem[0]) - this._storedCSS = { width: this.currentItem[0].style.width, height: this.currentItem[0].style.height, position: this.currentItem.css("position"), top: this.currentItem.css("top"), left: this.currentItem.css("left") }; - - if(helper[0].style.width == '' || o.forceHelperSize) helper.width(this.currentItem.width()); - if(helper[0].style.height == '' || o.forceHelperSize) helper.height(this.currentItem.height()); - - return helper; - - }, - - _adjustOffsetFromHelper: function(obj) { - if (typeof obj == 'string') { - obj = obj.split(' '); - } - if ($.isArray(obj)) { - obj = {left: +obj[0], top: +obj[1] || 0}; - } - if ('left' in obj) { - this.offset.click.left = obj.left + this.margins.left; - } - if ('right' in obj) { - this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left; - } - if ('top' in obj) { - this.offset.click.top = obj.top + this.margins.top; - } - if ('bottom' in obj) { - this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top; - } - }, - - _getParentOffset: function() { - - - //Get the offsetParent and cache its position - this.offsetParent = this.helper.offsetParent(); - var po = this.offsetParent.offset(); - - // This is a special case where we need to modify a offset calculated on start, since the following happened: - // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent - // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that - // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag - if(this.cssPosition == 'absolute' && this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) { - po.left += this.scrollParent.scrollLeft(); - po.top += this.scrollParent.scrollTop(); - } - - if((this.offsetParent[0] == document.body) //This needs to be actually done for all browsers, since pageX/pageY includes this information - || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() == 'html' && $.browser.msie)) //Ugly IE fix - po = { top: 0, left: 0 }; - - return { - top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0), - left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0) - }; - - }, - - _getRelativeOffset: function() { - - if(this.cssPosition == "relative") { - var p = this.currentItem.position(); - return { - top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(), - left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft() - }; - } else { - return { top: 0, left: 0 }; - } - - }, - - _cacheMargins: function() { - this.margins = { - left: (parseInt(this.currentItem.css("marginLeft"),10) || 0), - top: (parseInt(this.currentItem.css("marginTop"),10) || 0) - }; - }, - - _cacheHelperProportions: function() { - this.helperProportions = { - width: this.helper.outerWidth(), - height: this.helper.outerHeight() - }; - }, - - _setContainment: function() { - - var o = this.options; - if(o.containment == 'parent') o.containment = this.helper[0].parentNode; - if(o.containment == 'document' || o.containment == 'window') this.containment = [ - 0 - this.offset.relative.left - this.offset.parent.left, - 0 - this.offset.relative.top - this.offset.parent.top, - $(o.containment == 'document' ? document : window).width() - this.helperProportions.width - this.margins.left, - ($(o.containment == 'document' ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top - ]; - - if(!(/^(document|window|parent)$/).test(o.containment)) { - var ce = $(o.containment)[0]; - var co = $(o.containment).offset(); - var over = ($(ce).css("overflow") != 'hidden'); - - this.containment = [ - co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0) - this.margins.left, - co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0) - this.margins.top, - co.left+(over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css("borderLeftWidth"),10) || 0) - (parseInt($(ce).css("paddingRight"),10) || 0) - this.helperProportions.width - this.margins.left, - co.top+(over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css("borderTopWidth"),10) || 0) - (parseInt($(ce).css("paddingBottom"),10) || 0) - this.helperProportions.height - this.margins.top - ]; - } - - }, - - _convertPositionTo: function(d, pos) { - - if(!pos) pos = this.position; - var mod = d == "absolute" ? 1 : -1; - var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); - - return { - top: ( - pos.top // The absolute mouse position - + this.offset.relative.top * mod // Only for relative positioned nodes: Relative offset from element to offset parent - + this.offset.parent.top * mod // The offsetParent's offset without borders (offset + border) - - ($.browser.safari && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod) - ), - left: ( - pos.left // The absolute mouse position - + this.offset.relative.left * mod // Only for relative positioned nodes: Relative offset from element to offset parent - + this.offset.parent.left * mod // The offsetParent's offset without borders (offset + border) - - ($.browser.safari && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod) - ) - }; - - }, - - _generatePosition: function(event) { - - var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); - - // This is another very weird special case that only happens for relative elements: - // 1. If the css position is relative - // 2. and the scroll parent is the document or similar to the offset parent - // we have to refresh the relative offset during the scroll so there are no jumps - if(this.cssPosition == 'relative' && !(this.scrollParent[0] != document && this.scrollParent[0] != this.offsetParent[0])) { - this.offset.relative = this._getRelativeOffset(); - } - - var pageX = event.pageX; - var pageY = event.pageY; - - /* - * - Position constraining - - * Constrain the position to a mix of grid, containment. - */ - - if(this.originalPosition) { //If we are not dragging yet, we won't check for options - - if(this.containment) { - if(event.pageX - this.offset.click.left < this.containment[0]) pageX = this.containment[0] + this.offset.click.left; - if(event.pageY - this.offset.click.top < this.containment[1]) pageY = this.containment[1] + this.offset.click.top; - if(event.pageX - this.offset.click.left > this.containment[2]) pageX = this.containment[2] + this.offset.click.left; - if(event.pageY - this.offset.click.top > this.containment[3]) pageY = this.containment[3] + this.offset.click.top; - } - - if(o.grid) { - var top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1]; - pageY = this.containment ? (!(top - this.offset.click.top < this.containment[1] || top - this.offset.click.top > this.containment[3]) ? top : (!(top - this.offset.click.top < this.containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top; - - var left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0]; - pageX = this.containment ? (!(left - this.offset.click.left < this.containment[0] || left - this.offset.click.left > this.containment[2]) ? left : (!(left - this.offset.click.left < this.containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left; - } - - } - - return { - top: ( - pageY // The absolute mouse position - - this.offset.click.top // Click offset (relative to the element) - - this.offset.relative.top // Only for relative positioned nodes: Relative offset from element to offset parent - - this.offset.parent.top // The offsetParent's offset without borders (offset + border) - + ($.browser.safari && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) )) - ), - left: ( - pageX // The absolute mouse position - - this.offset.click.left // Click offset (relative to the element) - - this.offset.relative.left // Only for relative positioned nodes: Relative offset from element to offset parent - - this.offset.parent.left // The offsetParent's offset without borders (offset + border) - + ($.browser.safari && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() )) - ) - }; - - }, - - _rearrange: function(event, i, a, hardRefresh) { - - a ? a[0].appendChild(this.placeholder[0]) : i.item[0].parentNode.insertBefore(this.placeholder[0], (this.direction == 'down' ? i.item[0] : i.item[0].nextSibling)); - - //Various things done here to improve the performance: - // 1. we create a setTimeout, that calls refreshPositions - // 2. on the instance, we have a counter variable, that get's higher after every append - // 3. on the local scope, we copy the counter variable, and check in the timeout, if it's still the same - // 4. this lets only the last addition to the timeout stack through - this.counter = this.counter ? ++this.counter : 1; - var self = this, counter = this.counter; - - window.setTimeout(function() { - if(counter == self.counter) self.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove - },0); - - }, - - _clear: function(event, noPropagation) { - - this.reverting = false; - // We delay all events that have to be triggered to after the point where the placeholder has been removed and - // everything else normalized again - var delayedTriggers = [], self = this; - - // We first have to update the dom position of the actual currentItem - // Note: don't do it if the current item is already removed (by a user), or it gets reappended (see #4088) - if(!this._noFinalSort && this.currentItem[0].parentNode) this.placeholder.before(this.currentItem); - this._noFinalSort = null; - - if(this.helper[0] == this.currentItem[0]) { - for(var i in this._storedCSS) { - if(this._storedCSS[i] == 'auto' || this._storedCSS[i] == 'static') this._storedCSS[i] = ''; - } - this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"); - } else { - this.currentItem.show(); - } - - if(this.fromOutside && !noPropagation) delayedTriggers.push(function(event) { this._trigger("receive", event, this._uiHash(this.fromOutside)); }); - if((this.fromOutside || this.domPosition.prev != this.currentItem.prev().not(".ui-sortable-helper")[0] || this.domPosition.parent != this.currentItem.parent()[0]) && !noPropagation) delayedTriggers.push(function(event) { this._trigger("update", event, this._uiHash()); }); //Trigger update callback if the DOM position has changed - if(!$.ui.contains(this.element[0], this.currentItem[0])) { //Node was moved out of the current element - if(!noPropagation) delayedTriggers.push(function(event) { this._trigger("remove", event, this._uiHash()); }); - for (var i = this.containers.length - 1; i >= 0; i--){ - if($.ui.contains(this.containers[i].element[0], this.currentItem[0]) && !noPropagation) { - delayedTriggers.push((function(c) { return function(event) { c._trigger("receive", event, this._uiHash(this)); }; }).call(this, this.containers[i])); - delayedTriggers.push((function(c) { return function(event) { c._trigger("update", event, this._uiHash(this)); }; }).call(this, this.containers[i])); - } - }; - }; - - //Post events to containers - for (var i = this.containers.length - 1; i >= 0; i--){ - if(!noPropagation) delayedTriggers.push((function(c) { return function(event) { c._trigger("deactivate", event, this._uiHash(this)); }; }).call(this, this.containers[i])); - if(this.containers[i].containerCache.over) { - delayedTriggers.push((function(c) { return function(event) { c._trigger("out", event, this._uiHash(this)); }; }).call(this, this.containers[i])); - this.containers[i].containerCache.over = 0; - } - } - - //Do what was originally in plugins - if(this._storedCursor) $('body').css("cursor", this._storedCursor); //Reset cursor - if(this._storedOpacity) this.helper.css("opacity", this._storedOpacity); //Reset opacity - if(this._storedZIndex) this.helper.css("zIndex", this._storedZIndex == 'auto' ? '' : this._storedZIndex); //Reset z-index - - this.dragging = false; - if(this.cancelHelperRemoval) { - if(!noPropagation) { - this._trigger("beforeStop", event, this._uiHash()); - for (var i=0; i < delayedTriggers.length; i++) { delayedTriggers[i].call(this, event); }; //Trigger all delayed events - this._trigger("stop", event, this._uiHash()); - } - return false; - } - - if(!noPropagation) this._trigger("beforeStop", event, this._uiHash()); - - //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node! - this.placeholder[0].parentNode.removeChild(this.placeholder[0]); - - if(this.helper[0] != this.currentItem[0]) this.helper.remove(); this.helper = null; - - if(!noPropagation) { - for (var i=0; i < delayedTriggers.length; i++) { delayedTriggers[i].call(this, event); }; //Trigger all delayed events - this._trigger("stop", event, this._uiHash()); - } - - this.fromOutside = false; - return true; - - }, - - _trigger: function() { - if ($.Widget.prototype._trigger.apply(this, arguments) === false) { - this.cancel(); - } - }, - - _uiHash: function(inst) { - var self = inst || this; - return { - helper: self.helper, - placeholder: self.placeholder || $([]), - position: self.position, - originalPosition: self.originalPosition, - offset: self.positionAbs, - item: self.currentItem, - sender: inst ? inst.element : null - }; - } - -}); - -$.extend($.ui.sortable, { - version: "@VERSION" -}); - -})(jQuery); diff --git a/ui/jquery.ui.tabs.js b/ui/jquery.ui.tabs.js deleted file mode 100644 index a934c0f218d..00000000000 --- a/ui/jquery.ui.tabs.js +++ /dev/null @@ -1,729 +0,0 @@ -/* - * jQuery UI Tabs @VERSION - * - * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT (MIT-LICENSE.txt) - * and GPL (GPL-LICENSE.txt) licenses. - * - * http://docs.jquery.com/UI/Tabs - * - * Depends: - * jquery.ui.core.js - * jquery.ui.widget.js - */ -(function($) { - -var tabId = 0, - listId = 0; - -function getNextTabId() { - return ++tabId; -} - -function getNextListId() { - return ++listId; -} - -$.widget("ui.tabs", { - options: { - add: null, - ajaxOptions: null, - cache: false, - cookie: null, // e.g. { expires: 7, path: '/', domain: 'jquery.com', secure: true } - collapsible: false, - disable: null, - disabled: [], - enable: null, - event: 'click', - fx: null, // e.g. { height: 'toggle', opacity: 'toggle', duration: 200 } - idPrefix: 'ui-tabs-', - load: null, - panelTemplate: '
        ', - remove: null, - select: null, - show: null, - spinner: 'Loading…', - tabTemplate: '
      • #{label}
      • ' - }, - _create: function() { - this._tabify(true); - }, - - _setOption: function(key, value) { - if (key == 'selected') { - if (this.options.collapsible && value == this.options.selected) { - return; - } - this.select(value); - } - else { - this.options[key] = value; - this._tabify(); - } - }, - - _tabId: function(a) { - return a.title && a.title.replace(/\s/g, '_').replace(/[^A-Za-z0-9\-_:\.]/g, '') || - this.options.idPrefix + getNextTabId(); - }, - - _sanitizeSelector: function(hash) { - return hash.replace(/:/g, '\\:'); // we need this because an id may contain a ":" - }, - - _cookie: function() { - var cookie = this.cookie || (this.cookie = this.options.cookie.name || 'ui-tabs-' + getNextListId()); - return $.cookie.apply(null, [cookie].concat($.makeArray(arguments))); - }, - - _ui: function(tab, panel) { - return { - tab: tab, - panel: panel, - index: this.anchors.index(tab) - }; - }, - - _cleanup: function() { - // restore all former loading tabs labels - this.lis.filter('.ui-state-processing').removeClass('ui-state-processing') - .find('span:data(label.tabs)') - .each(function() { - var el = $(this); - el.html(el.data('label.tabs')).removeData('label.tabs'); - }); - }, - - _tabify: function(init) { - - this.list = this.element.find('ol,ul').eq(0); - this.lis = $('li:has(a[href])', this.list); - this.anchors = this.lis.map(function() { return $('a', this)[0]; }); - this.panels = $([]); - - var self = this, o = this.options; - - var fragmentId = /^#.+/; // Safari 2 reports '#' for an empty hash - this.anchors.each(function(i, a) { - var href = $(a).attr('href'); - - // For dynamically created HTML that contains a hash as href IE < 8 expands - // such href to the full page url with hash and then misinterprets tab as ajax. - // Same consideration applies for an added tab with a fragment identifier - // since a[href=#fragment-identifier] does unexpectedly not match. - // Thus normalize href attribute... - var hrefBase = href.split('#')[0], baseEl; - if (hrefBase && (hrefBase === location.toString().split('#')[0] || - (baseEl = $('base')[0]) && hrefBase === baseEl.href)) { - href = a.hash; - a.href = href; - } - - // inline tab - if (fragmentId.test(href)) { - self.panels = self.panels.add(self._sanitizeSelector(href)); - } - - // remote tab - else if (href != '#') { // prevent loading the page itself if href is just "#" - $.data(a, 'href.tabs', href); // required for restore on destroy - - // TODO until #3808 is fixed strip fragment identifier from url - // (IE fails to load from such url) - $.data(a, 'load.tabs', href.replace(/#.*$/, '')); // mutable data - - var id = self._tabId(a); - a.href = '#' + id; - var $panel = $('#' + id); - if (!$panel.length) { - $panel = $(o.panelTemplate).attr('id', id).addClass('ui-tabs-panel ui-widget-content ui-corner-bottom') - .insertAfter(self.panels[i - 1] || self.list); - $panel.data('destroy.tabs', true); - } - self.panels = self.panels.add($panel); - } - - // invalid tab href - else { - o.disabled.push(i); - } - }); - - // initialization from scratch - if (init) { - - // attach necessary classes for styling - this.element.addClass('ui-tabs ui-widget ui-widget-content ui-corner-all'); - this.list.addClass('ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all'); - this.lis.addClass('ui-state-default ui-corner-top'); - this.panels.addClass('ui-tabs-panel ui-widget-content ui-corner-bottom'); - - // Selected tab - // use "selected" option or try to retrieve: - // 1. from fragment identifier in url - // 2. from cookie - // 3. from selected class attribute on
      • - if (o.selected === undefined) { - if (location.hash) { - this.anchors.each(function(i, a) { - if (a.hash == location.hash) { - o.selected = i; - return false; // break - } - }); - } - if (typeof o.selected != 'number' && o.cookie) { - o.selected = parseInt(self._cookie(), 10); - } - if (typeof o.selected != 'number' && this.lis.filter('.ui-tabs-selected').length) { - o.selected = this.lis.index(this.lis.filter('.ui-tabs-selected')); - } - o.selected = o.selected || (this.lis.length ? 0 : -1); - } - else if (o.selected === null) { // usage of null is deprecated, TODO remove in next release - o.selected = -1; - } - - // sanity check - default to first tab... - o.selected = ((o.selected >= 0 && this.anchors[o.selected]) || o.selected < 0) ? o.selected : 0; - - // Take disabling tabs via class attribute from HTML - // into account and update option properly. - // A selected tab cannot become disabled. - o.disabled = $.unique(o.disabled.concat( - $.map(this.lis.filter('.ui-state-disabled'), - function(n, i) { return self.lis.index(n); } ) - )).sort(); - - if ($.inArray(o.selected, o.disabled) != -1) { - o.disabled.splice($.inArray(o.selected, o.disabled), 1); - } - - // highlight selected tab - this.panels.addClass('ui-tabs-hide'); - this.lis.removeClass('ui-tabs-selected ui-state-active'); - if (o.selected >= 0 && this.anchors.length) { // check for length avoids error when initializing empty list - this.panels.eq(o.selected).removeClass('ui-tabs-hide'); - this.lis.eq(o.selected).addClass('ui-tabs-selected ui-state-active'); - - // seems to be expected behavior that the show callback is fired - self.element.queue("tabs", function() { - self._trigger('show', null, self._ui(self.anchors[o.selected], self.panels[o.selected])); - }); - - this.load(o.selected); - } - - // clean up to avoid memory leaks in certain versions of IE 6 - $(window).bind('unload', function() { - self.lis.add(self.anchors).unbind('.tabs'); - self.lis = self.anchors = self.panels = null; - }); - - } - // update selected after add/remove - else { - o.selected = this.lis.index(this.lis.filter('.ui-tabs-selected')); - } - - // update collapsible - this.element[o.collapsible ? 'addClass' : 'removeClass']('ui-tabs-collapsible'); - - // set or update cookie after init and add/remove respectively - if (o.cookie) { - this._cookie(o.selected, o.cookie); - } - - // disable tabs - for (var i = 0, li; (li = this.lis[i]); i++) { - $(li)[$.inArray(i, o.disabled) != -1 && - !$(li).hasClass('ui-tabs-selected') ? 'addClass' : 'removeClass']('ui-state-disabled'); - } - - // reset cache if switching from cached to not cached - if (o.cache === false) { - this.anchors.removeData('cache.tabs'); - } - - // remove all handlers before, tabify may run on existing tabs after add or option change - this.lis.add(this.anchors).unbind('.tabs'); - - if (o.event != 'mouseover') { - var addState = function(state, el) { - if (el.is(':not(.ui-state-disabled)')) { - el.addClass('ui-state-' + state); - } - }; - var removeState = function(state, el) { - el.removeClass('ui-state-' + state); - }; - this.lis.bind('mouseover.tabs', function() { - addState('hover', $(this)); - }); - this.lis.bind('mouseout.tabs', function() { - removeState('hover', $(this)); - }); - this.anchors.bind('focus.tabs', function() { - addState('focus', $(this).closest('li')); - }); - this.anchors.bind('blur.tabs', function() { - removeState('focus', $(this).closest('li')); - }); - } - - // set up animations - var hideFx, showFx; - if (o.fx) { - if ($.isArray(o.fx)) { - hideFx = o.fx[0]; - showFx = o.fx[1]; - } - else { - hideFx = showFx = o.fx; - } - } - - // Reset certain styles left over from animation - // and prevent IE's ClearType bug... - function resetStyle($el, fx) { - $el.css({ display: '' }); - if (!$.support.opacity && fx.opacity) { - $el[0].style.removeAttribute('filter'); - } - } - - // Show a tab... - var showTab = showFx ? - function(clicked, $show) { - $(clicked).closest('li').addClass('ui-tabs-selected ui-state-active'); - $show.hide().removeClass('ui-tabs-hide') // avoid flicker that way - .animate(showFx, showFx.duration || 'normal', function() { - resetStyle($show, showFx); - self._trigger('show', null, self._ui(clicked, $show[0])); - }); - } : - function(clicked, $show) { - $(clicked).closest('li').addClass('ui-tabs-selected ui-state-active'); - $show.removeClass('ui-tabs-hide'); - self._trigger('show', null, self._ui(clicked, $show[0])); - }; - - // Hide a tab, $show is optional... - var hideTab = hideFx ? - function(clicked, $hide) { - $hide.animate(hideFx, hideFx.duration || 'normal', function() { - self.lis.removeClass('ui-tabs-selected ui-state-active'); - $hide.addClass('ui-tabs-hide'); - resetStyle($hide, hideFx); - self.element.dequeue("tabs"); - }); - } : - function(clicked, $hide, $show) { - self.lis.removeClass('ui-tabs-selected ui-state-active'); - $hide.addClass('ui-tabs-hide'); - self.element.dequeue("tabs"); - }; - - // attach tab event handler, unbind to avoid duplicates from former tabifying... - this.anchors.bind(o.event + '.tabs', function() { - var el = this, $li = $(this).closest('li'), $hide = self.panels.filter(':not(.ui-tabs-hide)'), - $show = $(self._sanitizeSelector(this.hash)); - - // If tab is already selected and not collapsible or tab disabled or - // or is already loading or click callback returns false stop here. - // Check if click handler returns false last so that it is not executed - // for a disabled or loading tab! - if (($li.hasClass('ui-tabs-selected') && !o.collapsible) || - $li.hasClass('ui-state-disabled') || - $li.hasClass('ui-state-processing') || - self._trigger('select', null, self._ui(this, $show[0])) === false) { - this.blur(); - return false; - } - - o.selected = self.anchors.index(this); - - self.abort(); - - // if tab may be closed - if (o.collapsible) { - if ($li.hasClass('ui-tabs-selected')) { - o.selected = -1; - - if (o.cookie) { - self._cookie(o.selected, o.cookie); - } - - self.element.queue("tabs", function() { - hideTab(el, $hide); - }).dequeue("tabs"); - - this.blur(); - return false; - } - else if (!$hide.length) { - if (o.cookie) { - self._cookie(o.selected, o.cookie); - } - - self.element.queue("tabs", function() { - showTab(el, $show); - }); - - self.load(self.anchors.index(this)); // TODO make passing in node possible, see also http://dev.jqueryui.com/ticket/3171 - - this.blur(); - return false; - } - } - - if (o.cookie) { - self._cookie(o.selected, o.cookie); - } - - // show new tab - if ($show.length) { - if ($hide.length) { - self.element.queue("tabs", function() { - hideTab(el, $hide); - }); - } - self.element.queue("tabs", function() { - showTab(el, $show); - }); - - self.load(self.anchors.index(this)); - } - else { - throw 'jQuery UI Tabs: Mismatching fragment identifier.'; - } - - // Prevent IE from keeping other link focussed when using the back button - // and remove dotted border from clicked link. This is controlled via CSS - // in modern browsers; blur() removes focus from address bar in Firefox - // which can become a usability and annoying problem with tabs('rotate'). - if ($.browser.msie) { - this.blur(); - } - - }); - - // disable click in any case - this.anchors.bind('click.tabs', function(){return false;}); - - }, - - destroy: function() { - var o = this.options; - - this.abort(); - - this.element.unbind('.tabs') - .removeClass('ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible') - .removeData('tabs'); - - this.list.removeClass('ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all'); - - this.anchors.each(function() { - var href = $.data(this, 'href.tabs'); - if (href) { - this.href = href; - } - var $this = $(this).unbind('.tabs'); - $.each(['href', 'load', 'cache'], function(i, prefix) { - $this.removeData(prefix + '.tabs'); - }); - }); - - this.lis.unbind('.tabs').add(this.panels).each(function() { - if ($.data(this, 'destroy.tabs')) { - $(this).remove(); - } - else { - $(this).removeClass([ - 'ui-state-default', - 'ui-corner-top', - 'ui-tabs-selected', - 'ui-state-active', - 'ui-state-hover', - 'ui-state-focus', - 'ui-state-disabled', - 'ui-tabs-panel', - 'ui-widget-content', - 'ui-corner-bottom', - 'ui-tabs-hide' - ].join(' ')); - } - }); - - if (o.cookie) { - this._cookie(null, o.cookie); - } - - return this; - }, - - add: function(url, label, index) { - if (index === undefined) { - index = this.anchors.length; // append by default - } - - var self = this, o = this.options, - $li = $(o.tabTemplate.replace(/#\{href\}/g, url).replace(/#\{label\}/g, label)), - id = !url.indexOf('#') ? url.replace('#', '') : this._tabId($('a', $li)[0]); - - $li.addClass('ui-state-default ui-corner-top').data('destroy.tabs', true); - - // try to find an existing element before creating a new one - var $panel = $('#' + id); - if (!$panel.length) { - $panel = $(o.panelTemplate).attr('id', id).data('destroy.tabs', true); - } - $panel.addClass('ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide'); - - if (index >= this.lis.length) { - $li.appendTo(this.list); - $panel.appendTo(this.list[0].parentNode); - } - else { - $li.insertBefore(this.lis[index]); - $panel.insertBefore(this.panels[index]); - } - - o.disabled = $.map(o.disabled, - function(n, i) { return n >= index ? ++n : n; }); - - this._tabify(); - - if (this.anchors.length == 1) { // after tabify - o.selected = 0; - $li.addClass('ui-tabs-selected ui-state-active'); - $panel.removeClass('ui-tabs-hide'); - this.element.queue("tabs", function() { - self._trigger('show', null, self._ui(self.anchors[0], self.panels[0])); - }); - - this.load(0); - } - - // callback - this._trigger('add', null, this._ui(this.anchors[index], this.panels[index])); - return this; - }, - - remove: function(index) { - var o = this.options, $li = this.lis.eq(index).remove(), - $panel = this.panels.eq(index).remove(); - - // If selected tab was removed focus tab to the right or - // in case the last tab was removed the tab to the left. - if ($li.hasClass('ui-tabs-selected') && this.anchors.length > 1) { - this.select(index + (index + 1 < this.anchors.length ? 1 : -1)); - } - - o.disabled = $.map($.grep(o.disabled, function(n, i) { return n != index; }), - function(n, i) { return n >= index ? --n : n; }); - - this._tabify(); - - // callback - this._trigger('remove', null, this._ui($li.find('a')[0], $panel[0])); - return this; - }, - - enable: function(index) { - var o = this.options; - if ($.inArray(index, o.disabled) == -1) { - return; - } - - this.lis.eq(index).removeClass('ui-state-disabled'); - o.disabled = $.grep(o.disabled, function(n, i) { return n != index; }); - - // callback - this._trigger('enable', null, this._ui(this.anchors[index], this.panels[index])); - return this; - }, - - disable: function(index) { - var self = this, o = this.options; - if (index != o.selected) { // cannot disable already selected tab - this.lis.eq(index).addClass('ui-state-disabled'); - - o.disabled.push(index); - o.disabled.sort(); - - // callback - this._trigger('disable', null, this._ui(this.anchors[index], this.panels[index])); - } - - return this; - }, - - select: function(index) { - if (typeof index == 'string') { - index = this.anchors.index(this.anchors.filter('[href$=' + index + ']')); - } - else if (index === null) { // usage of null is deprecated, TODO remove in next release - index = -1; - } - if (index == -1 && this.options.collapsible) { - index = this.options.selected; - } - - this.anchors.eq(index).trigger(this.options.event + '.tabs'); - return this; - }, - - load: function(index) { - var self = this, o = this.options, a = this.anchors.eq(index)[0], url = $.data(a, 'load.tabs'); - - this.abort(); - - // not remote or from cache - if (!url || this.element.queue("tabs").length !== 0 && $.data(a, 'cache.tabs')) { - this.element.dequeue("tabs"); - return; - } - - // load remote from here on - this.lis.eq(index).addClass('ui-state-processing'); - - if (o.spinner) { - var span = $('span', a); - span.data('label.tabs', span.html()).html(o.spinner); - } - - this.xhr = $.ajax($.extend({}, o.ajaxOptions, { - url: url, - success: function(r, s) { - $(self._sanitizeSelector(a.hash)).html(r); - - // take care of tab labels - self._cleanup(); - - if (o.cache) { - $.data(a, 'cache.tabs', true); // if loaded once do not load them again - } - - // callbacks - self._trigger('load', null, self._ui(self.anchors[index], self.panels[index])); - try { - o.ajaxOptions.success(r, s); - } - catch (e) {} - }, - error: function(xhr, s, e) { - // take care of tab labels - self._cleanup(); - - // callbacks - self._trigger('load', null, self._ui(self.anchors[index], self.panels[index])); - try { - // Passing index avoid a race condition when this method is - // called after the user has selected another tab. - // Pass the anchor that initiated this request allows - // loadError to manipulate the tab content panel via $(a.hash) - o.ajaxOptions.error(xhr, s, index, a); - } - catch (e) {} - } - })); - - // last, so that load event is fired before show... - self.element.dequeue("tabs"); - - return this; - }, - - abort: function() { - // stop possibly running animations - this.element.queue([]); - this.panels.stop(false, true); - - // "tabs" queue must not contain more than two elements, - // which are the callbacks for the latest clicked tab... - this.element.queue("tabs", this.element.queue("tabs").splice(-2, 2)); - - // terminate pending requests from other tabs - if (this.xhr) { - this.xhr.abort(); - delete this.xhr; - } - - // take care of tab labels - this._cleanup(); - return this; - }, - - url: function(index, url) { - this.anchors.eq(index).removeData('cache.tabs').data('load.tabs', url); - return this; - }, - - length: function() { - return this.anchors.length; - } - -}); - -$.extend($.ui.tabs, { - version: '@VERSION' -}); - -/* - * Tabs Extensions - */ - -/* - * Rotate - */ -$.extend($.ui.tabs.prototype, { - rotation: null, - rotate: function(ms, continuing) { - - var self = this, o = this.options; - - var rotate = self._rotate || (self._rotate = function(e) { - clearTimeout(self.rotation); - self.rotation = setTimeout(function() { - var t = o.selected; - self.select( ++t < self.anchors.length ? t : 0 ); - }, ms); - - if (e) { - e.stopPropagation(); - } - }); - - var stop = self._unrotate || (self._unrotate = !continuing ? - function(e) { - if (e.clientX) { // in case of a true click - self.rotate(null); - } - } : - function(e) { - t = o.selected; - rotate(); - }); - - // start rotation - if (ms) { - this.element.bind('tabsshow', rotate); - this.anchors.bind(o.event + '.tabs', stop); - rotate(); - } - // stop rotation - else { - clearTimeout(self.rotation); - this.element.unbind('tabsshow', rotate); - this.anchors.unbind(o.event + '.tabs', stop); - delete this._rotate; - delete this._unrotate; - } - - return this; - } -}); - -})(jQuery); diff --git a/ui/jquery.ui.widget.js b/ui/jquery.ui.widget.js deleted file mode 100644 index a9829d2e520..00000000000 --- a/ui/jquery.ui.widget.js +++ /dev/null @@ -1,236 +0,0 @@ -/*! - * jQuery UI Widget @VERSION - * - * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT (MIT-LICENSE.txt) - * and GPL (GPL-LICENSE.txt) licenses. - * - * http://docs.jquery.com/UI/Widget - */ -(function( $ ) { - -var _remove = $.fn.remove; - -$.fn.remove = function( selector, keepData ) { - return this.each(function() { - if ( !keepData ) { - if ( !selector || $.filter( selector, [ this ] ).length ) { - $( "*", this ).add( this ).each(function() { - $( this ).triggerHandler( "remove" ); - }); - } - } - return _remove.call( $(this), selector, keepData ); - }); -}; - -$.widget = function( name, base, prototype ) { - var namespace = name.split( "." )[ 0 ], - fullName; - name = name.split( "." )[ 1 ]; - fullName = namespace + "-" + name; - - if ( !prototype ) { - prototype = base; - base = $.Widget; - } - - // create selector for plugin - $.expr[ ":" ][ fullName ] = function( elem ) { - return !!$.data( elem, name ); - }; - - $[ namespace ] = $[ namespace ] || {}; - $[ namespace ][ name ] = function( options, element ) { - // allow instantiation without initializing for simple inheritance - if ( arguments.length ) { - this._createWidget( options, element ); - } - }; - - var basePrototype = new base(); - // we need to make the options hash a property directly on the new instance - // otherwise we'll modify the options hash on the prototype that we're - // inheriting from -// $.each( basePrototype, function( key, val ) { -// if ( $.isPlainObject(val) ) { -// basePrototype[ key ] = $.extend( {}, val ); -// } -// }); - basePrototype.options = $.extend( {}, basePrototype.options ); - $[ namespace ][ name ].prototype = $.extend( true, basePrototype, { - namespace: namespace, - widgetName: name, - widgetEventPrefix: $[ namespace ][ name ].prototype.widgetEventPrefix || name, - widgetBaseClass: fullName - }, prototype ); - - $.widget.bridge( name, $[ namespace ][ name ] ); -}; - -$.widget.bridge = function( name, object ) { - $.fn[ name ] = function( options ) { - var isMethodCall = typeof options === "string", - args = Array.prototype.slice.call( arguments, 1 ), - returnValue = this; - - // allow multiple hashes to be passed on init - options = !isMethodCall && args.length ? - $.extend.apply( null, [ true, options ].concat(args) ) : - options; - - // prevent calls to internal methods - if ( isMethodCall && options.substring( 0, 1 ) === "_" ) { - return returnValue; - } - - if ( isMethodCall ) { - this.each(function() { - var instance = $.data( this, name ), - methodValue = instance && $.isFunction( instance[options] ) ? - instance[ options ].apply( instance, args ) : - instance; - if ( methodValue !== instance && methodValue !== undefined ) { - returnValue = methodValue; - return false; - } - }); - } else { - this.each(function() { - var instance = $.data( this, name ); - if ( instance ) { - if ( options ) { - instance.option( options ); - } - instance._init(); - } else { - $.data( this, name, new object( options, this ) ); - } - }); - } - - return returnValue; - }; -}; - -$.Widget = function( options, element ) { - // allow instantiation without initializing for simple inheritance - if ( arguments.length ) { - this._createWidget( options, element ); - } -}; - -$.Widget.prototype = { - widgetName: "widget", - widgetEventPrefix: "", - options: { - disabled: false - }, - _createWidget: function( options, element ) { - // $.widget.bridge stores the plugin instance, but we do it anyway - // so that it's stored even before the _create function runs - this.element = $( element ).data( this.widgetName, this ); - this.options = $.extend( true, {}, - this.options, - $.metadata && $.metadata.get( element )[ this.widgetName ], - options ); - - var self = this; - this.element.bind( "remove." + this.widgetName, function() { - self.destroy(); - }); - - this._create(); - this._init(); - }, - _create: function() {}, - _init: function() {}, - - destroy: function() { - this.element - .unbind( "." + this.widgetName ) - .removeData( this.widgetName ); - this.widget() - .unbind( "." + this.widgetName ) - .removeAttr( "aria-disabled" ) - .removeClass( - this.widgetBaseClass + "-disabled " + - "ui-state-disabled" ); - }, - - widget: function() { - return this.element; - }, - - option: function( key, value ) { - var options = key, - self = this; - - if ( arguments.length === 0 ) { - // don't return a reference to the internal hash - return $.extend( {}, self.options ); - } - - if (typeof key === "string" ) { - if ( value === undefined ) { - return this.options[ key ]; - } - options = {}; - options[ key ] = value; - } - - $.each( options, function( key, value ) { - self._setOption( key, value ); - }); - - return self; - }, - _setOption: function( key, value ) { - this.options[ key ] = value; - - if ( key === "disabled" ) { - this.widget() - [ value ? "addClass" : "removeClass"]( - this.widgetBaseClass + "-disabled" + " " + - "ui-state-disabled" ) - .attr( "aria-disabled", value ); - } - - return this; - }, - - enable: function() { - return this._setOption( "disabled", false ); - }, - disable: function() { - return this._setOption( "disabled", true ); - }, - - _trigger: function( type, event, data ) { - var callback = this.options[ type ]; - - event = $.Event( event ); - event.type = ( type === this.widgetEventPrefix ? - type : - this.widgetEventPrefix + type ).toLowerCase(); - data = data || {}; - - // copy original event properties over to the new event - // this would happen if we could call $.event.fix instead of $.Event - // but we don't have a way to force an event to be fixed multiple times - if ( event.originalEvent ) { - for ( var i = $.event.props.length, prop; i; ) { - prop = $.event.props[ --i ]; - event[ prop ] = event.originalEvent[ prop ]; - } - } - - this.element.trigger( event, data ); - - return !( $.isFunction(callback) && - callback.call( this.element[0], event, data ) === false || - event.isDefaultPrevented() ); - } -}; - -})( jQuery ); diff --git a/ui/keycode.js b/ui/keycode.js new file mode 100644 index 00000000000..32bfa5d3faf --- /dev/null +++ b/ui/keycode.js @@ -0,0 +1,49 @@ +/*! + * jQuery UI Keycode @VERSION + * https://jqueryui.com + * + * Copyright OpenJS Foundation and other contributors + * Released under the MIT license. + * https://jquery.org/license + */ + +//>>label: Keycode +//>>group: Core +//>>description: Provide keycodes as keynames +//>>docs: https://api.jqueryui.com/jQuery.ui.keyCode/ + +( function( factory ) { + "use strict"; + + if ( typeof define === "function" && define.amd ) { + + // AMD. Register as an anonymous module. + define( [ "jquery", "./version" ], factory ); + } else { + + // Browser globals + factory( jQuery ); + } +} )( function( $ ) { +"use strict"; + +return $.ui.keyCode = { + BACKSPACE: 8, + COMMA: 188, + DELETE: 46, + DOWN: 40, + END: 35, + ENTER: 13, + ESCAPE: 27, + HOME: 36, + LEFT: 37, + PAGE_DOWN: 34, + PAGE_UP: 33, + PERIOD: 190, + RIGHT: 39, + SPACE: 32, + TAB: 9, + UP: 38 +}; + +} ); diff --git a/ui/labels.js b/ui/labels.js new file mode 100644 index 00000000000..5ff44c28bb1 --- /dev/null +++ b/ui/labels.js @@ -0,0 +1,68 @@ +/*! + * jQuery UI Labels @VERSION + * https://jqueryui.com + * + * Copyright OpenJS Foundation and other contributors + * Released under the MIT license. + * https://jquery.org/license + */ + +//>>label: labels +//>>group: Core +//>>description: Find all the labels associated with a given input +//>>docs: https://api.jqueryui.com/labels/ + +( function( factory ) { + "use strict"; + + if ( typeof define === "function" && define.amd ) { + + // AMD. Register as an anonymous module. + define( [ "jquery", "./version" ], factory ); + } else { + + // Browser globals + factory( jQuery ); + } +} )( function( $ ) { +"use strict"; + +return $.fn.labels = function() { + var ancestor, selector, id, labels, ancestors; + + if ( !this.length ) { + return this.pushStack( [] ); + } + + // Check control.labels first + if ( this[ 0 ].labels && this[ 0 ].labels.length ) { + return this.pushStack( this[ 0 ].labels ); + } + + // If `control.labels` is empty - e.g. inside of document fragments - find + // the labels manually + labels = this.eq( 0 ).parents( "label" ); + + // Look for the label based on the id + id = this.attr( "id" ); + if ( id ) { + + // We don't search against the document in case the element + // is disconnected from the DOM + ancestor = this.eq( 0 ).parents().last(); + + // Get a full set of top level ancestors + ancestors = ancestor.add( ancestor.length ? ancestor.siblings() : this.siblings() ); + + // Create a selector for the label based on the id + selector = "label[for='" + CSS.escape( id ) + "']"; + + labels = labels.add( ancestors.find( selector ).addBack( selector ) ); + + } + + // Return whatever we have found for labels + return this.pushStack( labels ); +}; + +} ); diff --git a/ui/plugin.js b/ui/plugin.js new file mode 100644 index 00000000000..1e46017ad4a --- /dev/null +++ b/ui/plugin.js @@ -0,0 +1,47 @@ +( function( factory ) { + "use strict"; + + if ( typeof define === "function" && define.amd ) { + + // AMD. Register as an anonymous module. + define( [ "jquery", "./version" ], factory ); + } else { + + // Browser globals + factory( jQuery ); + } +} )( function( $ ) { +"use strict"; + +// $.ui.plugin is deprecated. Use $.widget() extensions instead. +return $.ui.plugin = { + add: function( module, option, set ) { + var i, + proto = $.ui[ module ].prototype; + for ( i in set ) { + proto.plugins[ i ] = proto.plugins[ i ] || []; + proto.plugins[ i ].push( [ option, set[ i ] ] ); + } + }, + call: function( instance, name, args, allowDisconnected ) { + var i, + set = instance.plugins[ name ]; + + if ( !set ) { + return; + } + + if ( !allowDisconnected && ( !instance.element[ 0 ].parentNode || + instance.element[ 0 ].parentNode.nodeType === 11 ) ) { + return; + } + + for ( i = 0; i < set.length; i++ ) { + if ( instance.options[ set[ i ][ 0 ] ] ) { + set[ i ][ 1 ].apply( instance.element, args ); + } + } + } +}; + +} ); diff --git a/ui/position.js b/ui/position.js new file mode 100644 index 00000000000..ea1dca86b73 --- /dev/null +++ b/ui/position.js @@ -0,0 +1,511 @@ +/*! + * jQuery UI Position @VERSION + * https://jqueryui.com + * + * Copyright OpenJS Foundation and other contributors + * Released under the MIT license. + * https://jquery.org/license + * + * https://api.jqueryui.com/position/ + */ + +//>>label: Position +//>>group: Core +//>>description: Positions elements relative to other elements. +//>>docs: https://api.jqueryui.com/position/ +//>>demos: https://jqueryui.com/position/ + +( function( factory ) { + "use strict"; + + if ( typeof define === "function" && define.amd ) { + + // AMD. Register as an anonymous module. + define( [ "jquery", "./version" ], factory ); + } else { + + // Browser globals + factory( jQuery ); + } +} )( function( $ ) { +"use strict"; + +( function() { +var cachedScrollbarWidth, + max = Math.max, + abs = Math.abs, + rhorizontal = /left|center|right/, + rvertical = /top|center|bottom/, + roffset = /[\+\-]\d+(\.[\d]+)?%?/, + rposition = /^\w+/, + rpercent = /%$/, + _position = $.fn.position; + +function getOffsets( offsets, width, height ) { + return [ + parseFloat( offsets[ 0 ] ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ), + parseFloat( offsets[ 1 ] ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 ) + ]; +} + +function parseCss( element, property ) { + return parseInt( $.css( element, property ), 10 ) || 0; +} + +function isWindow( obj ) { + return obj != null && obj === obj.window; +} + +function getDimensions( elem ) { + var raw = elem[ 0 ]; + if ( raw.nodeType === 9 ) { + return { + width: elem.width(), + height: elem.height(), + offset: { top: 0, left: 0 } + }; + } + if ( isWindow( raw ) ) { + return { + width: elem.width(), + height: elem.height(), + offset: { top: elem.scrollTop(), left: elem.scrollLeft() } + }; + } + if ( raw.preventDefault ) { + return { + width: 0, + height: 0, + offset: { top: raw.pageY, left: raw.pageX } + }; + } + return { + width: elem.outerWidth(), + height: elem.outerHeight(), + offset: elem.offset() + }; +} + +$.position = { + scrollbarWidth: function() { + if ( cachedScrollbarWidth !== undefined ) { + return cachedScrollbarWidth; + } + var w1, w2, + div = $( "
        " + + "
        " ), + innerDiv = div.children()[ 0 ]; + + $( "body" ).append( div ); + w1 = innerDiv.offsetWidth; + div.css( "overflow", "scroll" ); + + w2 = innerDiv.offsetWidth; + + if ( w1 === w2 ) { + w2 = div[ 0 ].clientWidth; + } + + div.remove(); + + return ( cachedScrollbarWidth = w1 - w2 ); + }, + getScrollInfo: function( within ) { + var overflowX = within.isWindow || within.isDocument ? "" : + within.element.css( "overflow-x" ), + overflowY = within.isWindow || within.isDocument ? "" : + within.element.css( "overflow-y" ), + hasOverflowX = overflowX === "scroll" || + ( overflowX === "auto" && within.width < within.element[ 0 ].scrollWidth ), + hasOverflowY = overflowY === "scroll" || + ( overflowY === "auto" && within.height < within.element[ 0 ].scrollHeight ); + return { + width: hasOverflowY ? $.position.scrollbarWidth() : 0, + height: hasOverflowX ? $.position.scrollbarWidth() : 0 + }; + }, + getWithinInfo: function( element ) { + var withinElement = $( element || window ), + isElemWindow = isWindow( withinElement[ 0 ] ), + isDocument = !!withinElement[ 0 ] && withinElement[ 0 ].nodeType === 9, + hasOffset = !isElemWindow && !isDocument; + return { + element: withinElement, + isWindow: isElemWindow, + isDocument: isDocument, + offset: hasOffset ? $( element ).offset() : { left: 0, top: 0 }, + scrollLeft: withinElement.scrollLeft(), + scrollTop: withinElement.scrollTop(), + width: withinElement.outerWidth(), + height: withinElement.outerHeight() + }; + } +}; + +$.fn.position = function( options ) { + if ( !options || !options.of ) { + return _position.apply( this, arguments ); + } + + // Make a copy, we don't want to modify arguments + options = $.extend( {}, options ); + + var atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions, + + // Make sure string options are treated as CSS selectors + target = typeof options.of === "string" ? + $( document ).find( options.of ) : + $( options.of ), + + within = $.position.getWithinInfo( options.within ), + scrollInfo = $.position.getScrollInfo( within ), + collision = ( options.collision || "flip" ).split( " " ), + offsets = {}; + + dimensions = getDimensions( target ); + if ( target[ 0 ].preventDefault ) { + + // Force left top to allow flipping + options.at = "left top"; + } + targetWidth = dimensions.width; + targetHeight = dimensions.height; + targetOffset = dimensions.offset; + + // Clone to reuse original targetOffset later + basePosition = $.extend( {}, targetOffset ); + + // Force my and at to have valid horizontal and vertical positions + // if a value is missing or invalid, it will be converted to center + $.each( [ "my", "at" ], function() { + var pos = ( options[ this ] || "" ).split( " " ), + horizontalOffset, + verticalOffset; + + if ( pos.length === 1 ) { + pos = rhorizontal.test( pos[ 0 ] ) ? + pos.concat( [ "center" ] ) : + rvertical.test( pos[ 0 ] ) ? + [ "center" ].concat( pos ) : + [ "center", "center" ]; + } + pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center"; + pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center"; + + // Calculate offsets + horizontalOffset = roffset.exec( pos[ 0 ] ); + verticalOffset = roffset.exec( pos[ 1 ] ); + offsets[ this ] = [ + horizontalOffset ? horizontalOffset[ 0 ] : 0, + verticalOffset ? verticalOffset[ 0 ] : 0 + ]; + + // Reduce to just the positions without the offsets + options[ this ] = [ + rposition.exec( pos[ 0 ] )[ 0 ], + rposition.exec( pos[ 1 ] )[ 0 ] + ]; + } ); + + // Normalize collision option + if ( collision.length === 1 ) { + collision[ 1 ] = collision[ 0 ]; + } + + if ( options.at[ 0 ] === "right" ) { + basePosition.left += targetWidth; + } else if ( options.at[ 0 ] === "center" ) { + basePosition.left += targetWidth / 2; + } + + if ( options.at[ 1 ] === "bottom" ) { + basePosition.top += targetHeight; + } else if ( options.at[ 1 ] === "center" ) { + basePosition.top += targetHeight / 2; + } + + atOffset = getOffsets( offsets.at, targetWidth, targetHeight ); + basePosition.left += atOffset[ 0 ]; + basePosition.top += atOffset[ 1 ]; + + return this.each( function() { + var collisionPosition, using, + elem = $( this ), + elemWidth = elem.outerWidth(), + elemHeight = elem.outerHeight(), + marginLeft = parseCss( this, "marginLeft" ), + marginTop = parseCss( this, "marginTop" ), + collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) + + scrollInfo.width, + collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) + + scrollInfo.height, + position = $.extend( {}, basePosition ), + myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() ); + + if ( options.my[ 0 ] === "right" ) { + position.left -= elemWidth; + } else if ( options.my[ 0 ] === "center" ) { + position.left -= elemWidth / 2; + } + + if ( options.my[ 1 ] === "bottom" ) { + position.top -= elemHeight; + } else if ( options.my[ 1 ] === "center" ) { + position.top -= elemHeight / 2; + } + + position.left += myOffset[ 0 ]; + position.top += myOffset[ 1 ]; + + collisionPosition = { + marginLeft: marginLeft, + marginTop: marginTop + }; + + $.each( [ "left", "top" ], function( i, dir ) { + if ( $.ui.position[ collision[ i ] ] ) { + $.ui.position[ collision[ i ] ][ dir ]( position, { + targetWidth: targetWidth, + targetHeight: targetHeight, + elemWidth: elemWidth, + elemHeight: elemHeight, + collisionPosition: collisionPosition, + collisionWidth: collisionWidth, + collisionHeight: collisionHeight, + offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ], + my: options.my, + at: options.at, + within: within, + elem: elem + } ); + } + } ); + + if ( options.using ) { + + // Adds feedback as second argument to using callback, if present + using = function( props ) { + var left = targetOffset.left - position.left, + right = left + targetWidth - elemWidth, + top = targetOffset.top - position.top, + bottom = top + targetHeight - elemHeight, + feedback = { + target: { + element: target, + left: targetOffset.left, + top: targetOffset.top, + width: targetWidth, + height: targetHeight + }, + element: { + element: elem, + left: position.left, + top: position.top, + width: elemWidth, + height: elemHeight + }, + horizontal: right < 0 ? "left" : left > 0 ? "right" : "center", + vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle" + }; + if ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) { + feedback.horizontal = "center"; + } + if ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) { + feedback.vertical = "middle"; + } + if ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) { + feedback.important = "horizontal"; + } else { + feedback.important = "vertical"; + } + options.using.call( this, props, feedback ); + }; + } + + elem.offset( $.extend( position, { using: using } ) ); + } ); +}; + +$.ui.position = { + fit: { + left: function( position, data ) { + var within = data.within, + withinOffset = within.isWindow ? within.scrollLeft : within.offset.left, + outerWidth = within.width, + collisionPosLeft = position.left - data.collisionPosition.marginLeft, + overLeft = withinOffset - collisionPosLeft, + overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset, + newOverRight; + + // Element is wider than within + if ( data.collisionWidth > outerWidth ) { + + // Element is initially over the left side of within + if ( overLeft > 0 && overRight <= 0 ) { + newOverRight = position.left + overLeft + data.collisionWidth - outerWidth - + withinOffset; + position.left += overLeft - newOverRight; + + // Element is initially over right side of within + } else if ( overRight > 0 && overLeft <= 0 ) { + position.left = withinOffset; + + // Element is initially over both left and right sides of within + } else { + if ( overLeft > overRight ) { + position.left = withinOffset + outerWidth - data.collisionWidth; + } else { + position.left = withinOffset; + } + } + + // Too far left -> align with left edge + } else if ( overLeft > 0 ) { + position.left += overLeft; + + // Too far right -> align with right edge + } else if ( overRight > 0 ) { + position.left -= overRight; + + // Adjust based on position and margin + } else { + position.left = max( position.left - collisionPosLeft, position.left ); + } + }, + top: function( position, data ) { + var within = data.within, + withinOffset = within.isWindow ? within.scrollTop : within.offset.top, + outerHeight = data.within.height, + collisionPosTop = position.top - data.collisionPosition.marginTop, + overTop = withinOffset - collisionPosTop, + overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset, + newOverBottom; + + // Element is taller than within + if ( data.collisionHeight > outerHeight ) { + + // Element is initially over the top of within + if ( overTop > 0 && overBottom <= 0 ) { + newOverBottom = position.top + overTop + data.collisionHeight - outerHeight - + withinOffset; + position.top += overTop - newOverBottom; + + // Element is initially over bottom of within + } else if ( overBottom > 0 && overTop <= 0 ) { + position.top = withinOffset; + + // Element is initially over both top and bottom of within + } else { + if ( overTop > overBottom ) { + position.top = withinOffset + outerHeight - data.collisionHeight; + } else { + position.top = withinOffset; + } + } + + // Too far up -> align with top + } else if ( overTop > 0 ) { + position.top += overTop; + + // Too far down -> align with bottom edge + } else if ( overBottom > 0 ) { + position.top -= overBottom; + + // Adjust based on position and margin + } else { + position.top = max( position.top - collisionPosTop, position.top ); + } + } + }, + flip: { + left: function( position, data ) { + var within = data.within, + withinOffset = within.offset.left + within.scrollLeft, + outerWidth = within.width, + offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left, + collisionPosLeft = position.left - data.collisionPosition.marginLeft, + overLeft = collisionPosLeft - offsetLeft, + overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft, + myOffset = data.my[ 0 ] === "left" ? + -data.elemWidth : + data.my[ 0 ] === "right" ? + data.elemWidth : + 0, + atOffset = data.at[ 0 ] === "left" ? + data.targetWidth : + data.at[ 0 ] === "right" ? + -data.targetWidth : + 0, + offset = -2 * data.offset[ 0 ], + newOverRight, + newOverLeft; + + if ( overLeft < 0 ) { + newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth - + outerWidth - withinOffset; + if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) { + position.left += myOffset + atOffset + offset; + } + } else if ( overRight > 0 ) { + newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset + + atOffset + offset - offsetLeft; + if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) { + position.left += myOffset + atOffset + offset; + } + } + }, + top: function( position, data ) { + var within = data.within, + withinOffset = within.offset.top + within.scrollTop, + outerHeight = within.height, + offsetTop = within.isWindow ? within.scrollTop : within.offset.top, + collisionPosTop = position.top - data.collisionPosition.marginTop, + overTop = collisionPosTop - offsetTop, + overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop, + top = data.my[ 1 ] === "top", + myOffset = top ? + -data.elemHeight : + data.my[ 1 ] === "bottom" ? + data.elemHeight : + 0, + atOffset = data.at[ 1 ] === "top" ? + data.targetHeight : + data.at[ 1 ] === "bottom" ? + -data.targetHeight : + 0, + offset = -2 * data.offset[ 1 ], + newOverTop, + newOverBottom; + if ( overTop < 0 ) { + newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight - + outerHeight - withinOffset; + if ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) { + position.top += myOffset + atOffset + offset; + } + } else if ( overBottom > 0 ) { + newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset + + offset - offsetTop; + if ( newOverTop > 0 || abs( newOverTop ) < overBottom ) { + position.top += myOffset + atOffset + offset; + } + } + } + }, + flipfit: { + left: function() { + $.ui.position.flip.left.apply( this, arguments ); + $.ui.position.fit.left.apply( this, arguments ); + }, + top: function() { + $.ui.position.flip.top.apply( this, arguments ); + $.ui.position.fit.top.apply( this, arguments ); + } + } +}; + +} )(); + +return $.ui.position; + +} ); diff --git a/ui/scroll-parent.js b/ui/scroll-parent.js new file mode 100644 index 00000000000..b8fb6ddac25 --- /dev/null +++ b/ui/scroll-parent.js @@ -0,0 +1,48 @@ +/*! + * jQuery UI Scroll Parent @VERSION + * https://jqueryui.com + * + * Copyright OpenJS Foundation and other contributors + * Released under the MIT license. + * https://jquery.org/license + */ + +//>>label: scrollParent +//>>group: Core +//>>description: Get the closest ancestor element that is scrollable. +//>>docs: https://api.jqueryui.com/scrollParent/ + +( function( factory ) { + "use strict"; + + if ( typeof define === "function" && define.amd ) { + + // AMD. Register as an anonymous module. + define( [ "jquery", "./version" ], factory ); + } else { + + // Browser globals + factory( jQuery ); + } +} )( function( $ ) { +"use strict"; + +return $.fn.scrollParent = function( includeHidden ) { + var position = this.css( "position" ), + excludeStaticParent = position === "absolute", + overflowRegex = includeHidden ? /(auto|scroll|hidden)/ : /(auto|scroll)/, + scrollParent = this.parents().filter( function() { + var parent = $( this ); + if ( excludeStaticParent && parent.css( "position" ) === "static" ) { + return false; + } + return overflowRegex.test( parent.css( "overflow" ) + parent.css( "overflow-y" ) + + parent.css( "overflow-x" ) ); + } ).eq( 0 ); + + return position === "fixed" || !scrollParent.length ? + $( this[ 0 ].ownerDocument || document ) : + scrollParent; +}; + +} ); diff --git a/ui/tabbable.js b/ui/tabbable.js new file mode 100644 index 00000000000..555484a92f3 --- /dev/null +++ b/ui/tabbable.js @@ -0,0 +1,38 @@ +/*! + * jQuery UI Tabbable @VERSION + * https://jqueryui.com + * + * Copyright OpenJS Foundation and other contributors + * Released under the MIT license. + * https://jquery.org/license + */ + +//>>label: :tabbable Selector +//>>group: Core +//>>description: Selects elements which can be tabbed to. +//>>docs: https://api.jqueryui.com/tabbable-selector/ + +( function( factory ) { + "use strict"; + + if ( typeof define === "function" && define.amd ) { + + // AMD. Register as an anonymous module. + define( [ "jquery", "./version", "./focusable" ], factory ); + } else { + + // Browser globals + factory( jQuery ); + } +} )( function( $ ) { +"use strict"; + +return $.extend( $.expr.pseudos, { + tabbable: function( element ) { + var tabIndex = $.attr( element, "tabindex" ), + hasTabindex = tabIndex != null; + return ( !hasTabindex || tabIndex >= 0 ) && $.ui.focusable( element, hasTabindex ); + } +} ); + +} ); diff --git a/ui/unique-id.js b/ui/unique-id.js new file mode 100644 index 00000000000..488e4e23282 --- /dev/null +++ b/ui/unique-id.js @@ -0,0 +1,52 @@ +/*! + * jQuery UI Unique ID @VERSION + * https://jqueryui.com + * + * Copyright OpenJS Foundation and other contributors + * Released under the MIT license. + * https://jquery.org/license + */ + +//>>label: uniqueId +//>>group: Core +//>>description: Functions to generate and remove uniqueId's +//>>docs: https://api.jqueryui.com/uniqueId/ + +( function( factory ) { + "use strict"; + + if ( typeof define === "function" && define.amd ) { + + // AMD. Register as an anonymous module. + define( [ "jquery", "./version" ], factory ); + } else { + + // Browser globals + factory( jQuery ); + } +} )( function( $ ) { +"use strict"; + +return $.fn.extend( { + uniqueId: ( function() { + var uuid = 0; + + return function() { + return this.each( function() { + if ( !this.id ) { + this.id = "ui-id-" + ( ++uuid ); + } + } ); + }; + } )(), + + removeUniqueId: function() { + return this.each( function() { + if ( /^ui-id-\d+$/.test( this.id ) ) { + $( this ).removeAttr( "id" ); + } + } ); + } +} ); + +} ); diff --git a/ui/vendor/jquery-color/LICENSE.txt b/ui/vendor/jquery-color/LICENSE.txt new file mode 100644 index 00000000000..6a864b8baf0 --- /dev/null +++ b/ui/vendor/jquery-color/LICENSE.txt @@ -0,0 +1,43 @@ +Copyright OpenJS Foundation and other contributors, https://openjsf.org/ + +This software consists of voluntary contributions made by many +individuals. For exact contribution history, see the revision history +available at https://github.com/jquery/jquery-color + +The following license applies to all parts of jQuery Color except as +documented below: + +==== + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +==== + +Copyright and related rights for sample code are waived via CC0. Sample +code is defined as all source code displayed within the README. + +CC0: http://creativecommons.org/publicdomain/zero/1.0/ + +==== + +All files located in the node_modules and external directories are +externally maintained libraries used by this software which have their +own licenses; we recommend you read them, as their terms may differ from +the terms above. diff --git a/ui/vendor/jquery-color/jquery.color.js b/ui/vendor/jquery-color/jquery.color.js new file mode 100644 index 00000000000..5fde068be3c --- /dev/null +++ b/ui/vendor/jquery-color/jquery.color.js @@ -0,0 +1,691 @@ +/*! + * jQuery Color Animations v3.0.0 + * https://github.com/jquery/jquery-color + * + * Copyright OpenJS Foundation and other contributors + * Released under the MIT license. + * https://jquery.org/license + * + * Date: Wed May 15 16:49:44 2024 +0200 + */ + +( function( root, factory ) { + "use strict"; + + if ( typeof define === "function" && define.amd ) { + + // AMD. Register as an anonymous module. + define( [ "jquery" ], factory ); + } else if ( typeof exports === "object" ) { + module.exports = factory( require( "jquery" ) ); + } else { + factory( root.jQuery ); + } +} )( this, function( jQuery, undefined ) { + "use strict"; + + var stepHooks = "backgroundColor borderBottomColor borderLeftColor borderRightColor " + + "borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor", + + class2type = {}, + toString = class2type.toString, + + // plusequals test for += 100 -= 100 + rplusequals = /^([\-+])=\s*(\d+\.?\d*)/, + + // a set of RE's that can match strings and generate color tuples. + stringParsers = [ { + re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/, + parse: function( execResult ) { + return [ + execResult[ 1 ], + execResult[ 2 ], + execResult[ 3 ], + execResult[ 4 ] + ]; + } + }, { + re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/, + parse: function( execResult ) { + return [ + execResult[ 1 ] * 2.55, + execResult[ 2 ] * 2.55, + execResult[ 3 ] * 2.55, + execResult[ 4 ] + ]; + } + }, { + + // this regex ignores A-F because it's compared against an already lowercased string + re: /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})?/, + parse: function( execResult ) { + return [ + parseInt( execResult[ 1 ], 16 ), + parseInt( execResult[ 2 ], 16 ), + parseInt( execResult[ 3 ], 16 ), + execResult[ 4 ] ? + ( parseInt( execResult[ 4 ], 16 ) / 255 ).toFixed( 2 ) : + 1 + ]; + } + }, { + + // this regex ignores A-F because it's compared against an already lowercased string + re: /#([a-f0-9])([a-f0-9])([a-f0-9])([a-f0-9])?/, + parse: function( execResult ) { + return [ + parseInt( execResult[ 1 ] + execResult[ 1 ], 16 ), + parseInt( execResult[ 2 ] + execResult[ 2 ], 16 ), + parseInt( execResult[ 3 ] + execResult[ 3 ], 16 ), + execResult[ 4 ] ? + ( parseInt( execResult[ 4 ] + execResult[ 4 ], 16 ) / 255 ) + .toFixed( 2 ) : + 1 + ]; + } + }, { + re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/, + space: "hsla", + parse: function( execResult ) { + return [ + execResult[ 1 ], + execResult[ 2 ] / 100, + execResult[ 3 ] / 100, + execResult[ 4 ] + ]; + } + } ], + + // jQuery.Color( ) + color = jQuery.Color = function( color, green, blue, alpha ) { + return new jQuery.Color.fn.parse( color, green, blue, alpha ); + }, + spaces = { + rgba: { + props: { + red: { + idx: 0, + type: "byte" + }, + green: { + idx: 1, + type: "byte" + }, + blue: { + idx: 2, + type: "byte" + } + } + }, + + hsla: { + props: { + hue: { + idx: 0, + type: "degrees" + }, + saturation: { + idx: 1, + type: "percent" + }, + lightness: { + idx: 2, + type: "percent" + } + } + } + }, + propTypes = { + "byte": { + floor: true, + max: 255 + }, + "percent": { + max: 1 + }, + "degrees": { + mod: 360, + floor: true + } + }, + + // colors = jQuery.Color.names + colors, + + // local aliases of functions called often + each = jQuery.each; + +// define cache name and alpha properties +// for rgba and hsla spaces +each( spaces, function( spaceName, space ) { + space.cache = "_" + spaceName; + space.props.alpha = { + idx: 3, + type: "percent", + def: 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(); + } ); + +function getType( obj ) { + if ( obj == null ) { + return obj + ""; + } + + return typeof obj === "object" ? + class2type[ toString.call( obj ) ] || "object" : + typeof obj; +} + +function clamp( value, prop, allowEmpty ) { + var type = propTypes[ prop.type ] || {}; + + if ( value == null ) { + return ( allowEmpty || !prop.def ) ? null : prop.def; + } + + // ~~ is an short way of doing floor for positive numbers + value = type.floor ? ~~value : parseFloat( value ); + + if ( type.mod ) { + + // we add mod before modding to make sure that negatives values + // get converted properly: -10 -> 350 + return ( value + type.mod ) % type.mod; + } + + // for now all property types without mod have min and max + return Math.min( type.max, Math.max( 0, value ) ); +} + +function stringParse( string ) { + var inst = color(), + rgba = inst._rgba = []; + + string = string.toLowerCase(); + + each( stringParsers, function( _i, parser ) { + var parsed, + match = parser.re.exec( string ), + values = match && parser.parse( match ), + spaceName = parser.space || "rgba"; + + if ( values ) { + parsed = inst[ spaceName ]( values ); + + // if this was an rgba parse the assignment might happen twice + // oh well.... + inst[ spaces[ spaceName ].cache ] = parsed[ spaces[ spaceName ].cache ]; + rgba = inst._rgba = parsed._rgba; + + // exit each( stringParsers ) here because we matched + return false; + } + } ); + + // Found a stringParser that handled it + if ( rgba.length ) { + + // if this came from a parsed string, force "transparent" when alpha is 0 + // chrome, (and maybe others) return "transparent" as rgba(0,0,0,0) + if ( rgba.join() === "0,0,0,0" ) { + jQuery.extend( rgba, colors.transparent ); + } + return inst; + } + + // named colors + return colors[ string ]; +} + +color.fn = jQuery.extend( color.prototype, { + parse: function( red, green, blue, alpha ) { + if ( red === undefined ) { + this._rgba = [ null, null, null, null ]; + return this; + } + if ( red.jquery || red.nodeType ) { + red = jQuery( red ).css( green ); + green = undefined; + } + + var inst = this, + type = getType( red ), + rgba = this._rgba = []; + + // more than 1 argument specified - assume ( red, green, blue, alpha ) + if ( green !== undefined ) { + red = [ red, green, blue, alpha ]; + type = "array"; + } + + if ( type === "string" ) { + return this.parse( stringParse( red ) || colors._default ); + } + + if ( type === "array" ) { + each( spaces.rgba.props, function( _key, prop ) { + rgba[ prop.idx ] = clamp( red[ prop.idx ], prop ); + } ); + return this; + } + + if ( type === "object" ) { + if ( red instanceof color ) { + each( spaces, function( _spaceName, space ) { + if ( red[ space.cache ] ) { + inst[ space.cache ] = red[ space.cache ].slice(); + } + } ); + } else { + each( spaces, function( _spaceName, space ) { + var cache = space.cache; + each( space.props, function( key, prop ) { + + // if the cache doesn't exist, and we know how to convert + if ( !inst[ cache ] && space.to ) { + + // if the value was null, we don't need to copy it + // if the key was alpha, we don't need to copy it either + if ( key === "alpha" || red[ key ] == null ) { + return; + } + inst[ cache ] = space.to( inst._rgba ); + } + + // this is the only case where we allow nulls for ALL properties. + // call clamp with alwaysAllowEmpty + inst[ cache ][ prop.idx ] = clamp( red[ key ], prop, true ); + } ); + + // everything defined but alpha? + if ( inst[ cache ] && jQuery.inArray( + null, + inst[ cache ].slice( 0, 3 ) + ) < 0 ) { + + // use the default of 1 + if ( inst[ cache ][ 3 ] == null ) { + inst[ cache ][ 3 ] = 1; + } + + if ( space.from ) { + inst._rgba = space.from( inst[ cache ] ); + } + } + } ); + } + return this; + } + }, + is: function( compare ) { + var is = color( compare ), + same = true, + inst = this; + + each( spaces, function( _, space ) { + var localCache, + isCache = is[ space.cache ]; + if ( isCache ) { + localCache = inst[ space.cache ] || space.to && space.to( inst._rgba ) || []; + each( space.props, function( _, prop ) { + if ( isCache[ prop.idx ] != null ) { + same = ( isCache[ prop.idx ] === localCache[ prop.idx ] ); + return same; + } + } ); + } + return same; + } ); + return same; + }, + _space: function() { + var used = [], + inst = this; + each( spaces, function( spaceName, space ) { + if ( inst[ space.cache ] ) { + used.push( spaceName ); + } + } ); + return used.pop(); + }, + transition: function( other, distance ) { + var end = color( other ), + spaceName = end._space(), + space = spaces[ spaceName ], + startColor = this.alpha() === 0 ? color( "transparent" ) : this, + start = startColor[ space.cache ] || space.to( startColor._rgba ), + result = start.slice(); + + end = end[ space.cache ]; + each( space.props, function( _key, prop ) { + var index = prop.idx, + startValue = start[ index ], + endValue = end[ index ], + type = propTypes[ prop.type ] || {}; + + // if null, don't override start value + if ( endValue === null ) { + return; + } + + // if null - use end + if ( startValue === null ) { + result[ index ] = endValue; + } else { + if ( type.mod ) { + if ( endValue - startValue > type.mod / 2 ) { + startValue += type.mod; + } else if ( startValue - endValue > type.mod / 2 ) { + startValue -= type.mod; + } + } + result[ index ] = clamp( ( endValue - startValue ) * distance + startValue, prop ); + } + } ); + return this[ spaceName ]( result ); + }, + blend: function( opaque ) { + + // if we are already opaque - return ourself + if ( this._rgba[ 3 ] === 1 ) { + return this; + } + + var rgb = this._rgba.slice(), + a = rgb.pop(), + blend = color( opaque )._rgba; + + return color( jQuery.map( rgb, function( v, i ) { + return ( 1 - a ) * blend[ i ] + a * v; + } ) ); + }, + toRgbaString: function() { + var prefix = "rgba(", + rgba = jQuery.map( this._rgba, function( v, i ) { + if ( v != null ) { + return v; + } + return i > 2 ? 1 : 0; + } ); + + if ( rgba[ 3 ] === 1 ) { + rgba.pop(); + prefix = "rgb("; + } + + return prefix + rgba.join( ", " ) + ")"; + }, + toHslaString: function() { + var prefix = "hsla(", + hsla = jQuery.map( this.hsla(), function( v, i ) { + if ( v == null ) { + v = i > 2 ? 1 : 0; + } + + // catch 1 and 2 + if ( i && i < 3 ) { + v = Math.round( v * 100 ) + "%"; + } + return v; + } ); + + if ( hsla[ 3 ] === 1 ) { + hsla.pop(); + prefix = "hsl("; + } + return prefix + hsla.join( ", " ) + ")"; + }, + toHexString: function( includeAlpha ) { + var rgba = this._rgba.slice(), + alpha = rgba.pop(); + + if ( includeAlpha ) { + rgba.push( ~~( alpha * 255 ) ); + } + + return "#" + jQuery.map( rgba, function( v ) { + + // default to 0 when nulls exist + return ( "0" + ( v || 0 ).toString( 16 ) ).substr( -2 ); + } ).join( "" ); + }, + toString: function() { + return this.toRgbaString(); + } +} ); +color.fn.parse.prototype = color.fn; + +// hsla conversions adapted from: +// https://code.google.com/p/maashaack/source/browse/packages/graphics/trunk/src/graphics/colors/HUE2RGB.as?r=5021 + +function hue2rgb( p, q, h ) { + h = ( h + 1 ) % 1; + if ( h * 6 < 1 ) { + return p + ( q - p ) * h * 6; + } + if ( h * 2 < 1 ) { + return q; + } + if ( h * 3 < 2 ) { + return p + ( q - p ) * ( ( 2 / 3 ) - h ) * 6; + } + return p; +} + +spaces.hsla.to = function( rgba ) { + if ( rgba[ 0 ] == null || rgba[ 1 ] == null || rgba[ 2 ] == null ) { + return [ null, null, null, rgba[ 3 ] ]; + } + var r = rgba[ 0 ] / 255, + g = rgba[ 1 ] / 255, + b = rgba[ 2 ] / 255, + a = rgba[ 3 ], + max = Math.max( r, g, b ), + min = Math.min( r, g, b ), + diff = max - min, + add = max + min, + l = add * 0.5, + h, s; + + if ( min === max ) { + h = 0; + } else if ( r === max ) { + h = ( 60 * ( g - b ) / diff ) + 360; + } else if ( g === max ) { + h = ( 60 * ( b - r ) / diff ) + 120; + } else { + h = ( 60 * ( r - g ) / diff ) + 240; + } + + // chroma (diff) == 0 means greyscale which, by definition, saturation = 0% + // otherwise, saturation is based on the ratio of chroma (diff) to lightness (add) + if ( diff === 0 ) { + s = 0; + } else if ( l <= 0.5 ) { + s = diff / add; + } else { + s = diff / ( 2 - add ); + } + return [ Math.round( h ) % 360, s, l, a == null ? 1 : a ]; +}; + +spaces.hsla.from = function( hsla ) { + if ( hsla[ 0 ] == null || hsla[ 1 ] == null || hsla[ 2 ] == null ) { + return [ null, null, null, hsla[ 3 ] ]; + } + var h = hsla[ 0 ] / 360, + s = hsla[ 1 ], + l = hsla[ 2 ], + a = hsla[ 3 ], + q = l <= 0.5 ? l * ( 1 + s ) : l + s - l * s, + p = 2 * l - q; + + return [ + Math.round( hue2rgb( p, q, h + ( 1 / 3 ) ) * 255 ), + Math.round( hue2rgb( p, q, h ) * 255 ), + Math.round( hue2rgb( p, q, h - ( 1 / 3 ) ) * 255 ), + a + ]; +}; + + +each( spaces, function( spaceName, space ) { + var props = space.props, + cache = space.cache, + to = space.to, + from = space.from; + + // makes rgba() and hsla() + color.fn[ spaceName ] = function( value ) { + + // generate a cache for this space if it doesn't exist + if ( to && !this[ cache ] ) { + this[ cache ] = to( this._rgba ); + } + if ( value === undefined ) { + return this[ cache ].slice(); + } + + var ret, + type = getType( value ), + arr = ( type === "array" || type === "object" ) ? value : arguments, + local = this[ cache ].slice(); + + each( props, function( key, prop ) { + var val = arr[ type === "object" ? key : prop.idx ]; + if ( val == null ) { + val = local[ prop.idx ]; + } + local[ prop.idx ] = clamp( val, prop ); + } ); + + if ( from ) { + ret = color( from( local ) ); + ret[ cache ] = local; + return ret; + } else { + return color( local ); + } + }; + + // makes red() green() blue() alpha() hue() saturation() lightness() + each( props, function( key, prop ) { + + // alpha is included in more than one space + if ( color.fn[ key ] ) { + return; + } + color.fn[ key ] = function( value ) { + var local, cur, match, fn, + vtype = getType( value ); + + if ( key === "alpha" ) { + fn = this._hsla ? "hsla" : "rgba"; + } else { + fn = spaceName; + } + local = this[ fn ](); + cur = local[ prop.idx ]; + + if ( vtype === "undefined" ) { + return cur; + } + + if ( vtype === "function" ) { + value = value.call( this, cur ); + vtype = getType( value ); + } + if ( value == null && prop.empty ) { + return this; + } + if ( vtype === "string" ) { + match = rplusequals.exec( value ); + if ( match ) { + value = cur + parseFloat( match[ 2 ] ) * ( match[ 1 ] === "+" ? 1 : -1 ); + } + } + local[ prop.idx ] = value; + return this[ fn ]( local ); + }; + } ); +} ); + +// add cssHook and .fx.step function for each named hook. +// accept a space separated string of properties +color.hook = function( hook ) { + var hooks = hook.split( " " ); + each( hooks, function( _i, hook ) { + jQuery.cssHooks[ hook ] = { + set: function( elem, value ) { + var parsed; + + if ( value !== "transparent" && + ( getType( value ) !== "string" || + ( parsed = stringParse( value ) ) ) ) { + value = color( parsed || value ); + value = value.toRgbaString(); + } + elem.style[ hook ] = value; + } + }; + jQuery.fx.step[ hook ] = function( fx ) { + if ( !fx.colorInit ) { + fx.start = color( fx.elem, hook ); + fx.end = color( fx.end ); + fx.colorInit = true; + } + jQuery.cssHooks[ hook ].set( fx.elem, fx.start.transition( fx.end, fx.pos ) ); + }; + } ); + +}; + +color.hook( stepHooks ); + +jQuery.cssHooks.borderColor = { + expand: function( value ) { + var expanded = {}; + + each( [ "Top", "Right", "Bottom", "Left" ], function( _i, part ) { + expanded[ "border" + part + "Color" ] = value; + } ); + return expanded; + } +}; + +// Basic color names only. +// Usage of any of the other color names requires adding yourself or including +// jquery.color.svg-names.js. +colors = jQuery.Color.names = { + + // 4.1. Basic color keywords + aqua: "#00ffff", + black: "#000000", + blue: "#0000ff", + fuchsia: "#ff00ff", + gray: "#808080", + green: "#008000", + lime: "#00ff00", + maroon: "#800000", + navy: "#000080", + olive: "#808000", + purple: "#800080", + red: "#ff0000", + silver: "#c0c0c0", + teal: "#008080", + white: "#ffffff", + yellow: "#ffff00", + + // 4.2.3. "transparent" color keyword + transparent: [ null, null, null, 0 ], + + _default: "#ffffff" +}; + +} ); diff --git a/ui/version.js b/ui/version.js new file mode 100644 index 00000000000..1767ec7b518 --- /dev/null +++ b/ui/version.js @@ -0,0 +1,20 @@ +( function( factory ) { + "use strict"; + + if ( typeof define === "function" && define.amd ) { + + // AMD. Register as an anonymous module. + define( [ "jquery" ], factory ); + } else { + + // Browser globals + factory( jQuery ); + } +} )( function( $ ) { +"use strict"; + +$.ui = $.ui || {}; + +return $.ui.version = "@VERSION"; + +} ); diff --git a/ui/widget.js b/ui/widget.js new file mode 100644 index 00000000000..d5fbd885cf0 --- /dev/null +++ b/ui/widget.js @@ -0,0 +1,759 @@ +/*! + * jQuery UI Widget @VERSION + * https://jqueryui.com + * + * Copyright OpenJS Foundation and other contributors + * Released under the MIT license. + * https://jquery.org/license + */ + +//>>label: Widget +//>>group: Core +//>>description: Provides a factory for creating stateful widgets with a common API. +//>>docs: https://api.jqueryui.com/jQuery.widget/ +//>>demos: https://jqueryui.com/widget/ + +( function( factory ) { + "use strict"; + + if ( typeof define === "function" && define.amd ) { + + // AMD. Register as an anonymous module. + define( [ "jquery", "./version" ], factory ); + } else { + + // Browser globals + factory( jQuery ); + } +} )( function( $ ) { +"use strict"; + +var widgetUuid = 0; +var widgetHasOwnProperty = Array.prototype.hasOwnProperty; +var widgetSlice = Array.prototype.slice; + +$.cleanData = ( function( orig ) { + return function( elems ) { + var events, elem, i; + for ( i = 0; ( elem = elems[ i ] ) != null; i++ ) { + + // Only trigger remove when necessary to save time + events = $._data( elem, "events" ); + if ( events && events.remove ) { + $( elem ).triggerHandler( "remove" ); + } + } + orig( elems ); + }; +} )( $.cleanData ); + +$.widget = function( name, base, prototype ) { + var existingConstructor, constructor, basePrototype; + + // ProxiedPrototype allows the provided prototype to remain unmodified + // so that it can be used as a mixin for multiple widgets (#8876) + var proxiedPrototype = {}; + + var namespace = name.split( "." )[ 0 ]; + name = name.split( "." )[ 1 ]; + if ( name === "__proto__" || name === "constructor" ) { + return $.error( "Invalid widget name: " + name ); + } + var fullName = namespace + "-" + name; + + if ( !prototype ) { + prototype = base; + base = $.Widget; + } + + if ( Array.isArray( prototype ) ) { + prototype = $.extend.apply( null, [ {} ].concat( prototype ) ); + } + + // Create selector for plugin + $.expr.pseudos[ fullName.toLowerCase() ] = function( elem ) { + return !!$.data( elem, fullName ); + }; + + $[ namespace ] = $[ namespace ] || {}; + existingConstructor = $[ namespace ][ name ]; + constructor = $[ namespace ][ name ] = function( options, element ) { + + // Allow instantiation without "new" keyword + if ( !this || !this._createWidget ) { + return new constructor( options, element ); + } + + // Allow instantiation without initializing for simple inheritance + // must use "new" keyword (the code above always passes args) + if ( arguments.length ) { + this._createWidget( options, element ); + } + }; + + // Extend with the existing constructor to carry over any static properties + $.extend( constructor, existingConstructor, { + version: prototype.version, + + // Copy the object used to create the prototype in case we need to + // redefine the widget later + _proto: $.extend( {}, prototype ), + + // Track widgets that inherit from this widget in case this widget is + // redefined after a widget inherits from it + _childConstructors: [] + } ); + + basePrototype = new base(); + + // We need to make the options hash a property directly on the new instance + // otherwise we'll modify the options hash on the prototype that we're + // inheriting from + basePrototype.options = $.widget.extend( {}, basePrototype.options ); + $.each( prototype, function( prop, value ) { + if ( typeof value !== "function" ) { + proxiedPrototype[ prop ] = value; + return; + } + proxiedPrototype[ prop ] = ( function() { + function _super() { + return base.prototype[ prop ].apply( this, arguments ); + } + + function _superApply( args ) { + return base.prototype[ prop ].apply( this, args ); + } + + return function() { + var __super = this._super; + var __superApply = this._superApply; + var returnValue; + + this._super = _super; + this._superApply = _superApply; + + returnValue = value.apply( this, arguments ); + + this._super = __super; + this._superApply = __superApply; + + return returnValue; + }; + } )(); + } ); + constructor.prototype = $.widget.extend( basePrototype, { + + // TODO: remove support for widgetEventPrefix + // always use the name + a colon as the prefix, e.g., draggable:start + // don't prefix for widgets that aren't DOM-based + widgetEventPrefix: existingConstructor ? ( basePrototype.widgetEventPrefix || name ) : name + }, proxiedPrototype, { + constructor: constructor, + namespace: namespace, + widgetName: name, + widgetFullName: fullName + } ); + + // If this widget is being redefined then we need to find all widgets that + // are inheriting from it and redefine all of them so that they inherit from + // the new version of this widget. We're essentially trying to replace one + // level in the prototype chain. + if ( existingConstructor ) { + $.each( existingConstructor._childConstructors, function( i, child ) { + var childPrototype = child.prototype; + + // Redefine the child widget using the same prototype that was + // originally used, but inherit from the new version of the base + $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, + child._proto ); + } ); + + // Remove the list of existing child constructors from the old constructor + // so the old child constructors can be garbage collected + delete existingConstructor._childConstructors; + } else { + base._childConstructors.push( constructor ); + } + + $.widget.bridge( name, constructor ); + + return constructor; +}; + +$.widget.extend = function( target ) { + var input = widgetSlice.call( arguments, 1 ); + var inputIndex = 0; + var inputLength = input.length; + var key; + var value; + + for ( ; inputIndex < inputLength; inputIndex++ ) { + for ( key in input[ inputIndex ] ) { + value = input[ inputIndex ][ key ]; + if ( widgetHasOwnProperty.call( input[ inputIndex ], key ) && value !== undefined ) { + + // Clone objects + if ( $.isPlainObject( value ) ) { + target[ key ] = $.isPlainObject( target[ key ] ) ? + $.widget.extend( {}, target[ key ], value ) : + + // Don't extend strings, arrays, etc. with objects + $.widget.extend( {}, value ); + + // Copy everything else by reference + } else { + target[ key ] = value; + } + } + } + } + return target; +}; + +$.widget.bridge = function( name, object ) { + var fullName = object.prototype.widgetFullName || name; + $.fn[ name ] = function( options ) { + var isMethodCall = typeof options === "string"; + var args = widgetSlice.call( arguments, 1 ); + var returnValue = this; + + if ( isMethodCall ) { + + // If this is an empty collection, we need to have the instance method + // return undefined instead of the jQuery instance + if ( !this.length && options === "instance" ) { + returnValue = undefined; + } else { + this.each( function() { + var methodValue; + var instance = $.data( this, fullName ); + + if ( options === "instance" ) { + returnValue = instance; + return false; + } + + if ( !instance ) { + return $.error( "cannot call methods on " + name + + " prior to initialization; " + + "attempted to call method '" + options + "'" ); + } + + if ( typeof instance[ options ] !== "function" || + options.charAt( 0 ) === "_" ) { + return $.error( "no such method '" + options + "' for " + name + + " widget instance" ); + } + + methodValue = instance[ options ].apply( instance, args ); + + if ( methodValue !== instance && methodValue !== undefined ) { + returnValue = methodValue && methodValue.jquery ? + returnValue.pushStack( methodValue.get() ) : + methodValue; + return false; + } + } ); + } + } else { + + // Allow multiple hashes to be passed on init + if ( args.length ) { + options = $.widget.extend.apply( null, [ options ].concat( args ) ); + } + + this.each( function() { + var instance = $.data( this, fullName ); + if ( instance ) { + instance.option( options || {} ); + if ( instance._init ) { + instance._init(); + } + } else { + $.data( this, fullName, new object( options, this ) ); + } + } ); + } + + return returnValue; + }; +}; + +$.Widget = function( /* options, element */ ) {}; +$.Widget._childConstructors = []; + +$.Widget.prototype = { + widgetName: "widget", + widgetEventPrefix: "", + defaultElement: "
        ", + + options: { + classes: {}, + disabled: false, + + // Callbacks + create: null + }, + + _createWidget: function( options, element ) { + element = $( element || this.defaultElement || this )[ 0 ]; + this.element = $( element ); + this.uuid = widgetUuid++; + this.eventNamespace = "." + this.widgetName + this.uuid; + + this.bindings = $(); + this.hoverable = $(); + this.focusable = $(); + this.classesElementLookup = {}; + + if ( element !== this ) { + $.data( element, this.widgetFullName, this ); + this._on( true, this.element, { + remove: function( event ) { + if ( event.target === element ) { + this.destroy(); + } + } + } ); + this.document = $( element.style ? + + // Element within the document + element.ownerDocument : + + // Element is window or document + element.document || element ); + this.window = $( this.document[ 0 ].defaultView || this.document[ 0 ].parentWindow ); + } + + this.options = $.widget.extend( {}, + this.options, + this._getCreateOptions(), + options ); + + this._create(); + + if ( this.options.disabled ) { + this._setOptionDisabled( this.options.disabled ); + } + + this._trigger( "create", null, this._getCreateEventData() ); + this._init(); + }, + + _getCreateOptions: function() { + return {}; + }, + + _getCreateEventData: $.noop, + + _create: $.noop, + + _init: $.noop, + + destroy: function() { + var that = this; + + this._destroy(); + $.each( this.classesElementLookup, function( key, value ) { + that._removeClass( value, key ); + } ); + + // We can probably remove the unbind calls in 2.0 + // all event bindings should go through this._on() + this.element + .off( this.eventNamespace ) + .removeData( this.widgetFullName ); + this.widget() + .off( this.eventNamespace ) + .removeAttr( "aria-disabled" ); + + // Clean up events and states + this.bindings.off( this.eventNamespace ); + }, + + _destroy: $.noop, + + widget: function() { + return this.element; + }, + + option: function( key, value ) { + var options = key; + var parts; + var curOption; + var i; + + if ( arguments.length === 0 ) { + + // Don't return a reference to the internal hash + return $.widget.extend( {}, this.options ); + } + + if ( typeof key === "string" ) { + + // Handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } } + options = {}; + parts = key.split( "." ); + key = parts.shift(); + if ( parts.length ) { + curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] ); + for ( i = 0; i < parts.length - 1; i++ ) { + curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {}; + curOption = curOption[ parts[ i ] ]; + } + key = parts.pop(); + if ( arguments.length === 1 ) { + return curOption[ key ] === undefined ? null : curOption[ key ]; + } + curOption[ key ] = value; + } else { + if ( arguments.length === 1 ) { + return this.options[ key ] === undefined ? null : this.options[ key ]; + } + options[ key ] = value; + } + } + + this._setOptions( options ); + + return this; + }, + + _setOptions: function( options ) { + var key; + + for ( key in options ) { + this._setOption( key, options[ key ] ); + } + + return this; + }, + + _setOption: function( key, value ) { + if ( key === "classes" ) { + this._setOptionClasses( value ); + } + + this.options[ key ] = value; + + if ( key === "disabled" ) { + this._setOptionDisabled( value ); + } + + return this; + }, + + _setOptionClasses: function( value ) { + var classKey, elements, currentElements; + + for ( classKey in value ) { + currentElements = this.classesElementLookup[ classKey ]; + if ( value[ classKey ] === this.options.classes[ classKey ] || + !currentElements || + !currentElements.length ) { + continue; + } + + // We are doing this to create a new jQuery object because the _removeClass() call + // on the next line is going to destroy the reference to the current elements being + // tracked. We need to save a copy of this collection so that we can add the new classes + // below. + elements = $( currentElements.get() ); + this._removeClass( currentElements, classKey ); + + // We don't use _addClass() here, because that uses this.options.classes + // for generating the string of classes. We want to use the value passed in from + // _setOption(), this is the new value of the classes option which was passed to + // _setOption(). We pass this value directly to _classes(). + elements.addClass( this._classes( { + element: elements, + keys: classKey, + classes: value, + add: true + } ) ); + } + }, + + _setOptionDisabled: function( value ) { + this._toggleClass( this.widget(), this.widgetFullName + "-disabled", null, !!value ); + + // If the widget is becoming disabled, then nothing is interactive + if ( value ) { + this._removeClass( this.hoverable, null, "ui-state-hover" ); + this._removeClass( this.focusable, null, "ui-state-focus" ); + } + }, + + enable: function() { + return this._setOptions( { disabled: false } ); + }, + + disable: function() { + return this._setOptions( { disabled: true } ); + }, + + _classes: function( options ) { + var full = []; + var that = this; + + options = $.extend( { + element: this.element, + classes: this.options.classes || {} + }, options ); + + function bindRemoveEvent() { + var nodesToBind = []; + + options.element.each( function( _, element ) { + var isTracked = $.map( that.classesElementLookup, function( elements ) { + return elements; + } ) + .some( function( elements ) { + return elements.is( element ); + } ); + + if ( !isTracked ) { + nodesToBind.push( element ); + } + } ); + + that._on( $( nodesToBind ), { + remove: "_untrackClassesElement" + } ); + } + + function processClassString( classes, checkOption ) { + var current, i; + for ( i = 0; i < classes.length; i++ ) { + current = that.classesElementLookup[ classes[ i ] ] || $(); + if ( options.add ) { + bindRemoveEvent(); + current = $( $.uniqueSort( current.get().concat( options.element.get() ) ) ); + } else { + current = $( current.not( options.element ).get() ); + } + that.classesElementLookup[ classes[ i ] ] = current; + full.push( classes[ i ] ); + if ( checkOption && options.classes[ classes[ i ] ] ) { + full.push( options.classes[ classes[ i ] ] ); + } + } + } + + if ( options.keys ) { + processClassString( options.keys.match( /\S+/g ) || [], true ); + } + if ( options.extra ) { + processClassString( options.extra.match( /\S+/g ) || [] ); + } + + return full.join( " " ); + }, + + _untrackClassesElement: function( event ) { + var that = this; + $.each( that.classesElementLookup, function( key, value ) { + if ( $.inArray( event.target, value ) !== -1 ) { + that.classesElementLookup[ key ] = $( value.not( event.target ).get() ); + } + } ); + + this._off( $( event.target ) ); + }, + + _removeClass: function( element, keys, extra ) { + return this._toggleClass( element, keys, extra, false ); + }, + + _addClass: function( element, keys, extra ) { + return this._toggleClass( element, keys, extra, true ); + }, + + _toggleClass: function( element, keys, extra, add ) { + add = ( typeof add === "boolean" ) ? add : extra; + var shift = ( typeof element === "string" || element === null ), + options = { + extra: shift ? keys : extra, + keys: shift ? element : keys, + element: shift ? this.element : element, + add: add + }; + options.element.toggleClass( this._classes( options ), add ); + return this; + }, + + _on: function( suppressDisabledCheck, element, handlers ) { + var delegateElement; + var instance = this; + + // No suppressDisabledCheck flag, shuffle arguments + if ( typeof suppressDisabledCheck !== "boolean" ) { + handlers = element; + element = suppressDisabledCheck; + suppressDisabledCheck = false; + } + + // No element argument, shuffle and use this.element + if ( !handlers ) { + handlers = element; + element = this.element; + delegateElement = this.widget(); + } else { + element = delegateElement = $( element ); + this.bindings = this.bindings.add( element ); + } + + $.each( handlers, function( event, handler ) { + function handlerProxy() { + + // Allow widgets to customize the disabled handling + // - disabled as an array instead of boolean + // - disabled class as method for disabling individual parts + if ( !suppressDisabledCheck && + ( instance.options.disabled === true || + $( this ).hasClass( "ui-state-disabled" ) ) ) { + return; + } + return ( typeof handler === "string" ? instance[ handler ] : handler ) + .apply( instance, arguments ); + } + + // Copy the guid so direct unbinding works + if ( typeof handler !== "string" ) { + handlerProxy.guid = handler.guid = + handler.guid || handlerProxy.guid || $.guid++; + } + + var match = event.match( /^([\w:-]*)\s*(.*)$/ ); + var eventName = match[ 1 ] + instance.eventNamespace; + var selector = match[ 2 ]; + + if ( selector ) { + delegateElement.on( eventName, selector, handlerProxy ); + } else { + element.on( eventName, handlerProxy ); + } + } ); + }, + + _off: function( element, eventName ) { + eventName = ( eventName || "" ).split( " " ).join( this.eventNamespace + " " ) + + this.eventNamespace; + element.off( eventName ); + + // Clear the stack to avoid memory leaks (#10056) + this.bindings = $( this.bindings.not( element ).get() ); + this.focusable = $( this.focusable.not( element ).get() ); + this.hoverable = $( this.hoverable.not( element ).get() ); + }, + + _delay: function( handler, delay ) { + function handlerProxy() { + return ( typeof handler === "string" ? instance[ handler ] : handler ) + .apply( instance, arguments ); + } + var instance = this; + return setTimeout( handlerProxy, delay || 0 ); + }, + + _hoverable: function( element ) { + this.hoverable = this.hoverable.add( element ); + this._on( element, { + mouseenter: function( event ) { + this._addClass( $( event.currentTarget ), null, "ui-state-hover" ); + }, + mouseleave: function( event ) { + this._removeClass( $( event.currentTarget ), null, "ui-state-hover" ); + } + } ); + }, + + _focusable: function( element ) { + this.focusable = this.focusable.add( element ); + this._on( element, { + focusin: function( event ) { + this._addClass( $( event.currentTarget ), null, "ui-state-focus" ); + }, + focusout: function( event ) { + this._removeClass( $( event.currentTarget ), null, "ui-state-focus" ); + } + } ); + }, + + _trigger: function( type, event, data ) { + var prop, orig; + var callback = this.options[ type ]; + + data = data || {}; + event = $.Event( event ); + event.type = ( type === this.widgetEventPrefix ? + type : + this.widgetEventPrefix + type ).toLowerCase(); + + // The original event may come from any element + // so we need to reset the target on the new event + event.target = this.element[ 0 ]; + + // Copy original event properties over to the new event + orig = event.originalEvent; + if ( orig ) { + for ( prop in orig ) { + if ( !( prop in event ) ) { + event[ prop ] = orig[ prop ]; + } + } + } + + this.element.trigger( event, data ); + return !( typeof callback === "function" && + callback.apply( this.element[ 0 ], [ event ].concat( data ) ) === false || + event.isDefaultPrevented() ); + } +}; + +$.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) { + $.Widget.prototype[ "_" + method ] = function( element, options, callback ) { + if ( typeof options === "string" ) { + options = { effect: options }; + } + + var hasOptions; + var effectName = !options ? + method : + options === true || typeof options === "number" ? + defaultEffect : + options.effect || defaultEffect; + + options = options || {}; + if ( typeof options === "number" ) { + options = { duration: options }; + } else if ( options === true ) { + options = {}; + } + + hasOptions = !$.isEmptyObject( options ); + options.complete = callback; + + if ( options.delay ) { + element.delay( options.delay ); + } + + if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) { + element[ method ]( options ); + } else if ( effectName !== method && element[ effectName ] ) { + element[ effectName ]( options.duration, options.easing, callback ); + } else { + element.queue( function( next ) { + $( this )[ method ](); + if ( callback ) { + callback.call( element[ 0 ] ); + } + next(); + } ); + } + }; +} ); + +return $.widget; + +} ); diff --git a/ui/widgets/accordion.js b/ui/widgets/accordion.js new file mode 100644 index 00000000000..43a50db8319 --- /dev/null +++ b/ui/widgets/accordion.js @@ -0,0 +1,620 @@ +/*! + * jQuery UI Accordion @VERSION + * https://jqueryui.com + * + * Copyright OpenJS Foundation and other contributors + * Released under the MIT license. + * https://jquery.org/license + */ + +//>>label: Accordion +//>>group: Widgets +//>>description: Displays collapsible content panels for presenting information in a limited amount of space. +//>>docs: https://api.jqueryui.com/accordion/ +//>>demos: https://jqueryui.com/accordion/ +//>>css.structure: ../../themes/base/core.css +//>>css.structure: ../../themes/base/accordion.css +//>>css.theme: ../../themes/base/theme.css + +( function( factory ) { + "use strict"; + + if ( typeof define === "function" && define.amd ) { + + // AMD. Register as an anonymous module. + define( [ + "jquery", + "../version", + "../keycode", + "../unique-id", + "../widget" + ], factory ); + } else { + + // Browser globals + factory( jQuery ); + } +} )( function( $ ) { +"use strict"; + +return $.widget( "ui.accordion", { + version: "@VERSION", + options: { + active: 0, + animate: {}, + classes: { + "ui-accordion-header": "ui-corner-top", + "ui-accordion-header-collapsed": "ui-corner-all", + "ui-accordion-content": "ui-corner-bottom" + }, + collapsible: false, + event: "click", + header: function( elem ) { + return elem + .find( "> li > :first-child" ) + .add( + elem.find( "> :not(li)" ) + + // Support: jQuery <3.5 only + // We could use `.even()` but that's unavailable in older jQuery. + .filter( function( i ) { + return i % 2 === 0; + } ) + ); + }, + heightStyle: "auto", + icons: { + activeHeader: "ui-icon-triangle-1-s", + header: "ui-icon-triangle-1-e" + }, + + // Callbacks + activate: null, + beforeActivate: null + }, + + hideProps: { + borderTopWidth: "hide", + borderBottomWidth: "hide", + paddingTop: "hide", + paddingBottom: "hide", + height: "hide" + }, + + showProps: { + borderTopWidth: "show", + borderBottomWidth: "show", + paddingTop: "show", + paddingBottom: "show", + height: "show" + }, + + _create: function() { + var options = this.options; + + this.prevShow = this.prevHide = $(); + this._addClass( "ui-accordion", "ui-widget ui-helper-reset" ); + this.element.attr( "role", "tablist" ); + + // Don't allow collapsible: false and active: false / null + if ( !options.collapsible && ( options.active === false || options.active == null ) ) { + options.active = 0; + } + + this._processPanels(); + + // handle negative values + if ( options.active < 0 ) { + options.active += this.headers.length; + } + this._refresh(); + }, + + _getCreateEventData: function() { + return { + header: this.active, + panel: !this.active.length ? $() : this.active.next() + }; + }, + + _createIcons: function() { + var icon, children, + icons = this.options.icons; + + if ( icons ) { + icon = $( "" ); + this._addClass( icon, "ui-accordion-header-icon", "ui-icon " + icons.header ); + icon.prependTo( this.headers ); + children = this.active.children( ".ui-accordion-header-icon" ); + this._removeClass( children, icons.header ) + ._addClass( children, null, icons.activeHeader ) + ._addClass( this.headers, "ui-accordion-icons" ); + } + }, + + _destroyIcons: function() { + this._removeClass( this.headers, "ui-accordion-icons" ); + this.headers.children( ".ui-accordion-header-icon" ).remove(); + }, + + _destroy: function() { + var contents; + + // Clean up main element + this.element.removeAttr( "role" ); + + // Clean up headers + this.headers + .removeAttr( "role aria-expanded aria-selected aria-controls tabIndex" ) + .removeUniqueId(); + + this._destroyIcons(); + + // Clean up content panels + contents = this.headers.next() + .css( "display", "" ) + .removeAttr( "role aria-hidden aria-labelledby" ) + .removeUniqueId(); + + if ( this.options.heightStyle !== "content" ) { + contents.css( "height", "" ); + } + }, + + _setOption: function( key, value ) { + if ( key === "active" ) { + + // _activate() will handle invalid values and update this.options + this._activate( value ); + return; + } + + if ( key === "event" ) { + if ( this.options.event ) { + this._off( this.headers, this.options.event ); + } + this._setupEvents( value ); + } + + this._super( key, value ); + + // Setting collapsible: false while collapsed; open first panel + if ( key === "collapsible" && !value && this.options.active === false ) { + this._activate( 0 ); + } + + if ( key === "icons" ) { + this._destroyIcons(); + if ( value ) { + this._createIcons(); + } + } + }, + + _setOptionDisabled: function( value ) { + this._super( value ); + + this.element.attr( "aria-disabled", value ); + this._toggleClass( null, "ui-state-disabled", !!value ); + }, + + _keydown: function( event ) { + if ( event.altKey || event.ctrlKey ) { + return; + } + + var keyCode = $.ui.keyCode, + length = this.headers.length, + currentIndex = this.headers.index( event.target ), + toFocus = false; + + switch ( event.keyCode ) { + case keyCode.RIGHT: + case keyCode.DOWN: + toFocus = this.headers[ ( currentIndex + 1 ) % length ]; + break; + case keyCode.LEFT: + case keyCode.UP: + toFocus = this.headers[ ( currentIndex - 1 + length ) % length ]; + break; + case keyCode.SPACE: + case keyCode.ENTER: + this._eventHandler( event ); + break; + case keyCode.HOME: + toFocus = this.headers[ 0 ]; + break; + case keyCode.END: + toFocus = this.headers[ length - 1 ]; + break; + } + + if ( toFocus ) { + $( event.target ).attr( "tabIndex", -1 ); + $( toFocus ).attr( "tabIndex", 0 ); + $( toFocus ).trigger( "focus" ); + event.preventDefault(); + } + }, + + _panelKeyDown: function( event ) { + if ( event.keyCode === $.ui.keyCode.UP && event.ctrlKey ) { + $( event.currentTarget ).prev().trigger( "focus" ); + } + }, + + refresh: function() { + var options = this.options; + this._processPanels(); + + // Was collapsed or no panel + if ( ( options.active === false && options.collapsible === true ) || + !this.headers.length ) { + options.active = false; + this.active = $(); + + // active false only when collapsible is true + } else if ( options.active === false ) { + this._activate( 0 ); + + // was active, but active panel is gone + } else if ( this.active.length && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) { + + // all remaining panel are disabled + if ( this.headers.length === this.headers.find( ".ui-state-disabled" ).length ) { + options.active = false; + this.active = $(); + + // activate previous panel + } else { + this._activate( Math.max( 0, options.active - 1 ) ); + } + + // was active, active panel still exists + } else { + + // make sure active index is correct + options.active = this.headers.index( this.active ); + } + + this._destroyIcons(); + + this._refresh(); + }, + + _processPanels: function() { + var prevHeaders = this.headers, + prevPanels = this.panels; + + if ( typeof this.options.header === "function" ) { + this.headers = this.options.header( this.element ); + } else { + this.headers = this.element.find( this.options.header ); + } + this._addClass( this.headers, "ui-accordion-header ui-accordion-header-collapsed", + "ui-state-default" ); + + this.panels = this.headers.next().filter( ":not(.ui-accordion-content-active)" ).hide(); + this._addClass( this.panels, "ui-accordion-content", "ui-helper-reset ui-widget-content" ); + + // Avoid memory leaks (#10056) + if ( prevPanels ) { + this._off( prevHeaders.not( this.headers ) ); + this._off( prevPanels.not( this.panels ) ); + } + }, + + _refresh: function() { + var maxHeight, + options = this.options, + heightStyle = options.heightStyle, + parent = this.element.parent(); + + this.active = this._findActive( options.active ); + this._addClass( this.active, "ui-accordion-header-active", "ui-state-active" ) + ._removeClass( this.active, "ui-accordion-header-collapsed" ); + this._addClass( this.active.next(), "ui-accordion-content-active" ); + this.active.next().show(); + + this.headers + .attr( "role", "tab" ) + .each( function() { + var header = $( this ), + headerId = header.uniqueId().attr( "id" ), + panel = header.next(), + panelId = panel.uniqueId().attr( "id" ); + header.attr( "aria-controls", panelId ); + panel.attr( "aria-labelledby", headerId ); + } ) + .next() + .attr( "role", "tabpanel" ); + + this.headers + .not( this.active ) + .attr( { + "aria-selected": "false", + "aria-expanded": "false", + tabIndex: -1 + } ) + .next() + .attr( { + "aria-hidden": "true" + } ) + .hide(); + + // Make sure at least one header is in the tab order + if ( !this.active.length ) { + this.headers.eq( 0 ).attr( "tabIndex", 0 ); + } else { + this.active.attr( { + "aria-selected": "true", + "aria-expanded": "true", + tabIndex: 0 + } ) + .next() + .attr( { + "aria-hidden": "false" + } ); + } + + this._createIcons(); + + this._setupEvents( options.event ); + + if ( heightStyle === "fill" ) { + maxHeight = parent.height(); + this.element.siblings( ":visible" ).each( function() { + var elem = $( this ), + position = elem.css( "position" ); + + if ( position === "absolute" || position === "fixed" ) { + return; + } + maxHeight -= elem.outerHeight( true ); + } ); + + this.headers.each( function() { + maxHeight -= $( this ).outerHeight( true ); + } ); + + this.headers.next() + .each( function() { + $( this ).height( Math.max( 0, maxHeight - + $( this ).innerHeight() + $( this ).height() ) ); + } ) + .css( "overflow", "auto" ); + } else if ( heightStyle === "auto" ) { + maxHeight = 0; + this.headers.next() + .each( function() { + var isVisible = $( this ).is( ":visible" ); + if ( !isVisible ) { + $( this ).show(); + } + maxHeight = Math.max( maxHeight, $( this ).css( "height", "" ).height() ); + if ( !isVisible ) { + $( this ).hide(); + } + } ) + .height( maxHeight ); + } + }, + + _activate: function( index ) { + var active = this._findActive( index )[ 0 ]; + + // Trying to activate the already active panel + if ( active === this.active[ 0 ] ) { + return; + } + + // Trying to collapse, simulate a click on the currently active header + active = active || this.active[ 0 ]; + + this._eventHandler( { + target: active, + currentTarget: active, + preventDefault: $.noop + } ); + }, + + _findActive: function( selector ) { + return typeof selector === "number" ? this.headers.eq( selector ) : $(); + }, + + _setupEvents: function( event ) { + var events = { + keydown: "_keydown" + }; + if ( event ) { + $.each( event.split( " " ), function( index, eventName ) { + events[ eventName ] = "_eventHandler"; + } ); + } + + this._off( this.headers.add( this.headers.next() ) ); + this._on( this.headers, events ); + this._on( this.headers.next(), { keydown: "_panelKeyDown" } ); + this._hoverable( this.headers ); + this._focusable( this.headers ); + }, + + _eventHandler: function( event ) { + var activeChildren, clickedChildren, + options = this.options, + active = this.active, + clicked = $( event.currentTarget ), + clickedIsActive = clicked[ 0 ] === active[ 0 ], + collapsing = clickedIsActive && options.collapsible, + toShow = collapsing ? $() : clicked.next(), + toHide = active.next(), + eventData = { + oldHeader: active, + oldPanel: toHide, + newHeader: collapsing ? $() : clicked, + newPanel: toShow + }; + + event.preventDefault(); + + if ( + + // click on active header, but not collapsible + ( clickedIsActive && !options.collapsible ) || + + // allow canceling activation + ( this._trigger( "beforeActivate", event, eventData ) === false ) ) { + return; + } + + options.active = collapsing ? false : this.headers.index( clicked ); + + // When the call to ._toggle() comes after the class changes + // it causes a very odd bug in IE 8 (see #6720) + this.active = clickedIsActive ? $() : clicked; + this._toggle( eventData ); + + // Switch classes + // corner classes on the previously active header stay after the animation + this._removeClass( active, "ui-accordion-header-active", "ui-state-active" ); + if ( options.icons ) { + activeChildren = active.children( ".ui-accordion-header-icon" ); + this._removeClass( activeChildren, null, options.icons.activeHeader ) + ._addClass( activeChildren, null, options.icons.header ); + } + + if ( !clickedIsActive ) { + this._removeClass( clicked, "ui-accordion-header-collapsed" ) + ._addClass( clicked, "ui-accordion-header-active", "ui-state-active" ); + if ( options.icons ) { + clickedChildren = clicked.children( ".ui-accordion-header-icon" ); + this._removeClass( clickedChildren, null, options.icons.header ) + ._addClass( clickedChildren, null, options.icons.activeHeader ); + } + + this._addClass( clicked.next(), "ui-accordion-content-active" ); + } + }, + + _toggle: function( data ) { + var toShow = data.newPanel, + toHide = this.prevShow.length ? this.prevShow : data.oldPanel; + + // Handle activating a panel during the animation for another activation + this.prevShow.add( this.prevHide ).stop( true, true ); + this.prevShow = toShow; + this.prevHide = toHide; + + if ( this.options.animate ) { + this._animate( toShow, toHide, data ); + } else { + toHide.hide(); + toShow.show(); + this._toggleComplete( data ); + } + + toHide.attr( { + "aria-hidden": "true" + } ); + toHide.prev().attr( { + "aria-selected": "false", + "aria-expanded": "false" + } ); + + // if we're switching panels, remove the old header from the tab order + // if we're opening from collapsed state, remove the previous header from the tab order + // if we're collapsing, then keep the collapsing header in the tab order + if ( toShow.length && toHide.length ) { + toHide.prev().attr( { + "tabIndex": -1, + "aria-expanded": "false" + } ); + } else if ( toShow.length ) { + this.headers.filter( function() { + return parseInt( $( this ).attr( "tabIndex" ), 10 ) === 0; + } ) + .attr( "tabIndex", -1 ); + } + + toShow + .attr( "aria-hidden", "false" ) + .prev() + .attr( { + "aria-selected": "true", + "aria-expanded": "true", + tabIndex: 0 + } ); + }, + + _animate: function( toShow, toHide, data ) { + var total, easing, duration, + that = this, + adjust = 0, + boxSizing = toShow.css( "box-sizing" ), + down = toShow.length && + ( !toHide.length || ( toShow.index() < toHide.index() ) ), + animate = this.options.animate || {}, + options = down && animate.down || animate, + complete = function() { + that._toggleComplete( data ); + }; + + if ( typeof options === "number" ) { + duration = options; + } + if ( typeof options === "string" ) { + easing = options; + } + + // fall back from options to animation in case of partial down settings + easing = easing || options.easing || animate.easing; + duration = duration || options.duration || animate.duration; + + if ( !toHide.length ) { + return toShow.animate( this.showProps, duration, easing, complete ); + } + if ( !toShow.length ) { + return toHide.animate( this.hideProps, duration, easing, complete ); + } + + total = toShow.show().outerHeight(); + toHide.animate( this.hideProps, { + duration: duration, + easing: easing, + step: function( now, fx ) { + fx.now = Math.round( now ); + } + } ); + toShow + .hide() + .animate( this.showProps, { + duration: duration, + easing: easing, + complete: complete, + step: function( now, fx ) { + fx.now = Math.round( now ); + if ( fx.prop !== "height" ) { + if ( boxSizing === "content-box" ) { + adjust += fx.now; + } + } else if ( that.options.heightStyle !== "content" ) { + fx.now = Math.round( total - toHide.outerHeight() - adjust ); + adjust = 0; + } + } + } ); + }, + + _toggleComplete: function( data ) { + var toHide = data.oldPanel, + prev = toHide.prev(); + + this._removeClass( toHide, "ui-accordion-content-active" ); + this._removeClass( prev, "ui-accordion-header-active" ) + ._addClass( prev, "ui-accordion-header-collapsed" ); + + this._trigger( "activate", null, data ); + } +} ); + +} ); diff --git a/ui/widgets/autocomplete.js b/ui/widgets/autocomplete.js new file mode 100644 index 00000000000..57e59820c6f --- /dev/null +++ b/ui/widgets/autocomplete.js @@ -0,0 +1,640 @@ +/*! + * jQuery UI Autocomplete @VERSION + * https://jqueryui.com + * + * Copyright OpenJS Foundation and other contributors + * Released under the MIT license. + * https://jquery.org/license + */ + +//>>label: Autocomplete +//>>group: Widgets +//>>description: Lists suggested words as the user is typing. +//>>docs: https://api.jqueryui.com/autocomplete/ +//>>demos: https://jqueryui.com/autocomplete/ +//>>css.structure: ../../themes/base/core.css +//>>css.structure: ../../themes/base/autocomplete.css +//>>css.theme: ../../themes/base/theme.css + +( function( factory ) { + "use strict"; + + if ( typeof define === "function" && define.amd ) { + + // AMD. Register as an anonymous module. + define( [ + "jquery", + "./menu", + "../keycode", + "../position", + "../version", + "../widget" + ], factory ); + } else { + + // Browser globals + factory( jQuery ); + } +} )( function( $ ) { +"use strict"; + +$.widget( "ui.autocomplete", { + version: "@VERSION", + defaultElement: "", + options: { + appendTo: null, + autoFocus: false, + delay: 300, + minLength: 1, + position: { + my: "left top", + at: "left bottom", + collision: "none" + }, + source: null, + + // Callbacks + change: null, + close: null, + focus: null, + open: null, + response: null, + search: null, + select: null + }, + + requestIndex: 0, + pending: 0, + liveRegionTimer: null, + + _create: function() { + + // Some browsers only repeat keydown events, not keypress events, + // so we use the suppressKeyPress flag to determine if we've already + // handled the keydown event. #7269 + // Unfortunately the code for & in keypress is the same as the up arrow, + // so we use the suppressKeyPressRepeat flag to avoid handling keypress + // events when we know the keydown event was used to modify the + // search term. #7799 + var suppressKeyPress, suppressKeyPressRepeat, suppressInput, + nodeName = this.element[ 0 ].nodeName.toLowerCase(), + isTextarea = nodeName === "textarea", + isInput = nodeName === "input"; + + // Textareas are always multi-line + // Inputs are always single-line, even if inside a contentEditable element + // All other element types are determined by whether they're contentEditable + this.isMultiLine = isTextarea || + !isInput && this.element.prop( "contentEditable" ) === "true"; + + this.valueMethod = this.element[ isTextarea || isInput ? "val" : "text" ]; + this.isNewMenu = true; + + this._addClass( "ui-autocomplete-input" ); + this.element.attr( "autocomplete", "off" ); + + this._on( this.element, { + keydown: function( event ) { + if ( this.element.prop( "readOnly" ) ) { + suppressKeyPress = true; + suppressInput = true; + suppressKeyPressRepeat = true; + return; + } + + suppressKeyPress = false; + suppressInput = false; + suppressKeyPressRepeat = false; + var keyCode = $.ui.keyCode; + switch ( event.keyCode ) { + case keyCode.PAGE_UP: + suppressKeyPress = true; + this._move( "previousPage", event ); + break; + case keyCode.PAGE_DOWN: + suppressKeyPress = true; + this._move( "nextPage", event ); + break; + case keyCode.UP: + suppressKeyPress = true; + this._keyEvent( "previous", event ); + break; + case keyCode.DOWN: + suppressKeyPress = true; + this._keyEvent( "next", event ); + break; + case keyCode.ENTER: + + // when menu is open and has focus + if ( this.menu.active ) { + + // #6055 - Opera still allows the keypress to occur + // which causes forms to submit + suppressKeyPress = true; + event.preventDefault(); + this.menu.select( event ); + } + break; + case keyCode.TAB: + if ( this.menu.active ) { + this.menu.select( event ); + } + break; + case keyCode.ESCAPE: + if ( this.menu.element.is( ":visible" ) ) { + if ( !this.isMultiLine ) { + this._value( this.term ); + } + this.close( event ); + + // Different browsers have different default behavior for escape + // Single press can mean undo or clear + event.preventDefault(); + } + break; + default: + suppressKeyPressRepeat = true; + + // search timeout should be triggered before the input value is changed + this._searchTimeout( event ); + break; + } + }, + keypress: function( event ) { + if ( suppressKeyPress ) { + suppressKeyPress = false; + if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) { + event.preventDefault(); + } + return; + } + if ( suppressKeyPressRepeat ) { + return; + } + + // Replicate some key handlers to allow them to repeat in Firefox and Opera + var keyCode = $.ui.keyCode; + switch ( event.keyCode ) { + case keyCode.PAGE_UP: + this._move( "previousPage", event ); + break; + case keyCode.PAGE_DOWN: + this._move( "nextPage", event ); + break; + case keyCode.UP: + this._keyEvent( "previous", event ); + break; + case keyCode.DOWN: + this._keyEvent( "next", event ); + break; + } + }, + input: function( event ) { + if ( suppressInput ) { + suppressInput = false; + event.preventDefault(); + return; + } + this._searchTimeout( event ); + }, + focus: function() { + this.selectedItem = null; + this.previous = this._value(); + }, + blur: function( event ) { + clearTimeout( this.searching ); + this.close( event ); + this._change( event ); + } + } ); + + this._initSource(); + this.menu = $( "