From c7e424af9f630a9283447b773ac588965bb1dd3e Mon Sep 17 00:00:00 2001 From: Karl Hudgell Date: Thu, 28 Jan 2016 08:24:06 +0000 Subject: [PATCH 1/5] first grid push --- GRID/.bowerrc | 4 + GRID/.gitignore | 7 + GRID/CHANGELOG.md | 185 + GRID/CONTRIBUTING.md | 143 + GRID/Gruntfile.js | 183 + GRID/LICENSE | 19 + GRID/README.md | 50 + GRID/assets/demo.css | 69 + GRID/assets/gridster_new.js | 104 + GRID/assets/jquery.gridster.js | 3232 ++++++ GRID/assets/jquery.js | 9404 ++++++++++++++++++ GRID/dist/jquery.gridster.css | 121 + GRID/dist/jquery.gridster.js | 3987 ++++++++ GRID/dist/jquery.gridster.min.css | 2 + GRID/dist/jquery.gridster.min.js | 2 + GRID/dist/jquery.gridster.with-extras.js | 4163 ++++++++ GRID/dist/jquery.gridster.with-extras.min.js | 2 + GRID/grid.php | 46 + GRID/jquery.gridder.html | 46 + GRID/jquery.gridder_test.js | 38 + GRID/package.json | 41 + GRID/src/jquery.collision.js | 242 + GRID/src/jquery.coords.js | 125 + GRID/src/jquery.draggable.js | 432 + GRID/src/jquery.gridster.css | 117 + GRID/src/jquery.gridster.extras.js | 175 + GRID/src/jquery.gridster.js | 3140 ++++++ GRID/src/utils.js | 72 + Pic/sickrage.png | Bin 116971 -> 130497 bytes assets/css/demo.css | 69 + assets/css/grid.css | 69 + assets/css/jquery.gridster.css | 64 + assets/css/jquery.gridster.min.css | 3 + assets/css/styles.css | 60 + assets/gridster_new.js | 107 + assets/jquery.gridster.js | 3232 ++++++ assets/jquery.js | 9404 ++++++++++++++++++ feeds/kknowledgefeed.php | 5 +- feeds/webclipfeed.php | 2 +- grid.php | 60 + links/jdownloader.php | 20 +- links/transmission.php | 5 +- links/utorrent.php | 7 +- newtest.php | 160 + right.php | 2 +- robots.txt | 5 + 46 files changed, 39413 insertions(+), 12 deletions(-) create mode 100644 GRID/.bowerrc create mode 100644 GRID/.gitignore create mode 100644 GRID/CHANGELOG.md create mode 100644 GRID/CONTRIBUTING.md create mode 100644 GRID/Gruntfile.js create mode 100644 GRID/LICENSE create mode 100644 GRID/README.md create mode 100644 GRID/assets/demo.css create mode 100644 GRID/assets/gridster_new.js create mode 100644 GRID/assets/jquery.gridster.js create mode 100644 GRID/assets/jquery.js create mode 100644 GRID/dist/jquery.gridster.css create mode 100644 GRID/dist/jquery.gridster.js create mode 100644 GRID/dist/jquery.gridster.min.css create mode 100644 GRID/dist/jquery.gridster.min.js create mode 100644 GRID/dist/jquery.gridster.with-extras.js create mode 100644 GRID/dist/jquery.gridster.with-extras.min.js create mode 100644 GRID/grid.php create mode 100644 GRID/jquery.gridder.html create mode 100644 GRID/jquery.gridder_test.js create mode 100644 GRID/package.json create mode 100644 GRID/src/jquery.collision.js create mode 100644 GRID/src/jquery.coords.js create mode 100644 GRID/src/jquery.draggable.js create mode 100644 GRID/src/jquery.gridster.css create mode 100644 GRID/src/jquery.gridster.extras.js create mode 100644 GRID/src/jquery.gridster.js create mode 100644 GRID/src/utils.js create mode 100644 assets/css/demo.css create mode 100644 assets/css/grid.css create mode 100644 assets/css/jquery.gridster.css create mode 100644 assets/css/jquery.gridster.min.css create mode 100644 assets/css/styles.css create mode 100644 assets/gridster_new.js create mode 100644 assets/jquery.gridster.js create mode 100644 assets/jquery.js create mode 100644 grid.php create mode 100644 newtest.php create mode 100644 robots.txt diff --git a/GRID/.bowerrc b/GRID/.bowerrc new file mode 100644 index 0000000..a33fd7a --- /dev/null +++ b/GRID/.bowerrc @@ -0,0 +1,4 @@ +{ + "directory": "libs", + "json": "package.json" +} \ No newline at end of file diff --git a/GRID/.gitignore b/GRID/.gitignore new file mode 100644 index 0000000..440a178 --- /dev/null +++ b/GRID/.gitignore @@ -0,0 +1,7 @@ +node_modules/ +libs/ +gh-pages/ +demo/ +.idea +.DS_Store +.idea diff --git a/GRID/CHANGELOG.md b/GRID/CHANGELOG.md new file mode 100644 index 0000000..6d6f1a2 --- /dev/null +++ b/GRID/CHANGELOG.md @@ -0,0 +1,185 @@ + +### v0.5.6 (2014-09-25) + + +#### Bug Fixes + +* **draggable:** namespace events with unique ids ([79aff38c](http://github.com/ducksboard/gridster.js/commit/79aff38c60cc6ce2c0f0160bd3c6f93cb2511642)) + + +### v0.5.5 (2014-07-25) + + +#### Bug Fixes + +* **gridster:** fire `positionschanged` when widget orig position changes ([9926ceff](http://github.com/ducksboard/gridster.js/commit/9926ceff59cba49c71542e45aa095be35eb1df58)) + + +### v0.5.4 (2014-07-16) + + +#### Bug Fixes + +* **gridster:** serialize returns an Array object, not a jQuery object ([93df6cf6](http://github.com/ducksboard/gridster.js/commit/93df6cf6907fd0fb8787b3d068c9a9c467dcc020), closes [#394](http://github.com/ducksboard/gridster.js/issues/394)) + + +### v0.5.3 (2014-07-04) + + +#### Bug Fixes + +* **gridster:** + * custom `ignore_dragging` overwrites the default value ([6bcfa6e1](http://github.com/ducksboard/gridster.js/commit/6bcfa6e16e4a88cbb5efff1ce29308737884a89d)) + * sort widgets appropriately when reading them from DOM ([5c6d25cb](http://github.com/ducksboard/gridster.js/commit/5c6d25cbbe3de021806408f3cff6cb1e139c0a25)) + + +#### Features + +* make gridster AMD compatible ([589d7fd5](http://github.com/ducksboard/gridster.js/commit/589d7fd509a570fd02666c2f8231545211d6c83f)) +* **gridster:** move widget up when added if there is space available ([8ec307b6](http://github.com/ducksboard/gridster.js/commit/8ec307b6f7173e94610409adcb1671372cc2c67d)) + + +### v0.5.2 (2014-06-16) + + +#### Bug Fixes + +* **draggable:** + * handle both touch and click events ([021a6c23](http://github.com/ducksboard/gridster.js/commit/021a6c23e851210c1b817bd353a1e5e19ce10b90), closes [#207](http://github.com/ducksboard/gridster.js/issues/207), [#236](http://github.com/ducksboard/gridster.js/issues/236), [#329](http://github.com/ducksboard/gridster.js/issues/329), [#380](http://github.com/ducksboard/gridster.js/issues/380)) + * replaced scrollX/Y with scrollLeft/Top ([bb7463a3](http://github.com/ducksboard/gridster.js/commit/bb7463a3241750397492dfbac133cea193f0254f)) + * fix offset during drag ([c726c4ad](http://github.com/ducksboard/gridster.js/commit/c726c4ad9c18fea95e4b46b9bacd36c42aa9691c)) + * bind drag events to $document ([dd6c7420](http://github.com/ducksboard/gridster.js/commit/dd6c7420087d5810a9f6b02bf9d81a04a60ae840)) +* **gridster:** + * fix add_widget to use correct size_y when adding rows ([7d22e6c8](http://github.com/ducksboard/gridster.js/commit/7d22e6c8b201de33e33def77a93dc9009d0aa4cb)) + * Removing previously added style tags before adding new one. ([93c46ff4](http://github.com/ducksboard/gridster.js/commit/93c46ff45ebe59f3658b7f32f05b67109aa87311)) + + +#### Features + +* **draggable:** + * allow ignore_dragging config option to be a function ([69fcfe45](http://github.com/ducksboard/gridster.js/commit/69fcfe459678e833cb53de040b9fbc96dd687543)) + * option to not remove helper on drag stop ([03910df9](http://github.com/ducksboard/gridster.js/commit/03910df967a1ae7bcb2fa3aadd58255e0bcbf327)) + + +### v0.5.1 (2014-03-05) + + +#### Features + +* **collision:** overlapping region as a config option ([720d487e](http://github.com/ducksboard/gridster.js/commit/720d487e3988593e2c60909c88aaff13fbd4f842)) +* **coords:** + * allow both (left/x1) and (top/y1) attr keys ([6f22217f](http://github.com/ducksboard/gridster.js/commit/6f22217f056e4fc52f6405f2af49596105aae150)) + * add destroy method ([fdeee4f6](http://github.com/ducksboard/gridster.js/commit/fdeee4f636266c7a0579ced833f04fec013b6863)) +* **draggable:** keep container position prop if different than static ([04868a38](http://github.com/ducksboard/gridster.js/commit/04868a384d655d110f2d153d2fddb94b1c6d54a9)) +* **gridster:** destroy element's data and optionally remove from DOM ([dc09f191](http://github.com/ducksboard/gridster.js/commit/dc09f191d8503669cfa4737122c77cb0f5b9c3d2)) + + +## v0.5.0 (2014-02-14) + + +#### Bug Fixes + +* **autogrow:** refining autogrow_cols behavior and grid width issues ([835c2df8](http://github.com/ducksboard/gridster.js/commit/835c2df84419a92b1641b687fcf083f3ff102627)) +* **resize.stop:** Call resize.stop at the latest possible moment ([e21f63a0](http://github.com/ducksboard/gridster.js/commit/e21f63a05a539f5c611eb49cd6861b1e38b36531)) + + +#### Features + +* **draggable:** Add toggle draggable method. ([073fdc40](http://github.com/ducksboard/gridster.js/commit/073fdc40e0a94dd371646fc54cd420e3ddab0254)) + + +### v0.4.4 (2014-02-13) + + +#### Features + +* **resize:** add start/stop/resize event triggers ([7ca8deec](http://github.com/ducksboard/gridster.js/commit/7ca8deec8559d950097a6dc351cb0c6fcef3458d)) + + +### v0.4.3 (2014-02-11) + + +#### Bug Fixes + +* **generated-styles:** cleaning cached serializations properly ([f8b04f29](http://github.com/ducksboard/gridster.js/commit/f8b04f298e12e46ca9b07f0bae0abc6b08ed6e18)) + + +### v0.4.2 (2014-02-07) + + +#### Bug Fixes + +* recalculate grid width when adding widgets ([47745978](http://github.com/ducksboard/gridster.js/commit/4774597834300601fc81d5111a31a8c1672c55e1)) + + +### v0.4.1 (2014-02-07) + +#### Bug Fixes + +* add resize.min_size option to default config object ([5672edb0](http://github.com/ducksboard/gridster.js/commit/5672edb05e39c6b9ff5e3ca31d68c9e94dfaa617)) + + +## v0.4.0 (2014-02-07) + + +#### Bug Fixes + +* **gridster:** + * leaking options with multiple Gridster instances ([07c71097](http://github.com/ducksboard/gridster.js/commit/07c7109771094d98be51d68448a20e1d2987b35d)) + * resize.axes default option only 'both' ([62988780](http://github.com/ducksboard/gridster.js/commit/6298878077d5db129daa9780939fec5237b82af9)) +* **licenses:** add required copyright message for underscore ([b563c094](http://github.com/ducksboard/gridster.js/commit/b563c094cf0f3a5da2288492f95759ae32e8967c)) +* **readme:** link title jsfiddle -> jsbin, edit 5) of process steps ([0641aa89](http://github.com/ducksboard/gridster.js/commit/0641aa89833ecf9d167f7d8e89ee8bd5b4304248)) + + +#### Features + +* **draggable:** + * method to set drag limits dynamically ([d4482ec1](http://github.com/ducksboard/gridster.js/commit/d4482ec1476f8a0b6fb6cdeb25b7774ef678d81c)) + * support horizontal scrolling while dragging ([ae4921b7](http://github.com/ducksboard/gridster.js/commit/ae4921b70798944211267cacf8a89e62d0818369)) +* **gridster:** increase grid width when dragging or resizing ([37c4e943](http://github.com/ducksboard/gridster.js/commit/37c4e94358b9392710452b9e7f96454837bf9845)) +* **resize:** add option to set min_size of a widget ([ff511872](http://github.com/ducksboard/gridster.js/commit/ff511872e65992ee89bd2a88d862caaf99733f38)) + + +## v0.3.0 (2013-11-18) + + +#### Features + +* **draggable:** + * method to set drag limits dynamically ([d4482ec1](http://github.com/ducksboard/gridster.js/commit/d4482ec1476f8a0b6fb6cdeb25b7774ef678d81c)) + * support horizontal scrolling while dragging ([ae4921b7](http://github.com/ducksboard/gridster.js/commit/ae4921b70798944211267cacf8a89e62d0818369)) +* **gridster:** increase grid width when dragging or resizing ([b61df653](http://github.com/ducksboard/gridster.js/commit/b61df6535f728970fb8c6f25a208275dbde66550)) + + +### v0.2.1 (2013-10-28) + + +#### Features + +* **resize:** Add start/stop/resize callbacks ([d4ec7140](http://github.com/ducksboard/gridster.js/commit/d4ec7140f736bc30697c75b54ed3242ddf1d75b9)) + + +## v0.2.0 (2013-10-26) + + +#### Bug Fixes + +* fixes and improvements in widget-resizing. ([ae02b32b](http://github.com/ducksboard/gridster.js/commit/ae02b32b9210c6328f4acc339e215ae50c134f77), closes [#32](http://github.com/ducksboard/gridster.js/issues/32)) +* **gridster:** + * the preview holder should not always use `li` ([1ade74e2](http://github.com/ducksboard/gridster.js/commit/1ade74e239485b07e870fca44e1eafb3ff1ae283)) + * overlapping widget problem ([31fd8d6b](http://github.com/ducksboard/gridster.js/commit/31fd8d6ba893e4c39b91ba30d429e37f3da30b24)) + * Orphan preview holder when dragging is interrupted ([1b13617d](http://github.com/ducksboard/gridster.js/commit/1b13617df2ce53235bdf3a1e38f1555f529663c3)) + * remove_widget Returns the instance of the Gridster Class ([5bfbc5c0](http://github.com/ducksboard/gridster.js/commit/5bfbc5c0b5ab49c2a7c651327ce2e0f30f594985)) + + +#### Features + +* **draggable:** + * new config option to move or not the dragged element ([4d9b2a84](http://github.com/ducksboard/gridster.js/commit/4d9b2a84f11cb7cb2ddad51c158d92b82e7bc447)) + * CSS selectors support in `ignore_dragging` config opt ([0f956249](http://github.com/ducksboard/gridster.js/commit/0f95624925be97aee7a8450707e04e887e4dac58)) + * pass previous position to the drag callback ([055cc0e4](http://github.com/ducksboard/gridster.js/commit/055cc0e4f6f9de5721986515656ac894855f9e02)) + * Don't start new drag if previous one hasn't stopped ([91ca6572](http://github.com/ducksboard/gridster.js/commit/91ca65721c2eb32b5dec82cdc5e5e7f81dac329e)) + * pass useful data to all drag callbacks ([8dda2410](http://github.com/ducksboard/gridster.js/commit/8dda2410f300592706985c05141ca6b702977dc0)) +* **gridster:** drag-and-drop widget resizing ([e1924053](http://github.com/ducksboard/gridster.js/commit/e19240532de0bad35ffe6e5fc63934819390adc5)) +* **utils:** add delay helper to utils ([faa6c5db](http://github.com/ducksboard/gridster.js/commit/faa6c5db0002feccf681e9f919ed583eef152773)) + diff --git a/GRID/CONTRIBUTING.md b/GRID/CONTRIBUTING.md new file mode 100644 index 0000000..032a9fa --- /dev/null +++ b/GRID/CONTRIBUTING.md @@ -0,0 +1,143 @@ +# Contributing to this project + +Please take a moment to review this document in order to make the contribution +process easy and effective for everyone involved. + +Following these guidelines helps to communicate that you respect the time of +the developers managing and developing this open source project. In return, +they should reciprocate that respect in addressing your issue or assessing +patches and features. + + +## Using the issue tracker + +The issue tracker is the preferred channel for [bug reports](#bugs), +[features requests](#features) and [submitting pull +requests](#pull-requests), but please respect the following restrictions: + +* Please **do not** use the issue tracker for personal support requests (use + [Stack Overflow](http://stackoverflow.com)). + +* Please **do not** derail or troll issues. Keep the discussion on topic and + respect the opinions of others. + + + +## Bug reports + +A bug is a _demonstrable problem_ that is caused by the code in the repository. +Good bug reports are extremely helpful - thank you! + +Guidelines for bug reports: + +1. **Use the GitHub issue search** — check if the issue has already been + reported. + +2. **Check if the issue has been fixed** — try to reproduce it using the + latest `master` or development branch in the repository. + +3. **Isolate the problem** — ideally create a [reduced test + case](http://css-tricks.com/6263-reduced-test-cases/) and a live example (you can use something like [jsfiddle](http://jsfiddle.net/) or [jsbin](http://jsbin.com/)) . + +A good bug report shouldn't leave others needing to chase you up for more +information. Please try to be as detailed as possible in your report. What is +your environment? What steps will reproduce the issue? What browser(s) and OS +experience the problem? What would you expect to be the outcome? All these +details will help people to fix any potential bugs. + +Example: + +> Short and descriptive example bug report title +> +> A summary of the issue and the browser/OS environment in which it occurs. If +> suitable, include the steps required to reproduce the bug. +> +> 1. This is the first step +> 2. This is the second step +> 3. Further steps, etc. +> +> `` - a link to the reduced test case +> +> Any other information you want to share that is relevant to the issue being +> reported. This might include the lines of code that you have identified as +> causing the bug, and potential solutions (and your opinions on their +> merits). + + + +## Feature requests + +Feature requests are welcome. But take a moment to find out whether your idea +fits with the scope and aims of the project. It's up to *you* to make a strong +case to convince the project's developers of the merits of this feature. Please +provide as much detail and context as possible. + +**Please, use the GitHub issue search** to check if the feature has already been requested. + + + +## Pull requests + +Good pull requests - patches, improvements, new features - are a fantastic +help. They should remain focused in scope and avoid containing unrelated +commits. + +**Please ask first** before embarking on any significant pull request (e.g. +implementing features, refactoring code, porting to a different language), +otherwise you risk spending a lot of time working on something that the +project's developers might not want to merge into the project. + +Code must follow, mostly, these [coding conventions](http://javascript.crockford.com/code.html) . + +Adhering to the following this process is the best way to get your work +included in the project: + +1. [Fork](http://help.github.com/fork-a-repo/) the project, clone your fork, + and configure the remotes: + + ```bash + # Clone your fork of the repo into the current directory + git clone https://github.com//gridster.js + # Navigate to the newly cloned directory + cd gridster.js + # Assign the original repo to a remote called "upstream" + git remote add upstream https://github.com/ducksboard/gridster.js + ``` + +2. If you cloned a while ago, get the latest changes from upstream: + + ```bash + git checkout master + git pull upstream master + ``` + +3. Create a new topic branch (off the main project development branch) to + contain your feature, change, or fix: + + ```bash + git checkout -b + ``` + +4. Commit your changes in logical chunks. Please adhere to these [git commit + message guidelines](https://docs.google.com/document/d/1QrDFcIiPjSLDn3EL15IJygNPiHORgU1_OOAqWjiDU5Y) + or your code is unlikely be merged into the main project. Use Git's + [interactive rebase](https://help.github.com/articles/interactive-rebase) + feature to tidy up your commits before making them public. + +5. Merge or rebase the upstream development branch into your topic branch: + + ```bash + git pull --rebase upstream master + ``` + +6. Push your topic branch up to your fork: + + ```bash + git push origin + ``` + +7. [Open a Pull Request](https://help.github.com/articles/using-pull-requests/) + with a clear title and description. + +**IMPORTANT**: By submitting a patch, you agree to allow the project owner to +license your work under the same license as that used by the project. diff --git a/GRID/Gruntfile.js b/GRID/Gruntfile.js new file mode 100644 index 0000000..48be913 --- /dev/null +++ b/GRID/Gruntfile.js @@ -0,0 +1,183 @@ +/*global module:false*/ +module.exports = function(grunt) { + + // Project configuration. + grunt.initConfig({ + pkg: grunt.file.readJSON('package.json'), + meta: { + banner: '/*! <%= pkg.title || pkg.name %> - v<%= pkg.version %> - ' + + '<%= grunt.template.today("yyyy-mm-dd") %>\n' + + '<%= pkg.homepage ? "* " + pkg.homepage : "" %>\n' + + '* Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>;' + + ' Licensed <%= _.pluck(pkg.licenses, "type").join(", ") %> */\n\n', + + minibanner: '/*! <%= pkg.title || pkg.name %> - v<%= pkg.version %> - ' + + '<%= grunt.template.today("yyyy-mm-dd") %> - ' + + '<%= pkg.homepage ? "* " + pkg.homepage + " - " : "" %>' + + 'Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>;' + + ' Licensed <%= _.pluck(pkg.licenses, "type").join(", ") %> */ ' + }, + concat: { + options: { + stripBanners: true, + banner: '<%= meta.banner %>' + }, + dist_js: { + src: ['src/jquery.coords.js', 'src/jquery.collision.js', 'src/utils.js', 'src/jquery.draggable.js', 'src/jquery.<%= pkg.name %>.js'], + dest: 'dist/jquery.<%= pkg.name %>.js' + }, + + dist_extras_js: { + src: ['src/jquery.coords.js', 'src/jquery.collision.js', 'src/utils.js', 'src/jquery.draggable.js', 'src/jquery.<%= pkg.name %>.js', 'src/jquery.<%= pkg.name %>.extras.js'], + dest: 'dist/jquery.<%= pkg.name %>.with-extras.js' + }, + + dist_css: { + src: ['src/jquery.<%= pkg.name %>.css'], + dest: 'dist/jquery.<%= pkg.name %>.css' + }, + + dist_demo_js: { + src: ['src/jquery.coords.js', 'src/jquery.collision.js', 'src/utils.js', 'src/jquery.draggable.js', 'src/jquery.<%= pkg.name %>.js'], + dest: 'gh-pages/dist/jquery.<%= pkg.name %>.js' + }, + + dist_extras_demo_js: { + src: ['src/jquery.coords.js', 'src/jquery.collision.js', 'src/utils.js', 'src/jquery.draggable.js', 'src/jquery.<%= pkg.name %>.js', 'src/jquery.<%= pkg.name %>.extras.js'], + dest: 'gh-pages/dist/jquery.<%= pkg.name %>.with-extras.js' + }, + + dist_demo_css: { + src: ['src/jquery.<%= pkg.name %>.css'], + dest: 'gh-pages/dist/jquery.<%= pkg.name %>.css' + } + }, + uglify: { + options: { + banner: '<%= meta.minibanner %>' + }, + dist: { + files: { + 'dist/jquery.<%= pkg.name %>.min.js': ['<%= concat.dist_js.dest %>'] + } + }, + + dist_extras: { + files: { + 'dist/jquery.<%= pkg.name %>.with-extras.min.js': ['<%= concat.dist_extras_js.dest %>'] + } + }, + + dist_demo: { + files: { + 'gh-pages/dist/jquery.<%= pkg.name %>.min.js': ['<%= concat.dist_js.dest %>'], + } + }, + + dist_extras_demo: { + files: { + 'gh-pages/dist/jquery.<%= pkg.name %>.with-extras.min.js': ['<%= concat.dist_extras_js.dest %>'] + } + } + }, + cssmin: { + compress: { + options: { + keepSpecialComments: 0, + banner: '<%= meta.minibanner %>' + }, + files: { + "dist/jquery.<%= pkg.name %>.min.css": ["dist/jquery.<%= pkg.name %>.css"], + "gh-pages/dist/jquery.<%= pkg.name %>.min.css": ["dist/jquery.<%= pkg.name %>.css"] + } + } + }, + jshint: { + files: ['grunt.js', 'src/**/*.js', 'test/**/*.js'] + }, + watch: { + files: ['<%= lint.files %>', 'src/jquery.<%= pkg.name %>.css'], + tasks: 'min concat' + }, + jshint: { + options: { + curly: true, + eqeqeq: true, + immed: true, + latedef: true, + newcap: true, + noarg: true, + sub: true, + undef: true, + boss: true, + eqnull: true, + browser: true + }, + globals: { + jQuery: true + } + }, + yuidoc: { + compile: { + "name": 'gridster.js', + "description": 'gridster.js, a drag-and-drop multi-column jQuery grid plugin', + "version": '0.1.0', + "url": 'http://gridster.net/', + "logo": 'https://ducksboard.com/static/images/svg/logo-ducksboard-black-small.svg', + options: { + paths: "src/", + outdir: "gh-pages/docs/" + } + } + }, + + bump: { + options: { + files: ['package.json'], + updateConfigs: ['pkg'], + commit: true, + commitMessage: 'Release v%VERSION%', + commitFiles: ['package.json', 'CHANGELOG.md', 'dist/'], // '-a' for all files + createTag: true, + tagName: 'v%VERSION%', + tagMessage: 'Version %VERSION%', + push: false, + pushTo: 'origin', + gitDescribeOptions: '--tags --always --abbrev=1 --dirty=-d' // options to use with '$ git describe' + } + }, + + changelog: { + options: { + dest: 'CHANGELOG.md' + } + }, + + watch: { + files: ['libs/*.js', 'src/*.js', 'src/*.css', 'Gruntfile.js'], + tasks: ['concat', 'uglify', 'cssmin'] + } + }); + + + grunt.loadNpmTasks('grunt-contrib-watch'); + grunt.loadNpmTasks('grunt-contrib-jshint'); + grunt.loadNpmTasks('grunt-contrib-concat'); + grunt.loadNpmTasks('grunt-contrib-uglify'); + grunt.loadNpmTasks('grunt-contrib-cssmin'); + grunt.loadNpmTasks('grunt-contrib-yuidoc'); + grunt.loadNpmTasks('grunt-bump'); + grunt.loadNpmTasks('grunt-conventional-changelog'); + + // Default task. + grunt.registerTask('default', ['jshint', 'concat', 'uglify', 'cssmin']); + grunt.registerTask('build', ['default']); + grunt.registerTask('docs', ['yuidoc']); + + grunt.registerTask('release', ['build', 'bump-only:patch', 'build', 'docs', 'changelog']); + grunt.registerTask('release:minor', ['build', 'bump-only:minor', 'build', 'docs', 'changelog']); + grunt.registerTask('release:major', ['build', 'bump-only:major', 'build', 'docs', 'changelog']); + grunt.registerTask('release:git', ['build', 'bump-only:git', 'build', 'docs', 'changelog', 'bump-commit']); + grunt.registerTask('release:commit', ['bump-commit']); + +}; diff --git a/GRID/LICENSE b/GRID/LICENSE new file mode 100644 index 0000000..869f81f --- /dev/null +++ b/GRID/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2012 Ducksboard + +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/GRID/README.md b/GRID/README.md new file mode 100644 index 0000000..00eff37 --- /dev/null +++ b/GRID/README.md @@ -0,0 +1,50 @@ +Gridster.js +=========== + +[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/ducksboard/gridster.js/trend.png)](https://bitdeli.com/free "Bitdeli Badge") + +Gridster is a jQuery plugin that makes building intuitive draggable +layouts from elements spanning multiple columns. You can even +dynamically add and remove elements from the grid. + +More at [http://gridster.net/](http://gridster.net/). + +[Releases](https://github.com/ducksboard/gridster.js/releases) + +[CHANGELOG](https://github.com/ducksboard/gridster.js/blob/master/CHANGELOG.md) + +Gridster is maintained by Ducksboard occasionally but not actively. +@dustmoo and @pushmatrix have also write permissions as Gridster maintainers +they are. Thank you guys! + +## Forks + +Mr @dustmoo (maintainer of Gridster) has his own fork of gridster.js +with some new interesting features like widget-swapping and static widgets. + +Can be found here: [dustmoo/gridster.js](https://github.com/dustmoo/gridster.js) + +@dustmoo is working in his spare time to merge all these changes into +ducksboard/gridster.js + +If anyone would like to help @dustmoo improve his fork and reconcile +it with the main library he would be happy for the help. + + +## Contributing to this project + +Anyone and everyone is welcome to contribute. Please take a moment to review the guidelines for contributing. + +* [Bug reports](CONTRIBUTING.md#bugs) +* [Feature requests](CONTRIBUTING.md#features) +* [Pull requests](CONTRIBUTING.md#pull-requests) + + +## License + +Distributed under the MIT license. + +## Whodunit + +Gridster is built by [Ducksboard](http://ducksboard.com/) with the help of all +these [wonderful people](https://github.com/ducksboard/gridster.js/graphs/contributors). diff --git a/GRID/assets/demo.css b/GRID/assets/demo.css new file mode 100644 index 0000000..c64eef7 --- /dev/null +++ b/GRID/assets/demo.css @@ -0,0 +1,69 @@ +.gridster * { + margin:0; + padding:0; +} + +ul { + list-style-type: none; +} + + +/*/ +/* demo +/*/ + + +body { + font-size: 16px; + font-family: 'Helvetica Neue', Arial, sans-serif; + color: #444; + margin: 30px 40px; +} + +.controls { + margin-bottom: 20px; +} + +/*/ +/* gridster +/*/ + +.gridster ul { + background-color: #EFEFEF; +} + +.gridster li { + font-size: 1em; + font-weight: bold; + text-align: center; + line-height: 100%; +} + + +.gridster { + margin: 0 auto; + + opacity: .8; + + -webkit-transition: opacity .6s; + -moz-transition: opacity .6s; + -o-transition: opacity .6s; + -ms-transition: opacity .6s; + transition: opacity .6s; +} + +.gridster .gs-w { + background: #DDD; + cursor: pointer; +} + +.gridster .player { + background: #BBB; +} + + +.gridster .preview-holder { + border: none!important; + background: red!important; +} + diff --git a/GRID/assets/gridster_new.js b/GRID/assets/gridster_new.js new file mode 100644 index 0000000..c4a06af --- /dev/null +++ b/GRID/assets/gridster_new.js @@ -0,0 +1,104 @@ + + $(window).ready(function () { + var localData = JSON.parse(localStorage.getItem('positions')); + + if(localData!=null) + { + $.each(localData, function(i,value){ + + var id_name; + + id_name="#"; + id_name = id_name + value.id; + console.log(id_name); + + $(id_name).attr({"data-col":value.col, "data-row":value.row, "data-sizex":value.size_x, "data-sizey":value.size_y}); + + +}); + } + else{ + console.log('No data returned by the server'); + } + + + // widget_selector: "> ul" + // Define which elements are the widgets. Can be a CSS Selector string or a jQuery collection of HTMLElements. + + // widget_margins: [3, 3] + // Horizontal and vertical margins respectively for widgets. + + // widget_base_dimensions: [110, 110] + // Base widget dimensions in pixels. The first index is the width, the second is the height. + + var grid_canvas = $(".gridster > ul").gridster({ + widget_margins: [3, 3], + widget_base_dimensions: [110, 110], + + // serialize_params: function($w, wgd) { return { id: $($w).attr('id'),col: wgd.col, row: wgd.row,size_x: wgd.size_x,size_y: wgd.size_y } + // A function to return serialized data for each each widget, used when calling the serialize method. Two arguments are passed: + // $w: the jQuery wrapped HTMLElement which is used to get the id, and wgd: the grid coords object with keys col, row, size_x and size_y. + + + serialize_params: function($w, wgd) + { + return { + id: $($w).attr('id'), + col: wgd.col, + row: wgd.row, + size_x: wgd.size_x, + size_y: wgd.size_y, + + }; + }, + + // draggable.stop: function(event, ui){} -- A callback for when dragging stops. + // You can also implement other draggable options based on your requirements + // draggable.start: function(event, ui){} -- A callback for when dragging starts. + // draggable.drag: function(event, ui){} -- A callback for when the mouse is moved during the dragging. + + draggable: + { + stop: function(event, ui) { + + // .serialize( ) + // Creates an array of objects representing the current position of all widgets in the grid. + // Returns an Array of Objects (ready to be encoded as a JSON string) with the data specified by the serialize_params option + // JSON.stringify() converts a primitive value, object or array to a JSON-formatted string that can later be parsed with JSON.parse(). + + var positions = JSON.stringify(this.serialize()); + + // With HTML5, web pages can store data locally within the user's browser. + // Earlier, this was done with cookies. However, Web Storage is more secure and faster. + // The data is not included with every server request, but used ONLY when asked for. + // It is also possible to store large amounts of data, without affecting the website's performance. + // The data is stored in key/value pairs, and a web page can only access data stored by itself. + + localStorage.setItem('positions', positions); + + + $.post( + "process.php", + {"positions": positions}, + function(data) + { + + // this is where you can check if your data is sent to the server or not. + // A status of 200 implies success + + console.log(data); + if(data==200) + console.log("Data successfully sent to the server"); + else + console.log + } + ); + + } + } + }).data('gridster'); + + + +}); + \ No newline at end of file diff --git a/GRID/assets/jquery.gridster.js b/GRID/assets/jquery.gridster.js new file mode 100644 index 0000000..947f4bb --- /dev/null +++ b/GRID/assets/jquery.gridster.js @@ -0,0 +1,3232 @@ +/*! gridster.js - v0.1.0 - 2012-10-20 +* http://gridster.net/ +* Copyright (c) 2012 ducksboard; Licensed MIT */ + +;(function($, window, document, undefined){ + /** + * Creates objects with coordinates (x1, y1, x2, y2, cx, cy, width, height) + * to simulate DOM elements on the screen. + * Coords is used by Gridster to create a faux grid with any DOM element can + * collide. + * + * @class Coords + * @param {HTMLElement|Object} obj The jQuery HTMLElement or a object with: left, + * top, width and height properties. + * @return {Object} Coords instance. + * @constructor + */ + function Coords(obj) { + if (obj[0] && $.isPlainObject(obj[0])) { + this.data = obj[0]; + }else { + this.el = obj; + } + + this.isCoords = true; + this.coords = {}; + this.init(); + return this; + } + + + var fn = Coords.prototype; + + + fn.init = function(){ + this.set(); + this.original_coords = this.get(); + }; + + + fn.set = function(update, not_update_offsets) { + var el = this.el; + + if (el && !update) { + this.data = el.offset(); + this.data.width = el.width(); + this.data.height = el.height(); + } + + if (el && update && !not_update_offsets) { + var offset = el.offset(); + this.data.top = offset.top; + this.data.left = offset.left; + } + + var d = this.data; + + this.coords.x1 = d.left; + this.coords.y1 = d.top; + this.coords.x2 = d.left + d.width; + this.coords.y2 = d.top + d.height; + this.coords.cx = d.left + (d.width / 2); + this.coords.cy = d.top + (d.height / 2); + this.coords.width = d.width; + this.coords.height = d.height; + this.coords.el = el || false ; + + return this; + }; + + + fn.update = function(data){ + if (!data && !this.el) { + return this; + } + + if (data) { + var new_data = $.extend({}, this.data, data); + this.data = new_data; + return this.set(true, true); + } + + this.set(true); + return this; + }; + + + fn.get = function(){ + return this.coords; + }; + + + //jQuery adapter + $.fn.coords = function() { + if (this.data('coords') ) { + return this.data('coords'); + } + + var ins = new Coords(this, arguments[0]); + this.data('coords', ins); + return ins; + }; + +}(jQuery, window, document)); + +;(function($, window, document, undefined){ + + var defaults = { + colliders_context: document.body + // ,on_overlap: function(collider_data){}, + // on_overlap_start : function(collider_data){}, + // on_overlap_stop : function(collider_data){} + }; + + + /** + * Detects collisions between a DOM element against other DOM elements or + * Coords objects. + * + * @class Collision + * @uses Coords + * @param {HTMLElement} el The jQuery wrapped HTMLElement. + * @param {HTMLElement|Array} colliders Can be a jQuery collection + * of HTMLElements or an Array of Coords instances. + * @param {Object} [options] An Object with all options you want to + * overwrite: + * @param {Function} [options.on_overlap_start] Executes a function the first + * time each `collider ` is overlapped. + * @param {Function} [options.on_overlap_stop] Executes a function when a + * `collider` is no longer collided. + * @param {Function} [options.on_overlap] Executes a function when the + * mouse is moved during the collision. + * @return {Object} Collision instance. + * @constructor + */ + function Collision(el, colliders, options) { + this.options = $.extend(defaults, options); + this.$element = el; + this.last_colliders = []; + this.last_colliders_coords = []; + if (typeof colliders === 'string' || colliders instanceof jQuery) { + this.$colliders = $(colliders, + this.options.colliders_context).not(this.$element); + }else{ + this.colliders = $(colliders); + } + + this.init(); + } + + + var fn = Collision.prototype; + + + fn.init = function() { + this.find_collisions(); + }; + + + fn.overlaps = function(a, b) { + var x = false; + var y = false; + + if ((b.x1 >= a.x1 && b.x1 <= a.x2) || + (b.x2 >= a.x1 && b.x2 <= a.x2) || + (a.x1 >= b.x1 && a.x2 <= b.x2) + ) { x = true; } + + if ((b.y1 >= a.y1 && b.y1 <= a.y2) || + (b.y2 >= a.y1 && b.y2 <= a.y2) || + (a.y1 >= b.y1 && a.y2 <= b.y2) + ) { y = true; } + + return (x && y); + }; + + + fn.detect_overlapping_region = function(a, b){ + var regionX = ''; + var regionY = ''; + + if (a.y1 > b.cy && a.y1 < b.y2) { regionX = 'N'; } + if (a.y2 > b.y1 && a.y2 < b.cy) { regionX = 'S'; } + if (a.x1 > b.cx && a.x1 < b.x2) { regionY = 'W'; } + if (a.x2 > b.x1 && a.x2 < b.cx) { regionY = 'E'; } + + return (regionX + regionY) || 'C'; + }; + + + fn.calculate_overlapped_area_coords = function(a, b){ + var x1 = Math.max(a.x1, b.x1); + var y1 = Math.max(a.y1, b.y1); + var x2 = Math.min(a.x2, b.x2); + var y2 = Math.min(a.y2, b.y2); + + return $({ + left: x1, + top: y1, + width : (x2 - x1), + height: (y2 - y1) + }).coords().get(); + }; + + + fn.calculate_overlapped_area = function(coords){ + return (coords.width * coords.height); + }; + + + fn.manage_colliders_start_stop = function(new_colliders_coords, start_callback, stop_callback){ + var last = this.last_colliders_coords; + + for (var i = 0, il = last.length; i < il; i++) { + if ($.inArray(last[i], new_colliders_coords) === -1) { + start_callback.call(this, last[i]); + } + } + + for (var j = 0, jl = new_colliders_coords.length; j < jl; j++) { + if ($.inArray(new_colliders_coords[j], last) === -1) { + stop_callback.call(this, new_colliders_coords[j]); + } + + } + }; + + + fn.find_collisions = function(player_data_coords){ + var self = this; + var colliders_coords = []; + var colliders_data = []; + var $colliders = (this.colliders || this.$colliders); + var count = $colliders.length; + var player_coords = self.$element.coords() + .update(player_data_coords || false).get(); + + while(count--){ + var $collider = self.$colliders ? + $($colliders[count]) : $colliders[count]; + var $collider_coords_ins = ($collider.isCoords) ? + $collider : $collider.coords(); + var collider_coords = $collider_coords_ins.get(); + var overlaps = self.overlaps(player_coords, collider_coords); + + if (!overlaps) { + continue; + } + + var region = self.detect_overlapping_region( + player_coords, collider_coords); + + //todo: make this an option + if (region === 'C'){ + var area_coords = self.calculate_overlapped_area_coords( + player_coords, collider_coords); + var area = self.calculate_overlapped_area(area_coords); + var collider_data = { + area: area, + area_coords : area_coords, + region: region, + coords: collider_coords, + player_coords: player_coords, + el: $collider + }; + + if (self.options.on_overlap) { + self.options.on_overlap.call(this, collider_data); + } + colliders_coords.push($collider_coords_ins); + colliders_data.push(collider_data); + } + } + + if (self.options.on_overlap_stop || self.options.on_overlap_start) { + this.manage_colliders_start_stop(colliders_coords, + self.options.on_overlap_stop, self.options.on_overlap_start); + } + + this.last_colliders_coords = colliders_coords; + + return colliders_data; + }; + + + fn.get_closest_colliders = function(player_data_coords){ + var colliders = this.find_collisions(player_data_coords); + + colliders.sort(function(a, b) { + /* if colliders are being overlapped by the "C" (center) region, + * we have to set a lower index in the array to which they are placed + * above in the grid. */ + if (a.region === 'C' && b.region === 'C') { + if (a.coords.y1 < b.coords.y1 || a.coords.x1 < b.coords.x1) { + return - 1; + }else{ + return 1; + } + } + + if (a.area < b.area) { + return 1; + } + + return 1; + }); + return colliders; + }; + + + //jQuery adapter + $.fn.collision = function(collider, options) { + return new Collision( this, collider, options ); + }; + + +}(jQuery, window, document)); + +;(function(window, undefined) { + /* Debounce and throttle functions taken from underscore.js */ + window.debounce = function(func, wait, immediate) { + var timeout; + return function() { + var context = this, args = arguments; + var later = function() { + timeout = null; + if (!immediate) func.apply(context, args); + }; + if (immediate && !timeout) func.apply(context, args); + clearTimeout(timeout); + timeout = setTimeout(later, wait); + }; + }; + + + window.throttle = function(func, wait) { + var context, args, timeout, throttling, more, result; + var whenDone = debounce( + function(){ more = throttling = false; }, wait); + return function() { + context = this; args = arguments; + var later = function() { + timeout = null; + if (more) func.apply(context, args); + whenDone(); + }; + if (!timeout) timeout = setTimeout(later, wait); + if (throttling) { + more = true; + } else { + result = func.apply(context, args); + } + whenDone(); + throttling = true; + return result; + }; + }; + +})(window); + +;(function($, window, document, undefined){ + + var defaults = { + items: '.gs_w', + distance: 1, + limit: true, + offset_left: 0, + autoscroll: true, + ignore_dragging: ['INPUT', 'TEXTAREA', 'SELECT', 'BUTTON'], + handle: null + // ,drag: function(e){}, + // start : function(e, ui){}, + // stop : function(e){} + }; + + var $window = $(window); + var isTouch = !!('ontouchstart' in window); + var pointer_events = { + start: isTouch ? 'touchstart' : 'mousedown.draggable', + move: isTouch ? 'touchmove' : 'mousemove.draggable', + end: isTouch ? 'touchend' : 'mouseup.draggable' + }; + + /** + * Basic drag implementation for DOM elements inside a container. + * Provide start/stop/drag callbacks. + * + * @class Draggable + * @param {HTMLElement} el The HTMLelement that contains all the widgets + * to be dragged. + * @param {Object} [options] An Object with all options you want to + * overwrite: + * @param {HTMLElement|String} [options.items] Define who will + * be the draggable items. Can be a CSS Selector String or a + * collection of HTMLElements. + * @param {Number} [options.distance] Distance in pixels after mousedown + * the mouse must move before dragging should start. + * @param {Boolean} [options.limit] Constrains dragging to the width of + * the container + * @param {offset_left} [options.offset_left] Offset added to the item + * that is being dragged. + * @param {Number} [options.drag] Executes a callback when the mouse is + * moved during the dragging. + * @param {Number} [options.start] Executes a callback when the drag + * starts. + * @param {Number} [options.stop] Executes a callback when the drag stops. + * @return {Object} Returns `el`. + * @constructor + */ + function Draggable(el, options) { + this.options = $.extend({}, defaults, options); + this.$body = $(document.body); + this.$container = $(el); + this.$dragitems = $(this.options.items, this.$container); + this.is_dragging = false; + this.player_min_left = 0 + this.options.offset_left; + this.init(); + } + + var fn = Draggable.prototype; + + fn.init = function() { + this.calculate_positions(); + this.$container.css('position', 'relative'); + this.disabled = false; + this.events(); + + $(window).bind('resize', + throttle($.proxy(this.calculate_positions, this), 200)); + }; + + fn.events = function() { + this.$container.on('selectstart', $.proxy(this.on_select_start, this)); + + this.$container.on(pointer_events.start, this.options.items, $.proxy( + this.drag_handler, this)); + + this.$body.on(pointer_events.end, $.proxy(function(e) { + this.is_dragging = false; + if (this.disabled) { return; } + this.$body.off(pointer_events.move); + if (this.drag_start) { + this.on_dragstop(e); + } + }, this)); + }; + + fn.get_actual_pos = function($el) { + var pos = $el.position(); + return pos; + }; + + + fn.get_mouse_pos = function(e) { + if (isTouch) { + var oe = e.originalEvent; + e = oe.touches.length ? oe.touches[0] : oe.changedTouches[0]; + } + + return { + left: e.clientX, + top: e.clientY + }; + }; + + + fn.get_offset = function(e) { + e.preventDefault(); + var mouse_actual_pos = this.get_mouse_pos(e); + var diff_x = Math.round( + mouse_actual_pos.left - this.mouse_init_pos.left); + var diff_y = Math.round(mouse_actual_pos.top - this.mouse_init_pos.top); + + var left = Math.round(this.el_init_offset.left + diff_x - this.baseX); + var top = Math.round( + this.el_init_offset.top + diff_y - this.baseY + this.scrollOffset); + + if (this.options.limit) { + if (left > this.player_max_left) { + left = this.player_max_left; + }else if(left < this.player_min_left) { + left = this.player_min_left; + } + } + + return { + left: left, + top: top, + mouse_left: mouse_actual_pos.left, + mouse_top: mouse_actual_pos.top + }; + }; + + + fn.manage_scroll = function(offset) { + /* scroll document */ + var nextScrollTop; + var scrollTop = $window.scrollTop(); + var min_window_y = scrollTop; + var max_window_y = min_window_y + this.window_height; + + var mouse_down_zone = max_window_y - 50; + var mouse_up_zone = min_window_y + 50; + + var abs_mouse_left = offset.mouse_left; + var abs_mouse_top = min_window_y + offset.mouse_top; + + var max_player_y = (this.doc_height - this.window_height + + this.player_height); + + if (abs_mouse_top >= mouse_down_zone) { + nextScrollTop = scrollTop + 30; + if (nextScrollTop < max_player_y) { + $window.scrollTop(nextScrollTop); + this.scrollOffset = this.scrollOffset + 30; + } + } + + if (abs_mouse_top <= mouse_up_zone) { + nextScrollTop = scrollTop - 30; + if (nextScrollTop > 0) { + $window.scrollTop(nextScrollTop); + this.scrollOffset = this.scrollOffset - 30; + } + } + }; + + + fn.calculate_positions = function(e) { + this.window_height = $window.height(); + }; + + + fn.drag_handler = function(e) { + var node = e.target.nodeName; + if (this.disabled || e.which !== 1 && !isTouch) { + return; + } + + if (this.ignore_drag(e)) { + return; + } + + var self = this; + var first = true; + this.$player = $(e.currentTarget); + + this.el_init_pos = this.get_actual_pos(this.$player); + this.mouse_init_pos = this.get_mouse_pos(e); + this.offsetY = this.mouse_init_pos.top - this.el_init_pos.top; + + this.$body.on(pointer_events.move, function(mme){ + var mouse_actual_pos = self.get_mouse_pos(mme); + var diff_x = Math.abs( + mouse_actual_pos.left - self.mouse_init_pos.left); + var diff_y = Math.abs( + mouse_actual_pos.top - self.mouse_init_pos.top); + if (!(diff_x > self.options.distance || + diff_y > self.options.distance) + ) { + return false; + } + + if (first) { + first = false; + self.on_dragstart.call(self, mme); + return false; + } + + if (self.is_dragging === true) { + self.on_dragmove.call(self, mme); + } + + return false; + }); + + return false; + }; + + + fn.on_dragstart = function(e) { + e.preventDefault(); + this.drag_start = true; + this.is_dragging = true; + var offset = this.$container.offset(); + this.baseX = Math.round(offset.left); + this.baseY = Math.round(offset.top); + this.doc_height = $(document).height(); + + if (this.options.helper === 'clone') { + this.$helper = this.$player.clone() + .appendTo(this.$container).addClass('helper'); + this.helper = true; + }else{ + this.helper = false; + } + this.scrollOffset = 0; + this.el_init_offset = this.$player.offset(); + this.player_width = this.$player.width(); + this.player_height = this.$player.height(); + this.player_max_left = (this.$container.width() - this.player_width + + this.options.offset_left); + + if (this.options.start) { + this.options.start.call(this.$player, e, { + helper: this.helper ? this.$helper : this.$player + }); + } + return false; + }; + + + fn.on_dragmove = function(e) { + var offset = this.get_offset(e); + + this.options.autoscroll && this.manage_scroll(offset); + + (this.helper ? this.$helper : this.$player).css({ + 'position': 'absolute', + 'left' : offset.left, + 'top' : offset.top + }); + + var ui = { + 'position': { + 'left': offset.left, + 'top': offset.top + } + }; + + if (this.options.drag) { + this.options.drag.call(this.$player, e, ui); + } + return false; + }; + + + fn.on_dragstop = function(e) { + var offset = this.get_offset(e); + this.drag_start = false; + + var ui = { + 'position': { + 'left': offset.left, + 'top': offset.top + } + }; + + if (this.options.stop) { + this.options.stop.call(this.$player, e, ui); + } + + if (this.helper) { + this.$helper.remove(); + } + + return false; + }; + + fn.on_select_start = function(e) { + if (this.disabled) { return; } + + if (this.ignore_drag(e)) { + return; + } + + return false; + }; + + fn.enable = function() { + this.disabled = false; + }; + + fn.disable = function() { + this.disabled = true; + }; + + + fn.destroy = function(){ + this.disable(); + $.removeData(this.$container, 'drag'); + }; + + fn.ignore_drag = function(event) { + if (this.options.handle) { + return !$(event.target).is(this.options.handle); + } + + return $.inArray(event.target.nodeName, this.options.ignore_dragging) >= 0; + }; + + //jQuery adapter + $.fn.drag = function ( options ) { + return this.each(function () { + if (!$.data(this, 'drag')) { + $.data(this, 'drag', new Draggable( this, options )); + } + }); + }; + + +}(jQuery, window, document)); + +;(function($, window, document, undefined) { + + var defaults = { + namespace: '', + widget_selector: 'li', + widget_margins: [10, 10], + widget_base_dimensions: [400, 225], + extra_rows: 0, + extra_cols: 0, + min_cols: 1, + min_rows: 15, + max_size_x: 6, + autogenerate_stylesheet: true, + avoid_overlapped_widgets: true, + serialize_params: function($w, wgd) { + return { + col: wgd.col, + row: wgd.row, + size_x: wgd.size_x, + size_y: wgd.size_y + }; + }, + collision: {}, + draggable: { + distance: 4 + } + }; + + + /** + * @class Gridster + * @uses Draggable + * @uses Collision + * @param {HTMLElement} el The HTMLelement that contains all the widgets. + * @param {Object} [options] An Object with all options you want to + * overwrite: + * @param {HTMLElement|String} [options.widget_selector] Define who will + * be the draggable widgets. Can be a CSS Selector String or a + * collection of HTMLElements + * @param {Array} [options.widget_margins] Margin between widgets. + * The first index for the horizontal margin (left, right) and + * the second for the vertical margin (top, bottom). + * @param {Array} [options.widget_base_dimensions] Base widget dimensions + * in pixels. The first index for the width and the second for the + * height. + * @param {Number} [options.extra_cols] Add more columns in addition to + * those that have been calculated. + * @param {Number} [options.extra_rows] Add more rows in addition to + * those that have been calculated. + * @param {Number} [options.min_cols] The minimum required columns. + * @param {Number} [options.min_rows] The minimum required rows. + * @param {Number} [options.max_size_x] The maximum number of columns + * that a widget can span. + * @param {Boolean} [options.autogenerate_stylesheet] If true, all the + * CSS required to position all widgets in their respective columns + * and rows will be generated automatically and injected to the + * `` of the document. You can set this to false, and write + * your own CSS targeting rows and cols via data-attributes like so: + * `[data-col="1"] { left: 10px; }` + * @param {Boolean} [options.avoid_overlapped_widgets] Avoid that widgets loaded + * from the DOM can be overlapped. It is helpful if the positions were + * bad stored in the database or if there was any conflict. + * @param {Function} [options.serialize_params] Return the data you want + * for each widget in the serialization. Two arguments are passed: + * `$w`: the jQuery wrapped HTMLElement, and `wgd`: the grid + * coords object (`col`, `row`, `size_x`, `size_y`). + * @param {Object} [options.collision] An Object with all options for + * Collision class you want to overwrite. See Collision docs for + * more info. + * @param {Object} [options.draggable] An Object with all options for + * Draggable class you want to overwrite. See Draggable docs for more + * info. + * + * @constructor + */ + function Gridster(el, options) { + this.options = $.extend(true, defaults, options); + this.$el = $(el); + this.$wrapper = this.$el.parent(); + this.$widgets = this.$el.children(this.options.widget_selector).addClass('gs_w'); + this.widgets = []; + this.$changed = $([]); + this.wrapper_width = this.$wrapper.width(); + this.min_widget_width = (this.options.widget_margins[0] * 2) + + this.options.widget_base_dimensions[0]; + this.min_widget_height = (this.options.widget_margins[1] * 2) + + this.options.widget_base_dimensions[1]; + this.init(); + } + + Gridster.generated_stylesheets = []; + + var fn = Gridster.prototype; + + fn.init = function() { + this.generate_grid_and_stylesheet(); + this.get_widgets_from_DOM(); + this.set_dom_grid_height(); + this.$wrapper.addClass('ready'); + this.draggable(); + + $(window).bind( + 'resize', throttle($.proxy(this.recalculate_faux_grid, this), 200)); + }; + + + /** + * Disables dragging. + * + * @method disable + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.disable = function() { + this.$wrapper.find('.player-revert').removeClass('player-revert'); + this.drag_api.disable(); + return this; + }; + + + /** + * Enables dragging. + * + * @method enable + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.enable = function() { + this.drag_api.enable(); + return this; + }; + + + /** + * Add a new widget to the grid. + * + * @method add_widget + * @param {String|HTMLElement} html The string representing the HTML of the widget + * or the HTMLElement. + * @param {Number} [size_x] The nº of rows the widget occupies horizontally. + * @param {Number} [size_y] The nº of columns the widget occupies vertically. + * @param {Number} [col] The column the widget should start in. + * @param {Number} [row] The row the widget should start in. + * @return {HTMLElement} Returns the jQuery wrapped HTMLElement representing. + * the widget that was just created. + */ + fn.add_widget = function(html, size_x, size_y, col, row) { + var pos; + size_x || (size_x = 1); + size_y || (size_y = 1); + + if (!col & !row) { + pos = this.next_position(size_x, size_y); + }else{ + pos = { + col: col, + row: row + }; + + this.empty_cells(col, row, size_x, size_y); + } + + var $w = $(html).attr({ + 'data-col': pos.col, + 'data-row': pos.row, + 'data-sizex' : size_x, + 'data-sizey' : size_y + }).addClass('gs_w').appendTo(this.$el).hide(); + + this.$widgets = this.$widgets.add($w); + + this.register_widget($w); + + this.add_faux_rows(pos.size_y); + //this.add_faux_cols(pos.size_x); + + this.set_dom_grid_height(); + + return $w.fadeIn(); + }; + + + + /** + * Change the size of a widget. + * + * @method resize_widget + * @param {HTMLElement} $widget The jQuery wrapped HTMLElement + * representing the widget. + * @param {Number} size_x The number of columns that will occupy the widget. + * @param {Number} size_y The number of rows that will occupy the widget. + * @return {HTMLElement} Returns $widget. + */ + fn.resize_widget = function($widget, size_x, size_y) { + var wgd = $widget.coords().grid; + size_x || (size_x = wgd.size_x); + size_y || (size_y = wgd.size_y); + + if (size_x > this.cols) { + size_x = this.cols; + } + + var old_cells_occupied = this.get_cells_occupied(wgd); + var old_size_x = wgd.size_x; + var old_size_y = wgd.size_y; + var old_col = wgd.col; + var new_col = old_col; + var wider = size_x > old_size_x; + var taller = size_y > old_size_y; + + if (old_col + size_x - 1 > this.cols) { + var diff = old_col + (size_x - 1) - this.cols; + var c = old_col - diff; + new_col = Math.max(1, c); + } + + var new_grid_data = { + col: new_col, + row: wgd.row, + size_x: size_x, + size_y: size_y + }; + + var new_cells_occupied = this.get_cells_occupied(new_grid_data); + + var empty_cols = []; + $.each(old_cells_occupied.cols, function(i, col) { + if ($.inArray(col, new_cells_occupied.cols) === -1) { + empty_cols.push(col); + } + }); + + var occupied_cols = []; + $.each(new_cells_occupied.cols, function(i, col) { + if ($.inArray(col, old_cells_occupied.cols) === -1) { + occupied_cols.push(col); + } + }); + + var empty_rows = []; + $.each(old_cells_occupied.rows, function(i, row) { + if ($.inArray(row, new_cells_occupied.rows) === -1) { + empty_rows.push(row); + } + }); + + var occupied_rows = []; + $.each(new_cells_occupied.rows, function(i, row) { + if ($.inArray(row, old_cells_occupied.rows) === -1) { + occupied_rows.push(row); + } + }); + + this.remove_from_gridmap(wgd); + + if (occupied_cols.length) { + var cols_to_empty = [ + new_col, wgd.row, size_x, Math.min(old_size_y, size_y), $widget + ]; + this.empty_cells.apply(this, cols_to_empty); + } + + if (occupied_rows.length) { + var rows_to_empty = [new_col, wgd.row, size_x, size_y, $widget]; + this.empty_cells.apply(this, rows_to_empty); + } + + wgd.col = new_col; + wgd.size_x = size_x; + wgd.size_y = size_y; + this.add_to_gridmap(new_grid_data, $widget); + + //update coords instance attributes + $widget.data('coords').update({ + width: (size_x * this.options.widget_base_dimensions[0] + + ((size_x - 1) * this.options.widget_margins[0]) * 2), + height: (size_y * this.options.widget_base_dimensions[1] + + ((size_y - 1) * this.options.widget_margins[1]) * 2) + }); + + if (size_y > old_size_y) { + this.add_faux_rows(size_y - old_size_y); + } + + if (size_x > old_size_x) { + this.add_faux_cols(size_x - old_size_x); + } + + $widget.attr({ + 'data-col': new_col, + 'data-sizex': size_x, + 'data-sizey': size_y + }); + + if (empty_cols.length) { + var cols_to_remove_holes = [ + empty_cols[0], wgd.row, + empty_cols.length, + Math.min(old_size_y, size_y), + $widget + ]; + + this.remove_empty_cells.apply(this, cols_to_remove_holes); + } + + if (empty_rows.length) { + var rows_to_remove_holes = [ + new_col, wgd.row, size_x, size_y, $widget + ]; + this.remove_empty_cells.apply(this, rows_to_remove_holes); + } + + return $widget; + }; + + /** + * Move down widgets in cells represented by the arguments col, row, size_x, + * size_y + * + * @method empty_cells + * @param {Number} col The column where the group of cells begin. + * @param {Number} row The row where the group of cells begin. + * @param {Number} size_x The number of columns that the group of cells + * occupy. + * @param {Number} size_y The number of rows that the group of cells + * occupy. + * @param {HTMLElement} $exclude Exclude widgets from being moved. + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.empty_cells = function(col, row, size_x, size_y, $exclude) { + var $nexts = this.widgets_below({ + col: col, + row: row - size_y, + size_x: size_x, + size_y: size_y + }); + + $nexts.not($exclude).each($.proxy(function(i, w) { + var wgd = $(w).coords().grid; + if (!(wgd.row <= (row + size_y - 1))) { return; } + var diff = (row + size_y) - wgd.row; + this.move_widget_down($(w), diff); + }, this)); + + this.set_dom_grid_height(); + + return this; + }; + + + /** + * Move up widgets below cells represented by the arguments col, row, size_x, + * size_y. + * + * @method remove_empty_cells + * @param {Number} col The column where the group of cells begin. + * @param {Number} row The row where the group of cells begin. + * @param {Number} size_x The number of columns that the group of cells + * occupy. + * @param {Number} size_y The number of rows that the group of cells + * occupy. + * @param {HTMLElement} $exclude Exclude widgets from being moved. + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.remove_empty_cells = function(col, row, size_x, size_y, exclude) { + var $nexts = this.widgets_below({ + col: col, + row: row, + size_x: size_x, + size_y: size_y + }); + + $nexts.not(exclude).each($.proxy(function(i, widget) { + this.move_widget_up( $(widget), size_y ); + }, this)); + + this.set_dom_grid_height(); + + return this; + }; + + + /** + * Get the most left column below to add a new widget. + * + * @method next_position + * @param {Number} size_x The nº of rows the widget occupies horizontally. + * @param {Number} size_y The nº of columns the widget occupies vertically. + * @return {Object} Returns a grid coords object representing the future + * widget coords. + */ + fn.next_position = function(size_x, size_y) { + size_x || (size_x = 1); + size_y || (size_y = 1); + var ga = this.gridmap; + var cols_l = ga.length; + var valid_pos = []; + var rows_l; + + for (var c = 1; c < cols_l; c++) { + rows_l = ga[c].length; + for (var r = 1; r <= rows_l; r++) { + var can_move_to = this.can_move_to({ + size_x: size_x, + size_y: size_y + }, c, r); + + if (can_move_to) { + valid_pos.push({ + col: c, + row: r, + size_y: size_y, + size_x: size_x + }); + } + } + } + + if (valid_pos.length) { + return this.sort_by_row_and_col_asc(valid_pos)[0]; + } + return false; + }; + + + /** + * Remove a widget from the grid. + * + * @method remove_widget + * @param {HTMLElement} el The jQuery wrapped HTMLElement you want to remove. + * @param {Boolean|Function} silent If true, widgets below the removed one + * will not move up. If a Function is passed it will be used as callback. + * @param {Function} callback Function executed when the widget is removed. + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.remove_widget = function(el, silent, callback) { + var $el = el instanceof jQuery ? el : $(el); + var wgd = $el.coords().grid; + + // if silent is a function assume it's a callback + if ($.isFunction(silent)) { + callback = silent; + silent = false; + } + + this.cells_occupied_by_placeholder = {}; + this.$widgets = this.$widgets.not($el); + + var $nexts = this.widgets_below($el); + + this.remove_from_gridmap(wgd); + + $el.fadeOut($.proxy(function() { + $el.remove(); + + if (!silent) { + $nexts.each($.proxy(function(i, widget) { + this.move_widget_up( $(widget), wgd.size_y ); + }, this)); + } + + this.set_dom_grid_height(); + + if (callback) { + callback.call(this, el); + } + }, this)); + }; + + + /** + * Remove all widgets from the grid. + * + * @method remove_all_widgets + * @param {Function} callback Function executed for each widget removed. + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.remove_all_widgets = function(callback) { + this.$widgets.each($.proxy(function(i, el){ + this.remove_widget(el, true, callback); + }, this)); + + return this; + }; + + + /** + * Returns a serialized array of the widgets in the grid. + * + * @method serialize + * @param {HTMLElement} [$widgets] The collection of jQuery wrapped + * HTMLElements you want to serialize. If no argument is passed all widgets + * will be serialized. + * @return {Array} Returns an Array of Objects with the data specified in + * the serialize_params option. + */ + fn.serialize = function($widgets) { + $widgets || ($widgets = this.$widgets); + var result = []; + $widgets.each($.proxy(function(i, widget) { + result.push(this.options.serialize_params( + $(widget), $(widget).coords().grid ) ); + }, this)); + + return result; + }; + + + /** + * Returns a serialized array of the widgets that have changed their + * position. + * + * @method serialize_changed + * @return {Array} Returns an Array of Objects with the data specified in + * the serialize_params option. + */ + fn.serialize_changed = function() { + return this.serialize(this.$changed); + }; + + + /** + * Creates the grid coords object representing the widget a add it to the + * mapped array of positions. + * + * @method register_widget + * @return {Array} Returns the instance of the Gridster class. + */ + fn.register_widget = function($el) { + + var wgd = { + 'col': parseInt($el.attr('data-col'), 10), + 'row': parseInt($el.attr('data-row'), 10), + 'size_x': parseInt($el.attr('data-sizex'), 10), + 'size_y': parseInt($el.attr('data-sizey'), 10), + 'el': $el + }; + + if (this.options.avoid_overlapped_widgets && + !this.can_move_to( + {size_x: wgd.size_x, size_y: wgd.size_y}, wgd.col, wgd.row) + ) { + wgd = this.next_position(wgd.size_x, wgd.size_y); + wgd.el = $el; + $el.attr({ + 'data-col': wgd.col, + 'data-row': wgd.row, + 'data-sizex': wgd.size_x, + 'data-sizey': wgd.size_y + }); + } + + // attach Coord object to player data-coord attribute + $el.data('coords', $el.coords()); + + // Extend Coord object with grid position info + $el.data('coords').grid = wgd; + + this.add_to_gridmap(wgd, $el); + + return this; + }; + + + /** + * Update in the mapped array of positions the value of cells represented by + * the grid coords object passed in the `grid_data` param. + * + * @param {Object} grid_data The grid coords object representing the cells + * to update in the mapped array. + * @param {HTMLElement|Boolean} value Pass `false` or the jQuery wrapped + * HTMLElement, depends if you want to delete an existing position or add + * a new one. + * @method update_widget_position + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.update_widget_position = function(grid_data, value) { + this.for_each_cell_occupied(grid_data, function(col, row) { + if (!this.gridmap[col]) { return this; } + this.gridmap[col][row] = value; + }); + return this; + }; + + + /** + * Remove a widget from the mapped array of positions. + * + * @method remove_from_gridmap + * @param {Object} grid_data The grid coords object representing the cells + * to update in the mapped array. + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.remove_from_gridmap = function(grid_data) { + return this.update_widget_position(grid_data, false); + }; + + + /** + * Add a widget to the mapped array of positions. + * + * @method add_to_gridmap + * @param {Object} grid_data The grid coords object representing the cells + * to update in the mapped array. + * @param {HTMLElement|Boolean} value The value to set in the specified + * position . + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.add_to_gridmap = function(grid_data, value) { + this.update_widget_position(grid_data, value || grid_data.el); + + if (grid_data.el) { + var $widgets = this.widgets_below(grid_data.el); + $widgets.each($.proxy(function(i, widget) { + this.move_widget_up( $(widget)); + }, this)); + } + }; + + + /** + * Make widgets draggable. + * + * @uses Draggable + * @method draggable + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.draggable = function() { + var self = this; + var draggable_options = $.extend(true, {}, this.options.draggable, { + offset_left: this.options.widget_margins[0], + start: function(event, ui) { + self.$widgets.filter('.player-revert') + .removeClass('player-revert'); + + self.$player = $(this); + self.$helper = self.options.draggable.helper === 'clone' ? + $(ui.helper) : self.$player; + self.helper = !self.$helper.is(self.$player); + + self.on_start_drag.call(self, event, ui); + self.$el.trigger('gridster:dragstart'); + }, + stop: function(event, ui) { + self.on_stop_drag.call(self, event, ui); + self.$el.trigger('gridster:dragstop'); + }, + drag: throttle(function(event, ui) { + self.on_drag.call(self, event, ui); + self.$el.trigger('gridster:drag'); + }, 60) + }); + + this.drag_api = this.$el.drag(draggable_options).data('drag'); + return this; + }; + + + /** + * This function is executed when the player begins to be dragged. + * + * @method on_start_drag + * @param {Event} The original browser event + * @param {Object} A prepared ui object. + */ + fn.on_start_drag = function(event, ui) { + + this.$helper.add(this.$player).add(this.$wrapper).addClass('dragging'); + + this.$player.addClass('player'); + this.player_grid_data = this.$player.coords().grid; + this.placeholder_grid_data = $.extend({}, this.player_grid_data); + + //set new grid height along the dragging period + this.$el.css('height', this.$el.height() + + (this.player_grid_data.size_y * this.min_widget_height)); + + var colliders = this.faux_grid; + var coords = this.$player.data('coords').coords; + + this.cells_occupied_by_player = this.get_cells_occupied( + this.player_grid_data); + this.cells_occupied_by_placeholder = this.get_cells_occupied( + this.placeholder_grid_data); + + this.last_cols = []; + this.last_rows = []; + + + // see jquery.collision.js + this.collision_api = this.$helper.collision( + colliders, this.options.collision); + + this.$preview_holder = $('
  • ', { + 'class': 'preview-holder', + 'data-row': this.$player.attr('data-row'), + 'data-col': this.$player.attr('data-col'), + css: { + width: coords.width, + height: coords.height + } + }).appendTo(this.$el); + + if (this.options.draggable.start) { + this.options.draggable.start.call(this, event, ui); + } + }; + + + /** + * This function is executed when the player is being dragged. + * + * @method on_drag + * @param {Event} The original browser event + * @param {Object} A prepared ui object. + */ + fn.on_drag = function(event, ui) { + //break if dragstop has been fired + if (this.$player === null) { + return false; + } + + var abs_offset = { + left: ui.position.left + this.baseX, + top: ui.position.top + this.baseY + }; + + this.colliders_data = this.collision_api.get_closest_colliders( + abs_offset); + + this.on_overlapped_column_change( + this.on_start_overlapping_column, + this.on_stop_overlapping_column + ); + + this.on_overlapped_row_change( + this.on_start_overlapping_row, + this.on_stop_overlapping_row + ); + + if (this.helper && this.$player) { + this.$player.css({ + 'left': ui.position.left, + 'top': ui.position.top + }); + } + + if (this.options.draggable.drag) { + this.options.draggable.drag.call(this, event, ui); + } + }; + + /** + * This function is executed when the player stops being dragged. + * + * @method on_stop_drag + * @param {Event} The original browser event + * @param {Object} A prepared ui object. + */ + fn.on_stop_drag = function(event, ui) { + this.$helper.add(this.$player).add(this.$wrapper) + .removeClass('dragging'); + + ui.position.left = ui.position.left + this.baseX; + ui.position.top = ui.position.top + this.baseY; + this.colliders_data = this.collision_api.get_closest_colliders(ui.position); + + this.on_overlapped_column_change( + this.on_start_overlapping_column, + this.on_stop_overlapping_column + ); + + this.on_overlapped_row_change( + this.on_start_overlapping_row, + this.on_stop_overlapping_row + ); + + this.$player.addClass('player-revert').removeClass('player') + .attr({ + 'data-col': this.placeholder_grid_data.col, + 'data-row': this.placeholder_grid_data.row + }).css({ + 'left': '', + 'top': '' + }); + + this.$changed = this.$changed.add(this.$player); + + this.cells_occupied_by_player = this.get_cells_occupied( + this.placeholder_grid_data); + this.set_cells_player_occupies( + this.placeholder_grid_data.col, this.placeholder_grid_data.row); + + this.$player.coords().grid.row = this.placeholder_grid_data.row; + this.$player.coords().grid.col = this.placeholder_grid_data.col; + + if (this.options.draggable.stop) { + this.options.draggable.stop.call(this, event, ui); + } + + this.$preview_holder.remove(); + + this.$player = null; + this.$helper = null; + this.placeholder_grid_data = {}; + this.player_grid_data = {}; + this.cells_occupied_by_placeholder = {}; + this.cells_occupied_by_player = {}; + + this.set_dom_grid_height(); + }; + + + /** + * Executes the callbacks passed as arguments when a column begins to be + * overlapped or stops being overlapped. + * + * @param {Function} start_callback Function executed when a new column + * begins to be overlapped. The column is passed as first argument. + * @param {Function} stop_callback Function executed when a column stops + * being overlapped. The column is passed as first argument. + * @method on_overlapped_column_change + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.on_overlapped_column_change = function(start_callback, stop_callback) { + if (!this.colliders_data.length) { + return; + } + var cols = this.get_targeted_columns( + this.colliders_data[0].el.data.col); + + var last_n_cols = this.last_cols.length; + var n_cols = cols.length; + var i; + + for (i = 0; i < n_cols; i++) { + if ($.inArray(cols[i], this.last_cols) === -1) { + (start_callback || $.noop).call(this, cols[i]); + } + } + + for (i = 0; i< last_n_cols; i++) { + if ($.inArray(this.last_cols[i], cols) === -1) { + (stop_callback || $.noop).call(this, this.last_cols[i]); + } + } + + this.last_cols = cols; + + return this; + }; + + + /** + * Executes the callbacks passed as arguments when a row starts to be + * overlapped or stops being overlapped. + * + * @param {Function} start_callback Function executed when a new row begins + * to be overlapped. The row is passed as first argument. + * @param {Function} stop_callback Function executed when a row stops being + * overlapped. The row is passed as first argument. + * @method on_overlapped_row_change + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.on_overlapped_row_change = function(start_callback, end_callback) { + if (!this.colliders_data.length) { + return; + } + var rows = this.get_targeted_rows(this.colliders_data[0].el.data.row); + var last_n_rows = this.last_rows.length; + var n_rows = rows.length; + var i; + + for (i = 0; i < n_rows; i++) { + if ($.inArray(rows[i], this.last_rows) === -1) { + (start_callback || $.noop).call(this, rows[i]); + } + } + + for (i = 0; i < last_n_rows; i++) { + if ($.inArray(this.last_rows[i], rows) === -1) { + (end_callback || $.noop).call(this, this.last_rows[i]); + } + } + + this.last_rows = rows; + }; + + + /** + * Sets the current position of the player + * + * @param {Function} start_callback Function executed when a new row begins + * to be overlapped. The row is passed as first argument. + * @param {Function} stop_callback Function executed when a row stops being + * overlapped. The row is passed as first argument. + * @method set_player + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.set_player = function(col, row, no_player) { + var self = this; + if (!no_player) { + this.empty_cells_player_occupies(); + } + var cell = !no_player ? self.colliders_data[0].el.data : {col: col}; + var to_col = cell.col; + var to_row = row || cell.row; + + this.player_grid_data = { + col: to_col, + row: to_row, + size_y : this.player_grid_data.size_y, + size_x : this.player_grid_data.size_x + }; + + this.cells_occupied_by_player = this.get_cells_occupied( + this.player_grid_data); + + var $overlapped_widgets = this.get_widgets_overlapped( + this.player_grid_data); + + var constraints = this.widgets_constraints($overlapped_widgets); + + this.manage_movements(constraints.can_go_up, to_col, to_row); + this.manage_movements(constraints.can_not_go_up, to_col, to_row); + + /* if there is not widgets overlapping in the new player position, + * update the new placeholder position. */ + if (!$overlapped_widgets.length) { + var pp = this.can_go_player_up(this.player_grid_data); + if (pp !== false) { + to_row = pp; + } + this.set_placeholder(to_col, to_row); + } + + return { + col: to_col, + row: to_row + }; + }; + + + /** + * See which of the widgets in the $widgets param collection can go to + * a upper row and which not. + * + * @method widgets_contraints + * @param {HTMLElements} $widgets A jQuery wrapped collection of + * HTMLElements. + * @return {Array} Returns a literal Object with two keys: `can_go_up` & + * `can_not_go_up`. Each contains a set of HTMLElements. + */ + fn.widgets_constraints = function($widgets) { + var $widgets_can_go_up = $([]); + var $widgets_can_not_go_up; + var wgd_can_go_up = []; + var wgd_can_not_go_up = []; + + $widgets.each($.proxy(function(i, w) { + var $w = $(w); + var wgd = $w.coords().grid; + if (this.can_go_widget_up(wgd)) { + $widgets_can_go_up = $widgets_can_go_up.add($w); + wgd_can_go_up.push(wgd); + }else{ + wgd_can_not_go_up.push(wgd); + } + }, this)); + + $widgets_can_not_go_up = $widgets.not($widgets_can_go_up); + + return { + can_go_up: this.sort_by_row_asc(wgd_can_go_up), + can_not_go_up: this.sort_by_row_desc(wgd_can_not_go_up) + }; + }; + + + /** + * Sorts an Array of grid coords objects (representing the grid coords of + * each widget) in ascending way. + * + * @method sort_by_row_asc + * @param {Array} widgets Array of grid coords objects + * @return {Array} Returns the array sorted. + */ + fn.sort_by_row_asc = function(widgets) { + widgets = widgets.sort(function(a, b) { + if (!a.row) { + a = $(a).coords().grid; + b = $(b).coords().grid; + } + + if (a.row > b.row) { + return 1; + } + return -1; + }); + + return widgets; + }; + + + /** + * Sorts an Array of grid coords objects (representing the grid coords of + * each widget) placing first the empty cells upper left. + * + * @method sort_by_row_and_col_asc + * @param {Array} widgets Array of grid coords objects + * @return {Array} Returns the array sorted. + */ + fn.sort_by_row_and_col_asc = function(widgets) { + widgets = widgets.sort(function(a, b) { + if (a.row > b.row || a.row === b.row && a.col > b.col) { + return 1; + } + return -1; + }); + + return widgets; + }; + + + /** + * Sorts an Array of grid coords objects by column (representing the grid + * coords of each widget) in ascending way. + * + * @method sort_by_col_asc + * @param {Array} widgets Array of grid coords objects + * @return {Array} Returns the array sorted. + */ + fn.sort_by_col_asc = function(widgets) { + widgets = widgets.sort(function(a, b) { + if (a.col > b.col) { + return 1; + } + return -1; + }); + + return widgets; + }; + + + /** + * Sorts an Array of grid coords objects (representing the grid coords of + * each widget) in descending way. + * + * @method sort_by_row_desc + * @param {Array} widgets Array of grid coords objects + * @return {Array} Returns the array sorted. + */ + fn.sort_by_row_desc = function(widgets) { + widgets = widgets.sort(function(a, b) { + if (a.row + a.size_y < b.row + b.size_y) { + return 1; + } + return -1; + }); + return widgets; + }; + + + /** + * Sorts an Array of grid coords objects (representing the grid coords of + * each widget) in descending way. + * + * @method manage_movements + * @param {HTMLElements} $widgets A jQuery collection of HTMLElements + * representing the widgets you want to move. + * @param {Number} to_col The column to which we want to move the widgets. + * @param {Number} to_row The row to which we want to move the widgets. + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.manage_movements = function($widgets, to_col, to_row) { + $.each($widgets, $.proxy(function(i, w) { + var wgd = w; + var $w = wgd.el; + + var can_go_widget_up = this.can_go_widget_up(wgd); + + if (can_go_widget_up) { + //target CAN go up + //so move widget up + this.move_widget_to($w, can_go_widget_up); + this.set_placeholder(to_col, can_go_widget_up + wgd.size_y); + + } else { + //target can't go up + var can_go_player_up = this.can_go_player_up( + this.player_grid_data); + + if (!can_go_player_up) { + // target can't go up + // player cant't go up + // so we need to move widget down to a position that dont + // overlaps player + var y = (to_row + this.player_grid_data.size_y) - wgd.row; + + this.move_widget_down($w, y); + this.set_placeholder(to_col, to_row); + } + } + }, this)); + + return this; + }; + + /** + * Determines if there is a widget in the row and col given. Or if the + * HTMLElement passed as first argument is the player. + * + * @method is_player + * @param {Number|HTMLElement} col_or_el A jQuery wrapped collection of + * HTMLElements. + * @param {Number} [row] The column to which we want to move the widgets. + * @return {Boolean} Returns true or false. + */ + fn.is_player = function(col_or_el, row) { + if (row && !this.gridmap[col_or_el]) { return false; } + var $w = row ? this.gridmap[col_or_el][row] : col_or_el; + return $w && ($w.is(this.$player) || $w.is(this.$helper)); + }; + + + /** + * Determines if the widget that is being dragged is currently over the row + * and col given. + * + * @method is_player_in + * @param {Number} col The column to check. + * @param {Number} row The row to check. + * @return {Boolean} Returns true or false. + */ + fn.is_player_in = function(col, row) { + var c = this.cells_occupied_by_player || {}; + return $.inArray(col, c.cols) >= 0 && $.inArray(row, c.rows) >= 0; + }; + + + /** + * Determines if the placeholder is currently over the row and col given. + * + * @method is_placeholder_in + * @param {Number} col The column to check. + * @param {Number} row The row to check. + * @return {Boolean} Returns true or false. + */ + fn.is_placeholder_in = function(col, row) { + var c = this.cells_occupied_by_placeholder || {}; + return this.is_placeholder_in_col(col) && $.inArray(row, c.rows) >= 0; + }; + + + /** + * Determines if the placeholder is currently over the column given. + * + * @method is_placeholder_in_col + * @param {Number} col The column to check. + * @return {Boolean} Returns true or false. + */ + fn.is_placeholder_in_col = function(col) { + var c = this.cells_occupied_by_placeholder || []; + return $.inArray(col, c.cols) >= 0; + }; + + + /** + * Determines if the cell represented by col and row params is empty. + * + * @method is_empty + * @param {Number} col The column to check. + * @param {Number} row The row to check. + * @return {Boolean} Returns true or false. + */ + fn.is_empty = function(col, row) { + if (typeof this.gridmap[col] !== 'undefined' && + typeof this.gridmap[col][row] !== 'undefined' && + this.gridmap[col][row] === false + ) { + return true; + } + return false; + }; + + + /** + * Determines if the cell represented by col and row params is occupied. + * + * @method is_occupied + * @param {Number} col The column to check. + * @param {Number} row The row to check. + * @return {Boolean} Returns true or false. + */ + fn.is_occupied = function(col, row) { + if (!this.gridmap[col]) { + return false; + } + + if (this.gridmap[col][row]) { + return true; + } + return false; + }; + + + /** + * Determines if there is a widget in the cell represented by col/row params. + * + * @method is_widget + * @param {Number} col The column to check. + * @param {Number} row The row to check. + * @return {Boolean|HTMLElement} Returns false if there is no widget, + * else returns the jQuery HTMLElement + */ + fn.is_widget = function(col, row) { + var cell = this.gridmap[col]; + if (!cell) { + return false; + } + + cell = cell[row]; + + if (cell) { + return cell; + } + + return false; + }; + + + /** + * Determines if there is a widget in the cell represented by col/row + * params and if this is under the widget that is being dragged. + * + * @method is_widget_under_player + * @param {Number} col The column to check. + * @param {Number} row The row to check. + * @return {Boolean} Returns true or false. + */ + fn.is_widget_under_player = function(col, row) { + if (this.is_widget(col, row)) { + return this.is_player_in(col, row); + } + return false; + }; + + + /** + * Get widgets overlapping with the player or with the object passed + * representing the grid cells. + * + * @method get_widgets_under_player + * @return {HTMLElement} Returns a jQuery collection of HTMLElements + */ + fn.get_widgets_under_player = function(cells) { + cells || (cells = this.cells_occupied_by_player || {cols: [], rows: []}); + var $widgets = $([]); + + $.each(cells.cols, $.proxy(function(i, col) { + $.each(cells.rows, $.proxy(function(i, row) { + if(this.is_widget(col, row)) { + $widgets = $widgets.add(this.gridmap[col][row]); + } + }, this)); + }, this)); + + return $widgets; + }; + + + /** + * Put placeholder at the row and column specified. + * + * @method set_placeholder + * @param {Number} col The column to which we want to move the + * placeholder. + * @param {Number} row The row to which we want to move the + * placeholder. + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.set_placeholder = function(col, row) { + var phgd = $.extend({}, this.placeholder_grid_data); + var $nexts = this.widgets_below({ + col: phgd.col, + row: phgd.row, + size_y: phgd.size_y, + size_x: phgd.size_x + }); + + // Prevents widgets go out of the grid + var right_col = (col + phgd.size_x - 1); + if (right_col > this.cols) { + col = col - (right_col - col); + } + + var moved_down = this.placeholder_grid_data.row < row; + var changed_column = this.placeholder_grid_data.col !== col; + + this.placeholder_grid_data.col = col; + this.placeholder_grid_data.row = row; + + this.cells_occupied_by_placeholder = this.get_cells_occupied( + this.placeholder_grid_data); + + this.$preview_holder.attr({ + 'data-row' : row, + 'data-col' : col + }); + + if (moved_down || changed_column) { + $nexts.each($.proxy(function(i, widget) { + this.move_widget_up( + $(widget), this.placeholder_grid_data.col - col + phgd.size_y); + }, this)); + } + + + var $widgets_under_ph = this.get_widgets_under_player(this.cells_occupied_by_placeholder); + if ($widgets_under_ph.length) { + $widgets_under_ph.each($.proxy(function(i, widget) { + var $w = $(widget); + this.move_widget_down( + $w, row + phgd.size_y - $w.data('coords').grid.row); + }, this)); + } + + }; + + + /** + * Determines whether the player can move to a position above. + * + * @method can_go_player_up + * @param {Object} widget_grid_data The actual grid coords object of the + * player. + * @return {Number|Boolean} If the player can be moved to an upper row + * returns the row number, else returns false. + */ + fn.can_go_player_up = function(widget_grid_data) { + var p_bottom_row = widget_grid_data.row + widget_grid_data.size_y - 1; + var result = true; + var upper_rows = []; + var min_row = 10000; + var $widgets_under_player = this.get_widgets_under_player(); + + /* generate an array with columns as index and array with upper rows + * empty as value */ + this.for_each_column_occupied(widget_grid_data, function(tcol) { + var grid_col = this.gridmap[tcol]; + var r = p_bottom_row + 1; + upper_rows[tcol] = []; + + while (--r > 0) { + if (this.is_empty(tcol, r) || this.is_player(tcol, r) || + this.is_widget(tcol, r) && + grid_col[r].is($widgets_under_player) + ) { + upper_rows[tcol].push(r); + min_row = r < min_row ? r : min_row; + }else{ + break; + } + } + + if (upper_rows[tcol].length === 0) { + result = false; + return true; //break + } + + upper_rows[tcol].sort(); + }); + + if (!result) { return false; } + + return this.get_valid_rows(widget_grid_data, upper_rows, min_row); + }; + + + /** + * Determines whether a widget can move to a position above. + * + * @method can_go_widget_up + * @param {Object} widget_grid_data The actual grid coords object of the + * widget we want to check. + * @return {Number|Boolean} If the widget can be moved to an upper row + * returns the row number, else returns false. + */ + fn.can_go_widget_up = function(widget_grid_data) { + var p_bottom_row = widget_grid_data.row + widget_grid_data.size_y - 1; + var result = true; + var upper_rows = []; + var min_row = 10000; + + /* generate an array with columns as index and array with topmost rows + * empty as value */ + this.for_each_column_occupied(widget_grid_data, function(tcol) { + var grid_col = this.gridmap[tcol]; + upper_rows[tcol] = []; + + var r = p_bottom_row + 1; + // iterate over each row + while (--r > 0) { + if (this.is_widget(tcol, r) && !this.is_player_in(tcol, r)) { + if (!grid_col[r].is(widget_grid_data.el)) { + break; + } + } + + if (!this.is_player(tcol, r) && + !this.is_placeholder_in(tcol, r) && + !this.is_player_in(tcol, r)) { + upper_rows[tcol].push(r); + } + + if (r < min_row) { + min_row = r; + } + } + + if (upper_rows[tcol].length === 0) { + result = false; + return true; //break + } + + upper_rows[tcol].sort(); + }); + + if (!result) { return false; } + + return this.get_valid_rows(widget_grid_data, upper_rows, min_row); + }; + + + /** + * Search a valid row for the widget represented by `widget_grid_data' in + * the `upper_rows` array. Iteration starts from row specified in `min_row`. + * + * @method get_valid_rows + * @param {Object} widget_grid_data The actual grid coords object of the + * player. + * @param {Array} upper_rows An array with columns as index and arrays + * of valid rows as values. + * @param {Number} min_row The upper row from which the iteration will start. + * @return {Number|Boolean} Returns the upper row valid from the `upper_rows` + * for the widget in question. + */ + fn.get_valid_rows = function(widget_grid_data, upper_rows, min_row) { + var p_top_row = widget_grid_data.row; + var p_bottom_row = widget_grid_data.row + widget_grid_data.size_y - 1; + var size_y = widget_grid_data.size_y; + var r = min_row - 1; + var valid_rows = []; + + while (++r <= p_bottom_row ) { + var common = true; + $.each(upper_rows, function(col, rows) { + if ($.isArray(rows) && $.inArray(r, rows) === -1) { + common = false; + } + }); + + if (common === true) { + valid_rows.push(r); + if (valid_rows.length === size_y) { + break; + } + } + } + + var new_row = false; + if (size_y === 1) { + if (valid_rows[0] !== p_top_row) { + new_row = valid_rows[0] || false; + } + }else{ + if (valid_rows[0] !== p_top_row) { + new_row = this.get_consecutive_numbers_index( + valid_rows, size_y); + } + } + + return new_row; + }; + + + fn.get_consecutive_numbers_index = function(arr, size_y) { + var max = arr.length; + var result = []; + var first = true; + var prev = -1; // or null? + + for (var i=0; i < max; i++) { + if (first || arr[i] === prev + 1) { + result.push(i); + if (result.length === size_y) { + break; + } + first = false; + }else{ + result = []; + first = true; + } + + prev = arr[i]; + } + + return result.length >= size_y ? arr[result[0]] : false; + }; + + + /** + * Get widgets overlapping with the player. + * + * @method get_widgets_overlapped + * @return {HTMLElements} Returns a jQuery collection of HTMLElements. + */ + fn.get_widgets_overlapped = function() { + var $w; + var $widgets = $([]); + var used = []; + var rows_from_bottom = this.cells_occupied_by_player.rows.slice(0); + rows_from_bottom.reverse(); + + $.each(this.cells_occupied_by_player.cols, $.proxy(function(i, col) { + $.each(rows_from_bottom, $.proxy(function(i, row) { + // if there is a widget in the player position + if (!this.gridmap[col]) { return true; } //next iteration + var $w = this.gridmap[col][row]; + if (this.is_occupied(col, row) && !this.is_player($w) && + $.inArray($w, used) === -1 + ) { + $widgets = $widgets.add($w); + used.push($w); + } + + }, this)); + }, this)); + + return $widgets; + }; + + + /** + * This callback is executed when the player begins to collide with a column. + * + * @method on_start_overlapping_column + * @param {Number} col The collided column. + * @return {HTMLElements} Returns a jQuery collection of HTMLElements. + */ + fn.on_start_overlapping_column = function(col) { + this.set_player(col, false); + }; + + + /** + * A callback executed when the player begins to collide with a row. + * + * @method on_start_overlapping_row + * @param {Number} col The collided row. + * @return {HTMLElements} Returns a jQuery collection of HTMLElements. + */ + fn.on_start_overlapping_row = function(row) { + this.set_player(false, row); + }; + + + /** + * A callback executed when the the player ends to collide with a column. + * + * @method on_stop_overlapping_column + * @param {Number} col The collided row. + * @return {HTMLElements} Returns a jQuery collection of HTMLElements. + */ + fn.on_stop_overlapping_column = function(col) { + this.set_player(col, false); + + var self = this; + this.for_each_widget_below(col, this.cells_occupied_by_player.rows[0], + function(tcol, trow) { + self.move_widget_up(this, self.player_grid_data.size_y); + }); + }; + + + /** + * This callback is executed when the player ends to collide with a row. + * + * @method on_stop_overlapping_row + * @param {Number} row The collided row. + * @return {HTMLElements} Returns a jQuery collection of HTMLElements. + */ + fn.on_stop_overlapping_row = function(row) { + this.set_player(false, row); + + var self = this; + var cols = this.cells_occupied_by_player.cols; + for (var c = 0, cl = cols.length; c < cl; c++) { + this.for_each_widget_below(cols[c], row, function(tcol, trow) { + self.move_widget_up(this, self.player_grid_data.size_y); + }); + } + }; + + + /** + * Move a widget to a specific row. The cell or cells must be empty. + * If the widget has widgets below, all of these widgets will be moved also + * if they can. + * + * @method move_widget_to + * @param {HTMLElement} $widget The jQuery wrapped HTMLElement of the + * widget is going to be moved. + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.move_widget_to = function($widget, row) { + var self = this; + var widget_grid_data = $widget.coords().grid; + var diff = row - widget_grid_data.row; + var $next_widgets = this.widgets_below($widget); + + var can_move_to_new_cell = this.can_move_to( + widget_grid_data, widget_grid_data.col, row, $widget); + + if (can_move_to_new_cell === false) { + return false; + } + + this.remove_from_gridmap(widget_grid_data); + widget_grid_data.row = row; + this.add_to_gridmap(widget_grid_data); + $widget.attr('data-row', row); + this.$changed = this.$changed.add($widget); + + + $next_widgets.each(function(i, widget) { + var $w = $(widget); + var wgd = $w.coords().grid; + var can_go_up = self.can_go_widget_up(wgd); + if (can_go_up && can_go_up !== wgd.row) { + self.move_widget_to($w, can_go_up); + } + }); + + return this; + }; + + + /** + * Move up the specified widget and all below it. + * + * @method move_widget_up + * @param {HTMLElement} $widget The widget you want to move. + * @param {Number} [y_units] The number of cells that the widget has to move. + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.move_widget_up = function($widget, y_units) { + var el_grid_data = $widget.coords().grid; + var actual_row = el_grid_data.row; + var moved = []; + var can_go_up = true; + y_units || (y_units = 1); + + if (!this.can_go_up($widget)) { return false; } //break; + + this.for_each_column_occupied(el_grid_data, function(col) { + // can_go_up + if ($.inArray($widget, moved) === -1) { + var widget_grid_data = $widget.coords().grid; + var next_row = actual_row - y_units; + next_row = this.can_go_up_to_row( + widget_grid_data, col, next_row); + + if (!next_row) { + return true; + } + + var $next_widgets = this.widgets_below($widget); + + this.remove_from_gridmap(widget_grid_data); + widget_grid_data.row = next_row; + this.add_to_gridmap(widget_grid_data); + $widget.attr('data-row', widget_grid_data.row); + this.$changed = this.$changed.add($widget); + + moved.push($widget); + + $next_widgets.each($.proxy(function(i, widget) { + this.move_widget_up($(widget), y_units); + }, this)); + } + }); + + }; + + + /** + * Move down the specified widget and all below it. + * + * @method move_widget_down + * @param {HTMLElement} $widget The jQuery object representing the widget + * you want to move. + * @param {Number} The number of cells that the widget has to move. + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.move_widget_down = function($widget, y_units) { + var el_grid_data = $widget.coords().grid; + var actual_row = el_grid_data.row; + var moved = []; + var y_diff = y_units; + + if (!$widget) { return false; } + + if ($.inArray($widget, moved) === -1) { + + var widget_grid_data = $widget.coords().grid; + var next_row = actual_row + y_units; + var $next_widgets = this.widgets_below($widget); + + this.remove_from_gridmap(widget_grid_data); + + $next_widgets.each($.proxy(function(i, widget) { + var $w = $(widget); + var wd = $w.coords().grid; + var tmp_y = this.displacement_diff( + wd, widget_grid_data, y_diff); + + if (tmp_y > 0) { + this.move_widget_down($w, tmp_y); + } + }, this)); + + widget_grid_data.row = next_row; + this.update_widget_position(widget_grid_data, $widget); + $widget.attr('data-row', widget_grid_data.row); + this.$changed = this.$changed.add($widget); + + moved.push($widget); + } + }; + + + /** + * Check if the widget can move to the specified row, else returns the + * upper row possible. + * + * @method can_go_up_to_row + * @param {Number} widget_grid_data The current grid coords object of the + * widget. + * @param {Number} col The target column. + * @param {Number} row The target row. + * @return {Boolean|Number} Returns the row number if the widget can move + * to the target position, else returns false. + */ + fn.can_go_up_to_row = function(widget_grid_data, col, row) { + var ga = this.gridmap; + var result = true; + var urc = []; // upper_rows_in_columns + var actual_row = widget_grid_data.row; + var r; + + /* generate an array with columns as index and array with + * upper rows empty in the column */ + this.for_each_column_occupied(widget_grid_data, function(tcol) { + var grid_col = ga[tcol]; + urc[tcol] = []; + + r = actual_row; + while (r--) { + if (this.is_empty(tcol, r) && + !this.is_placeholder_in(tcol, r) + ) { + urc[tcol].push(r); + }else{ + break; + } + } + + if (!urc[tcol].length) { + result = false; + return true; + } + + }); + + if (!result) { return false; } + + /* get common rows starting from upper position in all the columns + * that widget occupies */ + r = row; + for (r = 1; r < actual_row; r++) { + var common = true; + + for (var uc = 0, ucl = urc.length; uc < ucl; uc++) { + if (urc[uc] && $.inArray(r, urc[uc]) === -1) { + common = false; + } + } + + if (common === true) { + result = r; + break; + } + } + + return result; + }; + + + fn.displacement_diff = function(widget_grid_data, parent_bgd, y_units) { + var actual_row = widget_grid_data.row; + var diffs = []; + var parent_max_y = parent_bgd.row + parent_bgd.size_y; + + this.for_each_column_occupied(widget_grid_data, function(col) { + var temp_y_units = 0; + + for (var r = parent_max_y; r < actual_row; r++) { + if (this.is_empty(col, r)) { + temp_y_units = temp_y_units + 1; + } + } + + diffs.push(temp_y_units); + }); + + var max_diff = Math.max.apply(Math, diffs); + y_units = (y_units - max_diff); + + return y_units > 0 ? y_units : 0; + }; + + + /** + * Get widgets below a widget. + * + * @method widgets_below + * @param {HTMLElement} $el The jQuery wrapped HTMLElement. + * @return {HTMLElements} A jQuery collection of HTMLElements. + */ + fn.widgets_below = function($el) { + var el_grid_data = $.isPlainObject($el) ? $el : $el.coords().grid; + var self = this; + var ga = this.gridmap; + var next_row = el_grid_data.row + el_grid_data.size_y - 1; + var $nexts = $([]); + + this.for_each_column_occupied(el_grid_data, function(col) { + self.for_each_widget_below(col, next_row, function(tcol, trow) { + if (!self.is_player(this) && $.inArray(this, $nexts) === -1) { + $nexts = $nexts.add(this); + return true; // break + } + }); + }); + + return this.sort_by_row_asc($nexts); + }; + + + /** + * Update the array of mapped positions with the new player position. + * + * @method set_cells_player_occupies + * @param {Number} col The new player col. + * @param {Number} col The new player row. + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.set_cells_player_occupies = function(col, row) { + this.remove_from_gridmap(this.placeholder_grid_data); + this.placeholder_grid_data.col = col; + this.placeholder_grid_data.row = row; + this.add_to_gridmap(this.placeholder_grid_data, this.$player); + return this; + }; + + + /** + * Remove from the array of mapped positions the reference to the player. + * + * @method empty_cells_player_occupies + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.empty_cells_player_occupies = function() { + this.remove_from_gridmap(this.placeholder_grid_data); + return this; + }; + + + fn.can_go_up = function($el) { + var el_grid_data = $el.coords().grid; + var initial_row = el_grid_data.row; + var prev_row = initial_row - 1; + var ga = this.gridmap; + var upper_rows_by_column = []; + + var result = true; + if (initial_row === 1) { return false; } + + this.for_each_column_occupied(el_grid_data, function(col) { + var $w = this.is_widget(col, prev_row); + + if (this.is_occupied(col, prev_row) || + this.is_player(col, prev_row) || + this.is_placeholder_in(col, prev_row) || + this.is_player_in(col, prev_row) + ) { + result = false; + return true; //break + } + }); + + return result; + }; + + + + /** + * Check if it's possible to move a widget to a specific col/row. It takes + * into account the dimensions (`size_y` and `size_x` attrs. of the grid + * coords object) the widget occupies. + * + * @method can_move_to + * @param {Object} widget_grid_data The grid coords object that represents + * the widget. + * @param {Object} col The col to check. + * @param {Object} row The row to check. + * @param {Number} [max_row] The max row allowed. + * @return {Boolean} Returns true if all cells are empty, else return false. + */ + fn.can_move_to = function(widget_grid_data, col, row, max_row) { + var ga = this.gridmap; + var $w = widget_grid_data.el; + var future_wd = { + size_y: widget_grid_data.size_y, + size_x: widget_grid_data.size_x, + col: col, + row: row + }; + var result = true; + + //Prevents widgets go out of the grid + var right_col = col + widget_grid_data.size_x - 1; + if (right_col > this.cols) { + return false; + } + + if (max_row && max_row < row + widget_grid_data.size_y - 1) { + return false; + } + + this.for_each_cell_occupied(future_wd, function(tcol, trow) { + var $tw = this.is_widget(tcol, trow); + if ($tw && (!widget_grid_data.el || $tw.is($w))) { + result = false; + } + }); + + return result; + }; + + + /** + * Given the leftmost column returns all columns that are overlapping + * with the player. + * + * @method get_targeted_columns + * @param {Number} [from_col] The leftmost column. + * @return {Array} Returns an array with column numbers. + */ + fn.get_targeted_columns = function(from_col) { + var max = (from_col || this.player_grid_data.col) + + (this.player_grid_data.size_x - 1); + var cols = []; + for (var col = from_col; col <= max; col++) { + cols.push(col); + } + return cols; + }; + + + /** + * Given the upper row returns all rows that are overlapping with the player. + * + * @method get_targeted_rows + * @param {Number} [from_row] The upper row. + * @return {Array} Returns an array with row numbers. + */ + fn.get_targeted_rows = function(from_row) { + var max = (from_row || this.player_grid_data.row) + + (this.player_grid_data.size_y - 1); + var rows = []; + for (var row = from_row; row <= max; row++) { + rows.push(row); + } + return rows; + }; + + /** + * Get all columns and rows that a widget occupies. + * + * @method get_cells_occupied + * @param {Object} el_grid_data The grid coords object of the widget. + * @return {Object} Returns an object like `{ cols: [], rows: []}`. + */ + fn.get_cells_occupied = function(el_grid_data) { + var cells = { cols: [], rows: []}; + var i; + if (arguments[1] instanceof jQuery) { + el_grid_data = arguments[1].coords().grid; + } + + for (i = 0; i < el_grid_data.size_x; i++) { + var col = el_grid_data.col + i; + cells.cols.push(col); + } + + for (i = 0; i < el_grid_data.size_y; i++) { + var row = el_grid_data.row + i; + cells.rows.push(row); + } + + return cells; + }; + + + /** + * Iterate over the cells occupied by a widget executing a function for + * each one. + * + * @method for_each_cell_occupied + * @param {Object} el_grid_data The grid coords object that represents the + * widget. + * @param {Function} callback The function to execute on each column + * iteration. Column and row are passed as arguments. + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.for_each_cell_occupied = function(grid_data, callback) { + this.for_each_column_occupied(grid_data, function(col) { + this.for_each_row_occupied(grid_data, function(row) { + callback.call(this, col, row); + }); + }); + return this; + }; + + + /** + * Iterate over the columns occupied by a widget executing a function for + * each one. + * + * @method for_each_column_occupied + * @param {Object} el_grid_data The grid coords object that represents + * the widget. + * @param {Function} callback The function to execute on each column + * iteration. The column number is passed as first argument. + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.for_each_column_occupied = function(el_grid_data, callback) { + for (var i = 0; i < el_grid_data.size_x; i++) { + var col = el_grid_data.col + i; + callback.call(this, col, el_grid_data); + } + }; + + + /** + * Iterate over the rows occupied by a widget executing a function for + * each one. + * + * @method for_each_row_occupied + * @param {Object} el_grid_data The grid coords object that represents + * the widget. + * @param {Function} callback The function to execute on each column + * iteration. The row number is passed as first argument. + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.for_each_row_occupied = function(el_grid_data, callback) { + for (var i = 0; i < el_grid_data.size_y; i++) { + var row = el_grid_data.row + i; + callback.call(this, row, el_grid_data); + } + }; + + + + fn._traversing_widgets = function(type, direction, col, row, callback) { + var ga = this.gridmap; + if (!ga[col]) { return; } + + var cr, max; + var action = type + '/' + direction; + if (arguments[2] instanceof jQuery) { + var el_grid_data = arguments[2].coords().grid; + col = el_grid_data.col; + row = el_grid_data.row; + callback = arguments[3]; + } + var matched = []; + var trow = row; + + + var methods = { + 'for_each/above': function() { + while (trow--) { + if (trow > 0 && this.is_widget(col, trow) && + $.inArray(ga[col][trow], matched) === -1 + ) { + cr = callback.call(ga[col][trow], col, trow); + matched.push(ga[col][trow]); + if (cr) { break; } + } + } + }, + 'for_each/below': function() { + for (trow = row + 1, max = ga[col].length; trow < max; trow++) { + if (this.is_widget(col, trow) && + $.inArray(ga[col][trow], matched) === -1 + ) { + cr = callback.call(ga[col][trow], col, trow); + matched.push(ga[col][trow]); + if (cr) { break; } + } + } + } + }; + + if (methods[action]) { + methods[action].call(this); + } + }; + + + /** + * Iterate over each widget above the column and row specified. + * + * @method for_each_widget_above + * @param {Number} col The column to start iterating. + * @param {Number} row The row to start iterating. + * @param {Function} callback The function to execute on each widget + * iteration. The value of `this` inside the function is the jQuery + * wrapped HTMLElement. + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.for_each_widget_above = function(col, row, callback) { + this._traversing_widgets('for_each', 'above', col, row, callback); + return this; + }; + + + /** + * Iterate over each widget below the column and row specified. + * + * @method for_each_widget_below + * @param {Number} col The column to start iterating. + * @param {Number} row The row to start iterating. + * @param {Function} callback The function to execute on each widget + * iteration. The value of `this` inside the function is the jQuery wrapped + * HTMLElement. + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.for_each_widget_below = function(col, row, callback) { + this._traversing_widgets('for_each', 'below', col, row, callback); + return this; + }; + + + /** + * Returns the highest occupied cell in the grid. + * + * @method get_highest_occupied_cell + * @return {Object} Returns an object with `col` and `row` numbers. + */ + fn.get_highest_occupied_cell = function() { + var r; + var gm = this.gridmap; + var rows = []; + var row_in_col = []; + for (var c = gm.length - 1; c >= 1; c--) { + for (r = gm[c].length - 1; r >= 1; r--) { + if (this.is_widget(c, r)) { + rows.push(r); + row_in_col[r] = c; + break; + } + } + } + + var highest_row = Math.max.apply(Math, rows); + + this.highest_occupied_cell = { + col: row_in_col[highest_row], + row: highest_row + }; + + return this.highest_occupied_cell; + }; + + + fn.get_widgets_from = function(col, row) { + var ga = this.gridmap; + var $widgets = $(); + + if (col) { + $widgets = $widgets.add( + this.$widgets.filter(function() { + var tcol = $(this).attr('data-col'); + return (tcol === col || tcol > col); + }) + ); + } + + if (row) { + $widgets = $widgets.add( + this.$widgets.filter(function() { + var trow = $(this).attr('data-row'); + return (trow === row || trow > row); + }) + ); + } + + return $widgets; + }; + + + /** + * Set the current height of the parent grid. + * + * @method set_dom_grid_height + * @return {Object} Returns the instance of the Gridster class. + */ + fn.set_dom_grid_height = function() { + var r = this.get_highest_occupied_cell().row; + this.$el.css('height', r * this.min_widget_height); + return this; + }; + + + /** + * It generates the neccessary styles to position the widgets. + * + * @method generate_stylesheet + * @param {Number} rows Number of columns. + * @param {Number} cols Number of rows. + * @return {Object} Returns the instance of the Gridster class. + */ + fn.generate_stylesheet = function(opts) { + var styles = ''; + var max_size_x = this.options.max_size_x; + var max_rows = 0; + var max_cols = 0; + var i; + var rules; + + opts || (opts = {}); + opts.cols || (opts.cols = this.cols); + opts.rows || (opts.rows = this.rows); + opts.namespace || (opts.namespace = this.options.namespace); + opts.widget_base_dimensions || + (opts.widget_base_dimensions = this.options.widget_base_dimensions); + opts.widget_margins || + (opts.widget_margins = this.options.widget_margins); + opts.min_widget_width = (opts.widget_margins[0] * 2) + + opts.widget_base_dimensions[0]; + opts.min_widget_height = (opts.widget_margins[1] * 2) + + opts.widget_base_dimensions[1]; + + // don't duplicate stylesheets for the same configuration + var serialized_opts = $.param(opts); + if ($.inArray(serialized_opts, Gridster.generated_stylesheets) >= 0) { + return false; + } + + Gridster.generated_stylesheets.push(serialized_opts); + + /* generate CSS styles for cols */ + for (i = opts.cols; i >= 0; i--) { + styles += (opts.namespace + ' [data-col="'+ (i + 1) + '"] { left:' + + ((i * opts.widget_base_dimensions[0]) + + (i * opts.widget_margins[0]) + + ((i + 1) * opts.widget_margins[0])) + 'px;} '); + } + + /* generate CSS styles for rows */ + for (i = opts.rows; i >= 0; i--) { + styles += (opts.namespace + ' [data-row="' + (i + 1) + '"] { top:' + + ((i * opts.widget_base_dimensions[1]) + + (i * opts.widget_margins[1]) + + ((i + 1) * opts.widget_margins[1]) ) + 'px;} '); + } + + for (var y = 1; y <= opts.rows; y++) { + styles += (opts.namespace + ' [data-sizey="' + y + '"] { height:' + + (y * opts.widget_base_dimensions[1] + + (y - 1) * (opts.widget_margins[1] * 2)) + 'px;}'); + } + + for (var x = 1; x <= max_size_x; x++) { + styles += (opts.namespace + ' [data-sizex="' + x + '"] { width:' + + (x * opts.widget_base_dimensions[0] + + (x - 1) * (opts.widget_margins[0] * 2)) + 'px;}'); + } + + return this.add_style_tag(styles); + }; + + + /** + * Injects the given CSS as string to the head of the document. + * + * @method add_style_tag + * @param {String} css The styles to apply. + * @return {Object} Returns the instance of the Gridster class. + */ + fn.add_style_tag = function(css) { + var d = document; + var tag = d.createElement('style'); + + d.getElementsByTagName('head')[0].appendChild(tag); + tag.setAttribute('type', 'text/css'); + + if (tag.styleSheet) { + tag.styleSheet.cssText = css; + }else{ + tag.appendChild(document.createTextNode(css)); + } + return this; + }; + + + /** + * Generates a faux grid to collide with it when a widget is dragged and + * detect row or column that we want to go. + * + * @method generate_faux_grid + * @param {Number} rows Number of columns. + * @param {Number} cols Number of rows. + * @return {Object} Returns the instance of the Gridster class. + */ + fn.generate_faux_grid = function(rows, cols) { + this.faux_grid = []; + this.gridmap = []; + var col; + var row; + for (col = cols; col > 0; col--) { + this.gridmap[col] = []; + for (row = rows; row > 0; row--) { + this.add_faux_cell(row, col); + } + } + return this; + }; + + + /** + * Add cell to the faux grid. + * + * @method add_faux_cell + * @param {Number} row The row for the new faux cell. + * @param {Number} col The col for the new faux cell. + * @return {Object} Returns the instance of the Gridster class. + */ + fn.add_faux_cell = function(row, col) { + var coords = $({ + left: this.baseX + ((col - 1) * this.min_widget_width), + top: this.baseY + (row -1) * this.min_widget_height, + width: this.min_widget_width, + height: this.min_widget_height, + col: col, + row: row, + original_col: col, + original_row: row + }).coords(); + + if (!$.isArray(this.gridmap[col])) { + this.gridmap[col] = []; + } + + this.gridmap[col][row] = false; + this.faux_grid.push(coords); + + return this; + }; + + + /** + * Add rows to the faux grid. + * + * @method add_faux_rows + * @param {Number} rows The number of rows you want to add to the faux grid. + * @return {Object} Returns the instance of the Gridster class. + */ + fn.add_faux_rows = function(rows) { + var actual_rows = this.rows; + var max_rows = actual_rows + (rows || 1); + + for (var r = max_rows; r > actual_rows; r--) { + for (var c = this.cols; c >= 1; c--) { + this.add_faux_cell(r, c); + } + } + + this.rows = max_rows; + + if (this.options.autogenerate_stylesheet) { + this.generate_stylesheet(); + } + + return this; + }; + + /** + * Add cols to the faux grid. + * + * @method add_faux_cols + * @param {Number} cols The number of cols you want to add to the faux grid. + * @return {Object} Returns the instance of the Gridster class. + */ + fn.add_faux_cols = function(cols) { + var actual_cols = this.cols; + var max_cols = actual_cols + (cols || 1); + + for (var c = actual_cols; c < max_cols; c++) { + for (var r = this.rows; r >= 1; r--) { + this.add_faux_cell(r, c); + } + } + + this.cols = max_cols; + + if (this.options.autogenerate_stylesheet) { + this.generate_stylesheet(); + } + + return this; + }; + + + /** + * Recalculates the offsets for the faux grid. You need to use it when + * the browser is resized. + * + * @method recalculate_faux_grid + * @return {Object} Returns the instance of the Gridster class. + */ + fn.recalculate_faux_grid = function() { + var aw = this.$wrapper.width(); + this.baseX = ($(window).width() - aw) / 2; + this.baseY = this.$wrapper.offset().top; + + $.each(this.faux_grid, $.proxy(function(i, coords) { + this.faux_grid[i] = coords.update({ + left: this.baseX + (coords.data.col -1) * this.min_widget_width, + top: this.baseY + (coords.data.row -1) * this.min_widget_height + }); + + }, this)); + + return this; + }; + + + /** + * Get all widgets in the DOM and register them. + * + * @method get_widgets_from_DOM + * @return {Object} Returns the instance of the Gridster class. + */ + fn.get_widgets_from_DOM = function() { + this.$widgets.each($.proxy(function(i, widget) { + this.register_widget($(widget)); + }, this)); + return this; + }; + + + /** + * Calculate columns and rows to be set based on the configuration + * parameters, grid dimensions, etc ... + * + * @method generate_grid_and_stylesheet + * @return {Object} Returns the instance of the Gridster class. + */ + fn.generate_grid_and_stylesheet = function() { + var aw = this.$wrapper.width(); + var ah = this.$wrapper.height(); + + var cols = Math.floor(aw / this.min_widget_width) + + this.options.extra_cols; + + var actual_cols = this.$widgets.map(function() { + return $(this).attr('data-col'); + }); + actual_cols = Array.prototype.slice.call(actual_cols, 0); + //needed to pass tests with phantomjs + actual_cols.length || (actual_cols = [0]); + + var min_cols = Math.max.apply(Math, actual_cols); + + // get all rows that could be occupied by the current widgets + var max_rows = this.options.extra_rows; + this.$widgets.each(function(i, w) { + max_rows += (+$(w).attr('data-sizey')); + }); + + this.cols = Math.max(min_cols, cols, this.options.min_cols); + this.rows = Math.max(max_rows, this.options.min_rows); + + this.baseX = ($(window).width() - aw) / 2; + this.baseY = this.$wrapper.offset().top; + + if (this.options.autogenerate_stylesheet) { + this.generate_stylesheet(); + } + + return this.generate_faux_grid(this.rows, this.cols); + }; + + + //jQuery adapter + $.fn.gridster = function(options) { + return this.each(function() { + if (!$(this).data('gridster')) { + $(this).data('gridster', new Gridster( this, options )); + } + }); + }; + + $.Gridster = fn; + +}(jQuery, window, document)); diff --git a/GRID/assets/jquery.js b/GRID/assets/jquery.js new file mode 100644 index 0000000..3774ff9 --- /dev/null +++ b/GRID/assets/jquery.js @@ -0,0 +1,9404 @@ +/*! + * jQuery JavaScript Library v1.7.2 + * http://jquery.com/ + * + * Copyright 2011, John Resig + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * Copyright 2011, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * + * Date: Wed Mar 21 12:46:34 2012 -0700 + */ +(function( window, undefined ) { + +// Use the correct document accordingly with window argument (sandbox) +var document = window.document, + navigator = window.navigator, + location = window.location; +var jQuery = (function() { + +// Define a local copy of jQuery +var jQuery = function( selector, context ) { + // The jQuery object is actually just the init constructor 'enhanced' + return new jQuery.fn.init( selector, context, rootjQuery ); + }, + + // Map over jQuery in case of overwrite + _jQuery = window.jQuery, + + // Map over the $ in case of overwrite + _$ = window.$, + + // A central reference to the root jQuery(document) + rootjQuery, + + // A simple way to check for HTML strings or ID strings + // Prioritize #id over to avoid XSS via location.hash (#9521) + quickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/, + + // Check if a string has a non-whitespace character in it + rnotwhite = /\S/, + + // Used for trimming whitespace + trimLeft = /^\s+/, + trimRight = /\s+$/, + + // Match a standalone tag + rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/, + + // JSON RegExp + rvalidchars = /^[\],:{}\s]*$/, + rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, + rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, + rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g, + + // Useragent RegExp + rwebkit = /(webkit)[ \/]([\w.]+)/, + ropera = /(opera)(?:.*version)?[ \/]([\w.]+)/, + rmsie = /(msie) ([\w.]+)/, + rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/, + + // Matches dashed string for camelizing + rdashAlpha = /-([a-z]|[0-9])/ig, + rmsPrefix = /^-ms-/, + + // Used by jQuery.camelCase as callback to replace() + fcamelCase = function( all, letter ) { + return ( letter + "" ).toUpperCase(); + }, + + // Keep a UserAgent string for use with jQuery.browser + userAgent = navigator.userAgent, + + // For matching the engine and version of the browser + browserMatch, + + // The deferred used on DOM ready + readyList, + + // The ready event handler + DOMContentLoaded, + + // Save a reference to some core methods + toString = Object.prototype.toString, + hasOwn = Object.prototype.hasOwnProperty, + push = Array.prototype.push, + slice = Array.prototype.slice, + trim = String.prototype.trim, + indexOf = Array.prototype.indexOf, + + // [[Class]] -> type pairs + class2type = {}; + +jQuery.fn = jQuery.prototype = { + constructor: jQuery, + init: function( selector, context, rootjQuery ) { + var match, elem, ret, doc; + + // Handle $(""), $(null), or $(undefined) + if ( !selector ) { + return this; + } + + // Handle $(DOMElement) + if ( selector.nodeType ) { + this.context = this[0] = selector; + this.length = 1; + return this; + } + + // The body element only exists once, optimize finding it + if ( selector === "body" && !context && document.body ) { + this.context = document; + this[0] = document.body; + this.selector = selector; + this.length = 1; + return this; + } + + // Handle HTML strings + if ( typeof selector === "string" ) { + // Are we dealing with HTML string or an ID? + 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 = quickExpr.exec( selector ); + } + + // Verify a match, and that no context was specified for #id + if ( match && (match[1] || !context) ) { + + // HANDLE: $(html) -> $(array) + if ( match[1] ) { + context = context instanceof jQuery ? context[0] : context; + doc = ( context ? context.ownerDocument || context : document ); + + // If a single string is passed in and it's a single tag + // just do a createElement and skip the rest + ret = rsingleTag.exec( selector ); + + if ( ret ) { + if ( jQuery.isPlainObject( context ) ) { + selector = [ document.createElement( ret[1] ) ]; + jQuery.fn.attr.call( selector, context, true ); + + } else { + selector = [ doc.createElement( ret[1] ) ]; + } + + } else { + ret = jQuery.buildFragment( [ match[1] ], [ doc ] ); + selector = ( ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment ).childNodes; + } + + return jQuery.merge( this, selector ); + + // 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 || rootjQuery ).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( jQuery.isFunction( selector ) ) { + return rootjQuery.ready( selector ); + } + + if ( selector.selector !== undefined ) { + this.selector = selector.selector; + this.context = selector.context; + } + + return jQuery.makeArray( selector, this ); + }, + + // Start with an empty selector + selector: "", + + // The current version of jQuery being used + jquery: "1.7.2", + + // The default length of a jQuery object is 0 + length: 0, + + // The number of elements contained in the matched element set + size: function() { + return this.length; + }, + + toArray: function() { + return slice.call( this, 0 ); + }, + + // 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 a 'clean' array + this.toArray() : + + // Return just the object + ( num < 0 ? this[ this.length + num ] : this[ num ] ); + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems, name, selector ) { + // Build a new jQuery matched element set + var ret = this.constructor(); + + if ( jQuery.isArray( elems ) ) { + push.apply( ret, elems ); + + } else { + jQuery.merge( ret, elems ); + } + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + ret.context = this.context; + + if ( name === "find" ) { + ret.selector = this.selector + ( this.selector ? " " : "" ) + selector; + } else if ( name ) { + ret.selector = this.selector + "." + name + "(" + selector + ")"; + } + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + // (You can seed the arguments with an array of args, but this is + // only used internally.) + each: function( callback, args ) { + return jQuery.each( this, callback, args ); + }, + + ready: function( fn ) { + // Attach the listeners + jQuery.bindReady(); + + // Add the callback + readyList.add( fn ); + + return this; + }, + + eq: function( i ) { + i = +i; + return i === -1 ? + this.slice( i ) : + this.slice( i, i + 1 ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ), + "slice", slice.call(arguments).join(",") ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map(this, function( elem, i ) { + return callback.call( elem, i, elem ); + })); + }, + + end: function() { + return this.prevObject || this.constructor(null); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: [].sort, + splice: [].splice +}; + +// Give the init function the jQuery prototype for later instantiation +jQuery.fn.init.prototype = jQuery.fn; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[0] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + 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" && !jQuery.isFunction(target) ) { + target = {}; + } + + // extend jQuery itself if only one argument is passed + if ( length === i ) { + 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({ + noConflict: function( deep ) { + if ( window.$ === jQuery ) { + window.$ = _$; + } + + if ( deep && window.jQuery === jQuery ) { + window.jQuery = _jQuery; + } + + return jQuery; + }, + + // 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 ) { + // Either a released hold or an DOMready/load event and not yet ready + if ( (wait === true && !--jQuery.readyWait) || (wait !== true && !jQuery.isReady) ) { + // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). + if ( !document.body ) { + return setTimeout( jQuery.ready, 1 ); + } + + // 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.fireWith( document, [ jQuery ] ); + + // Trigger any bound ready events + if ( jQuery.fn.trigger ) { + jQuery( document ).trigger( "ready" ).off( "ready" ); + } + } + }, + + bindReady: function() { + if ( readyList ) { + return; + } + + readyList = jQuery.Callbacks( "once memory" ); + + // Catch cases where $(document).ready() is called after the + // browser event has already occurred. + if ( document.readyState === "complete" ) { + // Handle it asynchronously to allow scripts the opportunity to delay ready + return setTimeout( jQuery.ready, 1 ); + } + + // Mozilla, Opera and webkit nightlies currently support this event + if ( document.addEventListener ) { + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", jQuery.ready, false ); + + // If IE event model is used + } else if ( document.attachEvent ) { + // ensure firing before onload, + // maybe late but safe also for iframes + document.attachEvent( "onreadystatechange", DOMContentLoaded ); + + // A fallback to window.onload, that will always work + window.attachEvent( "onload", jQuery.ready ); + + // If IE and not a frame + // continually check to see if the document is ready + var toplevel = false; + + try { + toplevel = window.frameElement == null; + } catch(e) {} + + if ( document.documentElement.doScroll && toplevel ) { + doScrollCheck(); + } + } + }, + + // 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 ) { + return obj != null && obj == obj.window; + }, + + isNumeric: function( obj ) { + return !isNaN( parseFloat(obj) ) && isFinite( obj ); + }, + + type: function( obj ) { + return obj == null ? + String( obj ) : + class2type[ toString.call(obj) ] || "object"; + }, + + isPlainObject: function( obj ) { + // 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; + } + + // Own properties are enumerated firstly, so to speed up, + // if last one is own, then all properties are own. + + var key; + for ( key in obj ) {} + + return key === undefined || hasOwn.call( obj, key ); + }, + + isEmptyObject: function( obj ) { + for ( var name in obj ) { + return false; + } + return true; + }, + + error: function( msg ) { + throw new Error( msg ); + }, + + parseJSON: function( data ) { + if ( typeof data !== "string" || !data ) { + return null; + } + + // Make sure leading/trailing whitespace is removed (IE can't handle it) + data = jQuery.trim( data ); + + // Attempt to parse using the native JSON parser first + if ( window.JSON && window.JSON.parse ) { + return window.JSON.parse( data ); + } + + // Make sure the incoming data is actual JSON + // Logic borrowed from http://json.org/json2.js + if ( rvalidchars.test( data.replace( rvalidescape, "@" ) + .replace( rvalidtokens, "]" ) + .replace( rvalidbraces, "")) ) { + + return ( new Function( "return " + data ) )(); + + } + jQuery.error( "Invalid JSON: " + data ); + }, + + // Cross-browser xml parsing + parseXML: function( data ) { + if ( typeof data !== "string" || !data ) { + return null; + } + var xml, tmp; + try { + if ( window.DOMParser ) { // Standard + tmp = new DOMParser(); + xml = tmp.parseFromString( data , "text/xml" ); + } else { // IE + xml = new ActiveXObject( "Microsoft.XMLDOM" ); + xml.async = "false"; + xml.loadXML( data ); + } + } catch( e ) { + xml = undefined; + } + if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) { + jQuery.error( "Invalid XML: " + data ); + } + return xml; + }, + + noop: function() {}, + + // Evaluates a script in a global context + // 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 && rnotwhite.test( 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 ); + } )( 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.toUpperCase() === name.toUpperCase(); + }, + + // args is for internal usage only + each: function( object, callback, args ) { + var name, i = 0, + length = object.length, + isObj = length === undefined || jQuery.isFunction( object ); + + if ( args ) { + if ( isObj ) { + for ( name in object ) { + if ( callback.apply( object[ name ], args ) === false ) { + break; + } + } + } else { + for ( ; i < length; ) { + if ( callback.apply( object[ i++ ], args ) === false ) { + break; + } + } + } + + // A special, fast, case for the most common use of each + } else { + if ( isObj ) { + for ( name in object ) { + if ( callback.call( object[ name ], name, object[ name ] ) === false ) { + break; + } + } + } else { + for ( ; i < length; ) { + if ( callback.call( object[ i ], i, object[ i++ ] ) === false ) { + break; + } + } + } + } + + return object; + }, + + // Use native String.trim function wherever possible + trim: trim ? + function( text ) { + return text == null ? + "" : + trim.call( text ); + } : + + // Otherwise use our own trimming functionality + function( text ) { + return text == null ? + "" : + text.toString().replace( trimLeft, "" ).replace( trimRight, "" ); + }, + + // results is for internal usage only + makeArray: function( array, results ) { + var ret = results || []; + + if ( array != null ) { + // The window, strings (and functions) also have 'length' + // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930 + var type = jQuery.type( array ); + + if ( array.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( array ) ) { + push.call( ret, array ); + } else { + jQuery.merge( ret, array ); + } + } + + return ret; + }, + + inArray: function( elem, array, i ) { + var len; + + if ( array ) { + if ( indexOf ) { + return indexOf.call( array, elem, i ); + } + + len = array.length; + i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0; + + for ( ; i < len; i++ ) { + // Skip accessing in sparse arrays + if ( i in array && array[ i ] === elem ) { + return i; + } + } + } + + return -1; + }, + + merge: function( first, second ) { + var i = first.length, + j = 0; + + if ( typeof second.length === "number" ) { + for ( var l = second.length; j < l; j++ ) { + first[ i++ ] = second[ j ]; + } + + } else { + while ( second[j] !== undefined ) { + first[ i++ ] = second[ j++ ]; + } + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, inv ) { + var ret = [], retVal; + inv = !!inv; + + // Go through the array, only saving the items + // that pass the validator function + for ( var i = 0, length = elems.length; i < length; i++ ) { + retVal = !!callback( elems[ i ], i ); + if ( inv !== retVal ) { + ret.push( elems[ i ] ); + } + } + + return ret; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var value, key, ret = [], + i = 0, + length = elems.length, + // jquery objects are treated as arrays + isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ; + + // Go through the array, translating each of the items to their + if ( isArray ) { + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret[ ret.length ] = value; + } + } + + // Go through every key on the object, + } else { + for ( key in elems ) { + value = callback( elems[ key ], key, arg ); + + if ( value != null ) { + ret[ ret.length ] = value; + } + } + } + + // Flatten any nested arrays + return ret.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 ) { + if ( typeof context === "string" ) { + var 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 + var args = slice.call( arguments, 2 ), + proxy = function() { + return fn.apply( context, 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 || proxy.guid || jQuery.guid++; + + return proxy; + }, + + // Mutifunctional method to get and set values to a collection + // The value/s can optionally be executed if it's a function + access: function( elems, fn, key, value, chainable, emptyGet, pass ) { + var exec, + bulk = key == null, + i = 0, + length = elems.length; + + // Sets many values + if ( key && typeof key === "object" ) { + for ( i in key ) { + jQuery.access( elems, fn, i, key[i], 1, emptyGet, value ); + } + chainable = 1; + + // Sets one value + } else if ( value !== undefined ) { + // Optionally, function values get executed if exec is true + exec = pass === undefined && jQuery.isFunction( value ); + + if ( bulk ) { + // Bulk operations only iterate when executing function values + if ( exec ) { + exec = fn; + fn = function( elem, key, value ) { + return exec.call( jQuery( elem ), value ); + }; + + // Otherwise they run against the entire set + } else { + fn.call( elems, value ); + fn = null; + } + } + + if ( fn ) { + for (; i < length; i++ ) { + fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass ); + } + } + + chainable = 1; + } + + return chainable ? + elems : + + // Gets + bulk ? + fn.call( elems ) : + length ? fn( elems[0], key ) : emptyGet; + }, + + now: function() { + return ( new Date() ).getTime(); + }, + + // Use of jQuery.browser is frowned upon. + // More details: http://docs.jquery.com/Utilities/jQuery.browser + uaMatch: function( ua ) { + ua = ua.toLowerCase(); + + var match = rwebkit.exec( ua ) || + ropera.exec( ua ) || + rmsie.exec( ua ) || + ua.indexOf("compatible") < 0 && rmozilla.exec( ua ) || + []; + + return { browser: match[1] || "", version: match[2] || "0" }; + }, + + sub: function() { + function jQuerySub( selector, context ) { + return new jQuerySub.fn.init( selector, context ); + } + jQuery.extend( true, jQuerySub, this ); + jQuerySub.superclass = this; + jQuerySub.fn = jQuerySub.prototype = this(); + jQuerySub.fn.constructor = jQuerySub; + jQuerySub.sub = this.sub; + jQuerySub.fn.init = function init( selector, context ) { + if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) { + context = jQuerySub( context ); + } + + return jQuery.fn.init.call( this, selector, context, rootjQuerySub ); + }; + jQuerySub.fn.init.prototype = jQuerySub.fn; + var rootjQuerySub = jQuerySub(document); + return jQuerySub; + }, + + browser: {} +}); + +// Populate the class2type map +jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); +}); + +browserMatch = jQuery.uaMatch( userAgent ); +if ( browserMatch.browser ) { + jQuery.browser[ browserMatch.browser ] = true; + jQuery.browser.version = browserMatch.version; +} + +// Deprecated, use jQuery.browser.webkit instead +if ( jQuery.browser.webkit ) { + jQuery.browser.safari = true; +} + +// IE doesn't match non-breaking spaces with \s +if ( rnotwhite.test( "\xA0" ) ) { + trimLeft = /^[\s\xA0]+/; + trimRight = /[\s\xA0]+$/; +} + +// All jQuery objects should point back to these +rootjQuery = jQuery(document); + +// Cleanup functions for the document ready method +if ( document.addEventListener ) { + DOMContentLoaded = function() { + document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false ); + jQuery.ready(); + }; + +} else if ( document.attachEvent ) { + DOMContentLoaded = function() { + // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). + if ( document.readyState === "complete" ) { + document.detachEvent( "onreadystatechange", DOMContentLoaded ); + jQuery.ready(); + } + }; +} + +// The DOM ready check for Internet Explorer +function doScrollCheck() { + if ( jQuery.isReady ) { + return; + } + + try { + // If IE is used, use the trick by Diego Perini + // http://javascript.nwbox.com/IEContentLoaded/ + document.documentElement.doScroll("left"); + } catch(e) { + setTimeout( doScrollCheck, 1 ); + return; + } + + // and execute any waiting functions + jQuery.ready(); +} + +return jQuery; + +})(); + + +// String to Object flags format cache +var flagsCache = {}; + +// Convert String-formatted flags into Object-formatted ones and store in cache +function createFlags( flags ) { + var object = flagsCache[ flags ] = {}, + i, length; + flags = flags.split( /\s+/ ); + for ( i = 0, length = flags.length; i < length; i++ ) { + object[ flags[i] ] = true; + } + return object; +} + +/* + * Create a callback list using the following parameters: + * + * flags: an optional list of space-separated flags that will change how + * the callback list behaves + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible flags: + * + * 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( flags ) { + + // Convert flags from String-formatted to Object-formatted + // (we check in cache first) + flags = flags ? ( flagsCache[ flags ] || createFlags( flags ) ) : {}; + + var // Actual callback list + list = [], + // Stack of fire calls for repeatable lists + stack = [], + // Last fire value (for non-forgettable lists) + memory, + // Flag to know if list was already fired + fired, + // Flag to know if list is currently firing + firing, + // First callback to fire (used internally by add and fireWith) + firingStart, + // End of the loop when firing + firingLength, + // Index of currently firing callback (modified by remove if needed) + firingIndex, + // Add one or several callbacks to the list + add = function( args ) { + var i, + length, + elem, + type, + actual; + for ( i = 0, length = args.length; i < length; i++ ) { + elem = args[ i ]; + type = jQuery.type( elem ); + if ( type === "array" ) { + // Inspect recursively + add( elem ); + } else if ( type === "function" ) { + // Add if not in unique mode and callback is not in + if ( !flags.unique || !self.has( elem ) ) { + list.push( elem ); + } + } + } + }, + // Fire callbacks + fire = function( context, args ) { + args = args || []; + memory = !flags.memory || [ context, args ]; + fired = true; + firing = true; + firingIndex = firingStart || 0; + firingStart = 0; + firingLength = list.length; + for ( ; list && firingIndex < firingLength; firingIndex++ ) { + if ( list[ firingIndex ].apply( context, args ) === false && flags.stopOnFalse ) { + memory = true; // Mark as halted + break; + } + } + firing = false; + if ( list ) { + if ( !flags.once ) { + if ( stack && stack.length ) { + memory = stack.shift(); + self.fireWith( memory[ 0 ], memory[ 1 ] ); + } + } else if ( memory === true ) { + self.disable(); + } else { + list = []; + } + } + }, + // Actual Callbacks object + self = { + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + var length = list.length; + add( arguments ); + // Do we need to add the callbacks to the + // current firing batch? + if ( firing ) { + firingLength = list.length; + // With memory, if we're not firing then + // we should call right away, unless previous + // firing was halted (stopOnFalse) + } else if ( memory && memory !== true ) { + firingStart = length; + fire( memory[ 0 ], memory[ 1 ] ); + } + } + return this; + }, + // Remove a callback from the list + remove: function() { + if ( list ) { + var args = arguments, + argIndex = 0, + argLength = args.length; + for ( ; argIndex < argLength ; argIndex++ ) { + for ( var i = 0; i < list.length; i++ ) { + if ( args[ argIndex ] === list[ i ] ) { + // Handle firingIndex and firingLength + if ( firing ) { + if ( i <= firingLength ) { + firingLength--; + if ( i <= firingIndex ) { + firingIndex--; + } + } + } + // Remove the element + list.splice( i--, 1 ); + // If we have some unicity property then + // we only need to do this once + if ( flags.unique ) { + break; + } + } + } + } + } + return this; + }, + // Control if a given callback is in the list + has: function( fn ) { + if ( list ) { + var i = 0, + length = list.length; + for ( ; i < length; i++ ) { + if ( fn === list[ i ] ) { + return true; + } + } + } + return false; + }, + // Remove all callbacks from the list + empty: function() { + list = []; + return this; + }, + // Have the list do nothing anymore + disable: function() { + list = stack = memory = undefined; + return this; + }, + // Is it disabled? + disabled: function() { + return !list; + }, + // Lock the list in its current state + lock: function() { + stack = undefined; + if ( !memory || memory === true ) { + self.disable(); + } + return this; + }, + // Is it locked? + locked: function() { + return !stack; + }, + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + if ( stack ) { + if ( firing ) { + if ( !flags.once ) { + stack.push( [ context, args ] ); + } + } else if ( !( flags.once && memory ) ) { + fire( context, args ); + } + } + 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; +}; + + + + +var // Static reference to slice + sliceDeferred = [].slice; + +jQuery.extend({ + + Deferred: function( func ) { + var doneList = jQuery.Callbacks( "once memory" ), + failList = jQuery.Callbacks( "once memory" ), + progressList = jQuery.Callbacks( "memory" ), + state = "pending", + lists = { + resolve: doneList, + reject: failList, + notify: progressList + }, + promise = { + done: doneList.add, + fail: failList.add, + progress: progressList.add, + + state: function() { + return state; + }, + + // Deprecated + isResolved: doneList.fired, + isRejected: failList.fired, + + then: function( doneCallbacks, failCallbacks, progressCallbacks ) { + deferred.done( doneCallbacks ).fail( failCallbacks ).progress( progressCallbacks ); + return this; + }, + always: function() { + deferred.done.apply( deferred, arguments ).fail.apply( deferred, arguments ); + return this; + }, + pipe: function( fnDone, fnFail, fnProgress ) { + return jQuery.Deferred(function( newDefer ) { + jQuery.each( { + done: [ fnDone, "resolve" ], + fail: [ fnFail, "reject" ], + progress: [ fnProgress, "notify" ] + }, function( handler, data ) { + var fn = data[ 0 ], + action = data[ 1 ], + returned; + if ( jQuery.isFunction( fn ) ) { + deferred[ handler ](function() { + returned = fn.apply( this, arguments ); + if ( returned && jQuery.isFunction( returned.promise ) ) { + returned.promise().then( newDefer.resolve, newDefer.reject, newDefer.notify ); + } else { + newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] ); + } + }); + } else { + deferred[ handler ]( newDefer[ action ] ); + } + }); + }).promise(); + }, + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + if ( obj == null ) { + obj = promise; + } else { + for ( var key in promise ) { + obj[ key ] = promise[ key ]; + } + } + return obj; + } + }, + deferred = promise.promise({}), + key; + + for ( key in lists ) { + deferred[ key ] = lists[ key ].fire; + deferred[ key + "With" ] = lists[ key ].fireWith; + } + + // Handle state + deferred.done( function() { + state = "resolved"; + }, failList.disable, progressList.lock ).fail( function() { + state = "rejected"; + }, doneList.disable, progressList.lock ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( firstParam ) { + var args = sliceDeferred.call( arguments, 0 ), + i = 0, + length = args.length, + pValues = new Array( length ), + count = length, + pCount = length, + deferred = length <= 1 && firstParam && jQuery.isFunction( firstParam.promise ) ? + firstParam : + jQuery.Deferred(), + promise = deferred.promise(); + function resolveFunc( i ) { + return function( value ) { + args[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value; + if ( !( --count ) ) { + deferred.resolveWith( deferred, args ); + } + }; + } + function progressFunc( i ) { + return function( value ) { + pValues[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value; + deferred.notifyWith( promise, pValues ); + }; + } + if ( length > 1 ) { + for ( ; i < length; i++ ) { + if ( args[ i ] && args[ i ].promise && jQuery.isFunction( args[ i ].promise ) ) { + args[ i ].promise().then( resolveFunc(i), deferred.reject, progressFunc(i) ); + } else { + --count; + } + } + if ( !count ) { + deferred.resolveWith( deferred, args ); + } + } else if ( deferred !== firstParam ) { + deferred.resolveWith( deferred, length ? [ firstParam ] : [] ); + } + return promise; + } +}); + + + + +jQuery.support = (function() { + + var support, + all, + a, + select, + opt, + input, + fragment, + tds, + events, + eventName, + i, + isSupported, + div = document.createElement( "div" ), + documentElement = document.documentElement; + + // Preliminary tests + div.setAttribute("className", "t"); + div.innerHTML = "
    a"; + + all = div.getElementsByTagName( "*" ); + a = div.getElementsByTagName( "a" )[ 0 ]; + + // Can't get basic test support + if ( !all || !all.length || !a ) { + return {}; + } + + // First batch of supports tests + select = document.createElement( "select" ); + opt = select.appendChild( document.createElement("option") ); + input = div.getElementsByTagName( "input" )[ 0 ]; + + support = { + // IE strips leading whitespace when .innerHTML is used + leadingWhitespace: ( div.firstChild.nodeType === 3 ), + + // Make sure that tbody elements aren't automatically inserted + // IE will insert them into empty tables + tbody: !div.getElementsByTagName("tbody").length, + + // Make sure that link elements get serialized correctly by innerHTML + // This requires a wrapper element in IE + htmlSerialize: !!div.getElementsByTagName("link").length, + + // Get the style information from getAttribute + // (IE uses .cssText instead) + style: /top/.test( a.getAttribute("style") ), + + // Make sure that URLs aren't manipulated + // (IE normalizes it by default) + hrefNormalized: ( a.getAttribute("href") === "/a" ), + + // Make sure that element opacity exists + // (IE uses filter instead) + // Use a regex to work around a WebKit issue. See #5145 + opacity: /^0.55/.test( a.style.opacity ), + + // Verify style float existence + // (IE uses styleFloat instead of cssFloat) + cssFloat: !!a.style.cssFloat, + + // Make sure that if no value is specified for a checkbox + // that it defaults to "on". + // (WebKit defaults to "" instead) + checkOn: ( input.value === "on" ), + + // Make sure that a selected-by-default option has a working selected property. + // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) + optSelected: opt.selected, + + // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7) + getSetAttribute: div.className !== "t", + + // Tests for enctype support on a form(#6743) + enctype: !!document.createElement("form").enctype, + + // Makes sure cloning an html5 element does not cause problems + // Where outerHTML is undefined, this still works + html5Clone: document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav>", + + // Will be defined later + submitBubbles: true, + changeBubbles: true, + focusinBubbles: false, + deleteExpando: true, + noCloneEvent: true, + inlineBlockNeedsLayout: false, + shrinkWrapBlocks: false, + reliableMarginRight: true, + pixelMargin: true + }; + + // jQuery.boxModel DEPRECATED in 1.3, use jQuery.support.boxModel instead + jQuery.boxModel = support.boxModel = (document.compatMode === "CSS1Compat"); + + // Make sure checked status is properly cloned + input.checked = true; + support.noCloneChecked = input.cloneNode( true ).checked; + + // Make sure that the options inside disabled selects aren't marked as disabled + // (WebKit marks them as disabled) + select.disabled = true; + support.optDisabled = !opt.disabled; + + // Test to see if it's possible to delete an expando from an element + // Fails in Internet Explorer + try { + delete div.test; + } catch( e ) { + support.deleteExpando = false; + } + + if ( !div.addEventListener && div.attachEvent && div.fireEvent ) { + div.attachEvent( "onclick", function() { + // Cloning a node shouldn't copy over any + // bound event handlers (IE does this) + support.noCloneEvent = false; + }); + div.cloneNode( true ).fireEvent( "onclick" ); + } + + // Check if a radio maintains its value + // after being appended to the DOM + input = document.createElement("input"); + input.value = "t"; + input.setAttribute("type", "radio"); + support.radioValue = input.value === "t"; + + input.setAttribute("checked", "checked"); + + // #11217 - WebKit loses check when the name is after the checked attribute + input.setAttribute( "name", "t" ); + + div.appendChild( input ); + fragment = document.createDocumentFragment(); + fragment.appendChild( div.lastChild ); + + // WebKit doesn't clone checked state correctly in fragments + support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Check if a disconnected checkbox will retain its checked + // value of true after appended to the DOM (IE6/7) + support.appendChecked = input.checked; + + fragment.removeChild( input ); + fragment.appendChild( div ); + + // Technique from Juriy Zaytsev + // http://perfectionkills.com/detecting-event-support-without-browser-sniffing/ + // We only care about the case where non-standard event systems + // are used, namely in IE. Short-circuiting here helps us to + // avoid an eval call (in setAttribute) which can cause CSP + // to go haywire. See: https://developer.mozilla.org/en/Security/CSP + if ( div.attachEvent ) { + for ( i in { + submit: 1, + change: 1, + focusin: 1 + }) { + eventName = "on" + i; + isSupported = ( eventName in div ); + if ( !isSupported ) { + div.setAttribute( eventName, "return;" ); + isSupported = ( typeof div[ eventName ] === "function" ); + } + support[ i + "Bubbles" ] = isSupported; + } + } + + fragment.removeChild( div ); + + // Null elements to avoid leaks in IE + fragment = select = opt = div = input = null; + + // Run tests that need a body at doc ready + jQuery(function() { + var container, outer, inner, table, td, offsetSupport, + marginDiv, conMarginTop, style, html, positionTopLeftWidthHeight, + paddingMarginBorderVisibility, paddingMarginBorder, + body = document.getElementsByTagName("body")[0]; + + if ( !body ) { + // Return for frameset docs that don't have a body + return; + } + + conMarginTop = 1; + paddingMarginBorder = "padding:0;margin:0;border:"; + positionTopLeftWidthHeight = "position:absolute;top:0;left:0;width:1px;height:1px;"; + paddingMarginBorderVisibility = paddingMarginBorder + "0;visibility:hidden;"; + style = "style='" + positionTopLeftWidthHeight + paddingMarginBorder + "5px solid #000;"; + html = "
    " + + "" + + "
    "; + + container = document.createElement("div"); + container.style.cssText = paddingMarginBorderVisibility + "width:0;height:0;position:static;top:0;margin-top:" + conMarginTop + "px"; + body.insertBefore( container, body.firstChild ); + + // Construct the test element + div = document.createElement("div"); + container.appendChild( div ); + + // Check if table cells still have offsetWidth/Height when they are set + // to display:none and there are still other visible table cells in a + // table row; if so, offsetWidth/Height are not reliable for use when + // determining if an element has been hidden directly using + // display:none (it is still safe to use offsets if a parent element is + // hidden; don safety goggles and see bug #4512 for more information). + // (only IE 8 fails this test) + div.innerHTML = "
    t
    "; + tds = div.getElementsByTagName( "td" ); + isSupported = ( tds[ 0 ].offsetHeight === 0 ); + + tds[ 0 ].style.display = ""; + tds[ 1 ].style.display = "none"; + + // Check if empty table cells still have offsetWidth/Height + // (IE <= 8 fail this test) + support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 ); + + // Check if div with explicit width and no margin-right incorrectly + // gets computed margin-right based on width of container. For more + // info see bug #3333 + // Fails in WebKit before Feb 2011 nightlies + // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right + if ( window.getComputedStyle ) { + div.innerHTML = ""; + marginDiv = document.createElement( "div" ); + marginDiv.style.width = "0"; + marginDiv.style.marginRight = "0"; + div.style.width = "2px"; + div.appendChild( marginDiv ); + support.reliableMarginRight = + ( parseInt( ( window.getComputedStyle( marginDiv, null ) || { marginRight: 0 } ).marginRight, 10 ) || 0 ) === 0; + } + + if ( typeof div.style.zoom !== "undefined" ) { + // Check if natively block-level elements act like inline-block + // elements when setting their display to 'inline' and giving + // them layout + // (IE < 8 does this) + div.innerHTML = ""; + div.style.width = div.style.padding = "1px"; + div.style.border = 0; + div.style.overflow = "hidden"; + div.style.display = "inline"; + div.style.zoom = 1; + support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 ); + + // Check if elements with layout shrink-wrap their children + // (IE 6 does this) + div.style.display = "block"; + div.style.overflow = "visible"; + div.innerHTML = "
    "; + support.shrinkWrapBlocks = ( div.offsetWidth !== 3 ); + } + + div.style.cssText = positionTopLeftWidthHeight + paddingMarginBorderVisibility; + div.innerHTML = html; + + outer = div.firstChild; + inner = outer.firstChild; + td = outer.nextSibling.firstChild.firstChild; + + offsetSupport = { + doesNotAddBorder: ( inner.offsetTop !== 5 ), + doesAddBorderForTableAndCells: ( td.offsetTop === 5 ) + }; + + inner.style.position = "fixed"; + inner.style.top = "20px"; + + // safari subtracts parent border width here which is 5px + offsetSupport.fixedPosition = ( inner.offsetTop === 20 || inner.offsetTop === 15 ); + inner.style.position = inner.style.top = ""; + + outer.style.overflow = "hidden"; + outer.style.position = "relative"; + + offsetSupport.subtractsBorderForOverflowNotVisible = ( inner.offsetTop === -5 ); + offsetSupport.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== conMarginTop ); + + if ( window.getComputedStyle ) { + div.style.marginTop = "1%"; + support.pixelMargin = ( window.getComputedStyle( div, null ) || { marginTop: 0 } ).marginTop !== "1%"; + } + + if ( typeof container.style.zoom !== "undefined" ) { + container.style.zoom = 1; + } + + body.removeChild( container ); + marginDiv = div = container = null; + + jQuery.extend( support, offsetSupport ); + }); + + return support; +})(); + + + + +var rbrace = /^(?:\{.*\}|\[.*\])$/, + rmultiDash = /([A-Z])/g; + +jQuery.extend({ + cache: {}, + + // Please use with caution + uuid: 0, + + // Unique for each copy of jQuery on the page + // Non-digits removed to match rinlinejQuery + expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ), + + // The following elements throw uncatchable exceptions if you + // attempt to add expando properties to them. + noData: { + "embed": true, + // Ban all objects except for Flash (which handle expandos) + "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000", + "applet": true + }, + + hasData: function( elem ) { + elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ]; + return !!elem && !isEmptyDataObject( elem ); + }, + + data: function( elem, name, data, pvt /* Internal Use Only */ ) { + if ( !jQuery.acceptData( elem ) ) { + return; + } + + var privateCache, thisCache, ret, + internalKey = jQuery.expando, + getByName = typeof name === "string", + + // 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, + isEvents = name === "events"; + + // 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] || (!isEvents && !pvt && !cache[id].data)) && getByName && data === undefined ) { + 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 ) { + elem[ internalKey ] = id = ++jQuery.uuid; + } else { + id = internalKey; + } + } + + if ( !cache[ id ] ) { + cache[ id ] = {}; + + // Avoids exposing jQuery metadata on plain JS objects when the object + // is serialized using JSON.stringify + if ( !isNode ) { + cache[ id ].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 ); + } + } + + privateCache = 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; + } + + // Users should not attempt to inspect the internal events object using jQuery.data, + // it is undocumented and subject to change. But does anyone listen? No. + if ( isEvents && !thisCache[ name ] ) { + return privateCache.events; + } + + // Check for both converted-to-camel and non-converted data property names + // If a data property was specified + if ( getByName ) { + + // 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; + }, + + removeData: function( elem, name, pvt /* Internal Use Only */ ) { + if ( !jQuery.acceptData( elem ) ) { + return; + } + + var thisCache, i, l, + + // Reference to internal data cache key + internalKey = jQuery.expando, + + isNode = elem.nodeType, + + // See jQuery.data for more information + cache = isNode ? jQuery.cache : elem, + + // See jQuery.data for more information + id = isNode ? elem[ internalKey ] : internalKey; + + // 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( " " ); + } + } + } + + for ( i = 0, l = name.length; i < l; 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 : 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; + } + } + + // Browsers that fail expando deletion also refuse to delete expandos on + // the window, but it will allow it on all other JS objects; other browsers + // don't care + // Ensure that `cache` is not a window object #10080 + if ( jQuery.support.deleteExpando || !cache.setInterval ) { + delete cache[ id ]; + } else { + cache[ id ] = null; + } + + // We destroyed the cache and need to eliminate the expando on the node to avoid + // false lookups in the cache for entries that no longer exist + if ( isNode ) { + // IE does not allow us to delete expando properties from nodes, + // nor does it have a removeAttribute function on Document nodes; + // we must handle all of these cases + if ( jQuery.support.deleteExpando ) { + delete elem[ internalKey ]; + } else if ( elem.removeAttribute ) { + elem.removeAttribute( internalKey ); + } else { + elem[ internalKey ] = null; + } + } + }, + + // For internal use only. + _data: function( elem, name, data ) { + return jQuery.data( elem, name, data, true ); + }, + + // A method for determining if a DOM node can handle the data expando + acceptData: function( elem ) { + if ( elem.nodeName ) { + var match = jQuery.noData[ elem.nodeName.toLowerCase() ]; + + if ( match ) { + return !(match === true || elem.getAttribute("classid") !== match); + } + } + + return true; + } +}); + +jQuery.fn.extend({ + data: function( key, value ) { + var parts, part, attr, name, l, + elem = this[0], + i = 0, + data = null; + + // Gets all values + if ( key === undefined ) { + if ( this.length ) { + data = jQuery.data( elem ); + + if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) { + attr = elem.attributes; + for ( l = attr.length; i < l; i++ ) { + name = attr[i].name; + + if ( name.indexOf( "data-" ) === 0 ) { + name = jQuery.camelCase( name.substring(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 ); + }); + } + + parts = key.split( ".", 2 ); + parts[1] = parts[1] ? "." + parts[1] : ""; + part = parts[1] + "!"; + + return jQuery.access( this, function( value ) { + + if ( value === undefined ) { + data = this.triggerHandler( "getData" + part, [ parts[0] ] ); + + // Try to fetch any internally stored data first + if ( data === undefined && elem ) { + data = jQuery.data( elem, key ); + data = dataAttr( elem, key, data ); + } + + return data === undefined && parts[1] ? + this.data( parts[0] ) : + data; + } + + parts[1] = value; + this.each(function() { + var self = jQuery( this ); + + self.triggerHandler( "setData" + part, parts ); + jQuery.data( this, key, value ); + self.triggerHandler( "changeData" + part, parts ); + }); + }, null, value, arguments.length > 1, null, false ); + }, + + removeData: function( key ) { + return this.each(function() { + jQuery.removeData( this, key ); + }); + } +}); + +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 : + jQuery.isNumeric( 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 ) { + for ( var 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 handleQueueMarkDefer( elem, type, src ) { + var deferDataKey = type + "defer", + queueDataKey = type + "queue", + markDataKey = type + "mark", + defer = jQuery._data( elem, deferDataKey ); + if ( defer && + ( src === "queue" || !jQuery._data(elem, queueDataKey) ) && + ( src === "mark" || !jQuery._data(elem, markDataKey) ) ) { + // Give room for hard-coded callbacks to fire first + // and eventually mark/queue something else on the element + setTimeout( function() { + if ( !jQuery._data( elem, queueDataKey ) && + !jQuery._data( elem, markDataKey ) ) { + jQuery.removeData( elem, deferDataKey, true ); + defer.fire(); + } + }, 0 ); + } +} + +jQuery.extend({ + + _mark: function( elem, type ) { + if ( elem ) { + type = ( type || "fx" ) + "mark"; + jQuery._data( elem, type, (jQuery._data( elem, type ) || 0) + 1 ); + } + }, + + _unmark: function( force, elem, type ) { + if ( force !== true ) { + type = elem; + elem = force; + force = false; + } + if ( elem ) { + type = type || "fx"; + var key = type + "mark", + count = force ? 0 : ( (jQuery._data( elem, key ) || 1) - 1 ); + if ( count ) { + jQuery._data( elem, key, count ); + } else { + jQuery.removeData( elem, key, true ); + handleQueueMarkDefer( elem, type, "mark" ); + } + } + }, + + queue: function( elem, type, data ) { + var q; + if ( elem ) { + type = ( type || "fx" ) + "queue"; + q = jQuery._data( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !q || jQuery.isArray(data) ) { + q = jQuery._data( elem, type, jQuery.makeArray(data) ); + } else { + q.push( data ); + } + } + return q || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + fn = queue.shift(), + hooks = {}; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + } + + if ( fn ) { + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift( "inprogress" ); + } + + jQuery._data( elem, type + ".run", hooks ); + fn.call( elem, function() { + jQuery.dequeue( elem, type ); + }, hooks ); + } + + if ( !queue.length ) { + jQuery.removeData( elem, type + "queue " + type + ".run", true ); + handleQueueMarkDefer( elem, type, "queue" ); + } + } +}); + +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 ); + + if ( type === "fx" && queue[0] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + }); + }, + dequeue: function( type ) { + return this.each(function() { + jQuery.dequeue( this, type ); + }); + }, + // Based off of the plugin by Clint Helfers, with permission. + // http://blindsignals.com/index.php/2009/07/jquery-delay/ + delay: function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; + type = type || "fx"; + + return this.queue( type, function( next, hooks ) { + var timeout = setTimeout( next, time ); + hooks.stop = function() { + clearTimeout( timeout ); + }; + }); + }, + 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, object ) { + if ( typeof type !== "string" ) { + object = type; + type = undefined; + } + type = type || "fx"; + var defer = jQuery.Deferred(), + elements = this, + i = elements.length, + count = 1, + deferDataKey = type + "defer", + queueDataKey = type + "queue", + markDataKey = type + "mark", + tmp; + function resolve() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + } + while( i-- ) { + if (( tmp = jQuery.data( elements[ i ], deferDataKey, undefined, true ) || + ( jQuery.data( elements[ i ], queueDataKey, undefined, true ) || + jQuery.data( elements[ i ], markDataKey, undefined, true ) ) && + jQuery.data( elements[ i ], deferDataKey, jQuery.Callbacks( "once memory" ), true ) )) { + count++; + tmp.add( resolve ); + } + } + resolve(); + return defer.promise( object ); + } +}); + + + + +var rclass = /[\n\t\r]/g, + rspace = /\s+/, + rreturn = /\r/g, + rtype = /^(?:button|input)$/i, + rfocusable = /^(?:button|input|object|select|textarea)$/i, + rclickable = /^a(?:rea)?$/i, + rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i, + getSetAttribute = jQuery.support.getSetAttribute, + nodeHook, boolHook, fixSpecified; + +jQuery.fn.extend({ + attr: function( name, value ) { + return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 ); + }, + + removeAttr: function( name ) { + return this.each(function() { + jQuery.removeAttr( this, name ); + }); + }, + + prop: function( name, value ) { + return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 ); + }, + + removeProp: function( name ) { + name = jQuery.propFix[ name ] || name; + return this.each(function() { + // try/catch handles cases where IE balks (such as removing a property on window) + try { + this[ name ] = undefined; + delete this[ name ]; + } catch( e ) {} + }); + }, + + addClass: function( value ) { + var classNames, i, l, elem, + setClass, c, cl; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( j ) { + jQuery( this ).addClass( value.call(this, j, this.className) ); + }); + } + + if ( value && typeof value === "string" ) { + classNames = value.split( rspace ); + + for ( i = 0, l = this.length; i < l; i++ ) { + elem = this[ i ]; + + if ( elem.nodeType === 1 ) { + if ( !elem.className && classNames.length === 1 ) { + elem.className = value; + + } else { + setClass = " " + elem.className + " "; + + for ( c = 0, cl = classNames.length; c < cl; c++ ) { + if ( !~setClass.indexOf( " " + classNames[ c ] + " " ) ) { + setClass += classNames[ c ] + " "; + } + } + elem.className = jQuery.trim( setClass ); + } + } + } + } + + return this; + }, + + removeClass: function( value ) { + var classNames, i, l, elem, className, c, cl; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( j ) { + jQuery( this ).removeClass( value.call(this, j, this.className) ); + }); + } + + if ( (value && typeof value === "string") || value === undefined ) { + classNames = ( value || "" ).split( rspace ); + + for ( i = 0, l = this.length; i < l; i++ ) { + elem = this[ i ]; + + if ( elem.nodeType === 1 && elem.className ) { + if ( value ) { + className = (" " + elem.className + " ").replace( rclass, " " ); + for ( c = 0, cl = classNames.length; c < cl; c++ ) { + className = className.replace(" " + classNames[ c ] + " ", " "); + } + elem.className = jQuery.trim( className ); + + } else { + elem.className = ""; + } + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value, + isBool = typeof stateVal === "boolean"; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( i ) { + jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal ); + }); + } + + return this.each(function() { + if ( type === "string" ) { + // toggle individual class names + var className, + i = 0, + self = jQuery( this ), + state = stateVal, + classNames = value.split( rspace ); + + while ( (className = classNames[ i++ ]) ) { + // check each className given, space seperated list + state = isBool ? state : !self.hasClass( className ); + self[ state ? "addClass" : "removeClass" ]( className ); + } + + } else if ( type === "undefined" || type === "boolean" ) { + if ( this.className ) { + // store className if set + jQuery._data( this, "__className__", this.className ); + } + + // toggle whole className + this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || ""; + } + }); + }, + + hasClass: function( selector ) { + var className = " " + selector + " ", + i = 0, + l = this.length; + for ( ; i < l; i++ ) { + if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) { + return true; + } + } + + return false; + }, + + val: function( value ) { + var hooks, ret, isFunction, + elem = this[0]; + + if ( !arguments.length ) { + if ( elem ) { + hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ]; + + if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) { + return ret; + } + + ret = elem.value; + + return typeof ret === "string" ? + // handle most common string cases + ret.replace(rreturn, "") : + // handle cases where value is null/undef or number + ret == null ? "" : ret; + } + + return; + } + + isFunction = jQuery.isFunction( value ); + + return this.each(function( i ) { + var self = jQuery(this), val; + + if ( this.nodeType !== 1 ) { + return; + } + + if ( isFunction ) { + val = value.call( this, i, self.val() ); + } else { + val = value; + } + + // Treat null/undefined as ""; convert numbers to string + if ( val == null ) { + val = ""; + } else if ( typeof val === "number" ) { + val += ""; + } else if ( jQuery.isArray( val ) ) { + val = jQuery.map(val, function ( value ) { + return value == null ? "" : value + ""; + }); + } + + hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; + + // If set returns undefined, fall back to normal setting + if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) { + this.value = val; + } + }); + } +}); + +jQuery.extend({ + valHooks: { + option: { + get: function( elem ) { + // attributes.value is undefined in Blackberry 4.7 but + // uses .value. See #6932 + var val = elem.attributes.value; + return !val || val.specified ? elem.value : elem.text; + } + }, + select: { + get: function( elem ) { + var value, i, max, option, + index = elem.selectedIndex, + values = [], + options = elem.options, + one = elem.type === "select-one"; + + // Nothing was selected + if ( index < 0 ) { + return null; + } + + // Loop through all the selected options + i = one ? index : 0; + max = one ? index + 1 : options.length; + for ( ; i < max; i++ ) { + option = options[ i ]; + + // Don't return options that are disabled or in a disabled optgroup + if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) && + (!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) { + + // Get the specific value for the option + value = jQuery( option ).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + // Fixes Bug #2551 -- select.val() broken in IE after form.reset() + if ( one && !values.length && options.length ) { + return jQuery( options[ index ] ).val(); + } + + return values; + }, + + set: function( elem, value ) { + var values = jQuery.makeArray( value ); + + jQuery(elem).find("option").each(function() { + this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0; + }); + + if ( !values.length ) { + elem.selectedIndex = -1; + } + return values; + } + } + }, + + attrFn: { + val: true, + css: true, + html: true, + text: true, + data: true, + width: true, + height: true, + offset: true + }, + + attr: function( elem, name, value, pass ) { + var ret, hooks, notxml, + nType = elem.nodeType; + + // don't get/set attributes on text, comment and attribute nodes + if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + if ( pass && name in jQuery.attrFn ) { + return jQuery( elem )[ name ]( value ); + } + + // Fallback to prop when attributes are not supported + if ( typeof elem.getAttribute === "undefined" ) { + return jQuery.prop( elem, name, value ); + } + + notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); + + // All attributes are lowercase + // Grab necessary hook if one is defined + if ( notxml ) { + name = name.toLowerCase(); + hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook ); + } + + if ( value !== undefined ) { + + if ( value === null ) { + jQuery.removeAttr( elem, name ); + return; + + } else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) { + return ret; + + } else { + elem.setAttribute( name, "" + value ); + return value; + } + + } else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) { + return ret; + + } else { + + ret = elem.getAttribute( name ); + + // Non-existent attributes return null, we normalize to undefined + return ret === null ? + undefined : + ret; + } + }, + + removeAttr: function( elem, value ) { + var propName, attrNames, name, l, isBool, + i = 0; + + if ( value && elem.nodeType === 1 ) { + attrNames = value.toLowerCase().split( rspace ); + l = attrNames.length; + + for ( ; i < l; i++ ) { + name = attrNames[ i ]; + + if ( name ) { + propName = jQuery.propFix[ name ] || name; + isBool = rboolean.test( name ); + + // See #9699 for explanation of this approach (setting first, then removal) + // Do not do this for boolean attributes (see #10870) + if ( !isBool ) { + jQuery.attr( elem, name, "" ); + } + elem.removeAttribute( getSetAttribute ? name : propName ); + + // Set corresponding property to false for boolean attributes + if ( isBool && propName in elem ) { + elem[ propName ] = false; + } + } + } + } + }, + + attrHooks: { + type: { + set: function( elem, value ) { + // We can't allow the type property to be changed (since it causes problems in IE) + if ( rtype.test( elem.nodeName ) && elem.parentNode ) { + jQuery.error( "type property can't be changed" ); + } else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) { + // Setting the type on a radio button after the value resets the value in IE6-9 + // Reset value to it's default in case type is set after value + // This is for element creation + var val = elem.value; + elem.setAttribute( "type", value ); + if ( val ) { + elem.value = val; + } + return value; + } + } + }, + // Use the value property for back compat + // Use the nodeHook for button elements in IE6/7 (#1954) + value: { + get: function( elem, name ) { + if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { + return nodeHook.get( elem, name ); + } + return name in elem ? + elem.value : + null; + }, + set: function( elem, value, name ) { + if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { + return nodeHook.set( elem, value, name ); + } + // Does not return so that setAttribute is also used + elem.value = value; + } + } + }, + + propFix: { + tabindex: "tabIndex", + readonly: "readOnly", + "for": "htmlFor", + "class": "className", + maxlength: "maxLength", + cellspacing: "cellSpacing", + cellpadding: "cellPadding", + rowspan: "rowSpan", + colspan: "colSpan", + usemap: "useMap", + frameborder: "frameBorder", + contenteditable: "contentEditable" + }, + + prop: function( elem, name, value ) { + var ret, hooks, notxml, + nType = elem.nodeType; + + // don't get/set properties on text, comment and attribute nodes + if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); + + if ( notxml ) { + // Fix name and attach hooks + name = jQuery.propFix[ name ] || name; + hooks = jQuery.propHooks[ name ]; + } + + if ( value !== undefined ) { + if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) { + return ret; + + } else { + return ( elem[ name ] = value ); + } + + } else { + if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) { + return ret; + + } else { + return elem[ name ]; + } + } + }, + + propHooks: { + tabIndex: { + get: function( elem ) { + // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set + // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + var attributeNode = elem.getAttributeNode("tabindex"); + + return attributeNode && attributeNode.specified ? + parseInt( attributeNode.value, 10 ) : + rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? + 0 : + undefined; + } + } + } +}); + +// Add the tabIndex propHook to attrHooks for back-compat (different case is intentional) +jQuery.attrHooks.tabindex = jQuery.propHooks.tabIndex; + +// Hook for boolean attributes +boolHook = { + get: function( elem, name ) { + // Align boolean attributes with corresponding properties + // Fall back to attribute presence where some booleans are not supported + var attrNode, + property = jQuery.prop( elem, name ); + return property === true || typeof property !== "boolean" && ( attrNode = elem.getAttributeNode(name) ) && attrNode.nodeValue !== false ? + name.toLowerCase() : + undefined; + }, + set: function( elem, value, name ) { + var propName; + if ( value === false ) { + // Remove boolean attributes when set to false + jQuery.removeAttr( elem, name ); + } else { + // value is true since we know at this point it's type boolean and not false + // Set boolean attributes to the same name and set the DOM property + propName = jQuery.propFix[ name ] || name; + if ( propName in elem ) { + // Only set the IDL specifically if it already exists on the element + elem[ propName ] = true; + } + + elem.setAttribute( name, name.toLowerCase() ); + } + return name; + } +}; + +// IE6/7 do not support getting/setting some attributes with get/setAttribute +if ( !getSetAttribute ) { + + fixSpecified = { + name: true, + id: true, + coords: true + }; + + // Use this for any attribute in IE6/7 + // This fixes almost every IE6/7 issue + nodeHook = jQuery.valHooks.button = { + get: function( elem, name ) { + var ret; + ret = elem.getAttributeNode( name ); + return ret && ( fixSpecified[ name ] ? ret.nodeValue !== "" : ret.specified ) ? + ret.nodeValue : + undefined; + }, + set: function( elem, value, name ) { + // Set the existing or create a new attribute node + var ret = elem.getAttributeNode( name ); + if ( !ret ) { + ret = document.createAttribute( name ); + elem.setAttributeNode( ret ); + } + return ( ret.nodeValue = value + "" ); + } + }; + + // Apply the nodeHook to tabindex + jQuery.attrHooks.tabindex.set = nodeHook.set; + + // Set width and height to auto instead of 0 on empty string( Bug #8150 ) + // This is for removals + jQuery.each([ "width", "height" ], function( i, name ) { + jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { + set: function( elem, value ) { + if ( value === "" ) { + elem.setAttribute( name, "auto" ); + return value; + } + } + }); + }); + + // Set contenteditable to false on removals(#10429) + // Setting to empty string throws an error as an invalid value + jQuery.attrHooks.contenteditable = { + get: nodeHook.get, + set: function( elem, value, name ) { + if ( value === "" ) { + value = "false"; + } + nodeHook.set( elem, value, name ); + } + }; +} + + +// Some attributes require a special call on IE +if ( !jQuery.support.hrefNormalized ) { + jQuery.each([ "href", "src", "width", "height" ], function( i, name ) { + jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { + get: function( elem ) { + var ret = elem.getAttribute( name, 2 ); + return ret === null ? undefined : ret; + } + }); + }); +} + +if ( !jQuery.support.style ) { + jQuery.attrHooks.style = { + get: function( elem ) { + // Return undefined in the case of empty string + // Normalize to lowercase since IE uppercases css property names + return elem.style.cssText.toLowerCase() || undefined; + }, + set: function( elem, value ) { + return ( elem.style.cssText = "" + value ); + } + }; +} + +// Safari mis-reports the default selected property of an option +// Accessing the parent's selectedIndex property fixes it +if ( !jQuery.support.optSelected ) { + jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, { + get: function( elem ) { + var parent = elem.parentNode; + + if ( parent ) { + parent.selectedIndex; + + // Make sure that it also works with optgroups, see #5701 + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + return null; + } + }); +} + +// IE6/7 call enctype encoding +if ( !jQuery.support.enctype ) { + jQuery.propFix.enctype = "encoding"; +} + +// Radios and checkboxes getter/setter +if ( !jQuery.support.checkOn ) { + jQuery.each([ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = { + get: function( elem ) { + // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified + return elem.getAttribute("value") === null ? "on" : elem.value; + } + }; + }); +} +jQuery.each([ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], { + set: function( elem, value ) { + if ( jQuery.isArray( value ) ) { + return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 ); + } + } + }); +}); + + + + +var rformElems = /^(?:textarea|input|select)$/i, + rtypenamespace = /^([^\.]*)?(?:\.(.+))?$/, + rhoverHack = /(?:^|\s)hover(\.\S+)?\b/, + rkeyEvent = /^key/, + rmouseEvent = /^(?:mouse|contextmenu)|click/, + rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, + rquickIs = /^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/, + quickParse = function( selector ) { + var quick = rquickIs.exec( selector ); + if ( quick ) { + // 0 1 2 3 + // [ _, tag, id, class ] + quick[1] = ( quick[1] || "" ).toLowerCase(); + quick[3] = quick[3] && new RegExp( "(?:^|\\s)" + quick[3] + "(?:\\s|$)" ); + } + return quick; + }, + quickIs = function( elem, m ) { + var attrs = elem.attributes || {}; + return ( + (!m[1] || elem.nodeName.toLowerCase() === m[1]) && + (!m[2] || (attrs.id || {}).value === m[2]) && + (!m[3] || m[3].test( (attrs[ "class" ] || {}).value )) + ); + }, + hoverHack = function( events ) { + return jQuery.event.special.hover ? events : events.replace( rhoverHack, "mouseenter$1 mouseleave$1" ); + }; + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + add: function( elem, types, handler, data, selector ) { + + var elemData, eventHandle, events, + t, tns, type, namespaces, handleObj, + handleObjIn, quick, handlers, special; + + // Don't attach events to noData or text/comment nodes (allow plain objects tho) + if ( elem.nodeType === 3 || elem.nodeType === 8 || !types || !handler || !(elemData = jQuery._data( elem )) ) { + 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 + events = elemData.events; + if ( !events ) { + elemData.events = events = {}; + } + eventHandle = elemData.handle; + if ( !eventHandle ) { + elemData.handle = eventHandle = 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 + // jQuery(...).bind("mouseover mouseout", fn); + types = jQuery.trim( hoverHack(types) ).split( " " ); + for ( t = 0; t < types.length; t++ ) { + + tns = rtypenamespace.exec( types[t] ) || []; + type = tns[1]; + namespaces = ( tns[2] || "" ).split( "." ).sort(); + + // 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: tns[1], + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + quick: selector && quickParse( selector ), + namespace: namespaces.join(".") + }, handleObjIn ); + + // Init the event handler queue if we're the first + handlers = events[ type ]; + if ( !handlers ) { + 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; + }, + + global: {}, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + + var elemData = jQuery.hasData( elem ) && jQuery._data( elem ), + t, tns, type, origType, namespaces, origCount, + j, events, special, handle, eventType, handleObj; + + if ( !elemData || !(events = elemData.events) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = jQuery.trim( hoverHack( types || "" ) ).split(" "); + for ( t = 0; t < types.length; t++ ) { + tns = rtypenamespace.exec( types[t] ) || []; + type = origType = tns[1]; + namespaces = tns[2]; + + // 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; + eventType = events[ type ] || []; + origCount = eventType.length; + namespaces = namespaces ? new RegExp("(^|\\.)" + namespaces.split(".").sort().join("\\.(?:.*\\.)?") + "(\\.|$)") : null; + + // Remove matching events + for ( j = 0; j < eventType.length; j++ ) { + handleObj = eventType[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !namespaces || namespaces.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) { + eventType.splice( j--, 1 ); + + if ( handleObj.selector ) { + eventType.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 ( eventType.length === 0 && origCount !== eventType.length ) { + if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) { + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + handle = elemData.handle; + if ( handle ) { + handle.elem = null; + } + + // removeData also checks for emptiness and clears the expando if empty + // so use it instead of delete + jQuery.removeData( elem, [ "events", "handle" ], true ); + } + }, + + // Events that are safe to short-circuit if no handlers are attached. + // Native DOM events should not be added, they may have inline handlers. + customEvent: { + "getData": true, + "setData": true, + "changeData": true + }, + + trigger: function( event, data, elem, onlyHandlers ) { + // Don't do events on text and comment nodes + if ( elem && (elem.nodeType === 3 || elem.nodeType === 8) ) { + return; + } + + // Event object or event type + var type = event.type || event, + namespaces = [], + cache, exclusive, i, cur, old, ontype, special, handle, eventPath, bubbleType; + + // 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( "!" ) >= 0 ) { + // Exclusive events trigger only for the exact event (no namespaces) + type = type.slice(0, -1); + exclusive = true; + } + + if ( type.indexOf( "." ) >= 0 ) { + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split("."); + type = namespaces.shift(); + namespaces.sort(); + } + + if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) { + // No jQuery handlers for this event type, and it can't have inline handlers + return; + } + + // Caller can pass in an Event, Object, or just an event type string + event = typeof event === "object" ? + // jQuery.Event object + event[ jQuery.expando ] ? event : + // Object literal + new jQuery.Event( type, event ) : + // Just the event type (string) + new jQuery.Event( type ); + + event.type = type; + event.isTrigger = true; + event.exclusive = exclusive; + event.namespace = namespaces.join( "." ); + event.namespace_re = event.namespace? new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.)?") + "(\\.|$)") : null; + ontype = type.indexOf( ":" ) < 0 ? "on" + type : ""; + + // Handle a global trigger + if ( !elem ) { + + // TODO: Stop taunting the data cache; remove global events and always attach to document + cache = jQuery.cache; + for ( i in cache ) { + if ( cache[ i ].events && cache[ i ].events[ type ] ) { + jQuery.event.trigger( event, data, cache[ i ].handle.elem, true ); + } + } + return; + } + + // 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 ? jQuery.makeArray( data ) : []; + data.unshift( event ); + + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( 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) + eventPath = [[ elem, special.bindType || type ]]; + if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + cur = rfocusMorph.test( bubbleType + type ) ? elem : elem.parentNode; + old = null; + for ( ; cur; cur = cur.parentNode ) { + eventPath.push([ cur, bubbleType ]); + old = cur; + } + + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( old && old === elem.ownerDocument ) { + eventPath.push([ old.defaultView || old.parentWindow || window, bubbleType ]); + } + } + + // Fire handlers on the event path + for ( i = 0; i < eventPath.length && !event.isPropagationStopped(); i++ ) { + + cur = eventPath[i][0]; + event.type = eventPath[i][1]; + + handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + // Note that this is a bare JS function and not a jQuery handler + handle = ontype && cur[ ontype ]; + if ( handle && jQuery.acceptData( cur ) && handle.apply( cur, data ) === 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( elem.ownerDocument, data ) === false) && + !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.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) + // IE<9 dies on focus/blur to hidden element (#1486) + if ( ontype && elem[ type ] && ((type !== "focus" && type !== "blur") || event.target.offsetWidth !== 0) && !jQuery.isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + old = elem[ ontype ]; + + if ( old ) { + elem[ ontype ] = null; + } + + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + elem[ type ](); + jQuery.event.triggered = undefined; + + if ( old ) { + elem[ ontype ] = old; + } + } + } + } + + return event.result; + }, + + dispatch: function( event ) { + + // Make a writable jQuery.Event from the native event object + event = jQuery.event.fix( event || window.event ); + + var handlers = ( (jQuery._data( this, "events" ) || {} )[ event.type ] || []), + delegateCount = handlers.delegateCount, + args = [].slice.call( arguments, 0 ), + run_all = !event.exclusive && !event.namespace, + special = jQuery.event.special[ event.type ] || {}, + handlerQueue = [], + i, j, cur, jqcur, ret, selMatch, matched, matches, handleObj, sel, related; + + // 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 that should run if there are delegated events + // Avoid non-left-click bubbling in Firefox (#3861) + if ( delegateCount && !(event.button && event.type === "click") ) { + + // Pregenerate a single jQuery object for reuse with .is() + jqcur = jQuery(this); + jqcur.context = this.ownerDocument || this; + + for ( cur = event.target; cur != this; cur = cur.parentNode || this ) { + + // Don't process events on disabled elements (#6911, #8165) + if ( cur.disabled !== true ) { + selMatch = {}; + matches = []; + jqcur[0] = cur; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + sel = handleObj.selector; + + if ( selMatch[ sel ] === undefined ) { + selMatch[ sel ] = ( + handleObj.quick ? quickIs( cur, handleObj.quick ) : jqcur.is( sel ) + ); + } + if ( selMatch[ sel ] ) { + matches.push( handleObj ); + } + } + if ( matches.length ) { + handlerQueue.push({ elem: cur, matches: matches }); + } + } + } + } + + // Add the remaining (directly-bound) handlers + if ( handlers.length > delegateCount ) { + handlerQueue.push({ elem: this, matches: handlers.slice( delegateCount ) }); + } + + // Run delegates first; they may want to stop propagation beneath us + for ( i = 0; i < handlerQueue.length && !event.isPropagationStopped(); i++ ) { + matched = handlerQueue[ i ]; + event.currentTarget = matched.elem; + + for ( j = 0; j < matched.matches.length && !event.isImmediatePropagationStopped(); j++ ) { + handleObj = matched.matches[ j ]; + + // Triggered event must either 1) be non-exclusive and have no namespace, or + // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace). + if ( run_all || (!event.namespace && !handleObj.namespace) || event.namespace_re && event.namespace_re.test( handleObj.namespace ) ) { + + event.data = handleObj.data; + event.handleObj = handleObj; + + ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler ) + .apply( matched.elem, args ); + + if ( ret !== undefined ) { + event.result = ret; + if ( 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; + }, + + // Includes some event props shared by KeyEvent and MouseEvent + // *** attrChange attrName relatedNode srcElement are not normalized, non-W3C, deprecated, will be removed in 1.8 *** + props: "attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget 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 eventDoc, doc, body, + 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; + } + }, + + fix: function( event ) { + if ( event[ jQuery.expando ] ) { + return event; + } + + // Create a writable copy of the event object and normalize some properties + var i, prop, + originalEvent = event, + fixHook = jQuery.event.fixHooks[ event.type ] || {}, + copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props; + + event = jQuery.Event( originalEvent ); + + for ( i = copy.length; i; ) { + prop = copy[ --i ]; + event[ prop ] = originalEvent[ prop ]; + } + + // Fix target property, if necessary (#1925, IE 6/7/8 & Safari2) + if ( !event.target ) { + event.target = originalEvent.srcElement || document; + } + + // Target should not be a text node (#504, Safari) + if ( event.target.nodeType === 3 ) { + event.target = event.target.parentNode; + } + + // For mouse/key events; add metaKey if it's not there (#3368, IE6/7/8) + if ( event.metaKey === undefined ) { + event.metaKey = event.ctrlKey; + } + + return fixHook.filter? fixHook.filter( event, originalEvent ) : event; + }, + + special: { + ready: { + // Make sure the ready event is setup + setup: jQuery.bindReady + }, + + load: { + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + + focus: { + delegateType: "focusin" + }, + blur: { + delegateType: "focusout" + }, + + beforeunload: { + setup: function( data, namespaces, eventHandle ) { + // We only want to do this special case on windows + if ( jQuery.isWindow( this ) ) { + this.onbeforeunload = eventHandle; + } + }, + + teardown: function( namespaces, eventHandle ) { + if ( this.onbeforeunload === eventHandle ) { + this.onbeforeunload = null; + } + } + } + }, + + simulate: function( type, elem, event, bubble ) { + // Piggyback on a donor event to simulate a different one. + // Fake originalEvent to avoid donor's stopPropagation, but if the + // simulated event prevents default then we do the same on the donor. + var e = jQuery.extend( + new jQuery.Event(), + event, + { type: type, + isSimulated: true, + originalEvent: {} + } + ); + if ( bubble ) { + jQuery.event.trigger( e, null, elem ); + } else { + jQuery.event.dispatch.call( elem, e ); + } + if ( e.isDefaultPrevented() ) { + event.preventDefault(); + } + } +}; + +// Some plugins are using, but it's undocumented/deprecated and will be removed. +// The 1.7 special event interface should provide all the hooks needed now. +jQuery.event.handle = jQuery.event.dispatch; + +jQuery.removeEvent = document.removeEventListener ? + function( elem, type, handle ) { + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle, false ); + } + } : + function( elem, type, handle ) { + if ( elem.detachEvent ) { + elem.detachEvent( "on" + type, 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.returnValue === false || + src.getPreventDefault && src.getPreventDefault() ) ? 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; +}; + +function returnFalse() { + return false; +} +function returnTrue() { + return 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 = { + preventDefault: function() { + this.isDefaultPrevented = returnTrue; + + var e = this.originalEvent; + if ( !e ) { + return; + } + + // if preventDefault exists run it on the original event + if ( e.preventDefault ) { + e.preventDefault(); + + // otherwise set the returnValue property of the original event to false (IE) + } else { + e.returnValue = false; + } + }, + stopPropagation: function() { + this.isPropagationStopped = returnTrue; + + var e = this.originalEvent; + if ( !e ) { + return; + } + // if stopPropagation exists run it on the original event + if ( e.stopPropagation ) { + e.stopPropagation(); + } + // otherwise set the cancelBubble property of the original event to true (IE) + e.cancelBubble = true; + }, + stopImmediatePropagation: function() { + this.isImmediatePropagationStopped = returnTrue; + this.stopPropagation(); + }, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse +}; + +// Create mouseenter/leave events using mouseover/out and event-time checks +jQuery.each({ + mouseenter: "mouseover", + mouseleave: "mouseout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var target = this, + related = event.relatedTarget, + handleObj = event.handleObj, + selector = handleObj.selector, + ret; + + // For mousenter/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 ( !jQuery.support.submitBubbles ) { + + 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" ) ? elem.form : undefined; + if ( form && !form._submit_attached ) { + jQuery.event.add( form, "submit._submit", function( event ) { + event._submit_bubble = true; + }); + form._submit_attached = 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._submit_bubble ) { + delete event._submit_bubble; + if ( this.parentNode && !event.isTrigger ) { + jQuery.event.simulate( "submit", this.parentNode, event, true ); + } + } + }, + + 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 ( !jQuery.support.changeBubbles ) { + + 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._just_changed = true; + } + }); + jQuery.event.add( this, "click._change", function( event ) { + if ( this._just_changed && !event.isTrigger ) { + this._just_changed = false; + jQuery.event.simulate( "change", this, event, true ); + } + }); + } + 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 ) && !elem._change_attached ) { + jQuery.event.add( elem, "change._change", function( event ) { + if ( this.parentNode && !event.isSimulated && !event.isTrigger ) { + jQuery.event.simulate( "change", this.parentNode, event, true ); + } + }); + elem._change_attached = 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 ); + } + }; +} + +// Create "bubbling" focus and blur events +if ( !jQuery.support.focusinBubbles ) { + jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler while someone wants focusin/focusout + var attaches = 0, + handler = function( event ) { + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true ); + }; + + jQuery.event.special[ fix ] = { + setup: function() { + if ( attaches++ === 0 ) { + document.addEventListener( orig, handler, true ); + } + }, + teardown: function() { + if ( --attaches === 0 ) { + document.removeEventListener( orig, handler, true ); + } + } + }; + }); +} + +jQuery.fn.extend({ + + on: function( types, selector, data, fn, /*INTERNAL*/ one ) { + var origFn, type; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { // && selector != null + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + this.on( type, selector, data, types[ type ], one ); + } + return this; + } + + 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 this; + } + + 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 this.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + }); + }, + one: function( types, selector, data, fn ) { + return this.on( types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + if ( types && types.preventDefault && types.handleObj ) { + // ( event ) dispatched jQuery.Event + var 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 ( var 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 ); + }); + }, + + bind: function( types, data, fn ) { + return this.on( types, null, data, fn ); + }, + unbind: function( types, fn ) { + return this.off( types, null, fn ); + }, + + live: function( types, data, fn ) { + jQuery( this.context ).on( types, this.selector, data, fn ); + return this; + }, + die: function( types, fn ) { + jQuery( this.context ).off( types, this.selector || "**", fn ); + return this; + }, + + delegate: function( selector, types, data, fn ) { + return this.on( types, selector, data, fn ); + }, + undelegate: function( selector, types, fn ) { + // ( namespace ) or ( selector, types [, fn] ) + return arguments.length == 1? this.off( selector, "**" ) : this.off( types, selector, fn ); + }, + + trigger: function( type, data ) { + return this.each(function() { + jQuery.event.trigger( type, data, this ); + }); + }, + triggerHandler: function( type, data ) { + if ( this[0] ) { + return jQuery.event.trigger( type, data, this[0], true ); + } + }, + + toggle: function( fn ) { + // Save reference to arguments for access in closure + var args = arguments, + guid = fn.guid || jQuery.guid++, + i = 0, + toggler = function( event ) { + // Figure out which function to execute + var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i; + jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 ); + + // Make sure that clicks stop + event.preventDefault(); + + // and execute the function + return args[ lastToggle ].apply( this, arguments ) || false; + }; + + // link all the functions, so any of them can unbind this click handler + toggler.guid = guid; + while ( i < args.length ) { + args[ i++ ].guid = guid; + } + + return this.click( toggler ); + }, + + hover: function( fnOver, fnOut ) { + return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); + } +}); + +jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " + + "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + + "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) { + + // Handle event binding + jQuery.fn[ name ] = function( data, fn ) { + if ( fn == null ) { + fn = data; + data = null; + } + + return arguments.length > 0 ? + this.on( name, null, data, fn ) : + this.trigger( name ); + }; + + if ( jQuery.attrFn ) { + jQuery.attrFn[ name ] = true; + } + + if ( rkeyEvent.test( name ) ) { + jQuery.event.fixHooks[ name ] = jQuery.event.keyHooks; + } + + if ( rmouseEvent.test( name ) ) { + jQuery.event.fixHooks[ name ] = jQuery.event.mouseHooks; + } +}); + + + +/*! + * Sizzle CSS Selector Engine + * Copyright 2011, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * More information: http://sizzlejs.com/ + */ +(function(){ + +var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, + expando = "sizcache" + (Math.random() + '').replace('.', ''), + done = 0, + toString = Object.prototype.toString, + hasDuplicate = false, + baseHasDuplicate = true, + rBackslash = /\\/g, + rReturn = /\r\n/g, + rNonWord = /\W/; + +// Here we check if the JavaScript engine is using some sort of +// optimization where it does not always call our comparision +// function. If that is the case, discard the hasDuplicate value. +// Thus far that includes Google Chrome. +[0, 0].sort(function() { + baseHasDuplicate = false; + return 0; +}); + +var Sizzle = function( selector, context, results, seed ) { + results = results || []; + context = context || document; + + var origContext = context; + + if ( context.nodeType !== 1 && context.nodeType !== 9 ) { + return []; + } + + if ( !selector || typeof selector !== "string" ) { + return results; + } + + var m, set, checkSet, extra, ret, cur, pop, i, + prune = true, + contextXML = Sizzle.isXML( context ), + parts = [], + soFar = selector; + + // Reset the position of the chunker regexp (start from head) + do { + chunker.exec( "" ); + m = chunker.exec( soFar ); + + if ( m ) { + soFar = m[3]; + + parts.push( m[1] ); + + if ( m[2] ) { + extra = m[3]; + break; + } + } + } while ( m ); + + if ( parts.length > 1 && origPOS.exec( selector ) ) { + + if ( parts.length === 2 && Expr.relative[ parts[0] ] ) { + set = posProcess( parts[0] + parts[1], context, seed ); + + } else { + set = Expr.relative[ parts[0] ] ? + [ context ] : + Sizzle( parts.shift(), context ); + + while ( parts.length ) { + selector = parts.shift(); + + if ( Expr.relative[ selector ] ) { + selector += parts.shift(); + } + + set = posProcess( selector, set, seed ); + } + } + + } else { + // Take a shortcut and set the context if the root selector is an ID + // (but not if it'll be faster if the inner selector is an ID) + if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML && + Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) { + + ret = Sizzle.find( parts.shift(), context, contextXML ); + context = ret.expr ? + Sizzle.filter( ret.expr, ret.set )[0] : + ret.set[0]; + } + + if ( context ) { + ret = seed ? + { expr: parts.pop(), set: makeArray(seed) } : + Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML ); + + set = ret.expr ? + Sizzle.filter( ret.expr, ret.set ) : + ret.set; + + if ( parts.length > 0 ) { + checkSet = makeArray( set ); + + } else { + prune = false; + } + + while ( parts.length ) { + cur = parts.pop(); + pop = cur; + + if ( !Expr.relative[ cur ] ) { + cur = ""; + } else { + pop = parts.pop(); + } + + if ( pop == null ) { + pop = context; + } + + Expr.relative[ cur ]( checkSet, pop, contextXML ); + } + + } else { + checkSet = parts = []; + } + } + + if ( !checkSet ) { + checkSet = set; + } + + if ( !checkSet ) { + Sizzle.error( cur || selector ); + } + + if ( toString.call(checkSet) === "[object Array]" ) { + if ( !prune ) { + results.push.apply( results, checkSet ); + + } else if ( context && context.nodeType === 1 ) { + for ( i = 0; checkSet[i] != null; i++ ) { + if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && Sizzle.contains(context, checkSet[i])) ) { + results.push( set[i] ); + } + } + + } else { + for ( i = 0; checkSet[i] != null; i++ ) { + if ( checkSet[i] && checkSet[i].nodeType === 1 ) { + results.push( set[i] ); + } + } + } + + } else { + makeArray( checkSet, results ); + } + + if ( extra ) { + Sizzle( extra, origContext, results, seed ); + Sizzle.uniqueSort( results ); + } + + return results; +}; + +Sizzle.uniqueSort = function( results ) { + if ( sortOrder ) { + hasDuplicate = baseHasDuplicate; + results.sort( sortOrder ); + + if ( hasDuplicate ) { + for ( var i = 1; i < results.length; i++ ) { + if ( results[i] === results[ i - 1 ] ) { + results.splice( i--, 1 ); + } + } + } + } + + return results; +}; + +Sizzle.matches = function( expr, set ) { + return Sizzle( expr, null, null, set ); +}; + +Sizzle.matchesSelector = function( node, expr ) { + return Sizzle( expr, null, null, [node] ).length > 0; +}; + +Sizzle.find = function( expr, context, isXML ) { + var set, i, len, match, type, left; + + if ( !expr ) { + return []; + } + + for ( i = 0, len = Expr.order.length; i < len; i++ ) { + type = Expr.order[i]; + + if ( (match = Expr.leftMatch[ type ].exec( expr )) ) { + left = match[1]; + match.splice( 1, 1 ); + + if ( left.substr( left.length - 1 ) !== "\\" ) { + match[1] = (match[1] || "").replace( rBackslash, "" ); + set = Expr.find[ type ]( match, context, isXML ); + + if ( set != null ) { + expr = expr.replace( Expr.match[ type ], "" ); + break; + } + } + } + } + + if ( !set ) { + set = typeof context.getElementsByTagName !== "undefined" ? + context.getElementsByTagName( "*" ) : + []; + } + + return { set: set, expr: expr }; +}; + +Sizzle.filter = function( expr, set, inplace, not ) { + var match, anyFound, + type, found, item, filter, left, + i, pass, + old = expr, + result = [], + curLoop = set, + isXMLFilter = set && set[0] && Sizzle.isXML( set[0] ); + + while ( expr && set.length ) { + for ( type in Expr.filter ) { + if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) { + filter = Expr.filter[ type ]; + left = match[1]; + + anyFound = false; + + match.splice(1,1); + + if ( left.substr( left.length - 1 ) === "\\" ) { + continue; + } + + if ( curLoop === result ) { + result = []; + } + + if ( Expr.preFilter[ type ] ) { + match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter ); + + if ( !match ) { + anyFound = found = true; + + } else if ( match === true ) { + continue; + } + } + + if ( match ) { + for ( i = 0; (item = curLoop[i]) != null; i++ ) { + if ( item ) { + found = filter( item, match, i, curLoop ); + pass = not ^ found; + + if ( inplace && found != null ) { + if ( pass ) { + anyFound = true; + + } else { + curLoop[i] = false; + } + + } else if ( pass ) { + result.push( item ); + anyFound = true; + } + } + } + } + + if ( found !== undefined ) { + if ( !inplace ) { + curLoop = result; + } + + expr = expr.replace( Expr.match[ type ], "" ); + + if ( !anyFound ) { + return []; + } + + break; + } + } + } + + // Improper expression + if ( expr === old ) { + if ( anyFound == null ) { + Sizzle.error( expr ); + + } else { + break; + } + } + + old = expr; + } + + return curLoop; +}; + +Sizzle.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +/** + * Utility function for retreiving the text value of an array of DOM nodes + * @param {Array|Element} elem + */ +var getText = Sizzle.getText = function( elem ) { + var i, node, + nodeType = elem.nodeType, + ret = ""; + + if ( nodeType ) { + if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + // Use textContent || innerText for elements + if ( typeof elem.textContent === 'string' ) { + return elem.textContent; + } else if ( typeof elem.innerText === 'string' ) { + // Replace IE's carriage returns + return elem.innerText.replace( rReturn, '' ); + } else { + // Traverse it's children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling) { + ret += getText( elem ); + } + } + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + } else { + + // If no nodeType, this is expected to be an array + for ( i = 0; (node = elem[i]); i++ ) { + // Do not traverse comment nodes + if ( node.nodeType !== 8 ) { + ret += getText( node ); + } + } + } + return ret; +}; + +var Expr = Sizzle.selectors = { + order: [ "ID", "NAME", "TAG" ], + + match: { + ID: /#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/, + CLASS: /\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/, + NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/, + ATTR: /\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/, + TAG: /^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/, + CHILD: /:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/, + POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/, + PSEUDO: /:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/ + }, + + leftMatch: {}, + + attrMap: { + "class": "className", + "for": "htmlFor" + }, + + attrHandle: { + href: function( elem ) { + return elem.getAttribute( "href" ); + }, + type: function( elem ) { + return elem.getAttribute( "type" ); + } + }, + + relative: { + "+": function(checkSet, part){ + var isPartStr = typeof part === "string", + isTag = isPartStr && !rNonWord.test( part ), + isPartStrNotTag = isPartStr && !isTag; + + if ( isTag ) { + part = part.toLowerCase(); + } + + for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) { + if ( (elem = checkSet[i]) ) { + while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {} + + checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ? + elem || false : + elem === part; + } + } + + if ( isPartStrNotTag ) { + Sizzle.filter( part, checkSet, true ); + } + }, + + ">": function( checkSet, part ) { + var elem, + isPartStr = typeof part === "string", + i = 0, + l = checkSet.length; + + if ( isPartStr && !rNonWord.test( part ) ) { + part = part.toLowerCase(); + + for ( ; i < l; i++ ) { + elem = checkSet[i]; + + if ( elem ) { + var parent = elem.parentNode; + checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false; + } + } + + } else { + for ( ; i < l; i++ ) { + elem = checkSet[i]; + + if ( elem ) { + checkSet[i] = isPartStr ? + elem.parentNode : + elem.parentNode === part; + } + } + + if ( isPartStr ) { + Sizzle.filter( part, checkSet, true ); + } + } + }, + + "": function(checkSet, part, isXML){ + var nodeCheck, + doneName = done++, + checkFn = dirCheck; + + if ( typeof part === "string" && !rNonWord.test( part ) ) { + part = part.toLowerCase(); + nodeCheck = part; + checkFn = dirNodeCheck; + } + + checkFn( "parentNode", part, doneName, checkSet, nodeCheck, isXML ); + }, + + "~": function( checkSet, part, isXML ) { + var nodeCheck, + doneName = done++, + checkFn = dirCheck; + + if ( typeof part === "string" && !rNonWord.test( part ) ) { + part = part.toLowerCase(); + nodeCheck = part; + checkFn = dirNodeCheck; + } + + checkFn( "previousSibling", part, doneName, checkSet, nodeCheck, isXML ); + } + }, + + find: { + ID: function( match, context, isXML ) { + if ( typeof context.getElementById !== "undefined" && !isXML ) { + var m = context.getElementById(match[1]); + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + return m && m.parentNode ? [m] : []; + } + }, + + NAME: function( match, context ) { + if ( typeof context.getElementsByName !== "undefined" ) { + var ret = [], + results = context.getElementsByName( match[1] ); + + for ( var i = 0, l = results.length; i < l; i++ ) { + if ( results[i].getAttribute("name") === match[1] ) { + ret.push( results[i] ); + } + } + + return ret.length === 0 ? null : ret; + } + }, + + TAG: function( match, context ) { + if ( typeof context.getElementsByTagName !== "undefined" ) { + return context.getElementsByTagName( match[1] ); + } + } + }, + preFilter: { + CLASS: function( match, curLoop, inplace, result, not, isXML ) { + match = " " + match[1].replace( rBackslash, "" ) + " "; + + if ( isXML ) { + return match; + } + + for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) { + if ( elem ) { + if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n\r]/g, " ").indexOf(match) >= 0) ) { + if ( !inplace ) { + result.push( elem ); + } + + } else if ( inplace ) { + curLoop[i] = false; + } + } + } + + return false; + }, + + ID: function( match ) { + return match[1].replace( rBackslash, "" ); + }, + + TAG: function( match, curLoop ) { + return match[1].replace( rBackslash, "" ).toLowerCase(); + }, + + CHILD: function( match ) { + if ( match[1] === "nth" ) { + if ( !match[2] ) { + Sizzle.error( match[0] ); + } + + match[2] = match[2].replace(/^\+|\s*/g, ''); + + // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6' + var test = /(-?)(\d*)(?:n([+\-]?\d*))?/.exec( + match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" || + !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]); + + // calculate the numbers (first)n+(last) including if they are negative + match[2] = (test[1] + (test[2] || 1)) - 0; + match[3] = test[3] - 0; + } + else if ( match[2] ) { + Sizzle.error( match[0] ); + } + + // TODO: Move to normal caching system + match[0] = done++; + + return match; + }, + + ATTR: function( match, curLoop, inplace, result, not, isXML ) { + var name = match[1] = match[1].replace( rBackslash, "" ); + + if ( !isXML && Expr.attrMap[name] ) { + match[1] = Expr.attrMap[name]; + } + + // Handle if an un-quoted value was used + match[4] = ( match[4] || match[5] || "" ).replace( rBackslash, "" ); + + if ( match[2] === "~=" ) { + match[4] = " " + match[4] + " "; + } + + return match; + }, + + PSEUDO: function( match, curLoop, inplace, result, not ) { + if ( match[1] === "not" ) { + // If we're dealing with a complex expression, or a simple one + if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) { + match[3] = Sizzle(match[3], null, null, curLoop); + + } else { + var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not); + + if ( !inplace ) { + result.push.apply( result, ret ); + } + + return false; + } + + } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) { + return true; + } + + return match; + }, + + POS: function( match ) { + match.unshift( true ); + + return match; + } + }, + + filters: { + enabled: function( elem ) { + return elem.disabled === false && elem.type !== "hidden"; + }, + + disabled: function( elem ) { + return elem.disabled === true; + }, + + checked: function( elem ) { + return elem.checked === true; + }, + + 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; + }, + + parent: function( elem ) { + return !!elem.firstChild; + }, + + empty: function( elem ) { + return !elem.firstChild; + }, + + has: function( elem, i, match ) { + return !!Sizzle( match[3], elem ).length; + }, + + header: function( elem ) { + return (/h\d/i).test( elem.nodeName ); + }, + + text: function( elem ) { + var attr = elem.getAttribute( "type" ), type = elem.type; + // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) + // use getAttribute instead to test this case + return elem.nodeName.toLowerCase() === "input" && "text" === type && ( attr === type || attr === null ); + }, + + radio: function( elem ) { + return elem.nodeName.toLowerCase() === "input" && "radio" === elem.type; + }, + + checkbox: function( elem ) { + return elem.nodeName.toLowerCase() === "input" && "checkbox" === elem.type; + }, + + file: function( elem ) { + return elem.nodeName.toLowerCase() === "input" && "file" === elem.type; + }, + + password: function( elem ) { + return elem.nodeName.toLowerCase() === "input" && "password" === elem.type; + }, + + submit: function( elem ) { + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && "submit" === elem.type; + }, + + image: function( elem ) { + return elem.nodeName.toLowerCase() === "input" && "image" === elem.type; + }, + + reset: function( elem ) { + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && "reset" === elem.type; + }, + + button: function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && "button" === elem.type || name === "button"; + }, + + input: function( elem ) { + return (/input|select|textarea|button/i).test( elem.nodeName ); + }, + + focus: function( elem ) { + return elem === elem.ownerDocument.activeElement; + } + }, + setFilters: { + first: function( elem, i ) { + return i === 0; + }, + + last: function( elem, i, match, array ) { + return i === array.length - 1; + }, + + even: function( elem, i ) { + return i % 2 === 0; + }, + + odd: function( elem, i ) { + return i % 2 === 1; + }, + + lt: function( elem, i, match ) { + return i < match[3] - 0; + }, + + gt: function( elem, i, match ) { + return i > match[3] - 0; + }, + + nth: function( elem, i, match ) { + return match[3] - 0 === i; + }, + + eq: function( elem, i, match ) { + return match[3] - 0 === i; + } + }, + filter: { + PSEUDO: function( elem, match, i, array ) { + var name = match[1], + filter = Expr.filters[ name ]; + + if ( filter ) { + return filter( elem, i, match, array ); + + } else if ( name === "contains" ) { + return (elem.textContent || elem.innerText || getText([ elem ]) || "").indexOf(match[3]) >= 0; + + } else if ( name === "not" ) { + var not = match[3]; + + for ( var j = 0, l = not.length; j < l; j++ ) { + if ( not[j] === elem ) { + return false; + } + } + + return true; + + } else { + Sizzle.error( name ); + } + }, + + CHILD: function( elem, match ) { + var first, last, + doneName, parent, cache, + count, diff, + type = match[1], + node = elem; + + switch ( type ) { + case "only": + case "first": + while ( (node = node.previousSibling) ) { + if ( node.nodeType === 1 ) { + return false; + } + } + + if ( type === "first" ) { + return true; + } + + node = elem; + + /* falls through */ + case "last": + while ( (node = node.nextSibling) ) { + if ( node.nodeType === 1 ) { + return false; + } + } + + return true; + + case "nth": + first = match[2]; + last = match[3]; + + if ( first === 1 && last === 0 ) { + return true; + } + + doneName = match[0]; + parent = elem.parentNode; + + if ( parent && (parent[ expando ] !== doneName || !elem.nodeIndex) ) { + count = 0; + + for ( node = parent.firstChild; node; node = node.nextSibling ) { + if ( node.nodeType === 1 ) { + node.nodeIndex = ++count; + } + } + + parent[ expando ] = doneName; + } + + diff = elem.nodeIndex - last; + + if ( first === 0 ) { + return diff === 0; + + } else { + return ( diff % first === 0 && diff / first >= 0 ); + } + } + }, + + ID: function( elem, match ) { + return elem.nodeType === 1 && elem.getAttribute("id") === match; + }, + + TAG: function( elem, match ) { + return (match === "*" && elem.nodeType === 1) || !!elem.nodeName && elem.nodeName.toLowerCase() === match; + }, + + CLASS: function( elem, match ) { + return (" " + (elem.className || elem.getAttribute("class")) + " ") + .indexOf( match ) > -1; + }, + + ATTR: function( elem, match ) { + var name = match[1], + result = Sizzle.attr ? + Sizzle.attr( elem, name ) : + Expr.attrHandle[ name ] ? + Expr.attrHandle[ name ]( elem ) : + elem[ name ] != null ? + elem[ name ] : + elem.getAttribute( name ), + value = result + "", + type = match[2], + check = match[4]; + + return result == null ? + type === "!=" : + !type && Sizzle.attr ? + result != null : + type === "=" ? + value === check : + type === "*=" ? + value.indexOf(check) >= 0 : + type === "~=" ? + (" " + value + " ").indexOf(check) >= 0 : + !check ? + value && result !== false : + type === "!=" ? + value !== check : + type === "^=" ? + value.indexOf(check) === 0 : + type === "$=" ? + value.substr(value.length - check.length) === check : + type === "|=" ? + value === check || value.substr(0, check.length + 1) === check + "-" : + false; + }, + + POS: function( elem, match, i, array ) { + var name = match[2], + filter = Expr.setFilters[ name ]; + + if ( filter ) { + return filter( elem, i, match, array ); + } + } + } +}; + +var origPOS = Expr.match.POS, + fescape = function(all, num){ + return "\\" + (num - 0 + 1); + }; + +for ( var type in Expr.match ) { + Expr.match[ type ] = new RegExp( Expr.match[ type ].source + (/(?![^\[]*\])(?![^\(]*\))/.source) ); + Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, fescape) ); +} +// Expose origPOS +// "global" as in regardless of relation to brackets/parens +Expr.match.globalPOS = origPOS; + +var makeArray = function( array, results ) { + array = Array.prototype.slice.call( array, 0 ); + + if ( results ) { + results.push.apply( results, array ); + return results; + } + + return array; +}; + +// Perform a simple check to determine if the browser is capable of +// converting a NodeList to an array using builtin methods. +// Also verifies that the returned array holds DOM nodes +// (which is not the case in the Blackberry browser) +try { + Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType; + +// Provide a fallback method if it does not work +} catch( e ) { + makeArray = function( array, results ) { + var i = 0, + ret = results || []; + + if ( toString.call(array) === "[object Array]" ) { + Array.prototype.push.apply( ret, array ); + + } else { + if ( typeof array.length === "number" ) { + for ( var l = array.length; i < l; i++ ) { + ret.push( array[i] ); + } + + } else { + for ( ; array[i]; i++ ) { + ret.push( array[i] ); + } + } + } + + return ret; + }; +} + +var sortOrder, siblingCheck; + +if ( document.documentElement.compareDocumentPosition ) { + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) { + return a.compareDocumentPosition ? -1 : 1; + } + + return a.compareDocumentPosition(b) & 4 ? -1 : 1; + }; + +} else { + sortOrder = function( a, b ) { + // The nodes are identical, we can exit early + if ( a === b ) { + hasDuplicate = true; + return 0; + + // Fallback to using sourceIndex (in IE) if it's available on both nodes + } else if ( a.sourceIndex && b.sourceIndex ) { + return a.sourceIndex - b.sourceIndex; + } + + var al, bl, + ap = [], + bp = [], + aup = a.parentNode, + bup = b.parentNode, + cur = aup; + + // If the nodes are siblings (or identical) we can do a quick check + if ( aup === bup ) { + return siblingCheck( a, b ); + + // If no parents were found then the nodes are disconnected + } else if ( !aup ) { + return -1; + + } else if ( !bup ) { + return 1; + } + + // Otherwise they're somewhere else in the tree so we need + // to build up a full list of the parentNodes for comparison + while ( cur ) { + ap.unshift( cur ); + cur = cur.parentNode; + } + + cur = bup; + + while ( cur ) { + bp.unshift( cur ); + cur = cur.parentNode; + } + + al = ap.length; + bl = bp.length; + + // Start walking down the tree looking for a discrepancy + for ( var i = 0; i < al && i < bl; i++ ) { + if ( ap[i] !== bp[i] ) { + return siblingCheck( ap[i], bp[i] ); + } + } + + // We ended someplace up the tree so do a sibling check + return i === al ? + siblingCheck( a, bp[i], -1 ) : + siblingCheck( ap[i], b, 1 ); + }; + + siblingCheck = function( a, b, ret ) { + if ( a === b ) { + return ret; + } + + var cur = a.nextSibling; + + while ( cur ) { + if ( cur === b ) { + return -1; + } + + cur = cur.nextSibling; + } + + return 1; + }; +} + +// Check to see if the browser returns elements by name when +// querying by getElementById (and provide a workaround) +(function(){ + // We're going to inject a fake input element with a specified name + var form = document.createElement("div"), + id = "script" + (new Date()).getTime(), + root = document.documentElement; + + form.innerHTML = ""; + + // Inject it into the root element, check its status, and remove it quickly + root.insertBefore( form, root.firstChild ); + + // The workaround has to do additional checks after a getElementById + // Which slows things down for other browsers (hence the branching) + if ( document.getElementById( id ) ) { + Expr.find.ID = function( match, context, isXML ) { + if ( typeof context.getElementById !== "undefined" && !isXML ) { + var m = context.getElementById(match[1]); + + return m ? + m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? + [m] : + undefined : + []; + } + }; + + Expr.filter.ID = function( elem, match ) { + var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id"); + + return elem.nodeType === 1 && node && node.nodeValue === match; + }; + } + + root.removeChild( form ); + + // release memory in IE + root = form = null; +})(); + +(function(){ + // Check to see if the browser returns only elements + // when doing getElementsByTagName("*") + + // Create a fake element + var div = document.createElement("div"); + div.appendChild( document.createComment("") ); + + // Make sure no comments are found + if ( div.getElementsByTagName("*").length > 0 ) { + Expr.find.TAG = function( match, context ) { + var results = context.getElementsByTagName( match[1] ); + + // Filter out possible comments + if ( match[1] === "*" ) { + var tmp = []; + + for ( var i = 0; results[i]; i++ ) { + if ( results[i].nodeType === 1 ) { + tmp.push( results[i] ); + } + } + + results = tmp; + } + + return results; + }; + } + + // Check to see if an attribute returns normalized href attributes + div.innerHTML = ""; + + if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" && + div.firstChild.getAttribute("href") !== "#" ) { + + Expr.attrHandle.href = function( elem ) { + return elem.getAttribute( "href", 2 ); + }; + } + + // release memory in IE + div = null; +})(); + +if ( document.querySelectorAll ) { + (function(){ + var oldSizzle = Sizzle, + div = document.createElement("div"), + id = "__sizzle__"; + + div.innerHTML = "

    "; + + // Safari can't handle uppercase or unicode characters when + // in quirks mode. + if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) { + return; + } + + Sizzle = function( query, context, extra, seed ) { + context = context || document; + + // Only use querySelectorAll on non-XML documents + // (ID selectors don't work in non-HTML documents) + if ( !seed && !Sizzle.isXML(context) ) { + // See if we find a selector to speed up + var match = /^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec( query ); + + if ( match && (context.nodeType === 1 || context.nodeType === 9) ) { + // Speed-up: Sizzle("TAG") + if ( match[1] ) { + return makeArray( context.getElementsByTagName( query ), extra ); + + // Speed-up: Sizzle(".CLASS") + } else if ( match[2] && Expr.find.CLASS && context.getElementsByClassName ) { + return makeArray( context.getElementsByClassName( match[2] ), extra ); + } + } + + if ( context.nodeType === 9 ) { + // Speed-up: Sizzle("body") + // The body element only exists once, optimize finding it + if ( query === "body" && context.body ) { + return makeArray( [ context.body ], extra ); + + // Speed-up: Sizzle("#ID") + } else if ( match && match[3] ) { + var elem = context.getElementById( match[3] ); + + // 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[3] ) { + return makeArray( [ elem ], extra ); + } + + } else { + return makeArray( [], extra ); + } + } + + try { + return makeArray( context.querySelectorAll(query), extra ); + } catch(qsaError) {} + + // qSA works strangely on Element-rooted queries + // We can work around this by specifying an extra ID on the root + // and working up from there (Thanks to Andrew Dupont for the technique) + // IE 8 doesn't work on object elements + } else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) { + var oldContext = context, + old = context.getAttribute( "id" ), + nid = old || id, + hasParent = context.parentNode, + relativeHierarchySelector = /^\s*[+~]/.test( query ); + + if ( !old ) { + context.setAttribute( "id", nid ); + } else { + nid = nid.replace( /'/g, "\\$&" ); + } + if ( relativeHierarchySelector && hasParent ) { + context = context.parentNode; + } + + try { + if ( !relativeHierarchySelector || hasParent ) { + return makeArray( context.querySelectorAll( "[id='" + nid + "'] " + query ), extra ); + } + + } catch(pseudoError) { + } finally { + if ( !old ) { + oldContext.removeAttribute( "id" ); + } + } + } + } + + return oldSizzle(query, context, extra, seed); + }; + + for ( var prop in oldSizzle ) { + Sizzle[ prop ] = oldSizzle[ prop ]; + } + + // release memory in IE + div = null; + })(); +} + +(function(){ + var html = document.documentElement, + matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector; + + if ( matches ) { + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9 fails this) + var disconnectedMatch = !matches.call( document.createElement( "div" ), "div" ), + pseudoWorks = false; + + try { + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( document.documentElement, "[test!='']:sizzle" ); + + } catch( pseudoError ) { + pseudoWorks = true; + } + + Sizzle.matchesSelector = function( node, expr ) { + // Make sure that attribute selectors are quoted + expr = expr.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']"); + + if ( !Sizzle.isXML( node ) ) { + try { + if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) { + var ret = matches.call( node, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || !disconnectedMatch || + // As well, disconnected nodes are said to be in a document + // fragment in IE 9, so check for that + node.document && node.document.nodeType !== 11 ) { + return ret; + } + } + } catch(e) {} + } + + return Sizzle(expr, null, null, [node]).length > 0; + }; + } +})(); + +(function(){ + var div = document.createElement("div"); + + div.innerHTML = "
    "; + + // Opera can't find a second classname (in 9.6) + // Also, make sure that getElementsByClassName actually exists + if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) { + return; + } + + // Safari caches class attributes, doesn't catch changes (in 3.2) + div.lastChild.className = "e"; + + if ( div.getElementsByClassName("e").length === 1 ) { + return; + } + + Expr.order.splice(1, 0, "CLASS"); + Expr.find.CLASS = function( match, context, isXML ) { + if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) { + return context.getElementsByClassName(match[1]); + } + }; + + // release memory in IE + div = null; +})(); + +function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + + if ( elem ) { + var match = false; + + elem = elem[dir]; + + while ( elem ) { + if ( elem[ expando ] === doneName ) { + match = checkSet[elem.sizset]; + break; + } + + if ( elem.nodeType === 1 && !isXML ){ + elem[ expando ] = doneName; + elem.sizset = i; + } + + if ( elem.nodeName.toLowerCase() === cur ) { + match = elem; + break; + } + + elem = elem[dir]; + } + + checkSet[i] = match; + } + } +} + +function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + + if ( elem ) { + var match = false; + + elem = elem[dir]; + + while ( elem ) { + if ( elem[ expando ] === doneName ) { + match = checkSet[elem.sizset]; + break; + } + + if ( elem.nodeType === 1 ) { + if ( !isXML ) { + elem[ expando ] = doneName; + elem.sizset = i; + } + + if ( typeof cur !== "string" ) { + if ( elem === cur ) { + match = true; + break; + } + + } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) { + match = elem; + break; + } + } + + elem = elem[dir]; + } + + checkSet[i] = match; + } + } +} + +if ( document.documentElement.contains ) { + Sizzle.contains = function( a, b ) { + return a !== b && (a.contains ? a.contains(b) : true); + }; + +} else if ( document.documentElement.compareDocumentPosition ) { + Sizzle.contains = function( a, b ) { + return !!(a.compareDocumentPosition(b) & 16); + }; + +} else { + Sizzle.contains = function() { + return false; + }; +} + +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 : 0).documentElement; + + return documentElement ? documentElement.nodeName !== "HTML" : false; +}; + +var posProcess = function( selector, context, seed ) { + var match, + tmpSet = [], + later = "", + root = context.nodeType ? [context] : context; + + // Position selectors must be done after the filter + // And so must :not(positional) so we move all PSEUDOs to the end + while ( (match = Expr.match.PSEUDO.exec( selector )) ) { + later += match[0]; + selector = selector.replace( Expr.match.PSEUDO, "" ); + } + + selector = Expr.relative[selector] ? selector + "*" : selector; + + for ( var i = 0, l = root.length; i < l; i++ ) { + Sizzle( selector, root[i], tmpSet, seed ); + } + + return Sizzle.filter( later, tmpSet ); +}; + +// EXPOSE +// Override sizzle attribute retrieval +Sizzle.attr = jQuery.attr; +Sizzle.selectors.attrMap = {}; +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; +jQuery.expr[":"] = jQuery.expr.filters; +jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; + + +})(); + + +var runtil = /Until$/, + rparentsprev = /^(?:parents|prevUntil|prevAll)/, + // Note: This RegExp should be improved, or likely pulled from Sizzle + rmultiselector = /,/, + isSimple = /^.[^:#\[\.,]*$/, + slice = Array.prototype.slice, + POS = jQuery.expr.match.globalPOS, + // 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({ + find: function( selector ) { + var self = this, + i, l; + + if ( typeof selector !== "string" ) { + return jQuery( selector ).filter(function() { + for ( i = 0, l = self.length; i < l; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + }); + } + + var ret = this.pushStack( "", "find", selector ), + length, n, r; + + for ( i = 0, l = this.length; i < l; i++ ) { + length = ret.length; + jQuery.find( selector, this[i], ret ); + + if ( i > 0 ) { + // Make sure that the results are unique + for ( n = length; n < ret.length; n++ ) { + for ( r = 0; r < length; r++ ) { + if ( ret[r] === ret[n] ) { + ret.splice(n--, 1); + break; + } + } + } + } + } + + return ret; + }, + + has: function( target ) { + var targets = jQuery( target ); + return this.filter(function() { + for ( var i = 0, l = targets.length; i < l; i++ ) { + if ( jQuery.contains( this, targets[i] ) ) { + return true; + } + } + }); + }, + + not: function( selector ) { + return this.pushStack( winnow(this, selector, false), "not", selector); + }, + + filter: function( selector ) { + return this.pushStack( winnow(this, selector, true), "filter", selector ); + }, + + is: function( selector ) { + return !!selector && ( + typeof selector === "string" ? + // If this is a positional selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + POS.test( selector ) ? + jQuery( selector, this.context ).index( this[0] ) >= 0 : + jQuery.filter( selector, this ).length > 0 : + this.filter( selector ).length > 0 ); + }, + + closest: function( selectors, context ) { + var ret = [], i, l, cur = this[0]; + + // Array (deprecated as of jQuery 1.7) + if ( jQuery.isArray( selectors ) ) { + var level = 1; + + while ( cur && cur.ownerDocument && cur !== context ) { + for ( i = 0; i < selectors.length; i++ ) { + + if ( jQuery( cur ).is( selectors[ i ] ) ) { + ret.push({ selector: selectors[ i ], elem: cur, level: level }); + } + } + + cur = cur.parentNode; + level++; + } + + return ret; + } + + // String + var pos = POS.test( selectors ) || typeof selectors !== "string" ? + jQuery( selectors, context || this.context ) : + 0; + + for ( i = 0, l = this.length; i < l; i++ ) { + cur = this[i]; + + while ( cur ) { + if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) { + ret.push( cur ); + break; + + } else { + cur = cur.parentNode; + if ( !cur || !cur.ownerDocument || cur === context || cur.nodeType === 11 ) { + break; + } + } + } + } + + ret = ret.length > 1 ? jQuery.unique( ret ) : ret; + + return this.pushStack( ret, "closest", selectors ); + }, + + // 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.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 ) { + var set = typeof selector === "string" ? + jQuery( selector, context ) : + jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ), + all = jQuery.merge( this.get(), set ); + + return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ? + all : + jQuery.unique( all ) ); + }, + + andSelf: function() { + return this.add( this.prevObject ); + } +}); + +// A painfully simple check to see if an element is disconnected +// from a document (should be improved, where feasible). +function isDisconnected( node ) { + return !node || !node.parentNode || node.parentNode.nodeType === 11; +} + +jQuery.each({ + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return jQuery.dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, i, until ) { + return jQuery.dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return jQuery.nth( elem, 2, "nextSibling" ); + }, + prev: function( elem ) { + return jQuery.nth( elem, 2, "previousSibling" ); + }, + nextAll: function( elem ) { + return jQuery.dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return jQuery.dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, i, until ) { + return jQuery.dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, i, until ) { + return jQuery.dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem ); + }, + children: function( elem ) { + return jQuery.sibling( elem.firstChild ); + }, + contents: function( elem ) { + return jQuery.nodeName( elem, "iframe" ) ? + elem.contentDocument || elem.contentWindow.document : + jQuery.makeArray( elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var ret = jQuery.map( this, fn, until ); + + if ( !runtil.test( name ) ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + ret = jQuery.filter( selector, ret ); + } + + ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret; + + if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) { + ret = ret.reverse(); + } + + return this.pushStack( ret, name, slice.call( arguments ).join(",") ); + }; +}); + +jQuery.extend({ + filter: function( expr, elems, not ) { + if ( not ) { + expr = ":not(" + expr + ")"; + } + + return elems.length === 1 ? + jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] : + jQuery.find.matches(expr, elems); + }, + + dir: function( elem, dir, until ) { + var matched = [], + cur = elem[ dir ]; + + while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { + if ( cur.nodeType === 1 ) { + matched.push( cur ); + } + cur = cur[dir]; + } + return matched; + }, + + nth: function( cur, result, dir, elem ) { + result = result || 1; + var num = 0; + + for ( ; cur; cur = cur[dir] ) { + if ( cur.nodeType === 1 && ++num === result ) { + break; + } + } + + return cur; + }, + + sibling: function( n, elem ) { + var r = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + r.push( n ); + } + } + + return r; + } +}); + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, keep ) { + + // Can't pass null or undefined to indexOf in Firefox 4 + // Set to 0 to skip string check + qualifier = qualifier || 0; + + if ( jQuery.isFunction( qualifier ) ) { + return jQuery.grep(elements, function( elem, i ) { + var retVal = !!qualifier.call( elem, i, elem ); + return retVal === keep; + }); + + } else if ( qualifier.nodeType ) { + return jQuery.grep(elements, function( elem, i ) { + return ( elem === qualifier ) === keep; + }); + + } else if ( typeof qualifier === "string" ) { + var filtered = jQuery.grep(elements, function( elem ) { + return elem.nodeType === 1; + }); + + if ( isSimple.test( qualifier ) ) { + return jQuery.filter(qualifier, filtered, !keep); + } else { + qualifier = jQuery.filter( qualifier, filtered ); + } + } + + return jQuery.grep(elements, function( elem, i ) { + return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep; + }); +} + + + + +function createSafeFragment( document ) { + var list = nodeNames.split( "|" ), + safeFrag = document.createDocumentFragment(); + + if ( safeFrag.createElement ) { + while ( list.length ) { + safeFrag.createElement( + list.pop() + ); + } + } + return safeFrag; +} + +var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" + + "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video", + rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g, + rleadingWhitespace = /^\s+/, + rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig, + rtagName = /<([\w:]+)/, + rtbody = /]", "i"), + // checked="checked" or checked + rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i, + rscriptType = /\/(java|ecma)script/i, + rcleanScript = /^\s*", "" ], + legend: [ 1, "
    ", "
    " ], + thead: [ 1, "", "
    " ], + tr: [ 2, "", "
    " ], + td: [ 3, "", "
    " ], + col: [ 2, "", "
    " ], + area: [ 1, "", "" ], + _default: [ 0, "", "" ] + }, + safeFragment = createSafeFragment( document ); + +wrapMap.optgroup = wrapMap.option; +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + +// IE can't serialize and + + + + + diff --git a/GRID/jquery.gridder.html b/GRID/jquery.gridder.html new file mode 100644 index 0000000..a2b41d3 --- /dev/null +++ b/GRID/jquery.gridder.html @@ -0,0 +1,46 @@ + + + + + + + +
    +
      +
      + + + + + + + diff --git a/GRID/jquery.gridder_test.js b/GRID/jquery.gridder_test.js new file mode 100644 index 0000000..2df25e7 --- /dev/null +++ b/GRID/jquery.gridder_test.js @@ -0,0 +1,38 @@ +/*global QUnit:false, module:false, test:false, asyncTest:false, expect:false*/ +/*global start:false, stop:false ok:false, equal:false, notEqual:false, deepEqual:false*/ +/*global notDeepEqual:false, strictEqual:false, notStrictEqual:false, raises:false*/ +(function($) { + + /* + ======== A Handy Little QUnit Reference ======== + http://docs.jquery.com/QUnit + + Test methods: + expect(numAssertions) + stop(increment) + start(decrement) + Test assertions: + ok(value, [message]) + equal(actual, expected, [message]) + notEqual(actual, expected, [message]) + deepEqual(actual, expected, [message]) + notDeepEqual(actual, expected, [message]) + strictEqual(actual, expected, [message]) + notStrictEqual(actual, expected, [message]) + raises(block, [expected], [message]) + */ + + module('jQuery#gridster', { + setup: function() { + + this.el = $('#qunit-fixture').find(".wrapper ul"); + + } + }); + + // test('is chainable', 1, function() { + // // Not a bad test to run on collection methods. + // strictEqual(this.el, this.el.gridster(), 'should be chaninable'); + // }); + +}(jQuery)); diff --git a/GRID/package.json b/GRID/package.json new file mode 100644 index 0000000..23354b5 --- /dev/null +++ b/GRID/package.json @@ -0,0 +1,41 @@ +{ + "name": "gridster", + "title": "gridster.js", + "description": "a drag-and-drop multi-column jQuery grid plugin", + "version": "0.5.6", + "homepage": "http://gridster.net/", + "author": { + "name": "ducksboard", + "email": "hackers@ducksboard.com" + }, + "repository": { + "type": "git", + "url": "git://github.com/ducksboard/gridster.js.git" + }, + "bugs": { + "url": "https://github.com/ducksboard/gridster.js/issues" + }, + "licenses": [ + { + "type": "MIT", + "url": "https://github.com/ducksboard/gridster.js/blob/master/LICENSE" + } + ], + "keywords": [], + "dependencies": { + "jquery": "git+https://github.com/jquery/jquery.git#2.0.3" + }, + "devDependencies": { + "grunt": "~0.4.1", + "grunt-contrib-uglify": "~0.2.0", + "grunt-contrib-jshint": "~0.3.0", + "grunt-contrib-concat": "~0.1.3", + "grunt-contrib-watch": "~0.3.1", + "grunt-contrib-cssmin": "~0.5.0", + "grunt-contrib-yuidoc": "~0.4.0", + "bower": "~0.9.2", + "qunitjs": "~1.11.0", + "grunt-bump": "0.0.11", + "grunt-conventional-changelog": "~1.0.0" + } +} diff --git a/GRID/src/jquery.collision.js b/GRID/src/jquery.collision.js new file mode 100644 index 0000000..4a15e8e --- /dev/null +++ b/GRID/src/jquery.collision.js @@ -0,0 +1,242 @@ +/* + * jquery.collision + * https://github.com/ducksboard/gridster.js + * + * Copyright (c) 2012 ducksboard + * Licensed under the MIT licenses. + */ + +;(function(root, factory) { + + if (typeof define === 'function' && define.amd) { + define('gridster-collision', ['jquery', 'gridster-coords'], factory); + } else { + root.GridsterCollision = factory(root.$ || root.jQuery, + root.GridsterCoords); + } + +}(this, function($, Coords) { + + var defaults = { + colliders_context: document.body, + overlapping_region: 'C' + // ,on_overlap: function(collider_data){}, + // on_overlap_start : function(collider_data){}, + // on_overlap_stop : function(collider_data){} + }; + + + /** + * Detects collisions between a DOM element against other DOM elements or + * Coords objects. + * + * @class Collision + * @uses Coords + * @param {HTMLElement} el The jQuery wrapped HTMLElement. + * @param {HTMLElement|Array} colliders Can be a jQuery collection + * of HTMLElements or an Array of Coords instances. + * @param {Object} [options] An Object with all options you want to + * overwrite: + * @param {String} [options.overlapping_region] Determines when collision + * is valid, depending on the overlapped area. Values can be: 'N', 'S', + * 'W', 'E', 'C' or 'all'. Default is 'C'. + * @param {Function} [options.on_overlap_start] Executes a function the first + * time each `collider ` is overlapped. + * @param {Function} [options.on_overlap_stop] Executes a function when a + * `collider` is no longer collided. + * @param {Function} [options.on_overlap] Executes a function when the + * mouse is moved during the collision. + * @return {Object} Collision instance. + * @constructor + */ + function Collision(el, colliders, options) { + this.options = $.extend(defaults, options); + this.$element = el; + this.last_colliders = []; + this.last_colliders_coords = []; + this.set_colliders(colliders); + + this.init(); + } + + Collision.defaults = defaults; + + var fn = Collision.prototype; + + + fn.init = function() { + this.find_collisions(); + }; + + + fn.overlaps = function(a, b) { + var x = false; + var y = false; + + if ((b.x1 >= a.x1 && b.x1 <= a.x2) || + (b.x2 >= a.x1 && b.x2 <= a.x2) || + (a.x1 >= b.x1 && a.x2 <= b.x2) + ) { x = true; } + + if ((b.y1 >= a.y1 && b.y1 <= a.y2) || + (b.y2 >= a.y1 && b.y2 <= a.y2) || + (a.y1 >= b.y1 && a.y2 <= b.y2) + ) { y = true; } + + return (x && y); + }; + + + fn.detect_overlapping_region = function(a, b){ + var regionX = ''; + var regionY = ''; + + if (a.y1 > b.cy && a.y1 < b.y2) { regionX = 'N'; } + if (a.y2 > b.y1 && a.y2 < b.cy) { regionX = 'S'; } + if (a.x1 > b.cx && a.x1 < b.x2) { regionY = 'W'; } + if (a.x2 > b.x1 && a.x2 < b.cx) { regionY = 'E'; } + + return (regionX + regionY) || 'C'; + }; + + + fn.calculate_overlapped_area_coords = function(a, b){ + var x1 = Math.max(a.x1, b.x1); + var y1 = Math.max(a.y1, b.y1); + var x2 = Math.min(a.x2, b.x2); + var y2 = Math.min(a.y2, b.y2); + + return $({ + left: x1, + top: y1, + width : (x2 - x1), + height: (y2 - y1) + }).coords().get(); + }; + + + fn.calculate_overlapped_area = function(coords){ + return (coords.width * coords.height); + }; + + + fn.manage_colliders_start_stop = function(new_colliders_coords, start_callback, stop_callback){ + var last = this.last_colliders_coords; + + for (var i = 0, il = last.length; i < il; i++) { + if ($.inArray(last[i], new_colliders_coords) === -1) { + start_callback.call(this, last[i]); + } + } + + for (var j = 0, jl = new_colliders_coords.length; j < jl; j++) { + if ($.inArray(new_colliders_coords[j], last) === -1) { + stop_callback.call(this, new_colliders_coords[j]); + } + + } + }; + + + fn.find_collisions = function(player_data_coords){ + var self = this; + var overlapping_region = this.options.overlapping_region; + var colliders_coords = []; + var colliders_data = []; + var $colliders = (this.colliders || this.$colliders); + var count = $colliders.length; + var player_coords = self.$element.coords() + .update(player_data_coords || false).get(); + + while(count--){ + var $collider = self.$colliders ? + $($colliders[count]) : $colliders[count]; + var $collider_coords_ins = ($collider.isCoords) ? + $collider : $collider.coords(); + var collider_coords = $collider_coords_ins.get(); + var overlaps = self.overlaps(player_coords, collider_coords); + + if (!overlaps) { + continue; + } + + var region = self.detect_overlapping_region( + player_coords, collider_coords); + + //todo: make this an option + if (region === overlapping_region || overlapping_region === 'all') { + + var area_coords = self.calculate_overlapped_area_coords( + player_coords, collider_coords); + var area = self.calculate_overlapped_area(area_coords); + var collider_data = { + area: area, + area_coords : area_coords, + region: region, + coords: collider_coords, + player_coords: player_coords, + el: $collider + }; + + if (self.options.on_overlap) { + self.options.on_overlap.call(this, collider_data); + } + colliders_coords.push($collider_coords_ins); + colliders_data.push(collider_data); + } + } + + if (self.options.on_overlap_stop || self.options.on_overlap_start) { + this.manage_colliders_start_stop(colliders_coords, + self.options.on_overlap_start, self.options.on_overlap_stop); + } + + this.last_colliders_coords = colliders_coords; + + return colliders_data; + }; + + + fn.get_closest_colliders = function(player_data_coords){ + var colliders = this.find_collisions(player_data_coords); + + colliders.sort(function(a, b) { + /* if colliders are being overlapped by the "C" (center) region, + * we have to set a lower index in the array to which they are placed + * above in the grid. */ + if (a.region === 'C' && b.region === 'C') { + if (a.coords.y1 < b.coords.y1 || a.coords.x1 < b.coords.x1) { + return - 1; + }else{ + return 1; + } + } + + if (a.area < b.area) { + return 1; + } + + return 1; + }); + return colliders; + }; + + + fn.set_colliders = function(colliders) { + if (typeof colliders === 'string' || colliders instanceof $) { + this.$colliders = $(colliders, + this.options.colliders_context).not(this.$element); + }else{ + this.colliders = $(colliders); + } + }; + + + //jQuery adapter + $.fn.collision = function(collider, options) { + return new Collision( this, collider, options ); + }; + + return Collision; + +})); diff --git a/GRID/src/jquery.coords.js b/GRID/src/jquery.coords.js new file mode 100644 index 0000000..821b67c --- /dev/null +++ b/GRID/src/jquery.coords.js @@ -0,0 +1,125 @@ +/* + * jquery.coords + * https://github.com/ducksboard/gridster.js + * + * Copyright (c) 2012 ducksboard + * Licensed under the MIT licenses. + */ + +;(function(root, factory) { + + if (typeof define === 'function' && define.amd) { + define('gridster-coords', ['jquery'], factory); + } else { + root.GridsterCoords = factory(root.$ || root.jQuery); + } + +}(this, function($) { + /** + * Creates objects with coordinates (x1, y1, x2, y2, cx, cy, width, height) + * to simulate DOM elements on the screen. + * Coords is used by Gridster to create a faux grid with any DOM element can + * collide. + * + * @class Coords + * @param {HTMLElement|Object} obj The jQuery HTMLElement or a object with: left, + * top, width and height properties. + * @return {Object} Coords instance. + * @constructor + */ + function Coords(obj) { + if (obj[0] && $.isPlainObject(obj[0])) { + this.data = obj[0]; + }else { + this.el = obj; + } + + this.isCoords = true; + this.coords = {}; + this.init(); + return this; + } + + + var fn = Coords.prototype; + + + fn.init = function(){ + this.set(); + this.original_coords = this.get(); + }; + + + fn.set = function(update, not_update_offsets) { + var el = this.el; + + if (el && !update) { + this.data = el.offset(); + this.data.width = el.width(); + this.data.height = el.height(); + } + + if (el && update && !not_update_offsets) { + var offset = el.offset(); + this.data.top = offset.top; + this.data.left = offset.left; + } + + var d = this.data; + + typeof d.left === 'undefined' && (d.left = d.x1); + typeof d.top === 'undefined' && (d.top = d.y1); + + this.coords.x1 = d.left; + this.coords.y1 = d.top; + this.coords.x2 = d.left + d.width; + this.coords.y2 = d.top + d.height; + this.coords.cx = d.left + (d.width / 2); + this.coords.cy = d.top + (d.height / 2); + this.coords.width = d.width; + this.coords.height = d.height; + this.coords.el = el || false ; + + return this; + }; + + + fn.update = function(data){ + if (!data && !this.el) { + return this; + } + + if (data) { + var new_data = $.extend({}, this.data, data); + this.data = new_data; + return this.set(true, true); + } + + this.set(true); + return this; + }; + + + fn.get = function(){ + return this.coords; + }; + + fn.destroy = function() { + this.el.removeData('coords'); + delete this.el; + }; + + //jQuery adapter + $.fn.coords = function() { + if (this.data('coords') ) { + return this.data('coords'); + } + + var ins = new Coords(this, arguments[0]); + this.data('coords', ins); + return ins; + }; + + return Coords; + +})); diff --git a/GRID/src/jquery.draggable.js b/GRID/src/jquery.draggable.js new file mode 100644 index 0000000..d9b5d98 --- /dev/null +++ b/GRID/src/jquery.draggable.js @@ -0,0 +1,432 @@ +/* + * jquery.draggable + * https://github.com/ducksboard/gridster.js + * + * Copyright (c) 2012 ducksboard + * Licensed under the MIT licenses. + */ + +;(function(root, factory) { + + if (typeof define === 'function' && define.amd) { + define('gridster-draggable', ['jquery'], factory); + } else { + root.GridsterDraggable = factory(root.$ || root.jQuery); + } + +}(this, function($) { + + var defaults = { + items: 'li', + distance: 1, + limit: true, + offset_left: 0, + autoscroll: true, + ignore_dragging: ['INPUT', 'TEXTAREA', 'SELECT', 'BUTTON'], // or function + handle: null, + container_width: 0, // 0 == auto + move_element: true, + helper: false, // or 'clone' + remove_helper: true + // drag: function(e) {}, + // start : function(e, ui) {}, + // stop : function(e) {} + }; + + var $window = $(window); + var dir_map = { x : 'left', y : 'top' }; + var isTouch = !!('ontouchstart' in window); + + var capitalize = function(str) { + return str.charAt(0).toUpperCase() + str.slice(1); + }; + + var idCounter = 0; + var uniqId = function() { + return ++idCounter + ''; + } + + /** + * Basic drag implementation for DOM elements inside a container. + * Provide start/stop/drag callbacks. + * + * @class Draggable + * @param {HTMLElement} el The HTMLelement that contains all the widgets + * to be dragged. + * @param {Object} [options] An Object with all options you want to + * overwrite: + * @param {HTMLElement|String} [options.items] Define who will + * be the draggable items. Can be a CSS Selector String or a + * collection of HTMLElements. + * @param {Number} [options.distance] Distance in pixels after mousedown + * the mouse must move before dragging should start. + * @param {Boolean} [options.limit] Constrains dragging to the width of + * the container + * @param {Object|Function} [options.ignore_dragging] Array of node names + * that sould not trigger dragging, by default is `['INPUT', 'TEXTAREA', + * 'SELECT', 'BUTTON']`. If a function is used return true to ignore dragging. + * @param {offset_left} [options.offset_left] Offset added to the item + * that is being dragged. + * @param {Number} [options.drag] Executes a callback when the mouse is + * moved during the dragging. + * @param {Number} [options.start] Executes a callback when the drag + * starts. + * @param {Number} [options.stop] Executes a callback when the drag stops. + * @return {Object} Returns `el`. + * @constructor + */ + function Draggable(el, options) { + this.options = $.extend({}, defaults, options); + this.$document = $(document); + this.$container = $(el); + this.$dragitems = $(this.options.items, this.$container); + this.is_dragging = false; + this.player_min_left = 0 + this.options.offset_left; + this.id = uniqId(); + this.ns = '.gridster-draggable-' + this.id; + this.init(); + } + + Draggable.defaults = defaults; + + var fn = Draggable.prototype; + + fn.init = function() { + var pos = this.$container.css('position'); + this.calculate_dimensions(); + this.$container.css('position', pos === 'static' ? 'relative' : pos); + this.disabled = false; + this.events(); + + $(window).bind(this.nsEvent('resize'), + throttle($.proxy(this.calculate_dimensions, this), 200)); + }; + + fn.nsEvent = function(ev) { + return (ev || '') + this.ns; + }; + + fn.events = function() { + this.pointer_events = { + start: this.nsEvent('touchstart') + ' ' + this.nsEvent('mousedown'), + move: this.nsEvent('touchmove') + ' ' + this.nsEvent('mousemove'), + end: this.nsEvent('touchend') + ' ' + this.nsEvent('mouseup'), + }; + + this.$container.on(this.nsEvent('selectstart'), + $.proxy(this.on_select_start, this)); + + this.$container.on(this.pointer_events.start, this.options.items, + $.proxy(this.drag_handler, this)); + + this.$document.on(this.pointer_events.end, $.proxy(function(e) { + this.is_dragging = false; + if (this.disabled) { return; } + this.$document.off(this.pointer_events.move); + if (this.drag_start) { + this.on_dragstop(e); + } + }, this)); + }; + + fn.get_actual_pos = function($el) { + var pos = $el.position(); + return pos; + }; + + + fn.get_mouse_pos = function(e) { + if (e.originalEvent && e.originalEvent.touches) { + var oe = e.originalEvent; + e = oe.touches.length ? oe.touches[0] : oe.changedTouches[0]; + } + + return { + left: e.clientX, + top: e.clientY + }; + }; + + + fn.get_offset = function(e) { + e.preventDefault(); + var mouse_actual_pos = this.get_mouse_pos(e); + var diff_x = Math.round( + mouse_actual_pos.left - this.mouse_init_pos.left); + var diff_y = Math.round(mouse_actual_pos.top - this.mouse_init_pos.top); + + var left = Math.round(this.el_init_offset.left + + diff_x - this.baseX + $(window).scrollLeft() - this.win_offset_x); + var top = Math.round(this.el_init_offset.top + + diff_y - this.baseY + $(window).scrollTop() - this.win_offset_y); + + if (this.options.limit) { + if (left > this.player_max_left) { + left = this.player_max_left; + } else if(left < this.player_min_left) { + left = this.player_min_left; + } + } + + return { + position: { + left: left, + top: top + }, + pointer: { + left: mouse_actual_pos.left, + top: mouse_actual_pos.top, + diff_left: diff_x + ($(window).scrollLeft() - this.win_offset_x), + diff_top: diff_y + ($(window).scrollTop() - this.win_offset_y) + } + }; + }; + + + fn.get_drag_data = function(e) { + var offset = this.get_offset(e); + offset.$player = this.$player; + offset.$helper = this.helper ? this.$helper : this.$player; + + return offset; + }; + + + fn.set_limits = function(container_width) { + container_width || (container_width = this.$container.width()); + this.player_max_left = (container_width - this.player_width + + - this.options.offset_left); + + this.options.container_width = container_width; + + return this; + }; + + + fn.scroll_in = function(axis, data) { + var dir_prop = dir_map[axis]; + + var area_size = 50; + var scroll_inc = 30; + + var is_x = axis === 'x'; + var window_size = is_x ? this.window_width : this.window_height; + var doc_size = is_x ? $(document).width() : $(document).height(); + var player_size = is_x ? this.$player.width() : this.$player.height(); + + var next_scroll; + var scroll_offset = $window['scroll' + capitalize(dir_prop)](); + var min_window_pos = scroll_offset; + var max_window_pos = min_window_pos + window_size; + + var mouse_next_zone = max_window_pos - area_size; // down/right + var mouse_prev_zone = min_window_pos + area_size; // up/left + + var abs_mouse_pos = min_window_pos + data.pointer[dir_prop]; + + var max_player_pos = (doc_size - window_size + player_size); + + if (abs_mouse_pos >= mouse_next_zone) { + next_scroll = scroll_offset + scroll_inc; + if (next_scroll < max_player_pos) { + $window['scroll' + capitalize(dir_prop)](next_scroll); + this['scroll_offset_' + axis] += scroll_inc; + } + } + + if (abs_mouse_pos <= mouse_prev_zone) { + next_scroll = scroll_offset - scroll_inc; + if (next_scroll > 0) { + $window['scroll' + capitalize(dir_prop)](next_scroll); + this['scroll_offset_' + axis] -= scroll_inc; + } + } + + return this; + }; + + + fn.manage_scroll = function(data) { + this.scroll_in('x', data); + this.scroll_in('y', data); + }; + + + fn.calculate_dimensions = function(e) { + this.window_height = $window.height(); + this.window_width = $window.width(); + }; + + + fn.drag_handler = function(e) { + var node = e.target.nodeName; + // skip if drag is disabled, or click was not done with the mouse primary button + if (this.disabled || e.which !== 1 && !isTouch) { + return; + } + + if (this.ignore_drag(e)) { + return; + } + + var self = this; + var first = true; + this.$player = $(e.currentTarget); + + this.el_init_pos = this.get_actual_pos(this.$player); + this.mouse_init_pos = this.get_mouse_pos(e); + this.offsetY = this.mouse_init_pos.top - this.el_init_pos.top; + + this.$document.on(this.pointer_events.move, function(mme) { + var mouse_actual_pos = self.get_mouse_pos(mme); + var diff_x = Math.abs( + mouse_actual_pos.left - self.mouse_init_pos.left); + var diff_y = Math.abs( + mouse_actual_pos.top - self.mouse_init_pos.top); + if (!(diff_x > self.options.distance || + diff_y > self.options.distance) + ) { + return false; + } + + if (first) { + first = false; + self.on_dragstart.call(self, mme); + return false; + } + + if (self.is_dragging === true) { + self.on_dragmove.call(self, mme); + } + + return false; + }); + + if (!isTouch) { return false; } + }; + + + fn.on_dragstart = function(e) { + e.preventDefault(); + + if (this.is_dragging) { return this; } + + this.drag_start = this.is_dragging = true; + var offset = this.$container.offset(); + this.baseX = Math.round(offset.left); + this.baseY = Math.round(offset.top); + this.initial_container_width = this.options.container_width || this.$container.width(); + + if (this.options.helper === 'clone') { + this.$helper = this.$player.clone() + .appendTo(this.$container).addClass('helper'); + this.helper = true; + } else { + this.helper = false; + } + + this.win_offset_y = $(window).scrollTop(); + this.win_offset_x = $(window).scrollLeft(); + this.scroll_offset_y = 0; + this.scroll_offset_x = 0; + this.el_init_offset = this.$player.offset(); + this.player_width = this.$player.width(); + this.player_height = this.$player.height(); + + this.set_limits(this.options.container_width); + + if (this.options.start) { + this.options.start.call(this.$player, e, this.get_drag_data(e)); + } + return false; + }; + + + fn.on_dragmove = function(e) { + var data = this.get_drag_data(e); + + this.options.autoscroll && this.manage_scroll(data); + + if (this.options.move_element) { + (this.helper ? this.$helper : this.$player).css({ + 'position': 'absolute', + 'left' : data.position.left, + 'top' : data.position.top + }); + } + + var last_position = this.last_position || data.position; + data.prev_position = last_position; + + if (this.options.drag) { + this.options.drag.call(this.$player, e, data); + } + + this.last_position = data.position; + return false; + }; + + + fn.on_dragstop = function(e) { + var data = this.get_drag_data(e); + this.drag_start = false; + + if (this.options.stop) { + this.options.stop.call(this.$player, e, data); + } + + if (this.helper && this.options.remove_helper) { + this.$helper.remove(); + } + + return false; + }; + + fn.on_select_start = function(e) { + if (this.disabled) { return; } + + if (this.ignore_drag(e)) { + return; + } + + return false; + }; + + fn.enable = function() { + this.disabled = false; + }; + + fn.disable = function() { + this.disabled = true; + }; + + fn.destroy = function() { + this.disable(); + + this.$container.off(this.ns); + this.$document.off(this.ns); + $(window).off(this.ns); + + $.removeData(this.$container, 'drag'); + }; + + fn.ignore_drag = function(event) { + if (this.options.handle) { + return !$(event.target).is(this.options.handle); + } + + if ($.isFunction(this.options.ignore_dragging)) { + return this.options.ignore_dragging(event); + } + + return $(event.target).is(this.options.ignore_dragging.join(', ')); + }; + + //jQuery adapter + $.fn.drag = function ( options ) { + return new Draggable(this, options); + }; + + return Draggable; + +})); diff --git a/GRID/src/jquery.gridster.css b/GRID/src/jquery.gridster.css new file mode 100644 index 0000000..52feaab --- /dev/null +++ b/GRID/src/jquery.gridster.css @@ -0,0 +1,117 @@ +.gridster { + position:relative; +} + +.gridster > * { + margin: 0 auto; + -webkit-transition: height .4s, width .4s; + -moz-transition: height .4s, width .4s; + -o-transition: height .4s, width .4s; + -ms-transition: height .4s, width .4s; + transition: height .4s, width .4s; +} + +.gridster .gs-w { + z-index: 2; + position: absolute; +} + +.ready .gs-w:not(.preview-holder) { + -webkit-transition: opacity .3s, left .3s, top .3s; + -moz-transition: opacity .3s, left .3s, top .3s; + -o-transition: opacity .3s, left .3s, top .3s; + transition: opacity .3s, left .3s, top .3s; +} + +.ready .gs-w:not(.preview-holder), +.ready .resize-preview-holder { + -webkit-transition: opacity .3s, left .3s, top .3s, width .3s, height .3s; + -moz-transition: opacity .3s, left .3s, top .3s, width .3s, height .3s; + -o-transition: opacity .3s, left .3s, top .3s, width .3s, height .3s; + transition: opacity .3s, left .3s, top .3s, width .3s, height .3s; +} + +.gridster .preview-holder { + z-index: 1; + position: absolute; + background-color: #fff; + border-color: #fff; + opacity: 0.3; +} + +.gridster .player-revert { + z-index: 10!important; + -webkit-transition: left .3s, top .3s!important; + -moz-transition: left .3s, top .3s!important; + -o-transition: left .3s, top .3s!important; + transition: left .3s, top .3s!important; +} + +.gridster .dragging, +.gridster .resizing { + z-index: 10!important; + -webkit-transition: all 0s !important; + -moz-transition: all 0s !important; + -o-transition: all 0s !important; + transition: all 0s !important; +} + + +.gs-resize-handle { + position: absolute; + z-index: 1; +} + +.gs-resize-handle-both { + width: 20px; + height: 20px; + bottom: -8px; + right: -8px; + background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/Pg08IS0tIEdlbmVyYXRvcjogQWRvYmUgRmlyZXdvcmtzIENTNiwgRXhwb3J0IFNWRyBFeHRlbnNpb24gYnkgQWFyb24gQmVhbGwgKGh0dHA6Ly9maXJld29ya3MuYWJlYWxsLmNvbSkgLiBWZXJzaW9uOiAwLjYuMSAgLS0+DTwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+DTxzdmcgaWQ9IlVudGl0bGVkLVBhZ2UlMjAxIiB2aWV3Qm94PSIwIDAgNiA2IiBzdHlsZT0iYmFja2dyb3VuZC1jb2xvcjojZmZmZmZmMDAiIHZlcnNpb249IjEuMSINCXhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHhtbDpzcGFjZT0icHJlc2VydmUiDQl4PSIwcHgiIHk9IjBweCIgd2lkdGg9IjZweCIgaGVpZ2h0PSI2cHgiDT4NCTxnIG9wYWNpdHk9IjAuMzAyIj4NCQk8cGF0aCBkPSJNIDYgNiBMIDAgNiBMIDAgNC4yIEwgNCA0LjIgTCA0LjIgNC4yIEwgNC4yIDAgTCA2IDAgTCA2IDYgTCA2IDYgWiIgZmlsbD0iIzAwMDAwMCIvPg0JPC9nPg08L3N2Zz4='); + background-position: top left; + background-repeat: no-repeat; + cursor: se-resize; + z-index: 20; +} + +.gs-resize-handle-x { + top: 0; + bottom: 13px; + right: -5px; + width: 10px; + cursor: e-resize; +} + +.gs-resize-handle-y { + left: 0; + right: 13px; + bottom: -5px; + height: 10px; + cursor: s-resize; +} + +.gs-w:hover .gs-resize-handle, +.resizing .gs-resize-handle { + opacity: 1; +} + +.gs-resize-handle, +.gs-w.dragging .gs-resize-handle { + opacity: 0; +} + +.gs-resize-disabled .gs-resize-handle { + display: none!important; +} + +[data-max-sizex="1"] .gs-resize-handle-x, +[data-max-sizey="1"] .gs-resize-handle-y, +[data-max-sizey="1"][data-max-sizex="1"] .gs-resize-handle { + display: none !important; +} + +/* Uncomment this if you set helper : "clone" in draggable options */ +/*.gridster .player { + opacity:0; +} +*/ \ No newline at end of file diff --git a/GRID/src/jquery.gridster.extras.js b/GRID/src/jquery.gridster.extras.js new file mode 100644 index 0000000..e7ea59f --- /dev/null +++ b/GRID/src/jquery.gridster.extras.js @@ -0,0 +1,175 @@ +;(function(root, factory) { + + if (typeof define === 'function' && define.amd) { + define(['jquery', 'gridster'], factory); + } else { + root.Gridster = factory(root.$ || root.jQuery, root.Gridster); + } + +}(this, function($, Gridster) { + + var fn = Gridster.prototype; + + fn.widgets_in_col = function(col) { + if (!this.gridmap[col]) { + return false; + } + + for (var i = this.gridmap[col].length - 1; i >= 0; i--) { + if (this.is_widget(col, i) !== false) { + return true; + } + } + + return false; + }; + + fn.widgets_in_row = function(row) { + for (var i = this.gridmap.length; i >= 1; i--) { + if (this.is_widget(i, row) !== false) { + return true; + } + } + + return false; + }; + + + fn.widgets_in_range = function(col1, row1, col2, row2) { + var valid_cols = []; + var valid_rows = []; + var $widgets = $([]); + var c, r, $w, wgd; + + for (c = col2; c >= col1; c--) { + for (r = row2; r >= row1; r--) { + $w = this.is_widget(c, r); + + if ($w !== false) { + wgd = $w.data('coords').grid; + if (wgd.col >= col1 && wgd.col <= col2 && + wgd.row >= row1 && wgd.row <= row2 + ) { + $widgets = $widgets.add($w); + } + } + } + } + + return $widgets; + }; + + + fn.get_bottom_most_occupied_cell = function() { + var row = 0; + var col = 0; + this.for_each_cell(function($el, c, r) { + if ($el && r > row) { + row = r; + col = c; + } + }); + + return {col: col, row: row}; + }; + + + fn.get_right_most_occupied_cell = function() { + var row = 0; + var col = 0; + this.for_each_cell(function($el, c, r) { + if ($el) { + row = r; + col = c; + return false; + } + }); + + return {col: col, row: row}; + }; + + + fn.for_each_cell = function(callback, gridmap) { + gridmap || (gridmap = this.gridmap); + var cols = gridmap.length; + var rows = gridmap[1].length; + + cols_iter: + for (var c = cols - 1; c >= 1; c--) { + for (var r = rows - 1; r >= 1; r--) { + var $el = gridmap[c] && gridmap[c][r]; + if (callback) { + if (callback.call(this, $el, c, r) === false) { + break cols_iter; + } else { continue; } + } + } + } + }; + + + fn.next_position_in_range = function(size_x, size_y, max_rows) { + size_x || (size_x = 1); + size_y || (size_y = 1); + var ga = this.gridmap; + var cols_l = ga.length; + var valid_pos = []; + var rows_l; + + for (var c = 1; c < cols_l; c++) { + rows_l = max_rows || ga[c].length; + for (var r = 1; r <= rows_l; r++) { + var can_move_to = this.can_move_to({ + size_x: size_x, + size_y: size_y + }, c, r, max_rows); + + if (can_move_to) { + valid_pos.push({ + col: c, + row: r, + size_y: size_y, + size_x: size_x + }); + } + } + } + + if (valid_pos.length >= 1) { + return Gridster.sort_by_col_asc(valid_pos)[0]; + } + + return false; + }; + + + fn.closest_to_right = function(col, row) { + if (!this.gridmap[col]) { return false; } + var cols_l = this.gridmap.length - 1; + + for (var c = col; c <= cols_l; c++) { + if (this.gridmap[c][row]) { + return { col: c, row: row }; + } + } + + return false; + }; + + + fn.closest_to_left = function(col, row) { + var cols_l = this.gridmap.length - 1; + if (!this.gridmap[col]) { return false; } + + for (var c = col; c >= 1; c--) { + if (this.gridmap[c][row]) { + return { col: c, row: row }; + } + } + + return false; + }; + + return Gridster; + +})); diff --git a/GRID/src/jquery.gridster.js b/GRID/src/jquery.gridster.js new file mode 100644 index 0000000..7bac911 --- /dev/null +++ b/GRID/src/jquery.gridster.js @@ -0,0 +1,3140 @@ +/* + * jquery.gridster + * https://github.com/ducksboard/gridster.js + * + * Copyright (c) 2012 ducksboard + * Licensed under the MIT licenses. + */ + +;(function(root, factory) { + + if (typeof define === 'function' && define.amd) { + define(['jquery', 'gridster-draggable', 'gridster-collision'], factory); + } else { + root.Gridster = factory(root.$ || root.jQuery, root.GridsterDraggable, + root.GridsterCollision); + } + + }(this, function($, Draggable, Collision) { + + var defaults = { + namespace: '', + widget_selector: 'li', + widget_margins: [10, 10], + widget_base_dimensions: [400, 225], + extra_rows: 0, + extra_cols: 0, + min_cols: 1, + max_cols: Infinity, + min_rows: 15, + max_size_x: false, + autogrow_cols: false, + autogenerate_stylesheet: true, + avoid_overlapped_widgets: true, + auto_init: true, + serialize_params: function($w, wgd) { + return { + col: wgd.col, + row: wgd.row, + size_x: wgd.size_x, + size_y: wgd.size_y + }; + }, + collision: {}, + draggable: { + items: '.gs-w', + distance: 4, + ignore_dragging: Draggable.defaults.ignore_dragging.slice(0) + }, + resize: { + enabled: false, + axes: ['both'], + handle_append_to: '', + handle_class: 'gs-resize-handle', + max_size: [Infinity, Infinity], + min_size: [1, 1] + } + }; + + /** + * @class Gridster + * @uses Draggable + * @uses Collision + * @param {HTMLElement} el The HTMLelement that contains all the widgets. + * @param {Object} [options] An Object with all options you want to + * overwrite: + * @param {HTMLElement|String} [options.widget_selector] Define who will + * be the draggable widgets. Can be a CSS Selector String or a + * collection of HTMLElements + * @param {Array} [options.widget_margins] Margin between widgets. + * The first index for the horizontal margin (left, right) and + * the second for the vertical margin (top, bottom). + * @param {Array} [options.widget_base_dimensions] Base widget dimensions + * in pixels. The first index for the width and the second for the + * height. + * @param {Number} [options.extra_cols] Add more columns in addition to + * those that have been calculated. + * @param {Number} [options.extra_rows] Add more rows in addition to + * those that have been calculated. + * @param {Number} [options.min_cols] The minimum required columns. + * @param {Number} [options.max_cols] The maximum columns possible (set to null + * for no maximum). + * @param {Number} [options.min_rows] The minimum required rows. + * @param {Number} [options.max_size_x] The maximum number of columns + * that a widget can span. + * @param {Boolean} [options.autogenerate_stylesheet] If true, all the + * CSS required to position all widgets in their respective columns + * and rows will be generated automatically and injected to the + * `` of the document. You can set this to false, and write + * your own CSS targeting rows and cols via data-attributes like so: + * `[data-col="1"] { left: 10px; }` + * @param {Boolean} [options.avoid_overlapped_widgets] Avoid that widgets loaded + * from the DOM can be overlapped. It is helpful if the positions were + * bad stored in the database or if there was any conflict. + * @param {Boolean} [options.auto_init] Automatically call gridster init + * method or not when the plugin is instantiated. + * @param {Function} [options.serialize_params] Return the data you want + * for each widget in the serialization. Two arguments are passed: + * `$w`: the jQuery wrapped HTMLElement, and `wgd`: the grid + * coords object (`col`, `row`, `size_x`, `size_y`). + * @param {Object} [options.collision] An Object with all options for + * Collision class you want to overwrite. See Collision docs for + * more info. + * @param {Object} [options.draggable] An Object with all options for + * Draggable class you want to overwrite. See Draggable docs for more + * info. + * @param {Object|Function} [options.draggable.ignore_dragging] Note that + * if you use a Function, and resize is enabled, you should ignore the + * resize handlers manually (options.resize.handle_class). + * @param {Object} [options.resize] An Object with resize config options. + * @param {Boolean} [options.resize.enabled] Set to true to enable + * resizing. + * @param {Array} [options.resize.axes] Axes in which widgets can be + * resized. Possible values: ['x', 'y', 'both']. + * @param {String} [options.resize.handle_append_to] Set a valid CSS + * selector to append resize handles to. + * @param {String} [options.resize.handle_class] CSS class name used + * by resize handles. + * @param {Array} [options.resize.max_size] Limit widget dimensions + * when resizing. Array values should be integers: + * `[max_cols_occupied, max_rows_occupied]` + * @param {Array} [options.resize.min_size] Limit widget dimensions + * when resizing. Array values should be integers: + * `[min_cols_occupied, min_rows_occupied]` + * @param {Function} [options.resize.start] Function executed + * when resizing starts. + * @param {Function} [otions.resize.resize] Function executed + * during the resizing. + * @param {Function} [options.resize.stop] Function executed + * when resizing stops. + * + * @constructor + */ + function Gridster(el, options) { + this.options = $.extend(true, {}, defaults, options); + this.$el = $(el); + this.$wrapper = this.$el.parent(); + this.$widgets = this.$el.children( + this.options.widget_selector).addClass('gs-w'); + this.widgets = []; + this.$changed = $([]); + this.wrapper_width = this.$wrapper.width(); + this.min_widget_width = (this.options.widget_margins[0] * 2) + + this.options.widget_base_dimensions[0]; + this.min_widget_height = (this.options.widget_margins[1] * 2) + + this.options.widget_base_dimensions[1]; + + this.generated_stylesheets = []; + this.$style_tags = $([]); + + this.options.auto_init && this.init(); + } + + Gridster.defaults = defaults; + Gridster.generated_stylesheets = []; + + + /** + * Sorts an Array of grid coords objects (representing the grid coords of + * each widget) in ascending way. + * + * @method sort_by_row_asc + * @param {Array} widgets Array of grid coords objects + * @return {Array} Returns the array sorted. + */ + Gridster.sort_by_row_asc = function(widgets) { + widgets = widgets.sort(function(a, b) { + if (!a.row) { + a = $(a).coords().grid; + b = $(b).coords().grid; + } + + if (a.row > b.row) { + return 1; + } + return -1; + }); + + return widgets; + }; + + + /** + * Sorts an Array of grid coords objects (representing the grid coords of + * each widget) placing first the empty cells upper left. + * + * @method sort_by_row_and_col_asc + * @param {Array} widgets Array of grid coords objects + * @return {Array} Returns the array sorted. + */ + Gridster.sort_by_row_and_col_asc = function(widgets) { + widgets = widgets.sort(function(a, b) { + if (a.row > b.row || a.row === b.row && a.col > b.col) { + return 1; + } + return -1; + }); + + return widgets; + }; + + + /** + * Sorts an Array of grid coords objects by column (representing the grid + * coords of each widget) in ascending way. + * + * @method sort_by_col_asc + * @param {Array} widgets Array of grid coords objects + * @return {Array} Returns the array sorted. + */ + Gridster.sort_by_col_asc = function(widgets) { + widgets = widgets.sort(function(a, b) { + if (a.col > b.col) { + return 1; + } + return -1; + }); + + return widgets; + }; + + + /** + * Sorts an Array of grid coords objects (representing the grid coords of + * each widget) in descending way. + * + * @method sort_by_row_desc + * @param {Array} widgets Array of grid coords objects + * @return {Array} Returns the array sorted. + */ + Gridster.sort_by_row_desc = function(widgets) { + widgets = widgets.sort(function(a, b) { + if (a.row + a.size_y < b.row + b.size_y) { + return 1; + } + return -1; + }); + return widgets; + }; + + + + /** Instance Methods **/ + + var fn = Gridster.prototype; + + fn.init = function() { + this.options.resize.enabled && this.setup_resize(); + this.generate_grid_and_stylesheet(); + this.get_widgets_from_DOM(); + this.set_dom_grid_height(); + this.set_dom_grid_width(); + this.$wrapper.addClass('ready'); + this.draggable(); + this.options.resize.enabled && this.resizable(); + + $(window).bind('resize.gridster', throttle( + $.proxy(this.recalculate_faux_grid, this), 200)); + }; + + + /** + * Disables dragging. + * + * @method disable + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.disable = function() { + this.$wrapper.find('.player-revert').removeClass('player-revert'); + this.drag_api.disable(); + return this; + }; + + + /** + * Enables dragging. + * + * @method enable + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.enable = function() { + this.drag_api.enable(); + return this; + }; + + + + /** + * Disables drag-and-drop widget resizing. + * + * @method disable + * @return {Class} Returns instance of gridster Class. + */ + fn.disable_resize = function() { + this.$el.addClass('gs-resize-disabled'); + this.resize_api.disable(); + return this; + }; + + + /** + * Enables drag-and-drop widget resizing. + * + * @method enable + * @return {Class} Returns instance of gridster Class. + */ + fn.enable_resize = function() { + this.$el.removeClass('gs-resize-disabled'); + this.resize_api.enable(); + return this; + }; + + + /** + * Add a new widget to the grid. + * + * @method add_widget + * @param {String|HTMLElement} html The string representing the HTML of the widget + * or the HTMLElement. + * @param {Number} [size_x] The nº of rows the widget occupies horizontally. + * @param {Number} [size_y] The nº of columns the widget occupies vertically. + * @param {Number} [col] The column the widget should start in. + * @param {Number} [row] The row the widget should start in. + * @param {Array} [max_size] max_size Maximun size (in units) for width and height. + * @param {Array} [min_size] min_size Minimum size (in units) for width and height. + * @return {HTMLElement} Returns the jQuery wrapped HTMLElement representing. + * the widget that was just created. + */ + fn.add_widget = function(html, size_x, size_y, col, row, max_size, min_size) { + var pos; + size_x || (size_x = 1); + size_y || (size_y = 1); + + if (!col & !row) { + pos = this.next_position(size_x, size_y); + } else { + pos = { + col: col, + row: row, + size_x: size_x, + size_y: size_y + }; + + this.empty_cells(col, row, size_x, size_y); + } + + var $w = $(html).attr({ + 'data-col': pos.col, + 'data-row': pos.row, + 'data-sizex' : size_x, + 'data-sizey' : size_y + }).addClass('gs-w').appendTo(this.$el).hide(); + + this.$widgets = this.$widgets.add($w); + + this.register_widget($w); + + this.add_faux_rows(pos.size_y); + //this.add_faux_cols(pos.size_x); + + if (max_size) { + this.set_widget_max_size($w, max_size); + } + + if (min_size) { + this.set_widget_min_size($w, min_size); + } + + this.set_dom_grid_width(); + this.set_dom_grid_height(); + + this.drag_api.set_limits(this.cols * this.min_widget_width); + + return $w.fadeIn(); + }; + + + /** + * Change widget size limits. + * + * @method set_widget_min_size + * @param {HTMLElement|Number} $widget The jQuery wrapped HTMLElement + * representing the widget or an index representing the desired widget. + * @param {Array} min_size Minimum size (in units) for width and height. + * @return {HTMLElement} Returns instance of gridster Class. + */ + fn.set_widget_min_size = function($widget, min_size) { + $widget = typeof $widget === 'number' ? + this.$widgets.eq($widget) : $widget; + + if (!$widget.length) { return this; } + + var wgd = $widget.data('coords').grid; + wgd.min_size_x = min_size[0]; + wgd.min_size_y = min_size[1]; + + return this; + }; + + + /** + * Change widget size limits. + * + * @method set_widget_max_size + * @param {HTMLElement|Number} $widget The jQuery wrapped HTMLElement + * representing the widget or an index representing the desired widget. + * @param {Array} max_size Maximun size (in units) for width and height. + * @return {HTMLElement} Returns instance of gridster Class. + */ + fn.set_widget_max_size = function($widget, max_size) { + $widget = typeof $widget === 'number' ? + this.$widgets.eq($widget) : $widget; + + if (!$widget.length) { return this; } + + var wgd = $widget.data('coords').grid; + wgd.max_size_x = max_size[0]; + wgd.max_size_y = max_size[1]; + + return this; + }; + + + /** + * Append the resize handle into a widget. + * + * @method add_resize_handle + * @param {HTMLElement} $widget The jQuery wrapped HTMLElement + * representing the widget. + * @return {HTMLElement} Returns instance of gridster Class. + */ + fn.add_resize_handle = function($w) { + var append_to = this.options.resize.handle_append_to; + $(this.resize_handle_tpl).appendTo( append_to ? $(append_to, $w) : $w); + + return this; + }; + + + /** + * Change the size of a widget. Width is limited to the current grid width. + * + * @method resize_widget + * @param {HTMLElement} $widget The jQuery wrapped HTMLElement + * representing the widget. + * @param {Number} size_x The number of columns that will occupy the widget. + * By default size_x is limited to the space available from + * the column where the widget begins, until the last column to the right. + * @param {Number} size_y The number of rows that will occupy the widget. + * @param {Function} [callback] Function executed when the widget is removed. + * @return {HTMLElement} Returns $widget. + */ + fn.resize_widget = function($widget, size_x, size_y, callback) { + var wgd = $widget.coords().grid; + var col = wgd.col; + var max_cols = this.options.max_cols; + var old_size_y = wgd.size_y; + var old_col = wgd.col; + var new_col = old_col; + + size_x || (size_x = wgd.size_x); + size_y || (size_y = wgd.size_y); + + if (max_cols !== Infinity) { + size_x = Math.min(size_x, max_cols - col + 1); + } + + if (size_y > old_size_y) { + this.add_faux_rows(Math.max(size_y - old_size_y, 0)); + } + + var player_rcol = (col + size_x - 1); + if (player_rcol > this.cols) { + this.add_faux_cols(player_rcol - this.cols); + } + + var new_grid_data = { + col: new_col, + row: wgd.row, + size_x: size_x, + size_y: size_y + }; + + this.mutate_widget_in_gridmap($widget, wgd, new_grid_data); + + this.set_dom_grid_height(); + this.set_dom_grid_width(); + + if (callback) { + callback.call(this, new_grid_data.size_x, new_grid_data.size_y); + } + + return $widget; + }; + + + /** + * Mutate widget dimensions and position in the grid map. + * + * @method mutate_widget_in_gridmap + * @param {HTMLElement} $widget The jQuery wrapped HTMLElement + * representing the widget to mutate. + * @param {Object} wgd Current widget grid data (col, row, size_x, size_y). + * @param {Object} new_wgd New widget grid data. + * @return {HTMLElement} Returns instance of gridster Class. + */ + fn.mutate_widget_in_gridmap = function($widget, wgd, new_wgd) { + var old_size_x = wgd.size_x; + var old_size_y = wgd.size_y; + + var old_cells_occupied = this.get_cells_occupied(wgd); + var new_cells_occupied = this.get_cells_occupied(new_wgd); + + var empty_cols = []; + $.each(old_cells_occupied.cols, function(i, col) { + if ($.inArray(col, new_cells_occupied.cols) === -1) { + empty_cols.push(col); + } + }); + + var occupied_cols = []; + $.each(new_cells_occupied.cols, function(i, col) { + if ($.inArray(col, old_cells_occupied.cols) === -1) { + occupied_cols.push(col); + } + }); + + var empty_rows = []; + $.each(old_cells_occupied.rows, function(i, row) { + if ($.inArray(row, new_cells_occupied.rows) === -1) { + empty_rows.push(row); + } + }); + + var occupied_rows = []; + $.each(new_cells_occupied.rows, function(i, row) { + if ($.inArray(row, old_cells_occupied.rows) === -1) { + occupied_rows.push(row); + } + }); + + this.remove_from_gridmap(wgd); + + if (occupied_cols.length) { + var cols_to_empty = [ + new_wgd.col, new_wgd.row, new_wgd.size_x, Math.min(old_size_y, new_wgd.size_y), $widget + ]; + this.empty_cells.apply(this, cols_to_empty); + } + + if (occupied_rows.length) { + var rows_to_empty = [new_wgd.col, new_wgd.row, new_wgd.size_x, new_wgd.size_y, $widget]; + this.empty_cells.apply(this, rows_to_empty); + } + + // not the same that wgd = new_wgd; + wgd.col = new_wgd.col; + wgd.row = new_wgd.row; + wgd.size_x = new_wgd.size_x; + wgd.size_y = new_wgd.size_y; + + this.add_to_gridmap(new_wgd, $widget); + + $widget.removeClass('player-revert'); + + //update coords instance attributes + $widget.data('coords').update({ + width: (new_wgd.size_x * this.options.widget_base_dimensions[0] + + ((new_wgd.size_x - 1) * this.options.widget_margins[0]) * 2), + height: (new_wgd.size_y * this.options.widget_base_dimensions[1] + + ((new_wgd.size_y - 1) * this.options.widget_margins[1]) * 2) + }); + + $widget.attr({ + 'data-col': new_wgd.col, + 'data-row': new_wgd.row, + 'data-sizex': new_wgd.size_x, + 'data-sizey': new_wgd.size_y + }); + + if (empty_cols.length) { + var cols_to_remove_holes = [ + empty_cols[0], new_wgd.row, + empty_cols.length, + Math.min(old_size_y, new_wgd.size_y), + $widget + ]; + + this.remove_empty_cells.apply(this, cols_to_remove_holes); + } + + if (empty_rows.length) { + var rows_to_remove_holes = [ + new_wgd.col, new_wgd.row, new_wgd.size_x, new_wgd.size_y, $widget + ]; + this.remove_empty_cells.apply(this, rows_to_remove_holes); + } + + this.move_widget_up($widget); + + return this; + }; + + + /** + * Move down widgets in cells represented by the arguments col, row, size_x, + * size_y + * + * @method empty_cells + * @param {Number} col The column where the group of cells begin. + * @param {Number} row The row where the group of cells begin. + * @param {Number} size_x The number of columns that the group of cells + * occupy. + * @param {Number} size_y The number of rows that the group of cells + * occupy. + * @param {HTMLElement} $exclude Exclude widgets from being moved. + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.empty_cells = function(col, row, size_x, size_y, $exclude) { + var $nexts = this.widgets_below({ + col: col, + row: row - size_y, + size_x: size_x, + size_y: size_y + }); + + $nexts.not($exclude).each($.proxy(function(i, w) { + var wgd = $(w).coords().grid; + if ( !(wgd.row <= (row + size_y - 1))) { return; } + var diff = (row + size_y) - wgd.row; + this.move_widget_down($(w), diff); + }, this)); + + this.set_dom_grid_height(); + + return this; + }; + + + /** + * Move up widgets below cells represented by the arguments col, row, size_x, + * size_y. + * + * @method remove_empty_cells + * @param {Number} col The column where the group of cells begin. + * @param {Number} row The row where the group of cells begin. + * @param {Number} size_x The number of columns that the group of cells + * occupy. + * @param {Number} size_y The number of rows that the group of cells + * occupy. + * @param {HTMLElement} exclude Exclude widgets from being moved. + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.remove_empty_cells = function(col, row, size_x, size_y, exclude) { + var $nexts = this.widgets_below({ + col: col, + row: row, + size_x: size_x, + size_y: size_y + }); + + $nexts.not(exclude).each($.proxy(function(i, widget) { + this.move_widget_up( $(widget), size_y ); + }, this)); + + this.set_dom_grid_height(); + + return this; + }; + + + /** + * Get the most left column below to add a new widget. + * + * @method next_position + * @param {Number} size_x The nº of rows the widget occupies horizontally. + * @param {Number} size_y The nº of columns the widget occupies vertically. + * @return {Object} Returns a grid coords object representing the future + * widget coords. + */ + fn.next_position = function(size_x, size_y) { + size_x || (size_x = 1); + size_y || (size_y = 1); + var ga = this.gridmap; + var cols_l = ga.length; + var valid_pos = []; + var rows_l; + + for (var c = 1; c < cols_l; c++) { + rows_l = ga[c].length; + for (var r = 1; r <= rows_l; r++) { + var can_move_to = this.can_move_to({ + size_x: size_x, + size_y: size_y + }, c, r); + + if (can_move_to) { + valid_pos.push({ + col: c, + row: r, + size_y: size_y, + size_x: size_x + }); + } + } + } + + if (valid_pos.length) { + return Gridster.sort_by_row_and_col_asc(valid_pos)[0]; + } + return false; + }; + + + /** + * Remove a widget from the grid. + * + * @method remove_widget + * @param {HTMLElement} el The jQuery wrapped HTMLElement you want to remove. + * @param {Boolean|Function} silent If true, widgets below the removed one + * will not move up. If a Function is passed it will be used as callback. + * @param {Function} callback Function executed when the widget is removed. + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.remove_widget = function(el, silent, callback) { + var $el = el instanceof $ ? el : $(el); + var wgd = $el.coords().grid; + + // if silent is a function assume it's a callback + if ($.isFunction(silent)) { + callback = silent; + silent = false; + } + + this.cells_occupied_by_placeholder = {}; + this.$widgets = this.$widgets.not($el); + + var $nexts = this.widgets_below($el); + + this.remove_from_gridmap(wgd); + + $el.fadeOut($.proxy(function() { + $el.remove(); + + if (!silent) { + $nexts.each($.proxy(function(i, widget) { + this.move_widget_up( $(widget), wgd.size_y ); + }, this)); + } + + this.set_dom_grid_height(); + + if (callback) { + callback.call(this, el); + } + }, this)); + + return this; + }; + + + /** + * Remove all widgets from the grid. + * + * @method remove_all_widgets + * @param {Function} callback Function executed for each widget removed. + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.remove_all_widgets = function(callback) { + this.$widgets.each($.proxy(function(i, el){ + this.remove_widget(el, true, callback); + }, this)); + + return this; + }; + + + /** + * Returns a serialized array of the widgets in the grid. + * + * @method serialize + * @param {HTMLElement} [$widgets] The collection of jQuery wrapped + * HTMLElements you want to serialize. If no argument is passed all widgets + * will be serialized. + * @return {Array} Returns an Array of Objects with the data specified in + * the serialize_params option. + */ + fn.serialize = function($widgets) { + $widgets || ($widgets = this.$widgets); + + return $widgets.map($.proxy(function(i, widget) { + var $w = $(widget); + return this.options.serialize_params($w, $w.coords().grid); + }, this)).get(); + }; + + + /** + * Returns a serialized array of the widgets that have changed their + * position. + * + * @method serialize_changed + * @return {Array} Returns an Array of Objects with the data specified in + * the serialize_params option. + */ + fn.serialize_changed = function() { + return this.serialize(this.$changed); + }; + + + /** + * Convert widgets from DOM elements to "widget grid data" Objects. + * + * @method dom_to_coords + * @param {HTMLElement} $widget The widget to be converted. + */ + fn.dom_to_coords = function($widget) { + return { + 'col': parseInt($widget.attr('data-col'), 10), + 'row': parseInt($widget.attr('data-row'), 10), + 'size_x': parseInt($widget.attr('data-sizex'), 10) || 1, + 'size_y': parseInt($widget.attr('data-sizey'), 10) || 1, + 'max_size_x': parseInt($widget.attr('data-max-sizex'), 10) || false, + 'max_size_y': parseInt($widget.attr('data-max-sizey'), 10) || false, + 'min_size_x': parseInt($widget.attr('data-min-sizex'), 10) || false, + 'min_size_y': parseInt($widget.attr('data-min-sizey'), 10) || false, + 'el': $widget + }; + }; + + + /** + * Creates the grid coords object representing the widget an add it to the + * mapped array of positions. + * + * @method register_widget + * @param {HTMLElement|Object} $el jQuery wrapped HTMLElement representing + * the widget, or an "widget grid data" Object with (col, row, el ...). + * @return {Boolean} Returns true if the widget final position is different + * than the original. + */ + fn.register_widget = function($el) { + var isDOM = $el instanceof jQuery; + var wgd = isDOM ? this.dom_to_coords($el) : $el; + var posChanged = false; + isDOM || ($el = wgd.el); + + var empty_upper_row = this.can_go_widget_up(wgd); + if (empty_upper_row) { + wgd.row = empty_upper_row; + $el.attr('data-row', empty_upper_row); + this.$el.trigger('gridster:positionchanged', [wgd]); + posChanged = true; + } + + if (this.options.avoid_overlapped_widgets && + !this.can_move_to( + {size_x: wgd.size_x, size_y: wgd.size_y}, wgd.col, wgd.row) + ) { + $.extend(wgd, this.next_position(wgd.size_x, wgd.size_y)); + $el.attr({ + 'data-col': wgd.col, + 'data-row': wgd.row, + 'data-sizex': wgd.size_x, + 'data-sizey': wgd.size_y + }); + posChanged = true; + } + + // attach Coord object to player data-coord attribute + $el.data('coords', $el.coords()); + // Extend Coord object with grid position info + $el.data('coords').grid = wgd; + + this.add_to_gridmap(wgd, $el); + + this.options.resize.enabled && this.add_resize_handle($el); + + return posChanged; + }; + + + /** + * Update in the mapped array of positions the value of cells represented by + * the grid coords object passed in the `grid_data` param. + * + * @param {Object} grid_data The grid coords object representing the cells + * to update in the mapped array. + * @param {HTMLElement|Boolean} value Pass `false` or the jQuery wrapped + * HTMLElement, depends if you want to delete an existing position or add + * a new one. + * @method update_widget_position + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.update_widget_position = function(grid_data, value) { + this.for_each_cell_occupied(grid_data, function(col, row) { + if (!this.gridmap[col]) { return this; } + this.gridmap[col][row] = value; + }); + return this; + }; + + + /** + * Remove a widget from the mapped array of positions. + * + * @method remove_from_gridmap + * @param {Object} grid_data The grid coords object representing the cells + * to update in the mapped array. + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.remove_from_gridmap = function(grid_data) { + return this.update_widget_position(grid_data, false); + }; + + + /** + * Add a widget to the mapped array of positions. + * + * @method add_to_gridmap + * @param {Object} grid_data The grid coords object representing the cells + * to update in the mapped array. + * @param {HTMLElement|Boolean} value The value to set in the specified + * position . + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.add_to_gridmap = function(grid_data, value) { + this.update_widget_position(grid_data, value || grid_data.el); + + if (grid_data.el) { + var $widgets = this.widgets_below(grid_data.el); + $widgets.each($.proxy(function(i, widget) { + this.move_widget_up( $(widget)); + }, this)); + } + }; + + + /** + * Make widgets draggable. + * + * @uses Draggable + * @method draggable + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.draggable = function() { + var self = this; + var draggable_options = $.extend(true, {}, this.options.draggable, { + offset_left: this.options.widget_margins[0], + offset_top: this.options.widget_margins[1], + container_width: this.cols * this.min_widget_width, + limit: true, + start: function(event, ui) { + self.$widgets.filter('.player-revert') + .removeClass('player-revert'); + + self.$player = $(this); + self.$helper = $(ui.$helper); + + self.helper = !self.$helper.is(self.$player); + + self.on_start_drag.call(self, event, ui); + self.$el.trigger('gridster:dragstart'); + }, + stop: function(event, ui) { + self.on_stop_drag.call(self, event, ui); + self.$el.trigger('gridster:dragstop'); + }, + drag: throttle(function(event, ui) { + self.on_drag.call(self, event, ui); + self.$el.trigger('gridster:drag'); + }, 60) + }); + + this.drag_api = this.$el.drag(draggable_options); + return this; + }; + + + /** + * Bind resize events to get resize working. + * + * @method resizable + * @return {Class} Returns instance of gridster Class. + */ + fn.resizable = function() { + this.resize_api = this.$el.drag({ + items: '.' + this.options.resize.handle_class, + offset_left: this.options.widget_margins[0], + container_width: this.container_width, + move_element: false, + resize: true, + limit: this.options.autogrow_cols ? false : true, + start: $.proxy(this.on_start_resize, this), + stop: $.proxy(function(event, ui) { + delay($.proxy(function() { + this.on_stop_resize(event, ui); + }, this), 120); + }, this), + drag: throttle($.proxy(this.on_resize, this), 60) + }); + + return this; + }; + + + /** + * Setup things required for resizing. Like build templates for drag handles. + * + * @method setup_resize + * @return {Class} Returns instance of gridster Class. + */ + fn.setup_resize = function() { + this.resize_handle_class = this.options.resize.handle_class; + var axes = this.options.resize.axes; + var handle_tpl = ''; + + this.resize_handle_tpl = $.map(axes, function(type) { + return handle_tpl.replace('{type}', type); + }).join(''); + + if ($.isArray(this.options.draggable.ignore_dragging)) { + this.options.draggable.ignore_dragging.push( + '.' + this.resize_handle_class); + } + + return this; + }; + + + /** + * This function is executed when the player begins to be dragged. + * + * @method on_start_drag + * @param {Event} event The original browser event + * @param {Object} ui A prepared ui object with useful drag-related data + */ + fn.on_start_drag = function(event, ui) { + this.$helper.add(this.$player).add(this.$wrapper).addClass('dragging'); + + this.highest_col = this.get_highest_occupied_cell().col; + + this.$player.addClass('player'); + this.player_grid_data = this.$player.coords().grid; + this.placeholder_grid_data = $.extend({}, this.player_grid_data); + + this.set_dom_grid_height(this.$el.height() + + (this.player_grid_data.size_y * this.min_widget_height)); + + this.set_dom_grid_width(this.cols); + + var pgd_sizex = this.player_grid_data.size_x; + var cols_diff = this.cols - this.highest_col; + + if (this.options.autogrow_cols && cols_diff <= pgd_sizex) { + this.add_faux_cols(Math.min(pgd_sizex - cols_diff, 1)); + } + + var colliders = this.faux_grid; + var coords = this.$player.data('coords').coords; + + this.cells_occupied_by_player = this.get_cells_occupied( + this.player_grid_data); + this.cells_occupied_by_placeholder = this.get_cells_occupied( + this.placeholder_grid_data); + + this.last_cols = []; + this.last_rows = []; + + // see jquery.collision.js + this.collision_api = this.$helper.collision( + colliders, this.options.collision); + + this.$preview_holder = $('<' + this.$player.get(0).tagName + ' />', { + 'class': 'preview-holder', + 'data-row': this.$player.attr('data-row'), + 'data-col': this.$player.attr('data-col'), + css: { + width: coords.width, + height: coords.height + } + }).appendTo(this.$el); + + if (this.options.draggable.start) { + this.options.draggable.start.call(this, event, ui); + } + }; + + + /** + * This function is executed when the player is being dragged. + * + * @method on_drag + * @param {Event} event The original browser event + * @param {Object} ui A prepared ui object with useful drag-related data + */ + fn.on_drag = function(event, ui) { + //break if dragstop has been fired + if (this.$player === null) { + return false; + } + + var abs_offset = { + left: ui.position.left + this.baseX, + top: ui.position.top + this.baseY + }; + + // auto grow cols + if (this.options.autogrow_cols) { + var prcol = this.placeholder_grid_data.col + + this.placeholder_grid_data.size_x - 1; + + // "- 1" due to adding at least 1 column in on_start_drag + if (prcol >= this.cols - 1 && this.options.max_cols >= this.cols + 1) { + this.add_faux_cols(1); + this.set_dom_grid_width(this.cols + 1); + this.drag_api.set_limits(this.container_width); + } + + this.collision_api.set_colliders(this.faux_grid); + } + + this.colliders_data = this.collision_api.get_closest_colliders( + abs_offset); + + this.on_overlapped_column_change( + this.on_start_overlapping_column, this.on_stop_overlapping_column); + + this.on_overlapped_row_change( + this.on_start_overlapping_row, this.on_stop_overlapping_row); + + + if (this.helper && this.$player) { + this.$player.css({ + 'left': ui.position.left, + 'top': ui.position.top + }); + } + + if (this.options.draggable.drag) { + this.options.draggable.drag.call(this, event, ui); + } + }; + + + /** + * This function is executed when the player stops being dragged. + * + * @method on_stop_drag + * @param {Event} event The original browser event + * @param {Object} ui A prepared ui object with useful drag-related data + */ + fn.on_stop_drag = function(event, ui) { + this.$helper.add(this.$player).add(this.$wrapper) + .removeClass('dragging'); + + ui.position.left = ui.position.left + this.baseX; + ui.position.top = ui.position.top + this.baseY; + this.colliders_data = this.collision_api.get_closest_colliders( + ui.position); + + this.on_overlapped_column_change( + this.on_start_overlapping_column, + this.on_stop_overlapping_column + ); + + this.on_overlapped_row_change( + this.on_start_overlapping_row, + this.on_stop_overlapping_row + ); + + this.$player.addClass('player-revert').removeClass('player') + .attr({ + 'data-col': this.placeholder_grid_data.col, + 'data-row': this.placeholder_grid_data.row + }).css({ + 'left': '', + 'top': '' + }); + + this.$changed = this.$changed.add(this.$player); + + this.cells_occupied_by_player = this.get_cells_occupied( + this.placeholder_grid_data); + this.set_cells_player_occupies( + this.placeholder_grid_data.col, this.placeholder_grid_data.row); + + this.$player.coords().grid.row = this.placeholder_grid_data.row; + this.$player.coords().grid.col = this.placeholder_grid_data.col; + + if (this.options.draggable.stop) { + this.options.draggable.stop.call(this, event, ui); + } + + this.$preview_holder.remove(); + + this.$player = null; + this.$helper = null; + this.placeholder_grid_data = {}; + this.player_grid_data = {}; + this.cells_occupied_by_placeholder = {}; + this.cells_occupied_by_player = {}; + + this.set_dom_grid_height(); + this.set_dom_grid_width(); + + if (this.options.autogrow_cols) { + this.drag_api.set_limits(this.cols * this.min_widget_width); + } + }; + + + /** + * This function is executed every time a widget starts to be resized. + * + * @method on_start_resize + * @param {Event} event The original browser event + * @param {Object} ui A prepared ui object with useful drag-related data + */ + fn.on_start_resize = function(event, ui) { + this.$resized_widget = ui.$player.closest('.gs-w'); + this.resize_coords = this.$resized_widget.coords(); + this.resize_wgd = this.resize_coords.grid; + this.resize_initial_width = this.resize_coords.coords.width; + this.resize_initial_height = this.resize_coords.coords.height; + this.resize_initial_sizex = this.resize_coords.grid.size_x; + this.resize_initial_sizey = this.resize_coords.grid.size_y; + this.resize_initial_col = this.resize_coords.grid.col; + this.resize_last_sizex = this.resize_initial_sizex; + this.resize_last_sizey = this.resize_initial_sizey; + + this.resize_max_size_x = Math.min(this.resize_wgd.max_size_x || + this.options.resize.max_size[0], + this.options.max_cols - this.resize_initial_col + 1); + this.resize_max_size_y = this.resize_wgd.max_size_y || + this.options.resize.max_size[1]; + + this.resize_min_size_x = (this.resize_wgd.min_size_x || + this.options.resize.min_size[0] || 1); + this.resize_min_size_y = (this.resize_wgd.min_size_y || + this.options.resize.min_size[1] || 1); + + this.resize_initial_last_col = this.get_highest_occupied_cell().col; + + this.set_dom_grid_width(this.cols); + + this.resize_dir = { + right: ui.$player.is('.' + this.resize_handle_class + '-x'), + bottom: ui.$player.is('.' + this.resize_handle_class + '-y') + }; + + this.$resized_widget.css({ + 'min-width': this.options.widget_base_dimensions[0], + 'min-height': this.options.widget_base_dimensions[1] + }); + + var nodeName = this.$resized_widget.get(0).tagName; + this.$resize_preview_holder = $('<' + nodeName + ' />', { + 'class': 'preview-holder resize-preview-holder', + 'data-row': this.$resized_widget.attr('data-row'), + 'data-col': this.$resized_widget.attr('data-col'), + 'css': { + 'width': this.resize_initial_width, + 'height': this.resize_initial_height + } + }).appendTo(this.$el); + + this.$resized_widget.addClass('resizing'); + + if (this.options.resize.start) { + this.options.resize.start.call(this, event, ui, this.$resized_widget); + } + + this.$el.trigger('gridster:resizestart'); + }; + + + /** + * This function is executed every time a widget stops being resized. + * + * @method on_stop_resize + * @param {Event} event The original browser event + * @param {Object} ui A prepared ui object with useful drag-related data + */ + fn.on_stop_resize = function(event, ui) { + this.$resized_widget + .removeClass('resizing') + .css({ + 'width': '', + 'height': '' + }); + + delay($.proxy(function() { + this.$resize_preview_holder + .remove() + .css({ + 'min-width': '', + 'min-height': '' + }); + + if (this.options.resize.stop) { + this.options.resize.stop.call(this, event, ui, this.$resized_widget); + } + + this.$el.trigger('gridster:resizestop'); + }, this), 300); + + this.set_dom_grid_width(); + + if (this.options.autogrow_cols) { + this.drag_api.set_limits(this.cols * this.min_widget_width); + } + }; + + + /** + * This function is executed when a widget is being resized. + * + * @method on_resize + * @param {Event} event The original browser event + * @param {Object} ui A prepared ui object with useful drag-related data + */ + fn.on_resize = function(event, ui) { + var rel_x = (ui.pointer.diff_left); + var rel_y = (ui.pointer.diff_top); + var wbd_x = this.options.widget_base_dimensions[0]; + var wbd_y = this.options.widget_base_dimensions[1]; + var margin_x = this.options.widget_margins[0]; + var margin_y = this.options.widget_margins[1]; + var max_size_x = this.resize_max_size_x; + var min_size_x = this.resize_min_size_x; + var max_size_y = this.resize_max_size_y; + var min_size_y = this.resize_min_size_y; + var autogrow = this.options.autogrow_cols; + var width; + var max_width = Infinity; + var max_height = Infinity; + + var inc_units_x = Math.ceil((rel_x / (wbd_x + margin_x * 2)) - 0.2); + var inc_units_y = Math.ceil((rel_y / (wbd_y + margin_y * 2)) - 0.2); + + var size_x = Math.max(1, this.resize_initial_sizex + inc_units_x); + var size_y = Math.max(1, this.resize_initial_sizey + inc_units_y); + + var max_cols = (this.container_width / this.min_widget_width) - + this.resize_initial_col + 1; + var limit_width = ((max_cols * this.min_widget_width) - margin_x * 2); + + size_x = Math.max(Math.min(size_x, max_size_x), min_size_x); + size_x = Math.min(max_cols, size_x); + width = (max_size_x * wbd_x) + ((size_x - 1) * margin_x * 2); + max_width = Math.min(width, limit_width); + min_width = (min_size_x * wbd_x) + ((size_x - 1) * margin_x * 2); + + size_y = Math.max(Math.min(size_y, max_size_y), min_size_y); + max_height = (max_size_y * wbd_y) + ((size_y - 1) * margin_y * 2); + min_height = (min_size_y * wbd_y) + ((size_y - 1) * margin_y * 2); + + if (this.resize_dir.right) { + size_y = this.resize_initial_sizey; + } else if (this.resize_dir.bottom) { + size_x = this.resize_initial_sizex; + } + + if (autogrow) { + var last_widget_col = this.resize_initial_col + size_x - 1; + if (autogrow && this.resize_initial_last_col <= last_widget_col) { + this.set_dom_grid_width(Math.max(last_widget_col + 1, this.cols)); + + if (this.cols < last_widget_col) { + this.add_faux_cols(last_widget_col - this.cols); + } + } + } + + var css_props = {}; + !this.resize_dir.bottom && (css_props.width = Math.max(Math.min( + this.resize_initial_width + rel_x, max_width), min_width)); + !this.resize_dir.right && (css_props.height = Math.max(Math.min( + this.resize_initial_height + rel_y, max_height), min_height)); + + this.$resized_widget.css(css_props); + + if (size_x !== this.resize_last_sizex || + size_y !== this.resize_last_sizey) { + + this.resize_widget(this.$resized_widget, size_x, size_y); + this.set_dom_grid_width(this.cols); + + this.$resize_preview_holder.css({ + 'width': '', + 'height': '' + }).attr({ + 'data-row': this.$resized_widget.attr('data-row'), + 'data-sizex': size_x, + 'data-sizey': size_y + }); + } + + if (this.options.resize.resize) { + this.options.resize.resize.call(this, event, ui, this.$resized_widget); + } + + this.$el.trigger('gridster:resize'); + + this.resize_last_sizex = size_x; + this.resize_last_sizey = size_y; + }; + + + /** + * Executes the callbacks passed as arguments when a column begins to be + * overlapped or stops being overlapped. + * + * @param {Function} start_callback Function executed when a new column + * begins to be overlapped. The column is passed as first argument. + * @param {Function} stop_callback Function executed when a column stops + * being overlapped. The column is passed as first argument. + * @method on_overlapped_column_change + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.on_overlapped_column_change = function(start_callback, stop_callback) { + if (!this.colliders_data.length) { + return this; + } + var cols = this.get_targeted_columns( + this.colliders_data[0].el.data.col); + + var last_n_cols = this.last_cols.length; + var n_cols = cols.length; + var i; + + for (i = 0; i < n_cols; i++) { + if ($.inArray(cols[i], this.last_cols) === -1) { + (start_callback || $.noop).call(this, cols[i]); + } + } + + for (i = 0; i< last_n_cols; i++) { + if ($.inArray(this.last_cols[i], cols) === -1) { + (stop_callback || $.noop).call(this, this.last_cols[i]); + } + } + + this.last_cols = cols; + + return this; + }; + + + /** + * Executes the callbacks passed as arguments when a row starts to be + * overlapped or stops being overlapped. + * + * @param {Function} start_callback Function executed when a new row begins + * to be overlapped. The row is passed as first argument. + * @param {Function} end_callback Function executed when a row stops being + * overlapped. The row is passed as first argument. + * @method on_overlapped_row_change + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.on_overlapped_row_change = function(start_callback, end_callback) { + if (!this.colliders_data.length) { + return this; + } + var rows = this.get_targeted_rows(this.colliders_data[0].el.data.row); + var last_n_rows = this.last_rows.length; + var n_rows = rows.length; + var i; + + for (i = 0; i < n_rows; i++) { + if ($.inArray(rows[i], this.last_rows) === -1) { + (start_callback || $.noop).call(this, rows[i]); + } + } + + for (i = 0; i < last_n_rows; i++) { + if ($.inArray(this.last_rows[i], rows) === -1) { + (end_callback || $.noop).call(this, this.last_rows[i]); + } + } + + this.last_rows = rows; + }; + + + /** + * Sets the current position of the player + * + * @param {Number} col + * @param {Number} row + * @param {Boolean} no_player + * @method set_player + * @return {object} + */ + fn.set_player = function(col, row, no_player) { + var self = this; + if (!no_player) { + this.empty_cells_player_occupies(); + } + var cell = !no_player ? self.colliders_data[0].el.data : {col: col}; + var to_col = cell.col; + var to_row = row || cell.row; + + this.player_grid_data = { + col: to_col, + row: to_row, + size_y : this.player_grid_data.size_y, + size_x : this.player_grid_data.size_x + }; + + this.cells_occupied_by_player = this.get_cells_occupied( + this.player_grid_data); + + var $overlapped_widgets = this.get_widgets_overlapped( + this.player_grid_data); + + var constraints = this.widgets_constraints($overlapped_widgets); + + this.manage_movements(constraints.can_go_up, to_col, to_row); + this.manage_movements(constraints.can_not_go_up, to_col, to_row); + + /* if there is not widgets overlapping in the new player position, + * update the new placeholder position. */ + if (!$overlapped_widgets.length) { + var pp = this.can_go_player_up(this.player_grid_data); + if (pp !== false) { + to_row = pp; + } + this.set_placeholder(to_col, to_row); + } + + return { + col: to_col, + row: to_row + }; + }; + + + /** + * See which of the widgets in the $widgets param collection can go to + * a upper row and which not. + * + * @method widgets_contraints + * @param {jQuery} $widgets A jQuery wrapped collection of + * HTMLElements. + * @return {object} Returns a literal Object with two keys: `can_go_up` & + * `can_not_go_up`. Each contains a set of HTMLElements. + */ + fn.widgets_constraints = function($widgets) { + var $widgets_can_go_up = $([]); + var $widgets_can_not_go_up; + var wgd_can_go_up = []; + var wgd_can_not_go_up = []; + + $widgets.each($.proxy(function(i, w) { + var $w = $(w); + var wgd = $w.coords().grid; + if (this.can_go_widget_up(wgd)) { + $widgets_can_go_up = $widgets_can_go_up.add($w); + wgd_can_go_up.push(wgd); + } else { + wgd_can_not_go_up.push(wgd); + } + }, this)); + + $widgets_can_not_go_up = $widgets.not($widgets_can_go_up); + + return { + can_go_up: Gridster.sort_by_row_asc(wgd_can_go_up), + can_not_go_up: Gridster.sort_by_row_desc(wgd_can_not_go_up) + }; + }; + + + /** + * Sorts an Array of grid coords objects (representing the grid coords of + * each widget) in descending way. + * + * @method manage_movements + * @param {jQuery} $widgets A jQuery collection of HTMLElements + * representing the widgets you want to move. + * @param {Number} to_col The column to which we want to move the widgets. + * @param {Number} to_row The row to which we want to move the widgets. + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.manage_movements = function($widgets, to_col, to_row) { + $.each($widgets, $.proxy(function(i, w) { + var wgd = w; + var $w = wgd.el; + + var can_go_widget_up = this.can_go_widget_up(wgd); + + if (can_go_widget_up) { + //target CAN go up + //so move widget up + this.move_widget_to($w, can_go_widget_up); + this.set_placeholder(to_col, can_go_widget_up + wgd.size_y); + + } else { + //target can't go up + var can_go_player_up = this.can_go_player_up( + this.player_grid_data); + + if (!can_go_player_up) { + // target can't go up + // player cant't go up + // so we need to move widget down to a position that dont + // overlaps player + var y = (to_row + this.player_grid_data.size_y) - wgd.row; + + this.move_widget_down($w, y); + this.set_placeholder(to_col, to_row); + } + } + }, this)); + + return this; + }; + + /** + * Determines if there is a widget in the row and col given. Or if the + * HTMLElement passed as first argument is the player. + * + * @method is_player + * @param {Number|HTMLElement} col_or_el A jQuery wrapped collection of + * HTMLElements. + * @param {Number} [row] The column to which we want to move the widgets. + * @return {Boolean} Returns true or false. + */ + fn.is_player = function(col_or_el, row) { + if (row && !this.gridmap[col_or_el]) { return false; } + var $w = row ? this.gridmap[col_or_el][row] : col_or_el; + return $w && ($w.is(this.$player) || $w.is(this.$helper)); + }; + + + /** + * Determines if the widget that is being dragged is currently over the row + * and col given. + * + * @method is_player_in + * @param {Number} col The column to check. + * @param {Number} row The row to check. + * @return {Boolean} Returns true or false. + */ + fn.is_player_in = function(col, row) { + var c = this.cells_occupied_by_player || {}; + return $.inArray(col, c.cols) >= 0 && $.inArray(row, c.rows) >= 0; + }; + + + /** + * Determines if the placeholder is currently over the row and col given. + * + * @method is_placeholder_in + * @param {Number} col The column to check. + * @param {Number} row The row to check. + * @return {Boolean} Returns true or false. + */ + fn.is_placeholder_in = function(col, row) { + var c = this.cells_occupied_by_placeholder || {}; + return this.is_placeholder_in_col(col) && $.inArray(row, c.rows) >= 0; + }; + + + /** + * Determines if the placeholder is currently over the column given. + * + * @method is_placeholder_in_col + * @param {Number} col The column to check. + * @return {Boolean} Returns true or false. + */ + fn.is_placeholder_in_col = function(col) { + var c = this.cells_occupied_by_placeholder || []; + return $.inArray(col, c.cols) >= 0; + }; + + + /** + * Determines if the cell represented by col and row params is empty. + * + * @method is_empty + * @param {Number} col The column to check. + * @param {Number} row The row to check. + * @return {Boolean} Returns true or false. + */ + fn.is_empty = function(col, row) { + if (typeof this.gridmap[col] !== 'undefined') { + if(typeof this.gridmap[col][row] !== 'undefined' && + this.gridmap[col][row] === false + ) { + return true; + } + return false; + } + return true; + }; + + + /** + * Determines if the cell represented by col and row params is occupied. + * + * @method is_occupied + * @param {Number} col The column to check. + * @param {Number} row The row to check. + * @return {Boolean} Returns true or false. + */ + fn.is_occupied = function(col, row) { + if (!this.gridmap[col]) { + return false; + } + + if (this.gridmap[col][row]) { + return true; + } + return false; + }; + + + /** + * Determines if there is a widget in the cell represented by col/row params. + * + * @method is_widget + * @param {Number} col The column to check. + * @param {Number} row The row to check. + * @return {Boolean|HTMLElement} Returns false if there is no widget, + * else returns the jQuery HTMLElement + */ + fn.is_widget = function(col, row) { + var cell = this.gridmap[col]; + if (!cell) { + return false; + } + + cell = cell[row]; + + if (cell) { + return cell; + } + + return false; + }; + + + /** + * Determines if there is a widget in the cell represented by col/row + * params and if this is under the widget that is being dragged. + * + * @method is_widget_under_player + * @param {Number} col The column to check. + * @param {Number} row The row to check. + * @return {Boolean} Returns true or false. + */ + fn.is_widget_under_player = function(col, row) { + if (this.is_widget(col, row)) { + return this.is_player_in(col, row); + } + return false; + }; + + + /** + * Get widgets overlapping with the player or with the object passed + * representing the grid cells. + * + * @method get_widgets_under_player + * @return {HTMLElement} Returns a jQuery collection of HTMLElements + */ + fn.get_widgets_under_player = function(cells) { + cells || (cells = this.cells_occupied_by_player || {cols: [], rows: []}); + var $widgets = $([]); + + $.each(cells.cols, $.proxy(function(i, col) { + $.each(cells.rows, $.proxy(function(i, row) { + if(this.is_widget(col, row)) { + $widgets = $widgets.add(this.gridmap[col][row]); + } + }, this)); + }, this)); + + return $widgets; + }; + + + /** + * Put placeholder at the row and column specified. + * + * @method set_placeholder + * @param {Number} col The column to which we want to move the + * placeholder. + * @param {Number} row The row to which we want to move the + * placeholder. + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.set_placeholder = function(col, row) { + var phgd = $.extend({}, this.placeholder_grid_data); + var $nexts = this.widgets_below({ + col: phgd.col, + row: phgd.row, + size_y: phgd.size_y, + size_x: phgd.size_x + }); + + // Prevents widgets go out of the grid + var right_col = (col + phgd.size_x - 1); + if (right_col > this.cols) { + col = col - (right_col - col); + } + + var moved_down = this.placeholder_grid_data.row < row; + var changed_column = this.placeholder_grid_data.col !== col; + + this.placeholder_grid_data.col = col; + this.placeholder_grid_data.row = row; + + this.cells_occupied_by_placeholder = this.get_cells_occupied( + this.placeholder_grid_data); + + this.$preview_holder.attr({ + 'data-row' : row, + 'data-col' : col + }); + + if (moved_down || changed_column) { + $nexts.each($.proxy(function(i, widget) { + this.move_widget_up( + $(widget), this.placeholder_grid_data.col - col + phgd.size_y); + }, this)); + } + + var $widgets_under_ph = this.get_widgets_under_player( + this.cells_occupied_by_placeholder); + + if ($widgets_under_ph.length) { + $widgets_under_ph.each($.proxy(function(i, widget) { + var $w = $(widget); + this.move_widget_down( + $w, row + phgd.size_y - $w.data('coords').grid.row); + }, this)); + } + + }; + + + /** + * Determines whether the player can move to a position above. + * + * @method can_go_player_up + * @param {Object} widget_grid_data The actual grid coords object of the + * player. + * @return {Number|Boolean} If the player can be moved to an upper row + * returns the row number, else returns false. + */ + fn.can_go_player_up = function(widget_grid_data) { + var p_bottom_row = widget_grid_data.row + widget_grid_data.size_y - 1; + var result = true; + var upper_rows = []; + var min_row = 10000; + var $widgets_under_player = this.get_widgets_under_player(); + + /* generate an array with columns as index and array with upper rows + * empty as value */ + this.for_each_column_occupied(widget_grid_data, function(tcol) { + var grid_col = this.gridmap[tcol]; + var r = p_bottom_row + 1; + upper_rows[tcol] = []; + + while (--r > 0) { + if (this.is_empty(tcol, r) || this.is_player(tcol, r) || + this.is_widget(tcol, r) && + grid_col[r].is($widgets_under_player) + ) { + upper_rows[tcol].push(r); + min_row = r < min_row ? r : min_row; + } else { + break; + } + } + + if (upper_rows[tcol].length === 0) { + result = false; + return true; //break + } + + upper_rows[tcol].sort(function(a, b) { + return a - b; + }); + }); + + if (!result) { return false; } + + return this.get_valid_rows(widget_grid_data, upper_rows, min_row); + }; + + + /** + * Determines whether a widget can move to a position above. + * + * @method can_go_widget_up + * @param {Object} widget_grid_data The actual grid coords object of the + * widget we want to check. + * @return {Number|Boolean} If the widget can be moved to an upper row + * returns the row number, else returns false. + */ + fn.can_go_widget_up = function(widget_grid_data) { + var p_bottom_row = widget_grid_data.row + widget_grid_data.size_y - 1; + var result = true; + var upper_rows = []; + var min_row = 10000; + + /* generate an array with columns as index and array with topmost rows + * empty as value */ + this.for_each_column_occupied(widget_grid_data, function(tcol) { + var grid_col = this.gridmap[tcol]; + upper_rows[tcol] = []; + + var r = p_bottom_row + 1; + // iterate over each row + while (--r > 0) { + if (this.is_widget(tcol, r) && !this.is_player_in(tcol, r)) { + if (!grid_col[r].is(widget_grid_data.el)) { + break; + } + } + + if (!this.is_player(tcol, r) && + !this.is_placeholder_in(tcol, r) && + !this.is_player_in(tcol, r)) { + upper_rows[tcol].push(r); + } + + if (r < min_row) { + min_row = r; + } + } + + if (upper_rows[tcol].length === 0) { + result = false; + return true; //break + } + + upper_rows[tcol].sort(function(a, b) { + return a - b; + }); + }); + + if (!result) { return false; } + + return this.get_valid_rows(widget_grid_data, upper_rows, min_row); + }; + + + /** + * Search a valid row for the widget represented by `widget_grid_data' in + * the `upper_rows` array. Iteration starts from row specified in `min_row`. + * + * @method get_valid_rows + * @param {Object} widget_grid_data The actual grid coords object of the + * player. + * @param {Array} upper_rows An array with columns as index and arrays + * of valid rows as values. + * @param {Number} min_row The upper row from which the iteration will start. + * @return {Number|Boolean} Returns the upper row valid from the `upper_rows` + * for the widget in question. + */ + fn.get_valid_rows = function(widget_grid_data, upper_rows, min_row) { + var p_top_row = widget_grid_data.row; + var p_bottom_row = widget_grid_data.row + widget_grid_data.size_y - 1; + var size_y = widget_grid_data.size_y; + var r = min_row - 1; + var valid_rows = []; + + while (++r <= p_bottom_row ) { + var common = true; + $.each(upper_rows, function(col, rows) { + if ($.isArray(rows) && $.inArray(r, rows) === -1) { + common = false; + } + }); + + if (common === true) { + valid_rows.push(r); + if (valid_rows.length === size_y) { + break; + } + } + } + + var new_row = false; + if (size_y === 1) { + if (valid_rows[0] !== p_top_row) { + new_row = valid_rows[0] || false; + } + } else { + if (valid_rows[0] !== p_top_row) { + new_row = this.get_consecutive_numbers_index( + valid_rows, size_y); + } + } + + return new_row; + }; + + + fn.get_consecutive_numbers_index = function(arr, size_y) { + var max = arr.length; + var result = []; + var first = true; + var prev = -1; // or null? + + for (var i=0; i < max; i++) { + if (first || arr[i] === prev + 1) { + result.push(i); + if (result.length === size_y) { + break; + } + first = false; + } else { + result = []; + first = true; + } + + prev = arr[i]; + } + + return result.length >= size_y ? arr[result[0]] : false; + }; + + + /** + * Get widgets overlapping with the player. + * + * @method get_widgets_overlapped + * @return {jQuery} Returns a jQuery collection of HTMLElements. + */ + fn.get_widgets_overlapped = function() { + var $w; + var $widgets = $([]); + var used = []; + var rows_from_bottom = this.cells_occupied_by_player.rows.slice(0); + rows_from_bottom.reverse(); + + $.each(this.cells_occupied_by_player.cols, $.proxy(function(i, col) { + $.each(rows_from_bottom, $.proxy(function(i, row) { + // if there is a widget in the player position + if (!this.gridmap[col]) { return true; } //next iteration + var $w = this.gridmap[col][row]; + if (this.is_occupied(col, row) && !this.is_player($w) && + $.inArray($w, used) === -1 + ) { + $widgets = $widgets.add($w); + used.push($w); + } + + }, this)); + }, this)); + + return $widgets; + }; + + + /** + * This callback is executed when the player begins to collide with a column. + * + * @method on_start_overlapping_column + * @param {Number} col The collided column. + * @return {jQuery} Returns a jQuery collection of HTMLElements. + */ + fn.on_start_overlapping_column = function(col) { + this.set_player(col, false); + }; + + + /** + * A callback executed when the player begins to collide with a row. + * + * @method on_start_overlapping_row + * @param {Number} row The collided row. + * @return {jQuery} Returns a jQuery collection of HTMLElements. + */ + fn.on_start_overlapping_row = function(row) { + this.set_player(false, row); + }; + + + /** + * A callback executed when the the player ends to collide with a column. + * + * @method on_stop_overlapping_column + * @param {Number} col The collided row. + * @return {jQuery} Returns a jQuery collection of HTMLElements. + */ + fn.on_stop_overlapping_column = function(col) { + this.set_player(col, false); + + var self = this; + this.for_each_widget_below(col, this.cells_occupied_by_player.rows[0], + function(tcol, trow) { + self.move_widget_up(this, self.player_grid_data.size_y); + }); + }; + + + /** + * This callback is executed when the player ends to collide with a row. + * + * @method on_stop_overlapping_row + * @param {Number} row The collided row. + * @return {jQuery} Returns a jQuery collection of HTMLElements. + */ + fn.on_stop_overlapping_row = function(row) { + this.set_player(false, row); + + var self = this; + var cols = this.cells_occupied_by_player.cols; + for (var c = 0, cl = cols.length; c < cl; c++) { + this.for_each_widget_below(cols[c], row, function(tcol, trow) { + self.move_widget_up(this, self.player_grid_data.size_y); + }); + } + }; + + + /** + * Move a widget to a specific row. The cell or cells must be empty. + * If the widget has widgets below, all of these widgets will be moved also + * if they can. + * + * @method move_widget_to + * @param {HTMLElement} $widget The jQuery wrapped HTMLElement of the + * widget is going to be moved. + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.move_widget_to = function($widget, row) { + var self = this; + var widget_grid_data = $widget.coords().grid; + var diff = row - widget_grid_data.row; + var $next_widgets = this.widgets_below($widget); + + var can_move_to_new_cell = this.can_move_to( + widget_grid_data, widget_grid_data.col, row, $widget); + + if (can_move_to_new_cell === false) { + return false; + } + + this.remove_from_gridmap(widget_grid_data); + widget_grid_data.row = row; + this.add_to_gridmap(widget_grid_data); + $widget.attr('data-row', row); + this.$changed = this.$changed.add($widget); + + + $next_widgets.each(function(i, widget) { + var $w = $(widget); + var wgd = $w.coords().grid; + var can_go_up = self.can_go_widget_up(wgd); + if (can_go_up && can_go_up !== wgd.row) { + self.move_widget_to($w, can_go_up); + } + }); + + return this; + }; + + + /** + * Move up the specified widget and all below it. + * + * @method move_widget_up + * @param {HTMLElement} $widget The widget you want to move. + * @param {Number} [y_units] The number of cells that the widget has to move. + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.move_widget_up = function($widget, y_units) { + var el_grid_data = $widget.coords().grid; + var actual_row = el_grid_data.row; + var moved = []; + var can_go_up = true; + y_units || (y_units = 1); + + if (!this.can_go_up($widget)) { return false; } //break; + + this.for_each_column_occupied(el_grid_data, function(col) { + // can_go_up + if ($.inArray($widget, moved) === -1) { + var widget_grid_data = $widget.coords().grid; + var next_row = actual_row - y_units; + next_row = this.can_go_up_to_row( + widget_grid_data, col, next_row); + + if (!next_row) { + return true; + } + + var $next_widgets = this.widgets_below($widget); + + this.remove_from_gridmap(widget_grid_data); + widget_grid_data.row = next_row; + this.add_to_gridmap(widget_grid_data); + $widget.attr('data-row', widget_grid_data.row); + this.$changed = this.$changed.add($widget); + + moved.push($widget); + + $next_widgets.each($.proxy(function(i, widget) { + this.move_widget_up($(widget), y_units); + }, this)); + } + }); + + }; + + + /** + * Move down the specified widget and all below it. + * + * @method move_widget_down + * @param {jQuery} $widget The jQuery object representing the widget + * you want to move. + * @param {Number} y_units The number of cells that the widget has to move. + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.move_widget_down = function($widget, y_units) { + var el_grid_data, actual_row, moved, y_diff; + + if (y_units <= 0) { return false; } + + el_grid_data = $widget.coords().grid; + actual_row = el_grid_data.row; + moved = []; + y_diff = y_units; + + if (!$widget) { return false; } + + if ($.inArray($widget, moved) === -1) { + + var widget_grid_data = $widget.coords().grid; + var next_row = actual_row + y_units; + var $next_widgets = this.widgets_below($widget); + + this.remove_from_gridmap(widget_grid_data); + + $next_widgets.each($.proxy(function(i, widget) { + var $w = $(widget); + var wd = $w.coords().grid; + var tmp_y = this.displacement_diff( + wd, widget_grid_data, y_diff); + + if (tmp_y > 0) { + this.move_widget_down($w, tmp_y); + } + }, this)); + + widget_grid_data.row = next_row; + this.update_widget_position(widget_grid_data, $widget); + $widget.attr('data-row', widget_grid_data.row); + this.$changed = this.$changed.add($widget); + + moved.push($widget); + } + }; + + + /** + * Check if the widget can move to the specified row, else returns the + * upper row possible. + * + * @method can_go_up_to_row + * @param {Number} widget_grid_data The current grid coords object of the + * widget. + * @param {Number} col The target column. + * @param {Number} row The target row. + * @return {Boolean|Number} Returns the row number if the widget can move + * to the target position, else returns false. + */ + fn.can_go_up_to_row = function(widget_grid_data, col, row) { + var ga = this.gridmap; + var result = true; + var urc = []; // upper_rows_in_columns + var actual_row = widget_grid_data.row; + var r; + + /* generate an array with columns as index and array with + * upper rows empty in the column */ + this.for_each_column_occupied(widget_grid_data, function(tcol) { + var grid_col = ga[tcol]; + urc[tcol] = []; + + r = actual_row; + while (r--) { + if (this.is_empty(tcol, r) && + !this.is_placeholder_in(tcol, r) + ) { + urc[tcol].push(r); + } else { + break; + } + } + + if (!urc[tcol].length) { + result = false; + return true; + } + + }); + + if (!result) { return false; } + + /* get common rows starting from upper position in all the columns + * that widget occupies */ + r = row; + for (r = 1; r < actual_row; r++) { + var common = true; + + for (var uc = 0, ucl = urc.length; uc < ucl; uc++) { + if (urc[uc] && $.inArray(r, urc[uc]) === -1) { + common = false; + } + } + + if (common === true) { + result = r; + break; + } + } + + return result; + }; + + + fn.displacement_diff = function(widget_grid_data, parent_bgd, y_units) { + var actual_row = widget_grid_data.row; + var diffs = []; + var parent_max_y = parent_bgd.row + parent_bgd.size_y; + + this.for_each_column_occupied(widget_grid_data, function(col) { + var temp_y_units = 0; + + for (var r = parent_max_y; r < actual_row; r++) { + if (this.is_empty(col, r)) { + temp_y_units = temp_y_units + 1; + } + } + + diffs.push(temp_y_units); + }); + + var max_diff = Math.max.apply(Math, diffs); + y_units = (y_units - max_diff); + + return y_units > 0 ? y_units : 0; + }; + + + /** + * Get widgets below a widget. + * + * @method widgets_below + * @param {HTMLElement} $el The jQuery wrapped HTMLElement. + * @return {jQuery} A jQuery collection of HTMLElements. + */ + fn.widgets_below = function($el) { + var el_grid_data = $.isPlainObject($el) ? $el : $el.coords().grid; + var self = this; + var ga = this.gridmap; + var next_row = el_grid_data.row + el_grid_data.size_y - 1; + var $nexts = $([]); + + this.for_each_column_occupied(el_grid_data, function(col) { + self.for_each_widget_below(col, next_row, function(tcol, trow) { + if (!self.is_player(this) && $.inArray(this, $nexts) === -1) { + $nexts = $nexts.add(this); + return true; // break + } + }); + }); + + return Gridster.sort_by_row_asc($nexts); + }; + + + /** + * Update the array of mapped positions with the new player position. + * + * @method set_cells_player_occupies + * @param {Number} col The new player col. + * @param {Number} col The new player row. + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.set_cells_player_occupies = function(col, row) { + this.remove_from_gridmap(this.placeholder_grid_data); + this.placeholder_grid_data.col = col; + this.placeholder_grid_data.row = row; + this.add_to_gridmap(this.placeholder_grid_data, this.$player); + return this; + }; + + + /** + * Remove from the array of mapped positions the reference to the player. + * + * @method empty_cells_player_occupies + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.empty_cells_player_occupies = function() { + this.remove_from_gridmap(this.placeholder_grid_data); + return this; + }; + + + fn.can_go_up = function($el) { + var el_grid_data = $el.coords().grid; + var initial_row = el_grid_data.row; + var prev_row = initial_row - 1; + var ga = this.gridmap; + var upper_rows_by_column = []; + + var result = true; + if (initial_row === 1) { return false; } + + this.for_each_column_occupied(el_grid_data, function(col) { + var $w = this.is_widget(col, prev_row); + + if (this.is_occupied(col, prev_row) || + this.is_player(col, prev_row) || + this.is_placeholder_in(col, prev_row) || + this.is_player_in(col, prev_row) + ) { + result = false; + return true; //break + } + }); + + return result; + }; + + + /** + * Check if it's possible to move a widget to a specific col/row. It takes + * into account the dimensions (`size_y` and `size_x` attrs. of the grid + * coords object) the widget occupies. + * + * @method can_move_to + * @param {Object} widget_grid_data The grid coords object that represents + * the widget. + * @param {Object} col The col to check. + * @param {Object} row The row to check. + * @param {Number} [max_row] The max row allowed. + * @return {Boolean} Returns true if all cells are empty, else return false. + */ + fn.can_move_to = function(widget_grid_data, col, row, max_row) { + var ga = this.gridmap; + var $w = widget_grid_data.el; + var future_wd = { + size_y: widget_grid_data.size_y, + size_x: widget_grid_data.size_x, + col: col, + row: row + }; + var result = true; + + //Prevents widgets go out of the grid + var right_col = col + widget_grid_data.size_x - 1; + if (right_col > this.cols) { + return false; + } + + if (max_row && max_row < row + widget_grid_data.size_y - 1) { + return false; + } + + this.for_each_cell_occupied(future_wd, function(tcol, trow) { + var $tw = this.is_widget(tcol, trow); + if ($tw && (!widget_grid_data.el || $tw.is($w))) { + result = false; + } + }); + + return result; + }; + + + /** + * Given the leftmost column returns all columns that are overlapping + * with the player. + * + * @method get_targeted_columns + * @param {Number} [from_col] The leftmost column. + * @return {Array} Returns an array with column numbers. + */ + fn.get_targeted_columns = function(from_col) { + var max = (from_col || this.player_grid_data.col) + + (this.player_grid_data.size_x - 1); + var cols = []; + for (var col = from_col; col <= max; col++) { + cols.push(col); + } + return cols; + }; + + + /** + * Given the upper row returns all rows that are overlapping with the player. + * + * @method get_targeted_rows + * @param {Number} [from_row] The upper row. + * @return {Array} Returns an array with row numbers. + */ + fn.get_targeted_rows = function(from_row) { + var max = (from_row || this.player_grid_data.row) + + (this.player_grid_data.size_y - 1); + var rows = []; + for (var row = from_row; row <= max; row++) { + rows.push(row); + } + return rows; + }; + + /** + * Get all columns and rows that a widget occupies. + * + * @method get_cells_occupied + * @param {Object} el_grid_data The grid coords object of the widget. + * @return {Object} Returns an object like `{ cols: [], rows: []}`. + */ + fn.get_cells_occupied = function(el_grid_data) { + var cells = { cols: [], rows: []}; + var i; + if (arguments[1] instanceof $) { + el_grid_data = arguments[1].coords().grid; + } + + for (i = 0; i < el_grid_data.size_x; i++) { + var col = el_grid_data.col + i; + cells.cols.push(col); + } + + for (i = 0; i < el_grid_data.size_y; i++) { + var row = el_grid_data.row + i; + cells.rows.push(row); + } + + return cells; + }; + + + /** + * Iterate over the cells occupied by a widget executing a function for + * each one. + * + * @method for_each_cell_occupied + * @param {Object} el_grid_data The grid coords object that represents the + * widget. + * @param {Function} callback The function to execute on each column + * iteration. Column and row are passed as arguments. + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.for_each_cell_occupied = function(grid_data, callback) { + this.for_each_column_occupied(grid_data, function(col) { + this.for_each_row_occupied(grid_data, function(row) { + callback.call(this, col, row); + }); + }); + return this; + }; + + + /** + * Iterate over the columns occupied by a widget executing a function for + * each one. + * + * @method for_each_column_occupied + * @param {Object} el_grid_data The grid coords object that represents + * the widget. + * @param {Function} callback The function to execute on each column + * iteration. The column number is passed as first argument. + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.for_each_column_occupied = function(el_grid_data, callback) { + for (var i = 0; i < el_grid_data.size_x; i++) { + var col = el_grid_data.col + i; + callback.call(this, col, el_grid_data); + } + }; + + + /** + * Iterate over the rows occupied by a widget executing a function for + * each one. + * + * @method for_each_row_occupied + * @param {Object} el_grid_data The grid coords object that represents + * the widget. + * @param {Function} callback The function to execute on each column + * iteration. The row number is passed as first argument. + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.for_each_row_occupied = function(el_grid_data, callback) { + for (var i = 0; i < el_grid_data.size_y; i++) { + var row = el_grid_data.row + i; + callback.call(this, row, el_grid_data); + } + }; + + + + fn._traversing_widgets = function(type, direction, col, row, callback) { + var ga = this.gridmap; + if (!ga[col]) { return; } + + var cr, max; + var action = type + '/' + direction; + if (arguments[2] instanceof $) { + var el_grid_data = arguments[2].coords().grid; + col = el_grid_data.col; + row = el_grid_data.row; + callback = arguments[3]; + } + var matched = []; + var trow = row; + + + var methods = { + 'for_each/above': function() { + while (trow--) { + if (trow > 0 && this.is_widget(col, trow) && + $.inArray(ga[col][trow], matched) === -1 + ) { + cr = callback.call(ga[col][trow], col, trow); + matched.push(ga[col][trow]); + if (cr) { break; } + } + } + }, + 'for_each/below': function() { + for (trow = row + 1, max = ga[col].length; trow < max; trow++) { + if (this.is_widget(col, trow) && + $.inArray(ga[col][trow], matched) === -1 + ) { + cr = callback.call(ga[col][trow], col, trow); + matched.push(ga[col][trow]); + if (cr) { break; } + } + } + } + }; + + if (methods[action]) { + methods[action].call(this); + } + }; + + + /** + * Iterate over each widget above the column and row specified. + * + * @method for_each_widget_above + * @param {Number} col The column to start iterating. + * @param {Number} row The row to start iterating. + * @param {Function} callback The function to execute on each widget + * iteration. The value of `this` inside the function is the jQuery + * wrapped HTMLElement. + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.for_each_widget_above = function(col, row, callback) { + this._traversing_widgets('for_each', 'above', col, row, callback); + return this; + }; + + + /** + * Iterate over each widget below the column and row specified. + * + * @method for_each_widget_below + * @param {Number} col The column to start iterating. + * @param {Number} row The row to start iterating. + * @param {Function} callback The function to execute on each widget + * iteration. The value of `this` inside the function is the jQuery wrapped + * HTMLElement. + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.for_each_widget_below = function(col, row, callback) { + this._traversing_widgets('for_each', 'below', col, row, callback); + return this; + }; + + + /** + * Returns the highest occupied cell in the grid. + * + * @method get_highest_occupied_cell + * @return {Object} Returns an object with `col` and `row` numbers. + */ + fn.get_highest_occupied_cell = function() { + var r; + var gm = this.gridmap; + var rl = gm[1].length; + var rows = [], cols = []; + var row_in_col = []; + for (var c = gm.length - 1; c >= 1; c--) { + for (r = rl - 1; r >= 1; r--) { + if (this.is_widget(c, r)) { + rows.push(r); + cols.push(c); + break; + } + } + } + + return { + col: Math.max.apply(Math, cols), + row: Math.max.apply(Math, rows) + }; + }; + + + fn.get_widgets_from = function(col, row) { + var ga = this.gridmap; + var $widgets = $(); + + if (col) { + $widgets = $widgets.add( + this.$widgets.filter(function() { + var tcol = $(this).attr('data-col'); + return (tcol === col || tcol > col); + }) + ); + } + + if (row) { + $widgets = $widgets.add( + this.$widgets.filter(function() { + var trow = $(this).attr('data-row'); + return (trow === row || trow > row); + }) + ); + } + + return $widgets; + }; + + + /** + * Set the current height of the parent grid. + * + * @method set_dom_grid_height + * @return {Object} Returns the instance of the Gridster class. + */ + fn.set_dom_grid_height = function(height) { + if (typeof height === 'undefined') { + var r = this.get_highest_occupied_cell().row; + height = r * this.min_widget_height; + } + + this.container_height = height; + this.$el.css('height', this.container_height); + return this; + }; + + /** + * Set the current width of the parent grid. + * + * @method set_dom_grid_width + * @return {Object} Returns the instance of the Gridster class. + */ + fn.set_dom_grid_width = function(cols) { + if (typeof cols === 'undefined') { + cols = this.get_highest_occupied_cell().col; + } + + var max_cols = (this.options.autogrow_cols ? this.options.max_cols : + this.cols); + + cols = Math.min(max_cols, Math.max(cols, this.options.min_cols)); + this.container_width = cols * this.min_widget_width; + this.$el.css('width', this.container_width); + return this; + }; + + + /** + * It generates the neccessary styles to position the widgets. + * + * @method generate_stylesheet + * @param {Number} rows Number of columns. + * @param {Number} cols Number of rows. + * @return {Object} Returns the instance of the Gridster class. + */ + fn.generate_stylesheet = function(opts) { + var styles = ''; + var max_size_x = this.options.max_size_x || this.cols; + var max_rows = 0; + var max_cols = 0; + var i; + var rules; + + opts || (opts = {}); + opts.cols || (opts.cols = this.cols); + opts.rows || (opts.rows = this.rows); + opts.namespace || (opts.namespace = this.options.namespace); + opts.widget_base_dimensions || + (opts.widget_base_dimensions = this.options.widget_base_dimensions); + opts.widget_margins || + (opts.widget_margins = this.options.widget_margins); + opts.min_widget_width = (opts.widget_margins[0] * 2) + + opts.widget_base_dimensions[0]; + opts.min_widget_height = (opts.widget_margins[1] * 2) + + opts.widget_base_dimensions[1]; + + // don't duplicate stylesheets for the same configuration + var serialized_opts = $.param(opts); + if ($.inArray(serialized_opts, Gridster.generated_stylesheets) >= 0) { + return false; + } + + this.generated_stylesheets.push(serialized_opts); + Gridster.generated_stylesheets.push(serialized_opts); + + /* generate CSS styles for cols */ + for (i = opts.cols; i >= 0; i--) { + styles += (opts.namespace + ' [data-col="'+ (i + 1) + '"] { left:' + + ((i * opts.widget_base_dimensions[0]) + + (i * opts.widget_margins[0]) + + ((i + 1) * opts.widget_margins[0])) + 'px; }\n'); + } + + /* generate CSS styles for rows */ + for (i = opts.rows; i >= 0; i--) { + styles += (opts.namespace + ' [data-row="' + (i + 1) + '"] { top:' + + ((i * opts.widget_base_dimensions[1]) + + (i * opts.widget_margins[1]) + + ((i + 1) * opts.widget_margins[1]) ) + 'px; }\n'); + } + + for (var y = 1; y <= opts.rows; y++) { + styles += (opts.namespace + ' [data-sizey="' + y + '"] { height:' + + (y * opts.widget_base_dimensions[1] + + (y - 1) * (opts.widget_margins[1] * 2)) + 'px; }\n'); + } + + for (var x = 1; x <= max_size_x; x++) { + styles += (opts.namespace + ' [data-sizex="' + x + '"] { width:' + + (x * opts.widget_base_dimensions[0] + + (x - 1) * (opts.widget_margins[0] * 2)) + 'px; }\n'); + } + + this.remove_style_tags(); + + return this.add_style_tag(styles); + }; + + + /** + * Injects the given CSS as string to the head of the document. + * + * @method add_style_tag + * @param {String} css The styles to apply. + * @return {Object} Returns the instance of the Gridster class. + */ + fn.add_style_tag = function(css) { + var d = document; + var tag = d.createElement('style'); + + d.getElementsByTagName('head')[0].appendChild(tag); + tag.setAttribute('type', 'text/css'); + + if (tag.styleSheet) { + tag.styleSheet.cssText = css; + } else { + tag.appendChild(document.createTextNode(css)); + } + + this.$style_tags = this.$style_tags.add(tag); + + return this; + }; + + + /** + * Remove the style tag with the associated id from the head of the document + * + * @method remove_style_tag + * @return {Object} Returns the instance of the Gridster class. + */ + fn.remove_style_tags = function() { + var all_styles = Gridster.generated_stylesheets; + var ins_styles = this.generated_stylesheets; + + this.$style_tags.remove(); + + Gridster.generated_stylesheets = $.map(all_styles, function(s) { + if ($.inArray(s, ins_styles) === -1) { return s; } + }); + }; + + + /** + * Generates a faux grid to collide with it when a widget is dragged and + * detect row or column that we want to go. + * + * @method generate_faux_grid + * @param {Number} rows Number of columns. + * @param {Number} cols Number of rows. + * @return {Object} Returns the instance of the Gridster class. + */ + fn.generate_faux_grid = function(rows, cols) { + this.faux_grid = []; + this.gridmap = []; + var col; + var row; + for (col = cols; col > 0; col--) { + this.gridmap[col] = []; + for (row = rows; row > 0; row--) { + this.add_faux_cell(row, col); + } + } + return this; + }; + + + /** + * Add cell to the faux grid. + * + * @method add_faux_cell + * @param {Number} row The row for the new faux cell. + * @param {Number} col The col for the new faux cell. + * @return {Object} Returns the instance of the Gridster class. + */ + fn.add_faux_cell = function(row, col) { + var coords = $({ + left: this.baseX + ((col - 1) * this.min_widget_width), + top: this.baseY + (row -1) * this.min_widget_height, + width: this.min_widget_width, + height: this.min_widget_height, + col: col, + row: row, + original_col: col, + original_row: row + }).coords(); + + if (!$.isArray(this.gridmap[col])) { + this.gridmap[col] = []; + } + + this.gridmap[col][row] = false; + this.faux_grid.push(coords); + + return this; + }; + + + /** + * Add rows to the faux grid. + * + * @method add_faux_rows + * @param {Number} rows The number of rows you want to add to the faux grid. + * @return {Object} Returns the instance of the Gridster class. + */ + fn.add_faux_rows = function(rows) { + var actual_rows = this.rows; + var max_rows = actual_rows + (rows || 1); + + for (var r = max_rows; r > actual_rows; r--) { + for (var c = this.cols; c >= 1; c--) { + this.add_faux_cell(r, c); + } + } + + this.rows = max_rows; + + if (this.options.autogenerate_stylesheet) { + this.generate_stylesheet(); + } + + return this; + }; + + /** + * Add cols to the faux grid. + * + * @method add_faux_cols + * @param {Number} cols The number of cols you want to add to the faux grid. + * @return {Object} Returns the instance of the Gridster class. + */ + fn.add_faux_cols = function(cols) { + var actual_cols = this.cols; + var max_cols = actual_cols + (cols || 1); + max_cols = Math.min(max_cols, this.options.max_cols); + + for (var c = actual_cols + 1; c <= max_cols; c++) { + for (var r = this.rows; r >= 1; r--) { + this.add_faux_cell(r, c); + } + } + + this.cols = max_cols; + + if (this.options.autogenerate_stylesheet) { + this.generate_stylesheet(); + } + + return this; + }; + + + /** + * Recalculates the offsets for the faux grid. You need to use it when + * the browser is resized. + * + * @method recalculate_faux_grid + * @return {Object} Returns the instance of the Gridster class. + */ + fn.recalculate_faux_grid = function() { + var aw = this.$wrapper.width(); + this.baseX = ($(window).width() - aw) / 2; + this.baseY = this.$wrapper.offset().top; + + $.each(this.faux_grid, $.proxy(function(i, coords) { + this.faux_grid[i] = coords.update({ + left: this.baseX + (coords.data.col -1) * this.min_widget_width, + top: this.baseY + (coords.data.row -1) * this.min_widget_height + }); + }, this)); + + return this; + }; + + + /** + * Get all widgets in the DOM and register them. + * + * @method get_widgets_from_DOM + * @return {Object} Returns the instance of the Gridster class. + */ + fn.get_widgets_from_DOM = function() { + var widgets_coords = this.$widgets.map($.proxy(function(i, widget) { + var $w = $(widget); + return this.dom_to_coords($w); + }, this)); + + widgets_coords = Gridster.sort_by_row_and_col_asc(widgets_coords); + + var changes = $(widgets_coords).map($.proxy(function(i, wgd) { + return this.register_widget(wgd) || null; + }, this)); + + if (changes.length) { + this.$el.trigger('gridster:positionschanged'); + } + + return this; + }; + + + /** + * Calculate columns and rows to be set based on the configuration + * parameters, grid dimensions, etc ... + * + * @method generate_grid_and_stylesheet + * @return {Object} Returns the instance of the Gridster class. + */ + fn.generate_grid_and_stylesheet = function() { + var aw = this.$wrapper.width(); + var max_cols = this.options.max_cols; + + var cols = Math.floor(aw / this.min_widget_width) + + this.options.extra_cols; + + var actual_cols = this.$widgets.map(function() { + return $(this).attr('data-col'); + }).get(); + + //needed to pass tests with phantomjs + actual_cols.length || (actual_cols = [0]); + + var min_cols = Math.max.apply(Math, actual_cols); + + this.cols = Math.max(min_cols, cols, this.options.min_cols); + + if (max_cols !== Infinity && max_cols >= min_cols && max_cols < this.cols) { + this.cols = max_cols; + } + + // get all rows that could be occupied by the current widgets + var max_rows = this.options.extra_rows; + this.$widgets.each(function(i, w) { + max_rows += (+$(w).attr('data-sizey')); + }); + + this.rows = Math.max(max_rows, this.options.min_rows); + + this.baseX = ($(window).width() - aw) / 2; + this.baseY = this.$wrapper.offset().top; + + if (this.options.autogenerate_stylesheet) { + this.generate_stylesheet(); + } + + return this.generate_faux_grid(this.rows, this.cols); + }; + + /** + * Destroy this gridster by removing any sign of its presence, making it easy to avoid memory leaks + * + * @method destroy + * @param {Boolean} remove If true, remove gridster from DOM. + * @return {Object} Returns the instance of the Gridster class. + */ + fn.destroy = function(remove) { + this.$el.removeData('gridster'); + + // remove bound callback on window resize + $(window).unbind('.gridster'); + + if (this.drag_api) { + this.drag_api.destroy(); + } + + this.remove_style_tags(); + + remove && this.$el.remove(); + + return this; + }; + + + //jQuery adapter + $.fn.gridster = function(options) { + return this.each(function() { + if (! $(this).data('gridster')) { + $(this).data('gridster', new Gridster( this, options )); + } + }); + }; + + return Gridster; + +})); diff --git a/GRID/src/utils.js b/GRID/src/utils.js new file mode 100644 index 0000000..f66910d --- /dev/null +++ b/GRID/src/utils.js @@ -0,0 +1,72 @@ +;(function(window, undefined) { + + /* Delay, debounce and throttle functions taken from underscore.js + * + * Copyright (c) 2009-2013 Jeremy Ashkenas, DocumentCloud and + * Investigative Reporters & Editors + * + * 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. + */ + + window.delay = function(func, wait) { + var args = Array.prototype.slice.call(arguments, 2); + return setTimeout(function(){ return func.apply(null, args); }, wait); + }; + + window.debounce = function(func, wait, immediate) { + var timeout; + return function() { + var context = this, args = arguments; + var later = function() { + timeout = null; + if (!immediate) func.apply(context, args); + }; + if (immediate && !timeout) func.apply(context, args); + clearTimeout(timeout); + timeout = setTimeout(later, wait); + }; + }; + + window.throttle = function(func, wait) { + var context, args, timeout, throttling, more, result; + var whenDone = debounce( + function(){ more = throttling = false; }, wait); + return function() { + context = this; args = arguments; + var later = function() { + timeout = null; + if (more) func.apply(context, args); + whenDone(); + }; + if (!timeout) timeout = setTimeout(later, wait); + if (throttling) { + more = true; + } else { + result = func.apply(context, args); + } + whenDone(); + throttling = true; + return result; + }; + }; + +})(window); diff --git a/Pic/sickrage.png b/Pic/sickrage.png index 80b76dd2c794fde1c67ba04af62fac8296c92c02..40446fee71f597c8602624f90c7e033b4ce3124d 100644 GIT binary patch literal 130497 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�GZmIaZsSss#-p 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 literal 116971 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

      <&rGeY%uIRz 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 z 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%0AxLy`W&YhXEb-sp;gd!@v7$IszOG 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 QY5)KL07*qoM6N<$f?yP-X8-^I diff --git a/assets/css/demo.css b/assets/css/demo.css new file mode 100644 index 0000000..c64eef7 --- /dev/null +++ b/assets/css/demo.css @@ -0,0 +1,69 @@ +.gridster * { + margin:0; + padding:0; +} + +ul { + list-style-type: none; +} + + +/*/ +/* demo +/*/ + + +body { + font-size: 16px; + font-family: 'Helvetica Neue', Arial, sans-serif; + color: #444; + margin: 30px 40px; +} + +.controls { + margin-bottom: 20px; +} + +/*/ +/* gridster +/*/ + +.gridster ul { + background-color: #EFEFEF; +} + +.gridster li { + font-size: 1em; + font-weight: bold; + text-align: center; + line-height: 100%; +} + + +.gridster { + margin: 0 auto; + + opacity: .8; + + -webkit-transition: opacity .6s; + -moz-transition: opacity .6s; + -o-transition: opacity .6s; + -ms-transition: opacity .6s; + transition: opacity .6s; +} + +.gridster .gs-w { + background: #DDD; + cursor: pointer; +} + +.gridster .player { + background: #BBB; +} + + +.gridster .preview-holder { + border: none!important; + background: red!important; +} + diff --git a/assets/css/grid.css b/assets/css/grid.css new file mode 100644 index 0000000..c64eef7 --- /dev/null +++ b/assets/css/grid.css @@ -0,0 +1,69 @@ +.gridster * { + margin:0; + padding:0; +} + +ul { + list-style-type: none; +} + + +/*/ +/* demo +/*/ + + +body { + font-size: 16px; + font-family: 'Helvetica Neue', Arial, sans-serif; + color: #444; + margin: 30px 40px; +} + +.controls { + margin-bottom: 20px; +} + +/*/ +/* gridster +/*/ + +.gridster ul { + background-color: #EFEFEF; +} + +.gridster li { + font-size: 1em; + font-weight: bold; + text-align: center; + line-height: 100%; +} + + +.gridster { + margin: 0 auto; + + opacity: .8; + + -webkit-transition: opacity .6s; + -moz-transition: opacity .6s; + -o-transition: opacity .6s; + -ms-transition: opacity .6s; + transition: opacity .6s; +} + +.gridster .gs-w { + background: #DDD; + cursor: pointer; +} + +.gridster .player { + background: #BBB; +} + + +.gridster .preview-holder { + border: none!important; + background: red!important; +} + diff --git a/assets/css/jquery.gridster.css b/assets/css/jquery.gridster.css new file mode 100644 index 0000000..c36d418 --- /dev/null +++ b/assets/css/jquery.gridster.css @@ -0,0 +1,64 @@ +/*! gridster.js - v0.1.0 - 2012-10-20 +* http://gridster.net/ +* Copyright (c) 2012 ducksboard; Licensed MIT */ + +.gridster { + position:relative; +} + +.gridster > * { + margin: 0 auto; + -webkit-transition: height .4s; + -moz-transition: height .4s; + -o-transition: height .4s; + -ms-transition: height .4s; + transition: height .4s; +} + +.gridster .gs_w{ + z-index: 2; + position: absolute; +} + +.ready .gs_w:not(.preview-holder) { + -webkit-transition: opacity .3s, left .3s, top .3s; + -moz-transition: opacity .3s, left .3s, top .3s; + -o-transition: opacity .3s, left .3s, top .3s; + transition: opacity .3s, left .3s, top .3s; +} + +.ready .gs_w:not(.preview-holder) { + -webkit-transition: opacity .3s, left .3s, top .3s, width .3s, height .3s; + -moz-transition: opacity .3s, left .3s, top .3s, width .3s, height .3s; + -o-transition: opacity .3s, left .3s, top .3s, width .3s, height .3s; + transition: opacity .3s, left .3s, top .3s, width .3s, height .3s; +} + +.gridster .preview-holder { + z-index: 1; + position: absolute; + background-color: #fff; + border-color: #fff; + opacity: 0.3; +} + +.gridster .player-revert { + z-index: 10!important; + -webkit-transition: left .3s, top .3s!important; + -moz-transition: left .3s, top .3s!important; + -o-transition: left .3s, top .3s!important; + transition: left .3s, top .3s!important; +} + +.gridster .dragging { + z-index: 10!important; + -webkit-transition: all 0s !important; + -moz-transition: all 0s !important; + -o-transition: all 0s !important; + transition: all 0s !important; +} + +/* Uncomment this if you set helper : "clone" in draggable options */ +/*.gridster .player { + opacity:0; +}*/ diff --git a/assets/css/jquery.gridster.min.css b/assets/css/jquery.gridster.min.css new file mode 100644 index 0000000..f11001c --- /dev/null +++ b/assets/css/jquery.gridster.min.css @@ -0,0 +1,3 @@ +/*! gridster.js - v0.1.0 - 2012-10-20 +* http://gridster.net/ +* Copyright (c) 2012 ducksboard; Licensed MIT */.gridster{position:relative}.gridster>*{margin:0 auto;-webkit-transition:height .4s;-moz-transition:height .4s;-o-transition:height .4s;-ms-transition:height .4s;transition:height .4s}.gridster .gs_w{z-index:2;position:absolute}.ready .gs_w:not(.preview-holder){-webkit-transition:opacity .3s,left .3s,top .3s;-moz-transition:opacity .3s,left .3s,top .3s;-o-transition:opacity .3s,left .3s,top .3s;transition:opacity .3s,left .3s,top .3s}.ready .gs_w:not(.preview-holder){-webkit-transition:opacity .3s,left .3s,top .3s,width .3s,height .3s;-moz-transition:opacity .3s,left .3s,top .3s,width .3s,height .3s;-o-transition:opacity .3s,left .3s,top .3s,width .3s,height .3s;transition:opacity .3s,left .3s,top .3s,width .3s,height .3s}.gridster .preview-holder{z-index:1;position:absolute;background-color:#fff;border-color:#fff;opacity:.3}.gridster .player-revert{z-index:10!important;-webkit-transition:left .3s,top .3s!important;-moz-transition:left .3s,top .3s!important;-o-transition:left .3s,top .3s!important;transition:left .3s,top .3s!important}.gridster .dragging{z-index:10!important;-webkit-transition:all 0s!important;-moz-transition:all 0s!important;-o-transition:all 0s!important;transition:all 0s!important} \ No newline at end of file diff --git a/assets/css/styles.css b/assets/css/styles.css new file mode 100644 index 0000000..ec0ce7f --- /dev/null +++ b/assets/css/styles.css @@ -0,0 +1,60 @@ +body { + background-color: #EEEEEE; + font-family: 'Helvetica Neue', Arial, sans-serif; + -webkit-font-smoothing: antialiased; + font-size: x-small; + color: #666666; +} + +ul, ol { + list-style: none; + margin:0px auto 0px auto; + text-align: center; + vertical-align: middle; + + +} + +h1 { + margin-bottom: 12px; + text-align: center; + font-size: 30px; + font-weight: 400; +} + +h3 { + font-size: 25px; + font-weight: 600; + color: white; +} + +/* Gridster styles */ +.demo { + margin: 3em 0; + padding: 7.5em 0 5.5em; + /* background: #004756; */ +} + +.demo:hover .gridster { + opacity: 1; +} + +.gridster { + width: 940px; + margin: 0 auto; + + opacity: .8; + + -webkit-transition: opacity .6s; + -moz-transition: opacity .6s; + -o-transition: opacity .6s; + -ms-transition: opacity .6s; + transition: opacity .6s; +} + +.gridster .gs_w { + /* background: #FFF; */ + cursor: pointer; + -webkit-box-shadow: 0 0 5px rgba(0,0,0,0.3); + /* box-shadow: 0 0 5px rgba(0,0,0,0.3); */ +} \ No newline at end of file diff --git a/assets/gridster_new.js b/assets/gridster_new.js new file mode 100644 index 0000000..aa63834 --- /dev/null +++ b/assets/gridster_new.js @@ -0,0 +1,107 @@ + + $(window).ready(function () { + var localData = JSON.parse(localStorage.getItem('positions')); + + if(localData!=null) + { + $.each(localData, function(i,value){ + + var id_name; + + id_name="#"; + id_name = id_name + value.id; + console.log(id_name); + + $(id_name).attr({"data-col":value.col, "data-row":value.row, "data-sizex":value.size_x, "data-sizey":value.size_y}); + + +}); + } + else{ + console.log('No data returned by the server'); + } + + + // widget_selector: "> ul" + // Define which elements are the widgets. Can be a CSS Selector string or a jQuery collection of HTMLElements. + + // widget_margins: [3, 3] + // Horizontal and vertical margins respectively for widgets. + + // widget_base_dimensions: [110, 110] + // Base widget dimensions in pixels. The first index is the width, the second is the height. + + var grid_canvas = $(".gridster > ul").gridster({ + widget_margins: [3, 3], + widget_base_dimensions: [140, 140], + draggable: {ignore_dragging: true}, + max_cols: [4], + max_rows: [4], + + // serialize_params: function($w, wgd) { return { id: $($w).attr('id'),col: wgd.col, row: wgd.row,size_x: wgd.size_x,size_y: wgd.size_y } + // A function to return serialized data for each each widget, used when calling the serialize method. Two arguments are passed: + // $w: the jQuery wrapped HTMLElement which is used to get the id, and wgd: the grid coords object with keys col, row, size_x and size_y. + + + serialize_params: function($w, wgd) + { + return { + id: $($w).attr('id'), + col: wgd.col, + row: wgd.row, + size_x: wgd.size_x, + size_y: wgd.size_y, + + }; + }, + + // draggable.stop: function(event, ui){} -- A callback for when dragging stops. + // You can also implement other draggable options based on your requirements + // draggable.start: function(event, ui){} -- A callback for when dragging starts. + // draggable.drag: function(event, ui){} -- A callback for when the mouse is moved during the dragging. + + draggable: + { + stop: function(event, ui) { + + // .serialize( ) + // Creates an array of objects representing the current position of all widgets in the grid. + // Returns an Array of Objects (ready to be encoded as a JSON string) with the data specified by the serialize_params option + // JSON.stringify() converts a primitive value, object or array to a JSON-formatted string that can later be parsed with JSON.parse(). + + var positions = JSON.stringify(this.serialize()); + + // With HTML5, web pages can store data locally within the user's browser. + // Earlier, this was done with cookies. However, Web Storage is more secure and faster. + // The data is not included with every server request, but used ONLY when asked for. + // It is also possible to store large amounts of data, without affecting the website's performance. + // The data is stored in key/value pairs, and a web page can only access data stored by itself. + + localStorage.setItem('positions', positions); + + + $.post( + "process.php", + {"positions": positions}, + function(data) + { + + // this is where you can check if your data is sent to the server or not. + // A status of 200 implies success + + console.log(data); + if(data==200) + console.log("Data successfully sent to the server"); + else + console.log + } + ); + + } + } + }).data('gridster'); + + + +}); + \ No newline at end of file diff --git a/assets/jquery.gridster.js b/assets/jquery.gridster.js new file mode 100644 index 0000000..947f4bb --- /dev/null +++ b/assets/jquery.gridster.js @@ -0,0 +1,3232 @@ +/*! gridster.js - v0.1.0 - 2012-10-20 +* http://gridster.net/ +* Copyright (c) 2012 ducksboard; Licensed MIT */ + +;(function($, window, document, undefined){ + /** + * Creates objects with coordinates (x1, y1, x2, y2, cx, cy, width, height) + * to simulate DOM elements on the screen. + * Coords is used by Gridster to create a faux grid with any DOM element can + * collide. + * + * @class Coords + * @param {HTMLElement|Object} obj The jQuery HTMLElement or a object with: left, + * top, width and height properties. + * @return {Object} Coords instance. + * @constructor + */ + function Coords(obj) { + if (obj[0] && $.isPlainObject(obj[0])) { + this.data = obj[0]; + }else { + this.el = obj; + } + + this.isCoords = true; + this.coords = {}; + this.init(); + return this; + } + + + var fn = Coords.prototype; + + + fn.init = function(){ + this.set(); + this.original_coords = this.get(); + }; + + + fn.set = function(update, not_update_offsets) { + var el = this.el; + + if (el && !update) { + this.data = el.offset(); + this.data.width = el.width(); + this.data.height = el.height(); + } + + if (el && update && !not_update_offsets) { + var offset = el.offset(); + this.data.top = offset.top; + this.data.left = offset.left; + } + + var d = this.data; + + this.coords.x1 = d.left; + this.coords.y1 = d.top; + this.coords.x2 = d.left + d.width; + this.coords.y2 = d.top + d.height; + this.coords.cx = d.left + (d.width / 2); + this.coords.cy = d.top + (d.height / 2); + this.coords.width = d.width; + this.coords.height = d.height; + this.coords.el = el || false ; + + return this; + }; + + + fn.update = function(data){ + if (!data && !this.el) { + return this; + } + + if (data) { + var new_data = $.extend({}, this.data, data); + this.data = new_data; + return this.set(true, true); + } + + this.set(true); + return this; + }; + + + fn.get = function(){ + return this.coords; + }; + + + //jQuery adapter + $.fn.coords = function() { + if (this.data('coords') ) { + return this.data('coords'); + } + + var ins = new Coords(this, arguments[0]); + this.data('coords', ins); + return ins; + }; + +}(jQuery, window, document)); + +;(function($, window, document, undefined){ + + var defaults = { + colliders_context: document.body + // ,on_overlap: function(collider_data){}, + // on_overlap_start : function(collider_data){}, + // on_overlap_stop : function(collider_data){} + }; + + + /** + * Detects collisions between a DOM element against other DOM elements or + * Coords objects. + * + * @class Collision + * @uses Coords + * @param {HTMLElement} el The jQuery wrapped HTMLElement. + * @param {HTMLElement|Array} colliders Can be a jQuery collection + * of HTMLElements or an Array of Coords instances. + * @param {Object} [options] An Object with all options you want to + * overwrite: + * @param {Function} [options.on_overlap_start] Executes a function the first + * time each `collider ` is overlapped. + * @param {Function} [options.on_overlap_stop] Executes a function when a + * `collider` is no longer collided. + * @param {Function} [options.on_overlap] Executes a function when the + * mouse is moved during the collision. + * @return {Object} Collision instance. + * @constructor + */ + function Collision(el, colliders, options) { + this.options = $.extend(defaults, options); + this.$element = el; + this.last_colliders = []; + this.last_colliders_coords = []; + if (typeof colliders === 'string' || colliders instanceof jQuery) { + this.$colliders = $(colliders, + this.options.colliders_context).not(this.$element); + }else{ + this.colliders = $(colliders); + } + + this.init(); + } + + + var fn = Collision.prototype; + + + fn.init = function() { + this.find_collisions(); + }; + + + fn.overlaps = function(a, b) { + var x = false; + var y = false; + + if ((b.x1 >= a.x1 && b.x1 <= a.x2) || + (b.x2 >= a.x1 && b.x2 <= a.x2) || + (a.x1 >= b.x1 && a.x2 <= b.x2) + ) { x = true; } + + if ((b.y1 >= a.y1 && b.y1 <= a.y2) || + (b.y2 >= a.y1 && b.y2 <= a.y2) || + (a.y1 >= b.y1 && a.y2 <= b.y2) + ) { y = true; } + + return (x && y); + }; + + + fn.detect_overlapping_region = function(a, b){ + var regionX = ''; + var regionY = ''; + + if (a.y1 > b.cy && a.y1 < b.y2) { regionX = 'N'; } + if (a.y2 > b.y1 && a.y2 < b.cy) { regionX = 'S'; } + if (a.x1 > b.cx && a.x1 < b.x2) { regionY = 'W'; } + if (a.x2 > b.x1 && a.x2 < b.cx) { regionY = 'E'; } + + return (regionX + regionY) || 'C'; + }; + + + fn.calculate_overlapped_area_coords = function(a, b){ + var x1 = Math.max(a.x1, b.x1); + var y1 = Math.max(a.y1, b.y1); + var x2 = Math.min(a.x2, b.x2); + var y2 = Math.min(a.y2, b.y2); + + return $({ + left: x1, + top: y1, + width : (x2 - x1), + height: (y2 - y1) + }).coords().get(); + }; + + + fn.calculate_overlapped_area = function(coords){ + return (coords.width * coords.height); + }; + + + fn.manage_colliders_start_stop = function(new_colliders_coords, start_callback, stop_callback){ + var last = this.last_colliders_coords; + + for (var i = 0, il = last.length; i < il; i++) { + if ($.inArray(last[i], new_colliders_coords) === -1) { + start_callback.call(this, last[i]); + } + } + + for (var j = 0, jl = new_colliders_coords.length; j < jl; j++) { + if ($.inArray(new_colliders_coords[j], last) === -1) { + stop_callback.call(this, new_colliders_coords[j]); + } + + } + }; + + + fn.find_collisions = function(player_data_coords){ + var self = this; + var colliders_coords = []; + var colliders_data = []; + var $colliders = (this.colliders || this.$colliders); + var count = $colliders.length; + var player_coords = self.$element.coords() + .update(player_data_coords || false).get(); + + while(count--){ + var $collider = self.$colliders ? + $($colliders[count]) : $colliders[count]; + var $collider_coords_ins = ($collider.isCoords) ? + $collider : $collider.coords(); + var collider_coords = $collider_coords_ins.get(); + var overlaps = self.overlaps(player_coords, collider_coords); + + if (!overlaps) { + continue; + } + + var region = self.detect_overlapping_region( + player_coords, collider_coords); + + //todo: make this an option + if (region === 'C'){ + var area_coords = self.calculate_overlapped_area_coords( + player_coords, collider_coords); + var area = self.calculate_overlapped_area(area_coords); + var collider_data = { + area: area, + area_coords : area_coords, + region: region, + coords: collider_coords, + player_coords: player_coords, + el: $collider + }; + + if (self.options.on_overlap) { + self.options.on_overlap.call(this, collider_data); + } + colliders_coords.push($collider_coords_ins); + colliders_data.push(collider_data); + } + } + + if (self.options.on_overlap_stop || self.options.on_overlap_start) { + this.manage_colliders_start_stop(colliders_coords, + self.options.on_overlap_stop, self.options.on_overlap_start); + } + + this.last_colliders_coords = colliders_coords; + + return colliders_data; + }; + + + fn.get_closest_colliders = function(player_data_coords){ + var colliders = this.find_collisions(player_data_coords); + + colliders.sort(function(a, b) { + /* if colliders are being overlapped by the "C" (center) region, + * we have to set a lower index in the array to which they are placed + * above in the grid. */ + if (a.region === 'C' && b.region === 'C') { + if (a.coords.y1 < b.coords.y1 || a.coords.x1 < b.coords.x1) { + return - 1; + }else{ + return 1; + } + } + + if (a.area < b.area) { + return 1; + } + + return 1; + }); + return colliders; + }; + + + //jQuery adapter + $.fn.collision = function(collider, options) { + return new Collision( this, collider, options ); + }; + + +}(jQuery, window, document)); + +;(function(window, undefined) { + /* Debounce and throttle functions taken from underscore.js */ + window.debounce = function(func, wait, immediate) { + var timeout; + return function() { + var context = this, args = arguments; + var later = function() { + timeout = null; + if (!immediate) func.apply(context, args); + }; + if (immediate && !timeout) func.apply(context, args); + clearTimeout(timeout); + timeout = setTimeout(later, wait); + }; + }; + + + window.throttle = function(func, wait) { + var context, args, timeout, throttling, more, result; + var whenDone = debounce( + function(){ more = throttling = false; }, wait); + return function() { + context = this; args = arguments; + var later = function() { + timeout = null; + if (more) func.apply(context, args); + whenDone(); + }; + if (!timeout) timeout = setTimeout(later, wait); + if (throttling) { + more = true; + } else { + result = func.apply(context, args); + } + whenDone(); + throttling = true; + return result; + }; + }; + +})(window); + +;(function($, window, document, undefined){ + + var defaults = { + items: '.gs_w', + distance: 1, + limit: true, + offset_left: 0, + autoscroll: true, + ignore_dragging: ['INPUT', 'TEXTAREA', 'SELECT', 'BUTTON'], + handle: null + // ,drag: function(e){}, + // start : function(e, ui){}, + // stop : function(e){} + }; + + var $window = $(window); + var isTouch = !!('ontouchstart' in window); + var pointer_events = { + start: isTouch ? 'touchstart' : 'mousedown.draggable', + move: isTouch ? 'touchmove' : 'mousemove.draggable', + end: isTouch ? 'touchend' : 'mouseup.draggable' + }; + + /** + * Basic drag implementation for DOM elements inside a container. + * Provide start/stop/drag callbacks. + * + * @class Draggable + * @param {HTMLElement} el The HTMLelement that contains all the widgets + * to be dragged. + * @param {Object} [options] An Object with all options you want to + * overwrite: + * @param {HTMLElement|String} [options.items] Define who will + * be the draggable items. Can be a CSS Selector String or a + * collection of HTMLElements. + * @param {Number} [options.distance] Distance in pixels after mousedown + * the mouse must move before dragging should start. + * @param {Boolean} [options.limit] Constrains dragging to the width of + * the container + * @param {offset_left} [options.offset_left] Offset added to the item + * that is being dragged. + * @param {Number} [options.drag] Executes a callback when the mouse is + * moved during the dragging. + * @param {Number} [options.start] Executes a callback when the drag + * starts. + * @param {Number} [options.stop] Executes a callback when the drag stops. + * @return {Object} Returns `el`. + * @constructor + */ + function Draggable(el, options) { + this.options = $.extend({}, defaults, options); + this.$body = $(document.body); + this.$container = $(el); + this.$dragitems = $(this.options.items, this.$container); + this.is_dragging = false; + this.player_min_left = 0 + this.options.offset_left; + this.init(); + } + + var fn = Draggable.prototype; + + fn.init = function() { + this.calculate_positions(); + this.$container.css('position', 'relative'); + this.disabled = false; + this.events(); + + $(window).bind('resize', + throttle($.proxy(this.calculate_positions, this), 200)); + }; + + fn.events = function() { + this.$container.on('selectstart', $.proxy(this.on_select_start, this)); + + this.$container.on(pointer_events.start, this.options.items, $.proxy( + this.drag_handler, this)); + + this.$body.on(pointer_events.end, $.proxy(function(e) { + this.is_dragging = false; + if (this.disabled) { return; } + this.$body.off(pointer_events.move); + if (this.drag_start) { + this.on_dragstop(e); + } + }, this)); + }; + + fn.get_actual_pos = function($el) { + var pos = $el.position(); + return pos; + }; + + + fn.get_mouse_pos = function(e) { + if (isTouch) { + var oe = e.originalEvent; + e = oe.touches.length ? oe.touches[0] : oe.changedTouches[0]; + } + + return { + left: e.clientX, + top: e.clientY + }; + }; + + + fn.get_offset = function(e) { + e.preventDefault(); + var mouse_actual_pos = this.get_mouse_pos(e); + var diff_x = Math.round( + mouse_actual_pos.left - this.mouse_init_pos.left); + var diff_y = Math.round(mouse_actual_pos.top - this.mouse_init_pos.top); + + var left = Math.round(this.el_init_offset.left + diff_x - this.baseX); + var top = Math.round( + this.el_init_offset.top + diff_y - this.baseY + this.scrollOffset); + + if (this.options.limit) { + if (left > this.player_max_left) { + left = this.player_max_left; + }else if(left < this.player_min_left) { + left = this.player_min_left; + } + } + + return { + left: left, + top: top, + mouse_left: mouse_actual_pos.left, + mouse_top: mouse_actual_pos.top + }; + }; + + + fn.manage_scroll = function(offset) { + /* scroll document */ + var nextScrollTop; + var scrollTop = $window.scrollTop(); + var min_window_y = scrollTop; + var max_window_y = min_window_y + this.window_height; + + var mouse_down_zone = max_window_y - 50; + var mouse_up_zone = min_window_y + 50; + + var abs_mouse_left = offset.mouse_left; + var abs_mouse_top = min_window_y + offset.mouse_top; + + var max_player_y = (this.doc_height - this.window_height + + this.player_height); + + if (abs_mouse_top >= mouse_down_zone) { + nextScrollTop = scrollTop + 30; + if (nextScrollTop < max_player_y) { + $window.scrollTop(nextScrollTop); + this.scrollOffset = this.scrollOffset + 30; + } + } + + if (abs_mouse_top <= mouse_up_zone) { + nextScrollTop = scrollTop - 30; + if (nextScrollTop > 0) { + $window.scrollTop(nextScrollTop); + this.scrollOffset = this.scrollOffset - 30; + } + } + }; + + + fn.calculate_positions = function(e) { + this.window_height = $window.height(); + }; + + + fn.drag_handler = function(e) { + var node = e.target.nodeName; + if (this.disabled || e.which !== 1 && !isTouch) { + return; + } + + if (this.ignore_drag(e)) { + return; + } + + var self = this; + var first = true; + this.$player = $(e.currentTarget); + + this.el_init_pos = this.get_actual_pos(this.$player); + this.mouse_init_pos = this.get_mouse_pos(e); + this.offsetY = this.mouse_init_pos.top - this.el_init_pos.top; + + this.$body.on(pointer_events.move, function(mme){ + var mouse_actual_pos = self.get_mouse_pos(mme); + var diff_x = Math.abs( + mouse_actual_pos.left - self.mouse_init_pos.left); + var diff_y = Math.abs( + mouse_actual_pos.top - self.mouse_init_pos.top); + if (!(diff_x > self.options.distance || + diff_y > self.options.distance) + ) { + return false; + } + + if (first) { + first = false; + self.on_dragstart.call(self, mme); + return false; + } + + if (self.is_dragging === true) { + self.on_dragmove.call(self, mme); + } + + return false; + }); + + return false; + }; + + + fn.on_dragstart = function(e) { + e.preventDefault(); + this.drag_start = true; + this.is_dragging = true; + var offset = this.$container.offset(); + this.baseX = Math.round(offset.left); + this.baseY = Math.round(offset.top); + this.doc_height = $(document).height(); + + if (this.options.helper === 'clone') { + this.$helper = this.$player.clone() + .appendTo(this.$container).addClass('helper'); + this.helper = true; + }else{ + this.helper = false; + } + this.scrollOffset = 0; + this.el_init_offset = this.$player.offset(); + this.player_width = this.$player.width(); + this.player_height = this.$player.height(); + this.player_max_left = (this.$container.width() - this.player_width + + this.options.offset_left); + + if (this.options.start) { + this.options.start.call(this.$player, e, { + helper: this.helper ? this.$helper : this.$player + }); + } + return false; + }; + + + fn.on_dragmove = function(e) { + var offset = this.get_offset(e); + + this.options.autoscroll && this.manage_scroll(offset); + + (this.helper ? this.$helper : this.$player).css({ + 'position': 'absolute', + 'left' : offset.left, + 'top' : offset.top + }); + + var ui = { + 'position': { + 'left': offset.left, + 'top': offset.top + } + }; + + if (this.options.drag) { + this.options.drag.call(this.$player, e, ui); + } + return false; + }; + + + fn.on_dragstop = function(e) { + var offset = this.get_offset(e); + this.drag_start = false; + + var ui = { + 'position': { + 'left': offset.left, + 'top': offset.top + } + }; + + if (this.options.stop) { + this.options.stop.call(this.$player, e, ui); + } + + if (this.helper) { + this.$helper.remove(); + } + + return false; + }; + + fn.on_select_start = function(e) { + if (this.disabled) { return; } + + if (this.ignore_drag(e)) { + return; + } + + return false; + }; + + fn.enable = function() { + this.disabled = false; + }; + + fn.disable = function() { + this.disabled = true; + }; + + + fn.destroy = function(){ + this.disable(); + $.removeData(this.$container, 'drag'); + }; + + fn.ignore_drag = function(event) { + if (this.options.handle) { + return !$(event.target).is(this.options.handle); + } + + return $.inArray(event.target.nodeName, this.options.ignore_dragging) >= 0; + }; + + //jQuery adapter + $.fn.drag = function ( options ) { + return this.each(function () { + if (!$.data(this, 'drag')) { + $.data(this, 'drag', new Draggable( this, options )); + } + }); + }; + + +}(jQuery, window, document)); + +;(function($, window, document, undefined) { + + var defaults = { + namespace: '', + widget_selector: 'li', + widget_margins: [10, 10], + widget_base_dimensions: [400, 225], + extra_rows: 0, + extra_cols: 0, + min_cols: 1, + min_rows: 15, + max_size_x: 6, + autogenerate_stylesheet: true, + avoid_overlapped_widgets: true, + serialize_params: function($w, wgd) { + return { + col: wgd.col, + row: wgd.row, + size_x: wgd.size_x, + size_y: wgd.size_y + }; + }, + collision: {}, + draggable: { + distance: 4 + } + }; + + + /** + * @class Gridster + * @uses Draggable + * @uses Collision + * @param {HTMLElement} el The HTMLelement that contains all the widgets. + * @param {Object} [options] An Object with all options you want to + * overwrite: + * @param {HTMLElement|String} [options.widget_selector] Define who will + * be the draggable widgets. Can be a CSS Selector String or a + * collection of HTMLElements + * @param {Array} [options.widget_margins] Margin between widgets. + * The first index for the horizontal margin (left, right) and + * the second for the vertical margin (top, bottom). + * @param {Array} [options.widget_base_dimensions] Base widget dimensions + * in pixels. The first index for the width and the second for the + * height. + * @param {Number} [options.extra_cols] Add more columns in addition to + * those that have been calculated. + * @param {Number} [options.extra_rows] Add more rows in addition to + * those that have been calculated. + * @param {Number} [options.min_cols] The minimum required columns. + * @param {Number} [options.min_rows] The minimum required rows. + * @param {Number} [options.max_size_x] The maximum number of columns + * that a widget can span. + * @param {Boolean} [options.autogenerate_stylesheet] If true, all the + * CSS required to position all widgets in their respective columns + * and rows will be generated automatically and injected to the + * `` of the document. You can set this to false, and write + * your own CSS targeting rows and cols via data-attributes like so: + * `[data-col="1"] { left: 10px; }` + * @param {Boolean} [options.avoid_overlapped_widgets] Avoid that widgets loaded + * from the DOM can be overlapped. It is helpful if the positions were + * bad stored in the database or if there was any conflict. + * @param {Function} [options.serialize_params] Return the data you want + * for each widget in the serialization. Two arguments are passed: + * `$w`: the jQuery wrapped HTMLElement, and `wgd`: the grid + * coords object (`col`, `row`, `size_x`, `size_y`). + * @param {Object} [options.collision] An Object with all options for + * Collision class you want to overwrite. See Collision docs for + * more info. + * @param {Object} [options.draggable] An Object with all options for + * Draggable class you want to overwrite. See Draggable docs for more + * info. + * + * @constructor + */ + function Gridster(el, options) { + this.options = $.extend(true, defaults, options); + this.$el = $(el); + this.$wrapper = this.$el.parent(); + this.$widgets = this.$el.children(this.options.widget_selector).addClass('gs_w'); + this.widgets = []; + this.$changed = $([]); + this.wrapper_width = this.$wrapper.width(); + this.min_widget_width = (this.options.widget_margins[0] * 2) + + this.options.widget_base_dimensions[0]; + this.min_widget_height = (this.options.widget_margins[1] * 2) + + this.options.widget_base_dimensions[1]; + this.init(); + } + + Gridster.generated_stylesheets = []; + + var fn = Gridster.prototype; + + fn.init = function() { + this.generate_grid_and_stylesheet(); + this.get_widgets_from_DOM(); + this.set_dom_grid_height(); + this.$wrapper.addClass('ready'); + this.draggable(); + + $(window).bind( + 'resize', throttle($.proxy(this.recalculate_faux_grid, this), 200)); + }; + + + /** + * Disables dragging. + * + * @method disable + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.disable = function() { + this.$wrapper.find('.player-revert').removeClass('player-revert'); + this.drag_api.disable(); + return this; + }; + + + /** + * Enables dragging. + * + * @method enable + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.enable = function() { + this.drag_api.enable(); + return this; + }; + + + /** + * Add a new widget to the grid. + * + * @method add_widget + * @param {String|HTMLElement} html The string representing the HTML of the widget + * or the HTMLElement. + * @param {Number} [size_x] The nº of rows the widget occupies horizontally. + * @param {Number} [size_y] The nº of columns the widget occupies vertically. + * @param {Number} [col] The column the widget should start in. + * @param {Number} [row] The row the widget should start in. + * @return {HTMLElement} Returns the jQuery wrapped HTMLElement representing. + * the widget that was just created. + */ + fn.add_widget = function(html, size_x, size_y, col, row) { + var pos; + size_x || (size_x = 1); + size_y || (size_y = 1); + + if (!col & !row) { + pos = this.next_position(size_x, size_y); + }else{ + pos = { + col: col, + row: row + }; + + this.empty_cells(col, row, size_x, size_y); + } + + var $w = $(html).attr({ + 'data-col': pos.col, + 'data-row': pos.row, + 'data-sizex' : size_x, + 'data-sizey' : size_y + }).addClass('gs_w').appendTo(this.$el).hide(); + + this.$widgets = this.$widgets.add($w); + + this.register_widget($w); + + this.add_faux_rows(pos.size_y); + //this.add_faux_cols(pos.size_x); + + this.set_dom_grid_height(); + + return $w.fadeIn(); + }; + + + + /** + * Change the size of a widget. + * + * @method resize_widget + * @param {HTMLElement} $widget The jQuery wrapped HTMLElement + * representing the widget. + * @param {Number} size_x The number of columns that will occupy the widget. + * @param {Number} size_y The number of rows that will occupy the widget. + * @return {HTMLElement} Returns $widget. + */ + fn.resize_widget = function($widget, size_x, size_y) { + var wgd = $widget.coords().grid; + size_x || (size_x = wgd.size_x); + size_y || (size_y = wgd.size_y); + + if (size_x > this.cols) { + size_x = this.cols; + } + + var old_cells_occupied = this.get_cells_occupied(wgd); + var old_size_x = wgd.size_x; + var old_size_y = wgd.size_y; + var old_col = wgd.col; + var new_col = old_col; + var wider = size_x > old_size_x; + var taller = size_y > old_size_y; + + if (old_col + size_x - 1 > this.cols) { + var diff = old_col + (size_x - 1) - this.cols; + var c = old_col - diff; + new_col = Math.max(1, c); + } + + var new_grid_data = { + col: new_col, + row: wgd.row, + size_x: size_x, + size_y: size_y + }; + + var new_cells_occupied = this.get_cells_occupied(new_grid_data); + + var empty_cols = []; + $.each(old_cells_occupied.cols, function(i, col) { + if ($.inArray(col, new_cells_occupied.cols) === -1) { + empty_cols.push(col); + } + }); + + var occupied_cols = []; + $.each(new_cells_occupied.cols, function(i, col) { + if ($.inArray(col, old_cells_occupied.cols) === -1) { + occupied_cols.push(col); + } + }); + + var empty_rows = []; + $.each(old_cells_occupied.rows, function(i, row) { + if ($.inArray(row, new_cells_occupied.rows) === -1) { + empty_rows.push(row); + } + }); + + var occupied_rows = []; + $.each(new_cells_occupied.rows, function(i, row) { + if ($.inArray(row, old_cells_occupied.rows) === -1) { + occupied_rows.push(row); + } + }); + + this.remove_from_gridmap(wgd); + + if (occupied_cols.length) { + var cols_to_empty = [ + new_col, wgd.row, size_x, Math.min(old_size_y, size_y), $widget + ]; + this.empty_cells.apply(this, cols_to_empty); + } + + if (occupied_rows.length) { + var rows_to_empty = [new_col, wgd.row, size_x, size_y, $widget]; + this.empty_cells.apply(this, rows_to_empty); + } + + wgd.col = new_col; + wgd.size_x = size_x; + wgd.size_y = size_y; + this.add_to_gridmap(new_grid_data, $widget); + + //update coords instance attributes + $widget.data('coords').update({ + width: (size_x * this.options.widget_base_dimensions[0] + + ((size_x - 1) * this.options.widget_margins[0]) * 2), + height: (size_y * this.options.widget_base_dimensions[1] + + ((size_y - 1) * this.options.widget_margins[1]) * 2) + }); + + if (size_y > old_size_y) { + this.add_faux_rows(size_y - old_size_y); + } + + if (size_x > old_size_x) { + this.add_faux_cols(size_x - old_size_x); + } + + $widget.attr({ + 'data-col': new_col, + 'data-sizex': size_x, + 'data-sizey': size_y + }); + + if (empty_cols.length) { + var cols_to_remove_holes = [ + empty_cols[0], wgd.row, + empty_cols.length, + Math.min(old_size_y, size_y), + $widget + ]; + + this.remove_empty_cells.apply(this, cols_to_remove_holes); + } + + if (empty_rows.length) { + var rows_to_remove_holes = [ + new_col, wgd.row, size_x, size_y, $widget + ]; + this.remove_empty_cells.apply(this, rows_to_remove_holes); + } + + return $widget; + }; + + /** + * Move down widgets in cells represented by the arguments col, row, size_x, + * size_y + * + * @method empty_cells + * @param {Number} col The column where the group of cells begin. + * @param {Number} row The row where the group of cells begin. + * @param {Number} size_x The number of columns that the group of cells + * occupy. + * @param {Number} size_y The number of rows that the group of cells + * occupy. + * @param {HTMLElement} $exclude Exclude widgets from being moved. + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.empty_cells = function(col, row, size_x, size_y, $exclude) { + var $nexts = this.widgets_below({ + col: col, + row: row - size_y, + size_x: size_x, + size_y: size_y + }); + + $nexts.not($exclude).each($.proxy(function(i, w) { + var wgd = $(w).coords().grid; + if (!(wgd.row <= (row + size_y - 1))) { return; } + var diff = (row + size_y) - wgd.row; + this.move_widget_down($(w), diff); + }, this)); + + this.set_dom_grid_height(); + + return this; + }; + + + /** + * Move up widgets below cells represented by the arguments col, row, size_x, + * size_y. + * + * @method remove_empty_cells + * @param {Number} col The column where the group of cells begin. + * @param {Number} row The row where the group of cells begin. + * @param {Number} size_x The number of columns that the group of cells + * occupy. + * @param {Number} size_y The number of rows that the group of cells + * occupy. + * @param {HTMLElement} $exclude Exclude widgets from being moved. + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.remove_empty_cells = function(col, row, size_x, size_y, exclude) { + var $nexts = this.widgets_below({ + col: col, + row: row, + size_x: size_x, + size_y: size_y + }); + + $nexts.not(exclude).each($.proxy(function(i, widget) { + this.move_widget_up( $(widget), size_y ); + }, this)); + + this.set_dom_grid_height(); + + return this; + }; + + + /** + * Get the most left column below to add a new widget. + * + * @method next_position + * @param {Number} size_x The nº of rows the widget occupies horizontally. + * @param {Number} size_y The nº of columns the widget occupies vertically. + * @return {Object} Returns a grid coords object representing the future + * widget coords. + */ + fn.next_position = function(size_x, size_y) { + size_x || (size_x = 1); + size_y || (size_y = 1); + var ga = this.gridmap; + var cols_l = ga.length; + var valid_pos = []; + var rows_l; + + for (var c = 1; c < cols_l; c++) { + rows_l = ga[c].length; + for (var r = 1; r <= rows_l; r++) { + var can_move_to = this.can_move_to({ + size_x: size_x, + size_y: size_y + }, c, r); + + if (can_move_to) { + valid_pos.push({ + col: c, + row: r, + size_y: size_y, + size_x: size_x + }); + } + } + } + + if (valid_pos.length) { + return this.sort_by_row_and_col_asc(valid_pos)[0]; + } + return false; + }; + + + /** + * Remove a widget from the grid. + * + * @method remove_widget + * @param {HTMLElement} el The jQuery wrapped HTMLElement you want to remove. + * @param {Boolean|Function} silent If true, widgets below the removed one + * will not move up. If a Function is passed it will be used as callback. + * @param {Function} callback Function executed when the widget is removed. + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.remove_widget = function(el, silent, callback) { + var $el = el instanceof jQuery ? el : $(el); + var wgd = $el.coords().grid; + + // if silent is a function assume it's a callback + if ($.isFunction(silent)) { + callback = silent; + silent = false; + } + + this.cells_occupied_by_placeholder = {}; + this.$widgets = this.$widgets.not($el); + + var $nexts = this.widgets_below($el); + + this.remove_from_gridmap(wgd); + + $el.fadeOut($.proxy(function() { + $el.remove(); + + if (!silent) { + $nexts.each($.proxy(function(i, widget) { + this.move_widget_up( $(widget), wgd.size_y ); + }, this)); + } + + this.set_dom_grid_height(); + + if (callback) { + callback.call(this, el); + } + }, this)); + }; + + + /** + * Remove all widgets from the grid. + * + * @method remove_all_widgets + * @param {Function} callback Function executed for each widget removed. + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.remove_all_widgets = function(callback) { + this.$widgets.each($.proxy(function(i, el){ + this.remove_widget(el, true, callback); + }, this)); + + return this; + }; + + + /** + * Returns a serialized array of the widgets in the grid. + * + * @method serialize + * @param {HTMLElement} [$widgets] The collection of jQuery wrapped + * HTMLElements you want to serialize. If no argument is passed all widgets + * will be serialized. + * @return {Array} Returns an Array of Objects with the data specified in + * the serialize_params option. + */ + fn.serialize = function($widgets) { + $widgets || ($widgets = this.$widgets); + var result = []; + $widgets.each($.proxy(function(i, widget) { + result.push(this.options.serialize_params( + $(widget), $(widget).coords().grid ) ); + }, this)); + + return result; + }; + + + /** + * Returns a serialized array of the widgets that have changed their + * position. + * + * @method serialize_changed + * @return {Array} Returns an Array of Objects with the data specified in + * the serialize_params option. + */ + fn.serialize_changed = function() { + return this.serialize(this.$changed); + }; + + + /** + * Creates the grid coords object representing the widget a add it to the + * mapped array of positions. + * + * @method register_widget + * @return {Array} Returns the instance of the Gridster class. + */ + fn.register_widget = function($el) { + + var wgd = { + 'col': parseInt($el.attr('data-col'), 10), + 'row': parseInt($el.attr('data-row'), 10), + 'size_x': parseInt($el.attr('data-sizex'), 10), + 'size_y': parseInt($el.attr('data-sizey'), 10), + 'el': $el + }; + + if (this.options.avoid_overlapped_widgets && + !this.can_move_to( + {size_x: wgd.size_x, size_y: wgd.size_y}, wgd.col, wgd.row) + ) { + wgd = this.next_position(wgd.size_x, wgd.size_y); + wgd.el = $el; + $el.attr({ + 'data-col': wgd.col, + 'data-row': wgd.row, + 'data-sizex': wgd.size_x, + 'data-sizey': wgd.size_y + }); + } + + // attach Coord object to player data-coord attribute + $el.data('coords', $el.coords()); + + // Extend Coord object with grid position info + $el.data('coords').grid = wgd; + + this.add_to_gridmap(wgd, $el); + + return this; + }; + + + /** + * Update in the mapped array of positions the value of cells represented by + * the grid coords object passed in the `grid_data` param. + * + * @param {Object} grid_data The grid coords object representing the cells + * to update in the mapped array. + * @param {HTMLElement|Boolean} value Pass `false` or the jQuery wrapped + * HTMLElement, depends if you want to delete an existing position or add + * a new one. + * @method update_widget_position + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.update_widget_position = function(grid_data, value) { + this.for_each_cell_occupied(grid_data, function(col, row) { + if (!this.gridmap[col]) { return this; } + this.gridmap[col][row] = value; + }); + return this; + }; + + + /** + * Remove a widget from the mapped array of positions. + * + * @method remove_from_gridmap + * @param {Object} grid_data The grid coords object representing the cells + * to update in the mapped array. + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.remove_from_gridmap = function(grid_data) { + return this.update_widget_position(grid_data, false); + }; + + + /** + * Add a widget to the mapped array of positions. + * + * @method add_to_gridmap + * @param {Object} grid_data The grid coords object representing the cells + * to update in the mapped array. + * @param {HTMLElement|Boolean} value The value to set in the specified + * position . + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.add_to_gridmap = function(grid_data, value) { + this.update_widget_position(grid_data, value || grid_data.el); + + if (grid_data.el) { + var $widgets = this.widgets_below(grid_data.el); + $widgets.each($.proxy(function(i, widget) { + this.move_widget_up( $(widget)); + }, this)); + } + }; + + + /** + * Make widgets draggable. + * + * @uses Draggable + * @method draggable + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.draggable = function() { + var self = this; + var draggable_options = $.extend(true, {}, this.options.draggable, { + offset_left: this.options.widget_margins[0], + start: function(event, ui) { + self.$widgets.filter('.player-revert') + .removeClass('player-revert'); + + self.$player = $(this); + self.$helper = self.options.draggable.helper === 'clone' ? + $(ui.helper) : self.$player; + self.helper = !self.$helper.is(self.$player); + + self.on_start_drag.call(self, event, ui); + self.$el.trigger('gridster:dragstart'); + }, + stop: function(event, ui) { + self.on_stop_drag.call(self, event, ui); + self.$el.trigger('gridster:dragstop'); + }, + drag: throttle(function(event, ui) { + self.on_drag.call(self, event, ui); + self.$el.trigger('gridster:drag'); + }, 60) + }); + + this.drag_api = this.$el.drag(draggable_options).data('drag'); + return this; + }; + + + /** + * This function is executed when the player begins to be dragged. + * + * @method on_start_drag + * @param {Event} The original browser event + * @param {Object} A prepared ui object. + */ + fn.on_start_drag = function(event, ui) { + + this.$helper.add(this.$player).add(this.$wrapper).addClass('dragging'); + + this.$player.addClass('player'); + this.player_grid_data = this.$player.coords().grid; + this.placeholder_grid_data = $.extend({}, this.player_grid_data); + + //set new grid height along the dragging period + this.$el.css('height', this.$el.height() + + (this.player_grid_data.size_y * this.min_widget_height)); + + var colliders = this.faux_grid; + var coords = this.$player.data('coords').coords; + + this.cells_occupied_by_player = this.get_cells_occupied( + this.player_grid_data); + this.cells_occupied_by_placeholder = this.get_cells_occupied( + this.placeholder_grid_data); + + this.last_cols = []; + this.last_rows = []; + + + // see jquery.collision.js + this.collision_api = this.$helper.collision( + colliders, this.options.collision); + + this.$preview_holder = $('
    • ', { + 'class': 'preview-holder', + 'data-row': this.$player.attr('data-row'), + 'data-col': this.$player.attr('data-col'), + css: { + width: coords.width, + height: coords.height + } + }).appendTo(this.$el); + + if (this.options.draggable.start) { + this.options.draggable.start.call(this, event, ui); + } + }; + + + /** + * This function is executed when the player is being dragged. + * + * @method on_drag + * @param {Event} The original browser event + * @param {Object} A prepared ui object. + */ + fn.on_drag = function(event, ui) { + //break if dragstop has been fired + if (this.$player === null) { + return false; + } + + var abs_offset = { + left: ui.position.left + this.baseX, + top: ui.position.top + this.baseY + }; + + this.colliders_data = this.collision_api.get_closest_colliders( + abs_offset); + + this.on_overlapped_column_change( + this.on_start_overlapping_column, + this.on_stop_overlapping_column + ); + + this.on_overlapped_row_change( + this.on_start_overlapping_row, + this.on_stop_overlapping_row + ); + + if (this.helper && this.$player) { + this.$player.css({ + 'left': ui.position.left, + 'top': ui.position.top + }); + } + + if (this.options.draggable.drag) { + this.options.draggable.drag.call(this, event, ui); + } + }; + + /** + * This function is executed when the player stops being dragged. + * + * @method on_stop_drag + * @param {Event} The original browser event + * @param {Object} A prepared ui object. + */ + fn.on_stop_drag = function(event, ui) { + this.$helper.add(this.$player).add(this.$wrapper) + .removeClass('dragging'); + + ui.position.left = ui.position.left + this.baseX; + ui.position.top = ui.position.top + this.baseY; + this.colliders_data = this.collision_api.get_closest_colliders(ui.position); + + this.on_overlapped_column_change( + this.on_start_overlapping_column, + this.on_stop_overlapping_column + ); + + this.on_overlapped_row_change( + this.on_start_overlapping_row, + this.on_stop_overlapping_row + ); + + this.$player.addClass('player-revert').removeClass('player') + .attr({ + 'data-col': this.placeholder_grid_data.col, + 'data-row': this.placeholder_grid_data.row + }).css({ + 'left': '', + 'top': '' + }); + + this.$changed = this.$changed.add(this.$player); + + this.cells_occupied_by_player = this.get_cells_occupied( + this.placeholder_grid_data); + this.set_cells_player_occupies( + this.placeholder_grid_data.col, this.placeholder_grid_data.row); + + this.$player.coords().grid.row = this.placeholder_grid_data.row; + this.$player.coords().grid.col = this.placeholder_grid_data.col; + + if (this.options.draggable.stop) { + this.options.draggable.stop.call(this, event, ui); + } + + this.$preview_holder.remove(); + + this.$player = null; + this.$helper = null; + this.placeholder_grid_data = {}; + this.player_grid_data = {}; + this.cells_occupied_by_placeholder = {}; + this.cells_occupied_by_player = {}; + + this.set_dom_grid_height(); + }; + + + /** + * Executes the callbacks passed as arguments when a column begins to be + * overlapped or stops being overlapped. + * + * @param {Function} start_callback Function executed when a new column + * begins to be overlapped. The column is passed as first argument. + * @param {Function} stop_callback Function executed when a column stops + * being overlapped. The column is passed as first argument. + * @method on_overlapped_column_change + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.on_overlapped_column_change = function(start_callback, stop_callback) { + if (!this.colliders_data.length) { + return; + } + var cols = this.get_targeted_columns( + this.colliders_data[0].el.data.col); + + var last_n_cols = this.last_cols.length; + var n_cols = cols.length; + var i; + + for (i = 0; i < n_cols; i++) { + if ($.inArray(cols[i], this.last_cols) === -1) { + (start_callback || $.noop).call(this, cols[i]); + } + } + + for (i = 0; i< last_n_cols; i++) { + if ($.inArray(this.last_cols[i], cols) === -1) { + (stop_callback || $.noop).call(this, this.last_cols[i]); + } + } + + this.last_cols = cols; + + return this; + }; + + + /** + * Executes the callbacks passed as arguments when a row starts to be + * overlapped or stops being overlapped. + * + * @param {Function} start_callback Function executed when a new row begins + * to be overlapped. The row is passed as first argument. + * @param {Function} stop_callback Function executed when a row stops being + * overlapped. The row is passed as first argument. + * @method on_overlapped_row_change + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.on_overlapped_row_change = function(start_callback, end_callback) { + if (!this.colliders_data.length) { + return; + } + var rows = this.get_targeted_rows(this.colliders_data[0].el.data.row); + var last_n_rows = this.last_rows.length; + var n_rows = rows.length; + var i; + + for (i = 0; i < n_rows; i++) { + if ($.inArray(rows[i], this.last_rows) === -1) { + (start_callback || $.noop).call(this, rows[i]); + } + } + + for (i = 0; i < last_n_rows; i++) { + if ($.inArray(this.last_rows[i], rows) === -1) { + (end_callback || $.noop).call(this, this.last_rows[i]); + } + } + + this.last_rows = rows; + }; + + + /** + * Sets the current position of the player + * + * @param {Function} start_callback Function executed when a new row begins + * to be overlapped. The row is passed as first argument. + * @param {Function} stop_callback Function executed when a row stops being + * overlapped. The row is passed as first argument. + * @method set_player + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.set_player = function(col, row, no_player) { + var self = this; + if (!no_player) { + this.empty_cells_player_occupies(); + } + var cell = !no_player ? self.colliders_data[0].el.data : {col: col}; + var to_col = cell.col; + var to_row = row || cell.row; + + this.player_grid_data = { + col: to_col, + row: to_row, + size_y : this.player_grid_data.size_y, + size_x : this.player_grid_data.size_x + }; + + this.cells_occupied_by_player = this.get_cells_occupied( + this.player_grid_data); + + var $overlapped_widgets = this.get_widgets_overlapped( + this.player_grid_data); + + var constraints = this.widgets_constraints($overlapped_widgets); + + this.manage_movements(constraints.can_go_up, to_col, to_row); + this.manage_movements(constraints.can_not_go_up, to_col, to_row); + + /* if there is not widgets overlapping in the new player position, + * update the new placeholder position. */ + if (!$overlapped_widgets.length) { + var pp = this.can_go_player_up(this.player_grid_data); + if (pp !== false) { + to_row = pp; + } + this.set_placeholder(to_col, to_row); + } + + return { + col: to_col, + row: to_row + }; + }; + + + /** + * See which of the widgets in the $widgets param collection can go to + * a upper row and which not. + * + * @method widgets_contraints + * @param {HTMLElements} $widgets A jQuery wrapped collection of + * HTMLElements. + * @return {Array} Returns a literal Object with two keys: `can_go_up` & + * `can_not_go_up`. Each contains a set of HTMLElements. + */ + fn.widgets_constraints = function($widgets) { + var $widgets_can_go_up = $([]); + var $widgets_can_not_go_up; + var wgd_can_go_up = []; + var wgd_can_not_go_up = []; + + $widgets.each($.proxy(function(i, w) { + var $w = $(w); + var wgd = $w.coords().grid; + if (this.can_go_widget_up(wgd)) { + $widgets_can_go_up = $widgets_can_go_up.add($w); + wgd_can_go_up.push(wgd); + }else{ + wgd_can_not_go_up.push(wgd); + } + }, this)); + + $widgets_can_not_go_up = $widgets.not($widgets_can_go_up); + + return { + can_go_up: this.sort_by_row_asc(wgd_can_go_up), + can_not_go_up: this.sort_by_row_desc(wgd_can_not_go_up) + }; + }; + + + /** + * Sorts an Array of grid coords objects (representing the grid coords of + * each widget) in ascending way. + * + * @method sort_by_row_asc + * @param {Array} widgets Array of grid coords objects + * @return {Array} Returns the array sorted. + */ + fn.sort_by_row_asc = function(widgets) { + widgets = widgets.sort(function(a, b) { + if (!a.row) { + a = $(a).coords().grid; + b = $(b).coords().grid; + } + + if (a.row > b.row) { + return 1; + } + return -1; + }); + + return widgets; + }; + + + /** + * Sorts an Array of grid coords objects (representing the grid coords of + * each widget) placing first the empty cells upper left. + * + * @method sort_by_row_and_col_asc + * @param {Array} widgets Array of grid coords objects + * @return {Array} Returns the array sorted. + */ + fn.sort_by_row_and_col_asc = function(widgets) { + widgets = widgets.sort(function(a, b) { + if (a.row > b.row || a.row === b.row && a.col > b.col) { + return 1; + } + return -1; + }); + + return widgets; + }; + + + /** + * Sorts an Array of grid coords objects by column (representing the grid + * coords of each widget) in ascending way. + * + * @method sort_by_col_asc + * @param {Array} widgets Array of grid coords objects + * @return {Array} Returns the array sorted. + */ + fn.sort_by_col_asc = function(widgets) { + widgets = widgets.sort(function(a, b) { + if (a.col > b.col) { + return 1; + } + return -1; + }); + + return widgets; + }; + + + /** + * Sorts an Array of grid coords objects (representing the grid coords of + * each widget) in descending way. + * + * @method sort_by_row_desc + * @param {Array} widgets Array of grid coords objects + * @return {Array} Returns the array sorted. + */ + fn.sort_by_row_desc = function(widgets) { + widgets = widgets.sort(function(a, b) { + if (a.row + a.size_y < b.row + b.size_y) { + return 1; + } + return -1; + }); + return widgets; + }; + + + /** + * Sorts an Array of grid coords objects (representing the grid coords of + * each widget) in descending way. + * + * @method manage_movements + * @param {HTMLElements} $widgets A jQuery collection of HTMLElements + * representing the widgets you want to move. + * @param {Number} to_col The column to which we want to move the widgets. + * @param {Number} to_row The row to which we want to move the widgets. + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.manage_movements = function($widgets, to_col, to_row) { + $.each($widgets, $.proxy(function(i, w) { + var wgd = w; + var $w = wgd.el; + + var can_go_widget_up = this.can_go_widget_up(wgd); + + if (can_go_widget_up) { + //target CAN go up + //so move widget up + this.move_widget_to($w, can_go_widget_up); + this.set_placeholder(to_col, can_go_widget_up + wgd.size_y); + + } else { + //target can't go up + var can_go_player_up = this.can_go_player_up( + this.player_grid_data); + + if (!can_go_player_up) { + // target can't go up + // player cant't go up + // so we need to move widget down to a position that dont + // overlaps player + var y = (to_row + this.player_grid_data.size_y) - wgd.row; + + this.move_widget_down($w, y); + this.set_placeholder(to_col, to_row); + } + } + }, this)); + + return this; + }; + + /** + * Determines if there is a widget in the row and col given. Or if the + * HTMLElement passed as first argument is the player. + * + * @method is_player + * @param {Number|HTMLElement} col_or_el A jQuery wrapped collection of + * HTMLElements. + * @param {Number} [row] The column to which we want to move the widgets. + * @return {Boolean} Returns true or false. + */ + fn.is_player = function(col_or_el, row) { + if (row && !this.gridmap[col_or_el]) { return false; } + var $w = row ? this.gridmap[col_or_el][row] : col_or_el; + return $w && ($w.is(this.$player) || $w.is(this.$helper)); + }; + + + /** + * Determines if the widget that is being dragged is currently over the row + * and col given. + * + * @method is_player_in + * @param {Number} col The column to check. + * @param {Number} row The row to check. + * @return {Boolean} Returns true or false. + */ + fn.is_player_in = function(col, row) { + var c = this.cells_occupied_by_player || {}; + return $.inArray(col, c.cols) >= 0 && $.inArray(row, c.rows) >= 0; + }; + + + /** + * Determines if the placeholder is currently over the row and col given. + * + * @method is_placeholder_in + * @param {Number} col The column to check. + * @param {Number} row The row to check. + * @return {Boolean} Returns true or false. + */ + fn.is_placeholder_in = function(col, row) { + var c = this.cells_occupied_by_placeholder || {}; + return this.is_placeholder_in_col(col) && $.inArray(row, c.rows) >= 0; + }; + + + /** + * Determines if the placeholder is currently over the column given. + * + * @method is_placeholder_in_col + * @param {Number} col The column to check. + * @return {Boolean} Returns true or false. + */ + fn.is_placeholder_in_col = function(col) { + var c = this.cells_occupied_by_placeholder || []; + return $.inArray(col, c.cols) >= 0; + }; + + + /** + * Determines if the cell represented by col and row params is empty. + * + * @method is_empty + * @param {Number} col The column to check. + * @param {Number} row The row to check. + * @return {Boolean} Returns true or false. + */ + fn.is_empty = function(col, row) { + if (typeof this.gridmap[col] !== 'undefined' && + typeof this.gridmap[col][row] !== 'undefined' && + this.gridmap[col][row] === false + ) { + return true; + } + return false; + }; + + + /** + * Determines if the cell represented by col and row params is occupied. + * + * @method is_occupied + * @param {Number} col The column to check. + * @param {Number} row The row to check. + * @return {Boolean} Returns true or false. + */ + fn.is_occupied = function(col, row) { + if (!this.gridmap[col]) { + return false; + } + + if (this.gridmap[col][row]) { + return true; + } + return false; + }; + + + /** + * Determines if there is a widget in the cell represented by col/row params. + * + * @method is_widget + * @param {Number} col The column to check. + * @param {Number} row The row to check. + * @return {Boolean|HTMLElement} Returns false if there is no widget, + * else returns the jQuery HTMLElement + */ + fn.is_widget = function(col, row) { + var cell = this.gridmap[col]; + if (!cell) { + return false; + } + + cell = cell[row]; + + if (cell) { + return cell; + } + + return false; + }; + + + /** + * Determines if there is a widget in the cell represented by col/row + * params and if this is under the widget that is being dragged. + * + * @method is_widget_under_player + * @param {Number} col The column to check. + * @param {Number} row The row to check. + * @return {Boolean} Returns true or false. + */ + fn.is_widget_under_player = function(col, row) { + if (this.is_widget(col, row)) { + return this.is_player_in(col, row); + } + return false; + }; + + + /** + * Get widgets overlapping with the player or with the object passed + * representing the grid cells. + * + * @method get_widgets_under_player + * @return {HTMLElement} Returns a jQuery collection of HTMLElements + */ + fn.get_widgets_under_player = function(cells) { + cells || (cells = this.cells_occupied_by_player || {cols: [], rows: []}); + var $widgets = $([]); + + $.each(cells.cols, $.proxy(function(i, col) { + $.each(cells.rows, $.proxy(function(i, row) { + if(this.is_widget(col, row)) { + $widgets = $widgets.add(this.gridmap[col][row]); + } + }, this)); + }, this)); + + return $widgets; + }; + + + /** + * Put placeholder at the row and column specified. + * + * @method set_placeholder + * @param {Number} col The column to which we want to move the + * placeholder. + * @param {Number} row The row to which we want to move the + * placeholder. + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.set_placeholder = function(col, row) { + var phgd = $.extend({}, this.placeholder_grid_data); + var $nexts = this.widgets_below({ + col: phgd.col, + row: phgd.row, + size_y: phgd.size_y, + size_x: phgd.size_x + }); + + // Prevents widgets go out of the grid + var right_col = (col + phgd.size_x - 1); + if (right_col > this.cols) { + col = col - (right_col - col); + } + + var moved_down = this.placeholder_grid_data.row < row; + var changed_column = this.placeholder_grid_data.col !== col; + + this.placeholder_grid_data.col = col; + this.placeholder_grid_data.row = row; + + this.cells_occupied_by_placeholder = this.get_cells_occupied( + this.placeholder_grid_data); + + this.$preview_holder.attr({ + 'data-row' : row, + 'data-col' : col + }); + + if (moved_down || changed_column) { + $nexts.each($.proxy(function(i, widget) { + this.move_widget_up( + $(widget), this.placeholder_grid_data.col - col + phgd.size_y); + }, this)); + } + + + var $widgets_under_ph = this.get_widgets_under_player(this.cells_occupied_by_placeholder); + if ($widgets_under_ph.length) { + $widgets_under_ph.each($.proxy(function(i, widget) { + var $w = $(widget); + this.move_widget_down( + $w, row + phgd.size_y - $w.data('coords').grid.row); + }, this)); + } + + }; + + + /** + * Determines whether the player can move to a position above. + * + * @method can_go_player_up + * @param {Object} widget_grid_data The actual grid coords object of the + * player. + * @return {Number|Boolean} If the player can be moved to an upper row + * returns the row number, else returns false. + */ + fn.can_go_player_up = function(widget_grid_data) { + var p_bottom_row = widget_grid_data.row + widget_grid_data.size_y - 1; + var result = true; + var upper_rows = []; + var min_row = 10000; + var $widgets_under_player = this.get_widgets_under_player(); + + /* generate an array with columns as index and array with upper rows + * empty as value */ + this.for_each_column_occupied(widget_grid_data, function(tcol) { + var grid_col = this.gridmap[tcol]; + var r = p_bottom_row + 1; + upper_rows[tcol] = []; + + while (--r > 0) { + if (this.is_empty(tcol, r) || this.is_player(tcol, r) || + this.is_widget(tcol, r) && + grid_col[r].is($widgets_under_player) + ) { + upper_rows[tcol].push(r); + min_row = r < min_row ? r : min_row; + }else{ + break; + } + } + + if (upper_rows[tcol].length === 0) { + result = false; + return true; //break + } + + upper_rows[tcol].sort(); + }); + + if (!result) { return false; } + + return this.get_valid_rows(widget_grid_data, upper_rows, min_row); + }; + + + /** + * Determines whether a widget can move to a position above. + * + * @method can_go_widget_up + * @param {Object} widget_grid_data The actual grid coords object of the + * widget we want to check. + * @return {Number|Boolean} If the widget can be moved to an upper row + * returns the row number, else returns false. + */ + fn.can_go_widget_up = function(widget_grid_data) { + var p_bottom_row = widget_grid_data.row + widget_grid_data.size_y - 1; + var result = true; + var upper_rows = []; + var min_row = 10000; + + /* generate an array with columns as index and array with topmost rows + * empty as value */ + this.for_each_column_occupied(widget_grid_data, function(tcol) { + var grid_col = this.gridmap[tcol]; + upper_rows[tcol] = []; + + var r = p_bottom_row + 1; + // iterate over each row + while (--r > 0) { + if (this.is_widget(tcol, r) && !this.is_player_in(tcol, r)) { + if (!grid_col[r].is(widget_grid_data.el)) { + break; + } + } + + if (!this.is_player(tcol, r) && + !this.is_placeholder_in(tcol, r) && + !this.is_player_in(tcol, r)) { + upper_rows[tcol].push(r); + } + + if (r < min_row) { + min_row = r; + } + } + + if (upper_rows[tcol].length === 0) { + result = false; + return true; //break + } + + upper_rows[tcol].sort(); + }); + + if (!result) { return false; } + + return this.get_valid_rows(widget_grid_data, upper_rows, min_row); + }; + + + /** + * Search a valid row for the widget represented by `widget_grid_data' in + * the `upper_rows` array. Iteration starts from row specified in `min_row`. + * + * @method get_valid_rows + * @param {Object} widget_grid_data The actual grid coords object of the + * player. + * @param {Array} upper_rows An array with columns as index and arrays + * of valid rows as values. + * @param {Number} min_row The upper row from which the iteration will start. + * @return {Number|Boolean} Returns the upper row valid from the `upper_rows` + * for the widget in question. + */ + fn.get_valid_rows = function(widget_grid_data, upper_rows, min_row) { + var p_top_row = widget_grid_data.row; + var p_bottom_row = widget_grid_data.row + widget_grid_data.size_y - 1; + var size_y = widget_grid_data.size_y; + var r = min_row - 1; + var valid_rows = []; + + while (++r <= p_bottom_row ) { + var common = true; + $.each(upper_rows, function(col, rows) { + if ($.isArray(rows) && $.inArray(r, rows) === -1) { + common = false; + } + }); + + if (common === true) { + valid_rows.push(r); + if (valid_rows.length === size_y) { + break; + } + } + } + + var new_row = false; + if (size_y === 1) { + if (valid_rows[0] !== p_top_row) { + new_row = valid_rows[0] || false; + } + }else{ + if (valid_rows[0] !== p_top_row) { + new_row = this.get_consecutive_numbers_index( + valid_rows, size_y); + } + } + + return new_row; + }; + + + fn.get_consecutive_numbers_index = function(arr, size_y) { + var max = arr.length; + var result = []; + var first = true; + var prev = -1; // or null? + + for (var i=0; i < max; i++) { + if (first || arr[i] === prev + 1) { + result.push(i); + if (result.length === size_y) { + break; + } + first = false; + }else{ + result = []; + first = true; + } + + prev = arr[i]; + } + + return result.length >= size_y ? arr[result[0]] : false; + }; + + + /** + * Get widgets overlapping with the player. + * + * @method get_widgets_overlapped + * @return {HTMLElements} Returns a jQuery collection of HTMLElements. + */ + fn.get_widgets_overlapped = function() { + var $w; + var $widgets = $([]); + var used = []; + var rows_from_bottom = this.cells_occupied_by_player.rows.slice(0); + rows_from_bottom.reverse(); + + $.each(this.cells_occupied_by_player.cols, $.proxy(function(i, col) { + $.each(rows_from_bottom, $.proxy(function(i, row) { + // if there is a widget in the player position + if (!this.gridmap[col]) { return true; } //next iteration + var $w = this.gridmap[col][row]; + if (this.is_occupied(col, row) && !this.is_player($w) && + $.inArray($w, used) === -1 + ) { + $widgets = $widgets.add($w); + used.push($w); + } + + }, this)); + }, this)); + + return $widgets; + }; + + + /** + * This callback is executed when the player begins to collide with a column. + * + * @method on_start_overlapping_column + * @param {Number} col The collided column. + * @return {HTMLElements} Returns a jQuery collection of HTMLElements. + */ + fn.on_start_overlapping_column = function(col) { + this.set_player(col, false); + }; + + + /** + * A callback executed when the player begins to collide with a row. + * + * @method on_start_overlapping_row + * @param {Number} col The collided row. + * @return {HTMLElements} Returns a jQuery collection of HTMLElements. + */ + fn.on_start_overlapping_row = function(row) { + this.set_player(false, row); + }; + + + /** + * A callback executed when the the player ends to collide with a column. + * + * @method on_stop_overlapping_column + * @param {Number} col The collided row. + * @return {HTMLElements} Returns a jQuery collection of HTMLElements. + */ + fn.on_stop_overlapping_column = function(col) { + this.set_player(col, false); + + var self = this; + this.for_each_widget_below(col, this.cells_occupied_by_player.rows[0], + function(tcol, trow) { + self.move_widget_up(this, self.player_grid_data.size_y); + }); + }; + + + /** + * This callback is executed when the player ends to collide with a row. + * + * @method on_stop_overlapping_row + * @param {Number} row The collided row. + * @return {HTMLElements} Returns a jQuery collection of HTMLElements. + */ + fn.on_stop_overlapping_row = function(row) { + this.set_player(false, row); + + var self = this; + var cols = this.cells_occupied_by_player.cols; + for (var c = 0, cl = cols.length; c < cl; c++) { + this.for_each_widget_below(cols[c], row, function(tcol, trow) { + self.move_widget_up(this, self.player_grid_data.size_y); + }); + } + }; + + + /** + * Move a widget to a specific row. The cell or cells must be empty. + * If the widget has widgets below, all of these widgets will be moved also + * if they can. + * + * @method move_widget_to + * @param {HTMLElement} $widget The jQuery wrapped HTMLElement of the + * widget is going to be moved. + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.move_widget_to = function($widget, row) { + var self = this; + var widget_grid_data = $widget.coords().grid; + var diff = row - widget_grid_data.row; + var $next_widgets = this.widgets_below($widget); + + var can_move_to_new_cell = this.can_move_to( + widget_grid_data, widget_grid_data.col, row, $widget); + + if (can_move_to_new_cell === false) { + return false; + } + + this.remove_from_gridmap(widget_grid_data); + widget_grid_data.row = row; + this.add_to_gridmap(widget_grid_data); + $widget.attr('data-row', row); + this.$changed = this.$changed.add($widget); + + + $next_widgets.each(function(i, widget) { + var $w = $(widget); + var wgd = $w.coords().grid; + var can_go_up = self.can_go_widget_up(wgd); + if (can_go_up && can_go_up !== wgd.row) { + self.move_widget_to($w, can_go_up); + } + }); + + return this; + }; + + + /** + * Move up the specified widget and all below it. + * + * @method move_widget_up + * @param {HTMLElement} $widget The widget you want to move. + * @param {Number} [y_units] The number of cells that the widget has to move. + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.move_widget_up = function($widget, y_units) { + var el_grid_data = $widget.coords().grid; + var actual_row = el_grid_data.row; + var moved = []; + var can_go_up = true; + y_units || (y_units = 1); + + if (!this.can_go_up($widget)) { return false; } //break; + + this.for_each_column_occupied(el_grid_data, function(col) { + // can_go_up + if ($.inArray($widget, moved) === -1) { + var widget_grid_data = $widget.coords().grid; + var next_row = actual_row - y_units; + next_row = this.can_go_up_to_row( + widget_grid_data, col, next_row); + + if (!next_row) { + return true; + } + + var $next_widgets = this.widgets_below($widget); + + this.remove_from_gridmap(widget_grid_data); + widget_grid_data.row = next_row; + this.add_to_gridmap(widget_grid_data); + $widget.attr('data-row', widget_grid_data.row); + this.$changed = this.$changed.add($widget); + + moved.push($widget); + + $next_widgets.each($.proxy(function(i, widget) { + this.move_widget_up($(widget), y_units); + }, this)); + } + }); + + }; + + + /** + * Move down the specified widget and all below it. + * + * @method move_widget_down + * @param {HTMLElement} $widget The jQuery object representing the widget + * you want to move. + * @param {Number} The number of cells that the widget has to move. + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.move_widget_down = function($widget, y_units) { + var el_grid_data = $widget.coords().grid; + var actual_row = el_grid_data.row; + var moved = []; + var y_diff = y_units; + + if (!$widget) { return false; } + + if ($.inArray($widget, moved) === -1) { + + var widget_grid_data = $widget.coords().grid; + var next_row = actual_row + y_units; + var $next_widgets = this.widgets_below($widget); + + this.remove_from_gridmap(widget_grid_data); + + $next_widgets.each($.proxy(function(i, widget) { + var $w = $(widget); + var wd = $w.coords().grid; + var tmp_y = this.displacement_diff( + wd, widget_grid_data, y_diff); + + if (tmp_y > 0) { + this.move_widget_down($w, tmp_y); + } + }, this)); + + widget_grid_data.row = next_row; + this.update_widget_position(widget_grid_data, $widget); + $widget.attr('data-row', widget_grid_data.row); + this.$changed = this.$changed.add($widget); + + moved.push($widget); + } + }; + + + /** + * Check if the widget can move to the specified row, else returns the + * upper row possible. + * + * @method can_go_up_to_row + * @param {Number} widget_grid_data The current grid coords object of the + * widget. + * @param {Number} col The target column. + * @param {Number} row The target row. + * @return {Boolean|Number} Returns the row number if the widget can move + * to the target position, else returns false. + */ + fn.can_go_up_to_row = function(widget_grid_data, col, row) { + var ga = this.gridmap; + var result = true; + var urc = []; // upper_rows_in_columns + var actual_row = widget_grid_data.row; + var r; + + /* generate an array with columns as index and array with + * upper rows empty in the column */ + this.for_each_column_occupied(widget_grid_data, function(tcol) { + var grid_col = ga[tcol]; + urc[tcol] = []; + + r = actual_row; + while (r--) { + if (this.is_empty(tcol, r) && + !this.is_placeholder_in(tcol, r) + ) { + urc[tcol].push(r); + }else{ + break; + } + } + + if (!urc[tcol].length) { + result = false; + return true; + } + + }); + + if (!result) { return false; } + + /* get common rows starting from upper position in all the columns + * that widget occupies */ + r = row; + for (r = 1; r < actual_row; r++) { + var common = true; + + for (var uc = 0, ucl = urc.length; uc < ucl; uc++) { + if (urc[uc] && $.inArray(r, urc[uc]) === -1) { + common = false; + } + } + + if (common === true) { + result = r; + break; + } + } + + return result; + }; + + + fn.displacement_diff = function(widget_grid_data, parent_bgd, y_units) { + var actual_row = widget_grid_data.row; + var diffs = []; + var parent_max_y = parent_bgd.row + parent_bgd.size_y; + + this.for_each_column_occupied(widget_grid_data, function(col) { + var temp_y_units = 0; + + for (var r = parent_max_y; r < actual_row; r++) { + if (this.is_empty(col, r)) { + temp_y_units = temp_y_units + 1; + } + } + + diffs.push(temp_y_units); + }); + + var max_diff = Math.max.apply(Math, diffs); + y_units = (y_units - max_diff); + + return y_units > 0 ? y_units : 0; + }; + + + /** + * Get widgets below a widget. + * + * @method widgets_below + * @param {HTMLElement} $el The jQuery wrapped HTMLElement. + * @return {HTMLElements} A jQuery collection of HTMLElements. + */ + fn.widgets_below = function($el) { + var el_grid_data = $.isPlainObject($el) ? $el : $el.coords().grid; + var self = this; + var ga = this.gridmap; + var next_row = el_grid_data.row + el_grid_data.size_y - 1; + var $nexts = $([]); + + this.for_each_column_occupied(el_grid_data, function(col) { + self.for_each_widget_below(col, next_row, function(tcol, trow) { + if (!self.is_player(this) && $.inArray(this, $nexts) === -1) { + $nexts = $nexts.add(this); + return true; // break + } + }); + }); + + return this.sort_by_row_asc($nexts); + }; + + + /** + * Update the array of mapped positions with the new player position. + * + * @method set_cells_player_occupies + * @param {Number} col The new player col. + * @param {Number} col The new player row. + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.set_cells_player_occupies = function(col, row) { + this.remove_from_gridmap(this.placeholder_grid_data); + this.placeholder_grid_data.col = col; + this.placeholder_grid_data.row = row; + this.add_to_gridmap(this.placeholder_grid_data, this.$player); + return this; + }; + + + /** + * Remove from the array of mapped positions the reference to the player. + * + * @method empty_cells_player_occupies + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.empty_cells_player_occupies = function() { + this.remove_from_gridmap(this.placeholder_grid_data); + return this; + }; + + + fn.can_go_up = function($el) { + var el_grid_data = $el.coords().grid; + var initial_row = el_grid_data.row; + var prev_row = initial_row - 1; + var ga = this.gridmap; + var upper_rows_by_column = []; + + var result = true; + if (initial_row === 1) { return false; } + + this.for_each_column_occupied(el_grid_data, function(col) { + var $w = this.is_widget(col, prev_row); + + if (this.is_occupied(col, prev_row) || + this.is_player(col, prev_row) || + this.is_placeholder_in(col, prev_row) || + this.is_player_in(col, prev_row) + ) { + result = false; + return true; //break + } + }); + + return result; + }; + + + + /** + * Check if it's possible to move a widget to a specific col/row. It takes + * into account the dimensions (`size_y` and `size_x` attrs. of the grid + * coords object) the widget occupies. + * + * @method can_move_to + * @param {Object} widget_grid_data The grid coords object that represents + * the widget. + * @param {Object} col The col to check. + * @param {Object} row The row to check. + * @param {Number} [max_row] The max row allowed. + * @return {Boolean} Returns true if all cells are empty, else return false. + */ + fn.can_move_to = function(widget_grid_data, col, row, max_row) { + var ga = this.gridmap; + var $w = widget_grid_data.el; + var future_wd = { + size_y: widget_grid_data.size_y, + size_x: widget_grid_data.size_x, + col: col, + row: row + }; + var result = true; + + //Prevents widgets go out of the grid + var right_col = col + widget_grid_data.size_x - 1; + if (right_col > this.cols) { + return false; + } + + if (max_row && max_row < row + widget_grid_data.size_y - 1) { + return false; + } + + this.for_each_cell_occupied(future_wd, function(tcol, trow) { + var $tw = this.is_widget(tcol, trow); + if ($tw && (!widget_grid_data.el || $tw.is($w))) { + result = false; + } + }); + + return result; + }; + + + /** + * Given the leftmost column returns all columns that are overlapping + * with the player. + * + * @method get_targeted_columns + * @param {Number} [from_col] The leftmost column. + * @return {Array} Returns an array with column numbers. + */ + fn.get_targeted_columns = function(from_col) { + var max = (from_col || this.player_grid_data.col) + + (this.player_grid_data.size_x - 1); + var cols = []; + for (var col = from_col; col <= max; col++) { + cols.push(col); + } + return cols; + }; + + + /** + * Given the upper row returns all rows that are overlapping with the player. + * + * @method get_targeted_rows + * @param {Number} [from_row] The upper row. + * @return {Array} Returns an array with row numbers. + */ + fn.get_targeted_rows = function(from_row) { + var max = (from_row || this.player_grid_data.row) + + (this.player_grid_data.size_y - 1); + var rows = []; + for (var row = from_row; row <= max; row++) { + rows.push(row); + } + return rows; + }; + + /** + * Get all columns and rows that a widget occupies. + * + * @method get_cells_occupied + * @param {Object} el_grid_data The grid coords object of the widget. + * @return {Object} Returns an object like `{ cols: [], rows: []}`. + */ + fn.get_cells_occupied = function(el_grid_data) { + var cells = { cols: [], rows: []}; + var i; + if (arguments[1] instanceof jQuery) { + el_grid_data = arguments[1].coords().grid; + } + + for (i = 0; i < el_grid_data.size_x; i++) { + var col = el_grid_data.col + i; + cells.cols.push(col); + } + + for (i = 0; i < el_grid_data.size_y; i++) { + var row = el_grid_data.row + i; + cells.rows.push(row); + } + + return cells; + }; + + + /** + * Iterate over the cells occupied by a widget executing a function for + * each one. + * + * @method for_each_cell_occupied + * @param {Object} el_grid_data The grid coords object that represents the + * widget. + * @param {Function} callback The function to execute on each column + * iteration. Column and row are passed as arguments. + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.for_each_cell_occupied = function(grid_data, callback) { + this.for_each_column_occupied(grid_data, function(col) { + this.for_each_row_occupied(grid_data, function(row) { + callback.call(this, col, row); + }); + }); + return this; + }; + + + /** + * Iterate over the columns occupied by a widget executing a function for + * each one. + * + * @method for_each_column_occupied + * @param {Object} el_grid_data The grid coords object that represents + * the widget. + * @param {Function} callback The function to execute on each column + * iteration. The column number is passed as first argument. + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.for_each_column_occupied = function(el_grid_data, callback) { + for (var i = 0; i < el_grid_data.size_x; i++) { + var col = el_grid_data.col + i; + callback.call(this, col, el_grid_data); + } + }; + + + /** + * Iterate over the rows occupied by a widget executing a function for + * each one. + * + * @method for_each_row_occupied + * @param {Object} el_grid_data The grid coords object that represents + * the widget. + * @param {Function} callback The function to execute on each column + * iteration. The row number is passed as first argument. + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.for_each_row_occupied = function(el_grid_data, callback) { + for (var i = 0; i < el_grid_data.size_y; i++) { + var row = el_grid_data.row + i; + callback.call(this, row, el_grid_data); + } + }; + + + + fn._traversing_widgets = function(type, direction, col, row, callback) { + var ga = this.gridmap; + if (!ga[col]) { return; } + + var cr, max; + var action = type + '/' + direction; + if (arguments[2] instanceof jQuery) { + var el_grid_data = arguments[2].coords().grid; + col = el_grid_data.col; + row = el_grid_data.row; + callback = arguments[3]; + } + var matched = []; + var trow = row; + + + var methods = { + 'for_each/above': function() { + while (trow--) { + if (trow > 0 && this.is_widget(col, trow) && + $.inArray(ga[col][trow], matched) === -1 + ) { + cr = callback.call(ga[col][trow], col, trow); + matched.push(ga[col][trow]); + if (cr) { break; } + } + } + }, + 'for_each/below': function() { + for (trow = row + 1, max = ga[col].length; trow < max; trow++) { + if (this.is_widget(col, trow) && + $.inArray(ga[col][trow], matched) === -1 + ) { + cr = callback.call(ga[col][trow], col, trow); + matched.push(ga[col][trow]); + if (cr) { break; } + } + } + } + }; + + if (methods[action]) { + methods[action].call(this); + } + }; + + + /** + * Iterate over each widget above the column and row specified. + * + * @method for_each_widget_above + * @param {Number} col The column to start iterating. + * @param {Number} row The row to start iterating. + * @param {Function} callback The function to execute on each widget + * iteration. The value of `this` inside the function is the jQuery + * wrapped HTMLElement. + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.for_each_widget_above = function(col, row, callback) { + this._traversing_widgets('for_each', 'above', col, row, callback); + return this; + }; + + + /** + * Iterate over each widget below the column and row specified. + * + * @method for_each_widget_below + * @param {Number} col The column to start iterating. + * @param {Number} row The row to start iterating. + * @param {Function} callback The function to execute on each widget + * iteration. The value of `this` inside the function is the jQuery wrapped + * HTMLElement. + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.for_each_widget_below = function(col, row, callback) { + this._traversing_widgets('for_each', 'below', col, row, callback); + return this; + }; + + + /** + * Returns the highest occupied cell in the grid. + * + * @method get_highest_occupied_cell + * @return {Object} Returns an object with `col` and `row` numbers. + */ + fn.get_highest_occupied_cell = function() { + var r; + var gm = this.gridmap; + var rows = []; + var row_in_col = []; + for (var c = gm.length - 1; c >= 1; c--) { + for (r = gm[c].length - 1; r >= 1; r--) { + if (this.is_widget(c, r)) { + rows.push(r); + row_in_col[r] = c; + break; + } + } + } + + var highest_row = Math.max.apply(Math, rows); + + this.highest_occupied_cell = { + col: row_in_col[highest_row], + row: highest_row + }; + + return this.highest_occupied_cell; + }; + + + fn.get_widgets_from = function(col, row) { + var ga = this.gridmap; + var $widgets = $(); + + if (col) { + $widgets = $widgets.add( + this.$widgets.filter(function() { + var tcol = $(this).attr('data-col'); + return (tcol === col || tcol > col); + }) + ); + } + + if (row) { + $widgets = $widgets.add( + this.$widgets.filter(function() { + var trow = $(this).attr('data-row'); + return (trow === row || trow > row); + }) + ); + } + + return $widgets; + }; + + + /** + * Set the current height of the parent grid. + * + * @method set_dom_grid_height + * @return {Object} Returns the instance of the Gridster class. + */ + fn.set_dom_grid_height = function() { + var r = this.get_highest_occupied_cell().row; + this.$el.css('height', r * this.min_widget_height); + return this; + }; + + + /** + * It generates the neccessary styles to position the widgets. + * + * @method generate_stylesheet + * @param {Number} rows Number of columns. + * @param {Number} cols Number of rows. + * @return {Object} Returns the instance of the Gridster class. + */ + fn.generate_stylesheet = function(opts) { + var styles = ''; + var max_size_x = this.options.max_size_x; + var max_rows = 0; + var max_cols = 0; + var i; + var rules; + + opts || (opts = {}); + opts.cols || (opts.cols = this.cols); + opts.rows || (opts.rows = this.rows); + opts.namespace || (opts.namespace = this.options.namespace); + opts.widget_base_dimensions || + (opts.widget_base_dimensions = this.options.widget_base_dimensions); + opts.widget_margins || + (opts.widget_margins = this.options.widget_margins); + opts.min_widget_width = (opts.widget_margins[0] * 2) + + opts.widget_base_dimensions[0]; + opts.min_widget_height = (opts.widget_margins[1] * 2) + + opts.widget_base_dimensions[1]; + + // don't duplicate stylesheets for the same configuration + var serialized_opts = $.param(opts); + if ($.inArray(serialized_opts, Gridster.generated_stylesheets) >= 0) { + return false; + } + + Gridster.generated_stylesheets.push(serialized_opts); + + /* generate CSS styles for cols */ + for (i = opts.cols; i >= 0; i--) { + styles += (opts.namespace + ' [data-col="'+ (i + 1) + '"] { left:' + + ((i * opts.widget_base_dimensions[0]) + + (i * opts.widget_margins[0]) + + ((i + 1) * opts.widget_margins[0])) + 'px;} '); + } + + /* generate CSS styles for rows */ + for (i = opts.rows; i >= 0; i--) { + styles += (opts.namespace + ' [data-row="' + (i + 1) + '"] { top:' + + ((i * opts.widget_base_dimensions[1]) + + (i * opts.widget_margins[1]) + + ((i + 1) * opts.widget_margins[1]) ) + 'px;} '); + } + + for (var y = 1; y <= opts.rows; y++) { + styles += (opts.namespace + ' [data-sizey="' + y + '"] { height:' + + (y * opts.widget_base_dimensions[1] + + (y - 1) * (opts.widget_margins[1] * 2)) + 'px;}'); + } + + for (var x = 1; x <= max_size_x; x++) { + styles += (opts.namespace + ' [data-sizex="' + x + '"] { width:' + + (x * opts.widget_base_dimensions[0] + + (x - 1) * (opts.widget_margins[0] * 2)) + 'px;}'); + } + + return this.add_style_tag(styles); + }; + + + /** + * Injects the given CSS as string to the head of the document. + * + * @method add_style_tag + * @param {String} css The styles to apply. + * @return {Object} Returns the instance of the Gridster class. + */ + fn.add_style_tag = function(css) { + var d = document; + var tag = d.createElement('style'); + + d.getElementsByTagName('head')[0].appendChild(tag); + tag.setAttribute('type', 'text/css'); + + if (tag.styleSheet) { + tag.styleSheet.cssText = css; + }else{ + tag.appendChild(document.createTextNode(css)); + } + return this; + }; + + + /** + * Generates a faux grid to collide with it when a widget is dragged and + * detect row or column that we want to go. + * + * @method generate_faux_grid + * @param {Number} rows Number of columns. + * @param {Number} cols Number of rows. + * @return {Object} Returns the instance of the Gridster class. + */ + fn.generate_faux_grid = function(rows, cols) { + this.faux_grid = []; + this.gridmap = []; + var col; + var row; + for (col = cols; col > 0; col--) { + this.gridmap[col] = []; + for (row = rows; row > 0; row--) { + this.add_faux_cell(row, col); + } + } + return this; + }; + + + /** + * Add cell to the faux grid. + * + * @method add_faux_cell + * @param {Number} row The row for the new faux cell. + * @param {Number} col The col for the new faux cell. + * @return {Object} Returns the instance of the Gridster class. + */ + fn.add_faux_cell = function(row, col) { + var coords = $({ + left: this.baseX + ((col - 1) * this.min_widget_width), + top: this.baseY + (row -1) * this.min_widget_height, + width: this.min_widget_width, + height: this.min_widget_height, + col: col, + row: row, + original_col: col, + original_row: row + }).coords(); + + if (!$.isArray(this.gridmap[col])) { + this.gridmap[col] = []; + } + + this.gridmap[col][row] = false; + this.faux_grid.push(coords); + + return this; + }; + + + /** + * Add rows to the faux grid. + * + * @method add_faux_rows + * @param {Number} rows The number of rows you want to add to the faux grid. + * @return {Object} Returns the instance of the Gridster class. + */ + fn.add_faux_rows = function(rows) { + var actual_rows = this.rows; + var max_rows = actual_rows + (rows || 1); + + for (var r = max_rows; r > actual_rows; r--) { + for (var c = this.cols; c >= 1; c--) { + this.add_faux_cell(r, c); + } + } + + this.rows = max_rows; + + if (this.options.autogenerate_stylesheet) { + this.generate_stylesheet(); + } + + return this; + }; + + /** + * Add cols to the faux grid. + * + * @method add_faux_cols + * @param {Number} cols The number of cols you want to add to the faux grid. + * @return {Object} Returns the instance of the Gridster class. + */ + fn.add_faux_cols = function(cols) { + var actual_cols = this.cols; + var max_cols = actual_cols + (cols || 1); + + for (var c = actual_cols; c < max_cols; c++) { + for (var r = this.rows; r >= 1; r--) { + this.add_faux_cell(r, c); + } + } + + this.cols = max_cols; + + if (this.options.autogenerate_stylesheet) { + this.generate_stylesheet(); + } + + return this; + }; + + + /** + * Recalculates the offsets for the faux grid. You need to use it when + * the browser is resized. + * + * @method recalculate_faux_grid + * @return {Object} Returns the instance of the Gridster class. + */ + fn.recalculate_faux_grid = function() { + var aw = this.$wrapper.width(); + this.baseX = ($(window).width() - aw) / 2; + this.baseY = this.$wrapper.offset().top; + + $.each(this.faux_grid, $.proxy(function(i, coords) { + this.faux_grid[i] = coords.update({ + left: this.baseX + (coords.data.col -1) * this.min_widget_width, + top: this.baseY + (coords.data.row -1) * this.min_widget_height + }); + + }, this)); + + return this; + }; + + + /** + * Get all widgets in the DOM and register them. + * + * @method get_widgets_from_DOM + * @return {Object} Returns the instance of the Gridster class. + */ + fn.get_widgets_from_DOM = function() { + this.$widgets.each($.proxy(function(i, widget) { + this.register_widget($(widget)); + }, this)); + return this; + }; + + + /** + * Calculate columns and rows to be set based on the configuration + * parameters, grid dimensions, etc ... + * + * @method generate_grid_and_stylesheet + * @return {Object} Returns the instance of the Gridster class. + */ + fn.generate_grid_and_stylesheet = function() { + var aw = this.$wrapper.width(); + var ah = this.$wrapper.height(); + + var cols = Math.floor(aw / this.min_widget_width) + + this.options.extra_cols; + + var actual_cols = this.$widgets.map(function() { + return $(this).attr('data-col'); + }); + actual_cols = Array.prototype.slice.call(actual_cols, 0); + //needed to pass tests with phantomjs + actual_cols.length || (actual_cols = [0]); + + var min_cols = Math.max.apply(Math, actual_cols); + + // get all rows that could be occupied by the current widgets + var max_rows = this.options.extra_rows; + this.$widgets.each(function(i, w) { + max_rows += (+$(w).attr('data-sizey')); + }); + + this.cols = Math.max(min_cols, cols, this.options.min_cols); + this.rows = Math.max(max_rows, this.options.min_rows); + + this.baseX = ($(window).width() - aw) / 2; + this.baseY = this.$wrapper.offset().top; + + if (this.options.autogenerate_stylesheet) { + this.generate_stylesheet(); + } + + return this.generate_faux_grid(this.rows, this.cols); + }; + + + //jQuery adapter + $.fn.gridster = function(options) { + return this.each(function() { + if (!$(this).data('gridster')) { + $(this).data('gridster', new Gridster( this, options )); + } + }); + }; + + $.Gridster = fn; + +}(jQuery, window, document)); diff --git a/assets/jquery.js b/assets/jquery.js new file mode 100644 index 0000000..3774ff9 --- /dev/null +++ b/assets/jquery.js @@ -0,0 +1,9404 @@ +/*! + * jQuery JavaScript Library v1.7.2 + * http://jquery.com/ + * + * Copyright 2011, John Resig + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * Copyright 2011, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * + * Date: Wed Mar 21 12:46:34 2012 -0700 + */ +(function( window, undefined ) { + +// Use the correct document accordingly with window argument (sandbox) +var document = window.document, + navigator = window.navigator, + location = window.location; +var jQuery = (function() { + +// Define a local copy of jQuery +var jQuery = function( selector, context ) { + // The jQuery object is actually just the init constructor 'enhanced' + return new jQuery.fn.init( selector, context, rootjQuery ); + }, + + // Map over jQuery in case of overwrite + _jQuery = window.jQuery, + + // Map over the $ in case of overwrite + _$ = window.$, + + // A central reference to the root jQuery(document) + rootjQuery, + + // A simple way to check for HTML strings or ID strings + // Prioritize #id over to avoid XSS via location.hash (#9521) + quickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/, + + // Check if a string has a non-whitespace character in it + rnotwhite = /\S/, + + // Used for trimming whitespace + trimLeft = /^\s+/, + trimRight = /\s+$/, + + // Match a standalone tag + rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/, + + // JSON RegExp + rvalidchars = /^[\],:{}\s]*$/, + rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, + rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, + rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g, + + // Useragent RegExp + rwebkit = /(webkit)[ \/]([\w.]+)/, + ropera = /(opera)(?:.*version)?[ \/]([\w.]+)/, + rmsie = /(msie) ([\w.]+)/, + rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/, + + // Matches dashed string for camelizing + rdashAlpha = /-([a-z]|[0-9])/ig, + rmsPrefix = /^-ms-/, + + // Used by jQuery.camelCase as callback to replace() + fcamelCase = function( all, letter ) { + return ( letter + "" ).toUpperCase(); + }, + + // Keep a UserAgent string for use with jQuery.browser + userAgent = navigator.userAgent, + + // For matching the engine and version of the browser + browserMatch, + + // The deferred used on DOM ready + readyList, + + // The ready event handler + DOMContentLoaded, + + // Save a reference to some core methods + toString = Object.prototype.toString, + hasOwn = Object.prototype.hasOwnProperty, + push = Array.prototype.push, + slice = Array.prototype.slice, + trim = String.prototype.trim, + indexOf = Array.prototype.indexOf, + + // [[Class]] -> type pairs + class2type = {}; + +jQuery.fn = jQuery.prototype = { + constructor: jQuery, + init: function( selector, context, rootjQuery ) { + var match, elem, ret, doc; + + // Handle $(""), $(null), or $(undefined) + if ( !selector ) { + return this; + } + + // Handle $(DOMElement) + if ( selector.nodeType ) { + this.context = this[0] = selector; + this.length = 1; + return this; + } + + // The body element only exists once, optimize finding it + if ( selector === "body" && !context && document.body ) { + this.context = document; + this[0] = document.body; + this.selector = selector; + this.length = 1; + return this; + } + + // Handle HTML strings + if ( typeof selector === "string" ) { + // Are we dealing with HTML string or an ID? + 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 = quickExpr.exec( selector ); + } + + // Verify a match, and that no context was specified for #id + if ( match && (match[1] || !context) ) { + + // HANDLE: $(html) -> $(array) + if ( match[1] ) { + context = context instanceof jQuery ? context[0] : context; + doc = ( context ? context.ownerDocument || context : document ); + + // If a single string is passed in and it's a single tag + // just do a createElement and skip the rest + ret = rsingleTag.exec( selector ); + + if ( ret ) { + if ( jQuery.isPlainObject( context ) ) { + selector = [ document.createElement( ret[1] ) ]; + jQuery.fn.attr.call( selector, context, true ); + + } else { + selector = [ doc.createElement( ret[1] ) ]; + } + + } else { + ret = jQuery.buildFragment( [ match[1] ], [ doc ] ); + selector = ( ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment ).childNodes; + } + + return jQuery.merge( this, selector ); + + // 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 || rootjQuery ).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( jQuery.isFunction( selector ) ) { + return rootjQuery.ready( selector ); + } + + if ( selector.selector !== undefined ) { + this.selector = selector.selector; + this.context = selector.context; + } + + return jQuery.makeArray( selector, this ); + }, + + // Start with an empty selector + selector: "", + + // The current version of jQuery being used + jquery: "1.7.2", + + // The default length of a jQuery object is 0 + length: 0, + + // The number of elements contained in the matched element set + size: function() { + return this.length; + }, + + toArray: function() { + return slice.call( this, 0 ); + }, + + // 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 a 'clean' array + this.toArray() : + + // Return just the object + ( num < 0 ? this[ this.length + num ] : this[ num ] ); + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems, name, selector ) { + // Build a new jQuery matched element set + var ret = this.constructor(); + + if ( jQuery.isArray( elems ) ) { + push.apply( ret, elems ); + + } else { + jQuery.merge( ret, elems ); + } + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + ret.context = this.context; + + if ( name === "find" ) { + ret.selector = this.selector + ( this.selector ? " " : "" ) + selector; + } else if ( name ) { + ret.selector = this.selector + "." + name + "(" + selector + ")"; + } + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + // (You can seed the arguments with an array of args, but this is + // only used internally.) + each: function( callback, args ) { + return jQuery.each( this, callback, args ); + }, + + ready: function( fn ) { + // Attach the listeners + jQuery.bindReady(); + + // Add the callback + readyList.add( fn ); + + return this; + }, + + eq: function( i ) { + i = +i; + return i === -1 ? + this.slice( i ) : + this.slice( i, i + 1 ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ), + "slice", slice.call(arguments).join(",") ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map(this, function( elem, i ) { + return callback.call( elem, i, elem ); + })); + }, + + end: function() { + return this.prevObject || this.constructor(null); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: [].sort, + splice: [].splice +}; + +// Give the init function the jQuery prototype for later instantiation +jQuery.fn.init.prototype = jQuery.fn; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[0] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + 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" && !jQuery.isFunction(target) ) { + target = {}; + } + + // extend jQuery itself if only one argument is passed + if ( length === i ) { + 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({ + noConflict: function( deep ) { + if ( window.$ === jQuery ) { + window.$ = _$; + } + + if ( deep && window.jQuery === jQuery ) { + window.jQuery = _jQuery; + } + + return jQuery; + }, + + // 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 ) { + // Either a released hold or an DOMready/load event and not yet ready + if ( (wait === true && !--jQuery.readyWait) || (wait !== true && !jQuery.isReady) ) { + // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). + if ( !document.body ) { + return setTimeout( jQuery.ready, 1 ); + } + + // 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.fireWith( document, [ jQuery ] ); + + // Trigger any bound ready events + if ( jQuery.fn.trigger ) { + jQuery( document ).trigger( "ready" ).off( "ready" ); + } + } + }, + + bindReady: function() { + if ( readyList ) { + return; + } + + readyList = jQuery.Callbacks( "once memory" ); + + // Catch cases where $(document).ready() is called after the + // browser event has already occurred. + if ( document.readyState === "complete" ) { + // Handle it asynchronously to allow scripts the opportunity to delay ready + return setTimeout( jQuery.ready, 1 ); + } + + // Mozilla, Opera and webkit nightlies currently support this event + if ( document.addEventListener ) { + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", jQuery.ready, false ); + + // If IE event model is used + } else if ( document.attachEvent ) { + // ensure firing before onload, + // maybe late but safe also for iframes + document.attachEvent( "onreadystatechange", DOMContentLoaded ); + + // A fallback to window.onload, that will always work + window.attachEvent( "onload", jQuery.ready ); + + // If IE and not a frame + // continually check to see if the document is ready + var toplevel = false; + + try { + toplevel = window.frameElement == null; + } catch(e) {} + + if ( document.documentElement.doScroll && toplevel ) { + doScrollCheck(); + } + } + }, + + // 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 ) { + return obj != null && obj == obj.window; + }, + + isNumeric: function( obj ) { + return !isNaN( parseFloat(obj) ) && isFinite( obj ); + }, + + type: function( obj ) { + return obj == null ? + String( obj ) : + class2type[ toString.call(obj) ] || "object"; + }, + + isPlainObject: function( obj ) { + // 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; + } + + // Own properties are enumerated firstly, so to speed up, + // if last one is own, then all properties are own. + + var key; + for ( key in obj ) {} + + return key === undefined || hasOwn.call( obj, key ); + }, + + isEmptyObject: function( obj ) { + for ( var name in obj ) { + return false; + } + return true; + }, + + error: function( msg ) { + throw new Error( msg ); + }, + + parseJSON: function( data ) { + if ( typeof data !== "string" || !data ) { + return null; + } + + // Make sure leading/trailing whitespace is removed (IE can't handle it) + data = jQuery.trim( data ); + + // Attempt to parse using the native JSON parser first + if ( window.JSON && window.JSON.parse ) { + return window.JSON.parse( data ); + } + + // Make sure the incoming data is actual JSON + // Logic borrowed from http://json.org/json2.js + if ( rvalidchars.test( data.replace( rvalidescape, "@" ) + .replace( rvalidtokens, "]" ) + .replace( rvalidbraces, "")) ) { + + return ( new Function( "return " + data ) )(); + + } + jQuery.error( "Invalid JSON: " + data ); + }, + + // Cross-browser xml parsing + parseXML: function( data ) { + if ( typeof data !== "string" || !data ) { + return null; + } + var xml, tmp; + try { + if ( window.DOMParser ) { // Standard + tmp = new DOMParser(); + xml = tmp.parseFromString( data , "text/xml" ); + } else { // IE + xml = new ActiveXObject( "Microsoft.XMLDOM" ); + xml.async = "false"; + xml.loadXML( data ); + } + } catch( e ) { + xml = undefined; + } + if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) { + jQuery.error( "Invalid XML: " + data ); + } + return xml; + }, + + noop: function() {}, + + // Evaluates a script in a global context + // 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 && rnotwhite.test( 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 ); + } )( 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.toUpperCase() === name.toUpperCase(); + }, + + // args is for internal usage only + each: function( object, callback, args ) { + var name, i = 0, + length = object.length, + isObj = length === undefined || jQuery.isFunction( object ); + + if ( args ) { + if ( isObj ) { + for ( name in object ) { + if ( callback.apply( object[ name ], args ) === false ) { + break; + } + } + } else { + for ( ; i < length; ) { + if ( callback.apply( object[ i++ ], args ) === false ) { + break; + } + } + } + + // A special, fast, case for the most common use of each + } else { + if ( isObj ) { + for ( name in object ) { + if ( callback.call( object[ name ], name, object[ name ] ) === false ) { + break; + } + } + } else { + for ( ; i < length; ) { + if ( callback.call( object[ i ], i, object[ i++ ] ) === false ) { + break; + } + } + } + } + + return object; + }, + + // Use native String.trim function wherever possible + trim: trim ? + function( text ) { + return text == null ? + "" : + trim.call( text ); + } : + + // Otherwise use our own trimming functionality + function( text ) { + return text == null ? + "" : + text.toString().replace( trimLeft, "" ).replace( trimRight, "" ); + }, + + // results is for internal usage only + makeArray: function( array, results ) { + var ret = results || []; + + if ( array != null ) { + // The window, strings (and functions) also have 'length' + // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930 + var type = jQuery.type( array ); + + if ( array.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( array ) ) { + push.call( ret, array ); + } else { + jQuery.merge( ret, array ); + } + } + + return ret; + }, + + inArray: function( elem, array, i ) { + var len; + + if ( array ) { + if ( indexOf ) { + return indexOf.call( array, elem, i ); + } + + len = array.length; + i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0; + + for ( ; i < len; i++ ) { + // Skip accessing in sparse arrays + if ( i in array && array[ i ] === elem ) { + return i; + } + } + } + + return -1; + }, + + merge: function( first, second ) { + var i = first.length, + j = 0; + + if ( typeof second.length === "number" ) { + for ( var l = second.length; j < l; j++ ) { + first[ i++ ] = second[ j ]; + } + + } else { + while ( second[j] !== undefined ) { + first[ i++ ] = second[ j++ ]; + } + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, inv ) { + var ret = [], retVal; + inv = !!inv; + + // Go through the array, only saving the items + // that pass the validator function + for ( var i = 0, length = elems.length; i < length; i++ ) { + retVal = !!callback( elems[ i ], i ); + if ( inv !== retVal ) { + ret.push( elems[ i ] ); + } + } + + return ret; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var value, key, ret = [], + i = 0, + length = elems.length, + // jquery objects are treated as arrays + isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ; + + // Go through the array, translating each of the items to their + if ( isArray ) { + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret[ ret.length ] = value; + } + } + + // Go through every key on the object, + } else { + for ( key in elems ) { + value = callback( elems[ key ], key, arg ); + + if ( value != null ) { + ret[ ret.length ] = value; + } + } + } + + // Flatten any nested arrays + return ret.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 ) { + if ( typeof context === "string" ) { + var 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 + var args = slice.call( arguments, 2 ), + proxy = function() { + return fn.apply( context, 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 || proxy.guid || jQuery.guid++; + + return proxy; + }, + + // Mutifunctional method to get and set values to a collection + // The value/s can optionally be executed if it's a function + access: function( elems, fn, key, value, chainable, emptyGet, pass ) { + var exec, + bulk = key == null, + i = 0, + length = elems.length; + + // Sets many values + if ( key && typeof key === "object" ) { + for ( i in key ) { + jQuery.access( elems, fn, i, key[i], 1, emptyGet, value ); + } + chainable = 1; + + // Sets one value + } else if ( value !== undefined ) { + // Optionally, function values get executed if exec is true + exec = pass === undefined && jQuery.isFunction( value ); + + if ( bulk ) { + // Bulk operations only iterate when executing function values + if ( exec ) { + exec = fn; + fn = function( elem, key, value ) { + return exec.call( jQuery( elem ), value ); + }; + + // Otherwise they run against the entire set + } else { + fn.call( elems, value ); + fn = null; + } + } + + if ( fn ) { + for (; i < length; i++ ) { + fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass ); + } + } + + chainable = 1; + } + + return chainable ? + elems : + + // Gets + bulk ? + fn.call( elems ) : + length ? fn( elems[0], key ) : emptyGet; + }, + + now: function() { + return ( new Date() ).getTime(); + }, + + // Use of jQuery.browser is frowned upon. + // More details: http://docs.jquery.com/Utilities/jQuery.browser + uaMatch: function( ua ) { + ua = ua.toLowerCase(); + + var match = rwebkit.exec( ua ) || + ropera.exec( ua ) || + rmsie.exec( ua ) || + ua.indexOf("compatible") < 0 && rmozilla.exec( ua ) || + []; + + return { browser: match[1] || "", version: match[2] || "0" }; + }, + + sub: function() { + function jQuerySub( selector, context ) { + return new jQuerySub.fn.init( selector, context ); + } + jQuery.extend( true, jQuerySub, this ); + jQuerySub.superclass = this; + jQuerySub.fn = jQuerySub.prototype = this(); + jQuerySub.fn.constructor = jQuerySub; + jQuerySub.sub = this.sub; + jQuerySub.fn.init = function init( selector, context ) { + if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) { + context = jQuerySub( context ); + } + + return jQuery.fn.init.call( this, selector, context, rootjQuerySub ); + }; + jQuerySub.fn.init.prototype = jQuerySub.fn; + var rootjQuerySub = jQuerySub(document); + return jQuerySub; + }, + + browser: {} +}); + +// Populate the class2type map +jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); +}); + +browserMatch = jQuery.uaMatch( userAgent ); +if ( browserMatch.browser ) { + jQuery.browser[ browserMatch.browser ] = true; + jQuery.browser.version = browserMatch.version; +} + +// Deprecated, use jQuery.browser.webkit instead +if ( jQuery.browser.webkit ) { + jQuery.browser.safari = true; +} + +// IE doesn't match non-breaking spaces with \s +if ( rnotwhite.test( "\xA0" ) ) { + trimLeft = /^[\s\xA0]+/; + trimRight = /[\s\xA0]+$/; +} + +// All jQuery objects should point back to these +rootjQuery = jQuery(document); + +// Cleanup functions for the document ready method +if ( document.addEventListener ) { + DOMContentLoaded = function() { + document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false ); + jQuery.ready(); + }; + +} else if ( document.attachEvent ) { + DOMContentLoaded = function() { + // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). + if ( document.readyState === "complete" ) { + document.detachEvent( "onreadystatechange", DOMContentLoaded ); + jQuery.ready(); + } + }; +} + +// The DOM ready check for Internet Explorer +function doScrollCheck() { + if ( jQuery.isReady ) { + return; + } + + try { + // If IE is used, use the trick by Diego Perini + // http://javascript.nwbox.com/IEContentLoaded/ + document.documentElement.doScroll("left"); + } catch(e) { + setTimeout( doScrollCheck, 1 ); + return; + } + + // and execute any waiting functions + jQuery.ready(); +} + +return jQuery; + +})(); + + +// String to Object flags format cache +var flagsCache = {}; + +// Convert String-formatted flags into Object-formatted ones and store in cache +function createFlags( flags ) { + var object = flagsCache[ flags ] = {}, + i, length; + flags = flags.split( /\s+/ ); + for ( i = 0, length = flags.length; i < length; i++ ) { + object[ flags[i] ] = true; + } + return object; +} + +/* + * Create a callback list using the following parameters: + * + * flags: an optional list of space-separated flags that will change how + * the callback list behaves + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible flags: + * + * 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( flags ) { + + // Convert flags from String-formatted to Object-formatted + // (we check in cache first) + flags = flags ? ( flagsCache[ flags ] || createFlags( flags ) ) : {}; + + var // Actual callback list + list = [], + // Stack of fire calls for repeatable lists + stack = [], + // Last fire value (for non-forgettable lists) + memory, + // Flag to know if list was already fired + fired, + // Flag to know if list is currently firing + firing, + // First callback to fire (used internally by add and fireWith) + firingStart, + // End of the loop when firing + firingLength, + // Index of currently firing callback (modified by remove if needed) + firingIndex, + // Add one or several callbacks to the list + add = function( args ) { + var i, + length, + elem, + type, + actual; + for ( i = 0, length = args.length; i < length; i++ ) { + elem = args[ i ]; + type = jQuery.type( elem ); + if ( type === "array" ) { + // Inspect recursively + add( elem ); + } else if ( type === "function" ) { + // Add if not in unique mode and callback is not in + if ( !flags.unique || !self.has( elem ) ) { + list.push( elem ); + } + } + } + }, + // Fire callbacks + fire = function( context, args ) { + args = args || []; + memory = !flags.memory || [ context, args ]; + fired = true; + firing = true; + firingIndex = firingStart || 0; + firingStart = 0; + firingLength = list.length; + for ( ; list && firingIndex < firingLength; firingIndex++ ) { + if ( list[ firingIndex ].apply( context, args ) === false && flags.stopOnFalse ) { + memory = true; // Mark as halted + break; + } + } + firing = false; + if ( list ) { + if ( !flags.once ) { + if ( stack && stack.length ) { + memory = stack.shift(); + self.fireWith( memory[ 0 ], memory[ 1 ] ); + } + } else if ( memory === true ) { + self.disable(); + } else { + list = []; + } + } + }, + // Actual Callbacks object + self = { + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + var length = list.length; + add( arguments ); + // Do we need to add the callbacks to the + // current firing batch? + if ( firing ) { + firingLength = list.length; + // With memory, if we're not firing then + // we should call right away, unless previous + // firing was halted (stopOnFalse) + } else if ( memory && memory !== true ) { + firingStart = length; + fire( memory[ 0 ], memory[ 1 ] ); + } + } + return this; + }, + // Remove a callback from the list + remove: function() { + if ( list ) { + var args = arguments, + argIndex = 0, + argLength = args.length; + for ( ; argIndex < argLength ; argIndex++ ) { + for ( var i = 0; i < list.length; i++ ) { + if ( args[ argIndex ] === list[ i ] ) { + // Handle firingIndex and firingLength + if ( firing ) { + if ( i <= firingLength ) { + firingLength--; + if ( i <= firingIndex ) { + firingIndex--; + } + } + } + // Remove the element + list.splice( i--, 1 ); + // If we have some unicity property then + // we only need to do this once + if ( flags.unique ) { + break; + } + } + } + } + } + return this; + }, + // Control if a given callback is in the list + has: function( fn ) { + if ( list ) { + var i = 0, + length = list.length; + for ( ; i < length; i++ ) { + if ( fn === list[ i ] ) { + return true; + } + } + } + return false; + }, + // Remove all callbacks from the list + empty: function() { + list = []; + return this; + }, + // Have the list do nothing anymore + disable: function() { + list = stack = memory = undefined; + return this; + }, + // Is it disabled? + disabled: function() { + return !list; + }, + // Lock the list in its current state + lock: function() { + stack = undefined; + if ( !memory || memory === true ) { + self.disable(); + } + return this; + }, + // Is it locked? + locked: function() { + return !stack; + }, + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + if ( stack ) { + if ( firing ) { + if ( !flags.once ) { + stack.push( [ context, args ] ); + } + } else if ( !( flags.once && memory ) ) { + fire( context, args ); + } + } + 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; +}; + + + + +var // Static reference to slice + sliceDeferred = [].slice; + +jQuery.extend({ + + Deferred: function( func ) { + var doneList = jQuery.Callbacks( "once memory" ), + failList = jQuery.Callbacks( "once memory" ), + progressList = jQuery.Callbacks( "memory" ), + state = "pending", + lists = { + resolve: doneList, + reject: failList, + notify: progressList + }, + promise = { + done: doneList.add, + fail: failList.add, + progress: progressList.add, + + state: function() { + return state; + }, + + // Deprecated + isResolved: doneList.fired, + isRejected: failList.fired, + + then: function( doneCallbacks, failCallbacks, progressCallbacks ) { + deferred.done( doneCallbacks ).fail( failCallbacks ).progress( progressCallbacks ); + return this; + }, + always: function() { + deferred.done.apply( deferred, arguments ).fail.apply( deferred, arguments ); + return this; + }, + pipe: function( fnDone, fnFail, fnProgress ) { + return jQuery.Deferred(function( newDefer ) { + jQuery.each( { + done: [ fnDone, "resolve" ], + fail: [ fnFail, "reject" ], + progress: [ fnProgress, "notify" ] + }, function( handler, data ) { + var fn = data[ 0 ], + action = data[ 1 ], + returned; + if ( jQuery.isFunction( fn ) ) { + deferred[ handler ](function() { + returned = fn.apply( this, arguments ); + if ( returned && jQuery.isFunction( returned.promise ) ) { + returned.promise().then( newDefer.resolve, newDefer.reject, newDefer.notify ); + } else { + newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] ); + } + }); + } else { + deferred[ handler ]( newDefer[ action ] ); + } + }); + }).promise(); + }, + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + if ( obj == null ) { + obj = promise; + } else { + for ( var key in promise ) { + obj[ key ] = promise[ key ]; + } + } + return obj; + } + }, + deferred = promise.promise({}), + key; + + for ( key in lists ) { + deferred[ key ] = lists[ key ].fire; + deferred[ key + "With" ] = lists[ key ].fireWith; + } + + // Handle state + deferred.done( function() { + state = "resolved"; + }, failList.disable, progressList.lock ).fail( function() { + state = "rejected"; + }, doneList.disable, progressList.lock ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( firstParam ) { + var args = sliceDeferred.call( arguments, 0 ), + i = 0, + length = args.length, + pValues = new Array( length ), + count = length, + pCount = length, + deferred = length <= 1 && firstParam && jQuery.isFunction( firstParam.promise ) ? + firstParam : + jQuery.Deferred(), + promise = deferred.promise(); + function resolveFunc( i ) { + return function( value ) { + args[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value; + if ( !( --count ) ) { + deferred.resolveWith( deferred, args ); + } + }; + } + function progressFunc( i ) { + return function( value ) { + pValues[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value; + deferred.notifyWith( promise, pValues ); + }; + } + if ( length > 1 ) { + for ( ; i < length; i++ ) { + if ( args[ i ] && args[ i ].promise && jQuery.isFunction( args[ i ].promise ) ) { + args[ i ].promise().then( resolveFunc(i), deferred.reject, progressFunc(i) ); + } else { + --count; + } + } + if ( !count ) { + deferred.resolveWith( deferred, args ); + } + } else if ( deferred !== firstParam ) { + deferred.resolveWith( deferred, length ? [ firstParam ] : [] ); + } + return promise; + } +}); + + + + +jQuery.support = (function() { + + var support, + all, + a, + select, + opt, + input, + fragment, + tds, + events, + eventName, + i, + isSupported, + div = document.createElement( "div" ), + documentElement = document.documentElement; + + // Preliminary tests + div.setAttribute("className", "t"); + div.innerHTML = "
      a"; + + all = div.getElementsByTagName( "*" ); + a = div.getElementsByTagName( "a" )[ 0 ]; + + // Can't get basic test support + if ( !all || !all.length || !a ) { + return {}; + } + + // First batch of supports tests + select = document.createElement( "select" ); + opt = select.appendChild( document.createElement("option") ); + input = div.getElementsByTagName( "input" )[ 0 ]; + + support = { + // IE strips leading whitespace when .innerHTML is used + leadingWhitespace: ( div.firstChild.nodeType === 3 ), + + // Make sure that tbody elements aren't automatically inserted + // IE will insert them into empty tables + tbody: !div.getElementsByTagName("tbody").length, + + // Make sure that link elements get serialized correctly by innerHTML + // This requires a wrapper element in IE + htmlSerialize: !!div.getElementsByTagName("link").length, + + // Get the style information from getAttribute + // (IE uses .cssText instead) + style: /top/.test( a.getAttribute("style") ), + + // Make sure that URLs aren't manipulated + // (IE normalizes it by default) + hrefNormalized: ( a.getAttribute("href") === "/a" ), + + // Make sure that element opacity exists + // (IE uses filter instead) + // Use a regex to work around a WebKit issue. See #5145 + opacity: /^0.55/.test( a.style.opacity ), + + // Verify style float existence + // (IE uses styleFloat instead of cssFloat) + cssFloat: !!a.style.cssFloat, + + // Make sure that if no value is specified for a checkbox + // that it defaults to "on". + // (WebKit defaults to "" instead) + checkOn: ( input.value === "on" ), + + // Make sure that a selected-by-default option has a working selected property. + // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) + optSelected: opt.selected, + + // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7) + getSetAttribute: div.className !== "t", + + // Tests for enctype support on a form(#6743) + enctype: !!document.createElement("form").enctype, + + // Makes sure cloning an html5 element does not cause problems + // Where outerHTML is undefined, this still works + html5Clone: document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav>", + + // Will be defined later + submitBubbles: true, + changeBubbles: true, + focusinBubbles: false, + deleteExpando: true, + noCloneEvent: true, + inlineBlockNeedsLayout: false, + shrinkWrapBlocks: false, + reliableMarginRight: true, + pixelMargin: true + }; + + // jQuery.boxModel DEPRECATED in 1.3, use jQuery.support.boxModel instead + jQuery.boxModel = support.boxModel = (document.compatMode === "CSS1Compat"); + + // Make sure checked status is properly cloned + input.checked = true; + support.noCloneChecked = input.cloneNode( true ).checked; + + // Make sure that the options inside disabled selects aren't marked as disabled + // (WebKit marks them as disabled) + select.disabled = true; + support.optDisabled = !opt.disabled; + + // Test to see if it's possible to delete an expando from an element + // Fails in Internet Explorer + try { + delete div.test; + } catch( e ) { + support.deleteExpando = false; + } + + if ( !div.addEventListener && div.attachEvent && div.fireEvent ) { + div.attachEvent( "onclick", function() { + // Cloning a node shouldn't copy over any + // bound event handlers (IE does this) + support.noCloneEvent = false; + }); + div.cloneNode( true ).fireEvent( "onclick" ); + } + + // Check if a radio maintains its value + // after being appended to the DOM + input = document.createElement("input"); + input.value = "t"; + input.setAttribute("type", "radio"); + support.radioValue = input.value === "t"; + + input.setAttribute("checked", "checked"); + + // #11217 - WebKit loses check when the name is after the checked attribute + input.setAttribute( "name", "t" ); + + div.appendChild( input ); + fragment = document.createDocumentFragment(); + fragment.appendChild( div.lastChild ); + + // WebKit doesn't clone checked state correctly in fragments + support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Check if a disconnected checkbox will retain its checked + // value of true after appended to the DOM (IE6/7) + support.appendChecked = input.checked; + + fragment.removeChild( input ); + fragment.appendChild( div ); + + // Technique from Juriy Zaytsev + // http://perfectionkills.com/detecting-event-support-without-browser-sniffing/ + // We only care about the case where non-standard event systems + // are used, namely in IE. Short-circuiting here helps us to + // avoid an eval call (in setAttribute) which can cause CSP + // to go haywire. See: https://developer.mozilla.org/en/Security/CSP + if ( div.attachEvent ) { + for ( i in { + submit: 1, + change: 1, + focusin: 1 + }) { + eventName = "on" + i; + isSupported = ( eventName in div ); + if ( !isSupported ) { + div.setAttribute( eventName, "return;" ); + isSupported = ( typeof div[ eventName ] === "function" ); + } + support[ i + "Bubbles" ] = isSupported; + } + } + + fragment.removeChild( div ); + + // Null elements to avoid leaks in IE + fragment = select = opt = div = input = null; + + // Run tests that need a body at doc ready + jQuery(function() { + var container, outer, inner, table, td, offsetSupport, + marginDiv, conMarginTop, style, html, positionTopLeftWidthHeight, + paddingMarginBorderVisibility, paddingMarginBorder, + body = document.getElementsByTagName("body")[0]; + + if ( !body ) { + // Return for frameset docs that don't have a body + return; + } + + conMarginTop = 1; + paddingMarginBorder = "padding:0;margin:0;border:"; + positionTopLeftWidthHeight = "position:absolute;top:0;left:0;width:1px;height:1px;"; + paddingMarginBorderVisibility = paddingMarginBorder + "0;visibility:hidden;"; + style = "style='" + positionTopLeftWidthHeight + paddingMarginBorder + "5px solid #000;"; + html = "
      " + + "" + + "
      "; + + container = document.createElement("div"); + container.style.cssText = paddingMarginBorderVisibility + "width:0;height:0;position:static;top:0;margin-top:" + conMarginTop + "px"; + body.insertBefore( container, body.firstChild ); + + // Construct the test element + div = document.createElement("div"); + container.appendChild( div ); + + // Check if table cells still have offsetWidth/Height when they are set + // to display:none and there are still other visible table cells in a + // table row; if so, offsetWidth/Height are not reliable for use when + // determining if an element has been hidden directly using + // display:none (it is still safe to use offsets if a parent element is + // hidden; don safety goggles and see bug #4512 for more information). + // (only IE 8 fails this test) + div.innerHTML = "
      t
      "; + tds = div.getElementsByTagName( "td" ); + isSupported = ( tds[ 0 ].offsetHeight === 0 ); + + tds[ 0 ].style.display = ""; + tds[ 1 ].style.display = "none"; + + // Check if empty table cells still have offsetWidth/Height + // (IE <= 8 fail this test) + support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 ); + + // Check if div with explicit width and no margin-right incorrectly + // gets computed margin-right based on width of container. For more + // info see bug #3333 + // Fails in WebKit before Feb 2011 nightlies + // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right + if ( window.getComputedStyle ) { + div.innerHTML = ""; + marginDiv = document.createElement( "div" ); + marginDiv.style.width = "0"; + marginDiv.style.marginRight = "0"; + div.style.width = "2px"; + div.appendChild( marginDiv ); + support.reliableMarginRight = + ( parseInt( ( window.getComputedStyle( marginDiv, null ) || { marginRight: 0 } ).marginRight, 10 ) || 0 ) === 0; + } + + if ( typeof div.style.zoom !== "undefined" ) { + // Check if natively block-level elements act like inline-block + // elements when setting their display to 'inline' and giving + // them layout + // (IE < 8 does this) + div.innerHTML = ""; + div.style.width = div.style.padding = "1px"; + div.style.border = 0; + div.style.overflow = "hidden"; + div.style.display = "inline"; + div.style.zoom = 1; + support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 ); + + // Check if elements with layout shrink-wrap their children + // (IE 6 does this) + div.style.display = "block"; + div.style.overflow = "visible"; + div.innerHTML = "
      "; + support.shrinkWrapBlocks = ( div.offsetWidth !== 3 ); + } + + div.style.cssText = positionTopLeftWidthHeight + paddingMarginBorderVisibility; + div.innerHTML = html; + + outer = div.firstChild; + inner = outer.firstChild; + td = outer.nextSibling.firstChild.firstChild; + + offsetSupport = { + doesNotAddBorder: ( inner.offsetTop !== 5 ), + doesAddBorderForTableAndCells: ( td.offsetTop === 5 ) + }; + + inner.style.position = "fixed"; + inner.style.top = "20px"; + + // safari subtracts parent border width here which is 5px + offsetSupport.fixedPosition = ( inner.offsetTop === 20 || inner.offsetTop === 15 ); + inner.style.position = inner.style.top = ""; + + outer.style.overflow = "hidden"; + outer.style.position = "relative"; + + offsetSupport.subtractsBorderForOverflowNotVisible = ( inner.offsetTop === -5 ); + offsetSupport.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== conMarginTop ); + + if ( window.getComputedStyle ) { + div.style.marginTop = "1%"; + support.pixelMargin = ( window.getComputedStyle( div, null ) || { marginTop: 0 } ).marginTop !== "1%"; + } + + if ( typeof container.style.zoom !== "undefined" ) { + container.style.zoom = 1; + } + + body.removeChild( container ); + marginDiv = div = container = null; + + jQuery.extend( support, offsetSupport ); + }); + + return support; +})(); + + + + +var rbrace = /^(?:\{.*\}|\[.*\])$/, + rmultiDash = /([A-Z])/g; + +jQuery.extend({ + cache: {}, + + // Please use with caution + uuid: 0, + + // Unique for each copy of jQuery on the page + // Non-digits removed to match rinlinejQuery + expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ), + + // The following elements throw uncatchable exceptions if you + // attempt to add expando properties to them. + noData: { + "embed": true, + // Ban all objects except for Flash (which handle expandos) + "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000", + "applet": true + }, + + hasData: function( elem ) { + elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ]; + return !!elem && !isEmptyDataObject( elem ); + }, + + data: function( elem, name, data, pvt /* Internal Use Only */ ) { + if ( !jQuery.acceptData( elem ) ) { + return; + } + + var privateCache, thisCache, ret, + internalKey = jQuery.expando, + getByName = typeof name === "string", + + // 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, + isEvents = name === "events"; + + // 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] || (!isEvents && !pvt && !cache[id].data)) && getByName && data === undefined ) { + 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 ) { + elem[ internalKey ] = id = ++jQuery.uuid; + } else { + id = internalKey; + } + } + + if ( !cache[ id ] ) { + cache[ id ] = {}; + + // Avoids exposing jQuery metadata on plain JS objects when the object + // is serialized using JSON.stringify + if ( !isNode ) { + cache[ id ].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 ); + } + } + + privateCache = 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; + } + + // Users should not attempt to inspect the internal events object using jQuery.data, + // it is undocumented and subject to change. But does anyone listen? No. + if ( isEvents && !thisCache[ name ] ) { + return privateCache.events; + } + + // Check for both converted-to-camel and non-converted data property names + // If a data property was specified + if ( getByName ) { + + // 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; + }, + + removeData: function( elem, name, pvt /* Internal Use Only */ ) { + if ( !jQuery.acceptData( elem ) ) { + return; + } + + var thisCache, i, l, + + // Reference to internal data cache key + internalKey = jQuery.expando, + + isNode = elem.nodeType, + + // See jQuery.data for more information + cache = isNode ? jQuery.cache : elem, + + // See jQuery.data for more information + id = isNode ? elem[ internalKey ] : internalKey; + + // 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( " " ); + } + } + } + + for ( i = 0, l = name.length; i < l; 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 : 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; + } + } + + // Browsers that fail expando deletion also refuse to delete expandos on + // the window, but it will allow it on all other JS objects; other browsers + // don't care + // Ensure that `cache` is not a window object #10080 + if ( jQuery.support.deleteExpando || !cache.setInterval ) { + delete cache[ id ]; + } else { + cache[ id ] = null; + } + + // We destroyed the cache and need to eliminate the expando on the node to avoid + // false lookups in the cache for entries that no longer exist + if ( isNode ) { + // IE does not allow us to delete expando properties from nodes, + // nor does it have a removeAttribute function on Document nodes; + // we must handle all of these cases + if ( jQuery.support.deleteExpando ) { + delete elem[ internalKey ]; + } else if ( elem.removeAttribute ) { + elem.removeAttribute( internalKey ); + } else { + elem[ internalKey ] = null; + } + } + }, + + // For internal use only. + _data: function( elem, name, data ) { + return jQuery.data( elem, name, data, true ); + }, + + // A method for determining if a DOM node can handle the data expando + acceptData: function( elem ) { + if ( elem.nodeName ) { + var match = jQuery.noData[ elem.nodeName.toLowerCase() ]; + + if ( match ) { + return !(match === true || elem.getAttribute("classid") !== match); + } + } + + return true; + } +}); + +jQuery.fn.extend({ + data: function( key, value ) { + var parts, part, attr, name, l, + elem = this[0], + i = 0, + data = null; + + // Gets all values + if ( key === undefined ) { + if ( this.length ) { + data = jQuery.data( elem ); + + if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) { + attr = elem.attributes; + for ( l = attr.length; i < l; i++ ) { + name = attr[i].name; + + if ( name.indexOf( "data-" ) === 0 ) { + name = jQuery.camelCase( name.substring(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 ); + }); + } + + parts = key.split( ".", 2 ); + parts[1] = parts[1] ? "." + parts[1] : ""; + part = parts[1] + "!"; + + return jQuery.access( this, function( value ) { + + if ( value === undefined ) { + data = this.triggerHandler( "getData" + part, [ parts[0] ] ); + + // Try to fetch any internally stored data first + if ( data === undefined && elem ) { + data = jQuery.data( elem, key ); + data = dataAttr( elem, key, data ); + } + + return data === undefined && parts[1] ? + this.data( parts[0] ) : + data; + } + + parts[1] = value; + this.each(function() { + var self = jQuery( this ); + + self.triggerHandler( "setData" + part, parts ); + jQuery.data( this, key, value ); + self.triggerHandler( "changeData" + part, parts ); + }); + }, null, value, arguments.length > 1, null, false ); + }, + + removeData: function( key ) { + return this.each(function() { + jQuery.removeData( this, key ); + }); + } +}); + +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 : + jQuery.isNumeric( 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 ) { + for ( var 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 handleQueueMarkDefer( elem, type, src ) { + var deferDataKey = type + "defer", + queueDataKey = type + "queue", + markDataKey = type + "mark", + defer = jQuery._data( elem, deferDataKey ); + if ( defer && + ( src === "queue" || !jQuery._data(elem, queueDataKey) ) && + ( src === "mark" || !jQuery._data(elem, markDataKey) ) ) { + // Give room for hard-coded callbacks to fire first + // and eventually mark/queue something else on the element + setTimeout( function() { + if ( !jQuery._data( elem, queueDataKey ) && + !jQuery._data( elem, markDataKey ) ) { + jQuery.removeData( elem, deferDataKey, true ); + defer.fire(); + } + }, 0 ); + } +} + +jQuery.extend({ + + _mark: function( elem, type ) { + if ( elem ) { + type = ( type || "fx" ) + "mark"; + jQuery._data( elem, type, (jQuery._data( elem, type ) || 0) + 1 ); + } + }, + + _unmark: function( force, elem, type ) { + if ( force !== true ) { + type = elem; + elem = force; + force = false; + } + if ( elem ) { + type = type || "fx"; + var key = type + "mark", + count = force ? 0 : ( (jQuery._data( elem, key ) || 1) - 1 ); + if ( count ) { + jQuery._data( elem, key, count ); + } else { + jQuery.removeData( elem, key, true ); + handleQueueMarkDefer( elem, type, "mark" ); + } + } + }, + + queue: function( elem, type, data ) { + var q; + if ( elem ) { + type = ( type || "fx" ) + "queue"; + q = jQuery._data( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !q || jQuery.isArray(data) ) { + q = jQuery._data( elem, type, jQuery.makeArray(data) ); + } else { + q.push( data ); + } + } + return q || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + fn = queue.shift(), + hooks = {}; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + } + + if ( fn ) { + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift( "inprogress" ); + } + + jQuery._data( elem, type + ".run", hooks ); + fn.call( elem, function() { + jQuery.dequeue( elem, type ); + }, hooks ); + } + + if ( !queue.length ) { + jQuery.removeData( elem, type + "queue " + type + ".run", true ); + handleQueueMarkDefer( elem, type, "queue" ); + } + } +}); + +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 ); + + if ( type === "fx" && queue[0] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + }); + }, + dequeue: function( type ) { + return this.each(function() { + jQuery.dequeue( this, type ); + }); + }, + // Based off of the plugin by Clint Helfers, with permission. + // http://blindsignals.com/index.php/2009/07/jquery-delay/ + delay: function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; + type = type || "fx"; + + return this.queue( type, function( next, hooks ) { + var timeout = setTimeout( next, time ); + hooks.stop = function() { + clearTimeout( timeout ); + }; + }); + }, + 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, object ) { + if ( typeof type !== "string" ) { + object = type; + type = undefined; + } + type = type || "fx"; + var defer = jQuery.Deferred(), + elements = this, + i = elements.length, + count = 1, + deferDataKey = type + "defer", + queueDataKey = type + "queue", + markDataKey = type + "mark", + tmp; + function resolve() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + } + while( i-- ) { + if (( tmp = jQuery.data( elements[ i ], deferDataKey, undefined, true ) || + ( jQuery.data( elements[ i ], queueDataKey, undefined, true ) || + jQuery.data( elements[ i ], markDataKey, undefined, true ) ) && + jQuery.data( elements[ i ], deferDataKey, jQuery.Callbacks( "once memory" ), true ) )) { + count++; + tmp.add( resolve ); + } + } + resolve(); + return defer.promise( object ); + } +}); + + + + +var rclass = /[\n\t\r]/g, + rspace = /\s+/, + rreturn = /\r/g, + rtype = /^(?:button|input)$/i, + rfocusable = /^(?:button|input|object|select|textarea)$/i, + rclickable = /^a(?:rea)?$/i, + rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i, + getSetAttribute = jQuery.support.getSetAttribute, + nodeHook, boolHook, fixSpecified; + +jQuery.fn.extend({ + attr: function( name, value ) { + return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 ); + }, + + removeAttr: function( name ) { + return this.each(function() { + jQuery.removeAttr( this, name ); + }); + }, + + prop: function( name, value ) { + return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 ); + }, + + removeProp: function( name ) { + name = jQuery.propFix[ name ] || name; + return this.each(function() { + // try/catch handles cases where IE balks (such as removing a property on window) + try { + this[ name ] = undefined; + delete this[ name ]; + } catch( e ) {} + }); + }, + + addClass: function( value ) { + var classNames, i, l, elem, + setClass, c, cl; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( j ) { + jQuery( this ).addClass( value.call(this, j, this.className) ); + }); + } + + if ( value && typeof value === "string" ) { + classNames = value.split( rspace ); + + for ( i = 0, l = this.length; i < l; i++ ) { + elem = this[ i ]; + + if ( elem.nodeType === 1 ) { + if ( !elem.className && classNames.length === 1 ) { + elem.className = value; + + } else { + setClass = " " + elem.className + " "; + + for ( c = 0, cl = classNames.length; c < cl; c++ ) { + if ( !~setClass.indexOf( " " + classNames[ c ] + " " ) ) { + setClass += classNames[ c ] + " "; + } + } + elem.className = jQuery.trim( setClass ); + } + } + } + } + + return this; + }, + + removeClass: function( value ) { + var classNames, i, l, elem, className, c, cl; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( j ) { + jQuery( this ).removeClass( value.call(this, j, this.className) ); + }); + } + + if ( (value && typeof value === "string") || value === undefined ) { + classNames = ( value || "" ).split( rspace ); + + for ( i = 0, l = this.length; i < l; i++ ) { + elem = this[ i ]; + + if ( elem.nodeType === 1 && elem.className ) { + if ( value ) { + className = (" " + elem.className + " ").replace( rclass, " " ); + for ( c = 0, cl = classNames.length; c < cl; c++ ) { + className = className.replace(" " + classNames[ c ] + " ", " "); + } + elem.className = jQuery.trim( className ); + + } else { + elem.className = ""; + } + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value, + isBool = typeof stateVal === "boolean"; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( i ) { + jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal ); + }); + } + + return this.each(function() { + if ( type === "string" ) { + // toggle individual class names + var className, + i = 0, + self = jQuery( this ), + state = stateVal, + classNames = value.split( rspace ); + + while ( (className = classNames[ i++ ]) ) { + // check each className given, space seperated list + state = isBool ? state : !self.hasClass( className ); + self[ state ? "addClass" : "removeClass" ]( className ); + } + + } else if ( type === "undefined" || type === "boolean" ) { + if ( this.className ) { + // store className if set + jQuery._data( this, "__className__", this.className ); + } + + // toggle whole className + this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || ""; + } + }); + }, + + hasClass: function( selector ) { + var className = " " + selector + " ", + i = 0, + l = this.length; + for ( ; i < l; i++ ) { + if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) { + return true; + } + } + + return false; + }, + + val: function( value ) { + var hooks, ret, isFunction, + elem = this[0]; + + if ( !arguments.length ) { + if ( elem ) { + hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ]; + + if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) { + return ret; + } + + ret = elem.value; + + return typeof ret === "string" ? + // handle most common string cases + ret.replace(rreturn, "") : + // handle cases where value is null/undef or number + ret == null ? "" : ret; + } + + return; + } + + isFunction = jQuery.isFunction( value ); + + return this.each(function( i ) { + var self = jQuery(this), val; + + if ( this.nodeType !== 1 ) { + return; + } + + if ( isFunction ) { + val = value.call( this, i, self.val() ); + } else { + val = value; + } + + // Treat null/undefined as ""; convert numbers to string + if ( val == null ) { + val = ""; + } else if ( typeof val === "number" ) { + val += ""; + } else if ( jQuery.isArray( val ) ) { + val = jQuery.map(val, function ( value ) { + return value == null ? "" : value + ""; + }); + } + + hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; + + // If set returns undefined, fall back to normal setting + if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) { + this.value = val; + } + }); + } +}); + +jQuery.extend({ + valHooks: { + option: { + get: function( elem ) { + // attributes.value is undefined in Blackberry 4.7 but + // uses .value. See #6932 + var val = elem.attributes.value; + return !val || val.specified ? elem.value : elem.text; + } + }, + select: { + get: function( elem ) { + var value, i, max, option, + index = elem.selectedIndex, + values = [], + options = elem.options, + one = elem.type === "select-one"; + + // Nothing was selected + if ( index < 0 ) { + return null; + } + + // Loop through all the selected options + i = one ? index : 0; + max = one ? index + 1 : options.length; + for ( ; i < max; i++ ) { + option = options[ i ]; + + // Don't return options that are disabled or in a disabled optgroup + if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) && + (!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) { + + // Get the specific value for the option + value = jQuery( option ).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + // Fixes Bug #2551 -- select.val() broken in IE after form.reset() + if ( one && !values.length && options.length ) { + return jQuery( options[ index ] ).val(); + } + + return values; + }, + + set: function( elem, value ) { + var values = jQuery.makeArray( value ); + + jQuery(elem).find("option").each(function() { + this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0; + }); + + if ( !values.length ) { + elem.selectedIndex = -1; + } + return values; + } + } + }, + + attrFn: { + val: true, + css: true, + html: true, + text: true, + data: true, + width: true, + height: true, + offset: true + }, + + attr: function( elem, name, value, pass ) { + var ret, hooks, notxml, + nType = elem.nodeType; + + // don't get/set attributes on text, comment and attribute nodes + if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + if ( pass && name in jQuery.attrFn ) { + return jQuery( elem )[ name ]( value ); + } + + // Fallback to prop when attributes are not supported + if ( typeof elem.getAttribute === "undefined" ) { + return jQuery.prop( elem, name, value ); + } + + notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); + + // All attributes are lowercase + // Grab necessary hook if one is defined + if ( notxml ) { + name = name.toLowerCase(); + hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook ); + } + + if ( value !== undefined ) { + + if ( value === null ) { + jQuery.removeAttr( elem, name ); + return; + + } else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) { + return ret; + + } else { + elem.setAttribute( name, "" + value ); + return value; + } + + } else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) { + return ret; + + } else { + + ret = elem.getAttribute( name ); + + // Non-existent attributes return null, we normalize to undefined + return ret === null ? + undefined : + ret; + } + }, + + removeAttr: function( elem, value ) { + var propName, attrNames, name, l, isBool, + i = 0; + + if ( value && elem.nodeType === 1 ) { + attrNames = value.toLowerCase().split( rspace ); + l = attrNames.length; + + for ( ; i < l; i++ ) { + name = attrNames[ i ]; + + if ( name ) { + propName = jQuery.propFix[ name ] || name; + isBool = rboolean.test( name ); + + // See #9699 for explanation of this approach (setting first, then removal) + // Do not do this for boolean attributes (see #10870) + if ( !isBool ) { + jQuery.attr( elem, name, "" ); + } + elem.removeAttribute( getSetAttribute ? name : propName ); + + // Set corresponding property to false for boolean attributes + if ( isBool && propName in elem ) { + elem[ propName ] = false; + } + } + } + } + }, + + attrHooks: { + type: { + set: function( elem, value ) { + // We can't allow the type property to be changed (since it causes problems in IE) + if ( rtype.test( elem.nodeName ) && elem.parentNode ) { + jQuery.error( "type property can't be changed" ); + } else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) { + // Setting the type on a radio button after the value resets the value in IE6-9 + // Reset value to it's default in case type is set after value + // This is for element creation + var val = elem.value; + elem.setAttribute( "type", value ); + if ( val ) { + elem.value = val; + } + return value; + } + } + }, + // Use the value property for back compat + // Use the nodeHook for button elements in IE6/7 (#1954) + value: { + get: function( elem, name ) { + if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { + return nodeHook.get( elem, name ); + } + return name in elem ? + elem.value : + null; + }, + set: function( elem, value, name ) { + if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { + return nodeHook.set( elem, value, name ); + } + // Does not return so that setAttribute is also used + elem.value = value; + } + } + }, + + propFix: { + tabindex: "tabIndex", + readonly: "readOnly", + "for": "htmlFor", + "class": "className", + maxlength: "maxLength", + cellspacing: "cellSpacing", + cellpadding: "cellPadding", + rowspan: "rowSpan", + colspan: "colSpan", + usemap: "useMap", + frameborder: "frameBorder", + contenteditable: "contentEditable" + }, + + prop: function( elem, name, value ) { + var ret, hooks, notxml, + nType = elem.nodeType; + + // don't get/set properties on text, comment and attribute nodes + if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); + + if ( notxml ) { + // Fix name and attach hooks + name = jQuery.propFix[ name ] || name; + hooks = jQuery.propHooks[ name ]; + } + + if ( value !== undefined ) { + if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) { + return ret; + + } else { + return ( elem[ name ] = value ); + } + + } else { + if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) { + return ret; + + } else { + return elem[ name ]; + } + } + }, + + propHooks: { + tabIndex: { + get: function( elem ) { + // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set + // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + var attributeNode = elem.getAttributeNode("tabindex"); + + return attributeNode && attributeNode.specified ? + parseInt( attributeNode.value, 10 ) : + rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? + 0 : + undefined; + } + } + } +}); + +// Add the tabIndex propHook to attrHooks for back-compat (different case is intentional) +jQuery.attrHooks.tabindex = jQuery.propHooks.tabIndex; + +// Hook for boolean attributes +boolHook = { + get: function( elem, name ) { + // Align boolean attributes with corresponding properties + // Fall back to attribute presence where some booleans are not supported + var attrNode, + property = jQuery.prop( elem, name ); + return property === true || typeof property !== "boolean" && ( attrNode = elem.getAttributeNode(name) ) && attrNode.nodeValue !== false ? + name.toLowerCase() : + undefined; + }, + set: function( elem, value, name ) { + var propName; + if ( value === false ) { + // Remove boolean attributes when set to false + jQuery.removeAttr( elem, name ); + } else { + // value is true since we know at this point it's type boolean and not false + // Set boolean attributes to the same name and set the DOM property + propName = jQuery.propFix[ name ] || name; + if ( propName in elem ) { + // Only set the IDL specifically if it already exists on the element + elem[ propName ] = true; + } + + elem.setAttribute( name, name.toLowerCase() ); + } + return name; + } +}; + +// IE6/7 do not support getting/setting some attributes with get/setAttribute +if ( !getSetAttribute ) { + + fixSpecified = { + name: true, + id: true, + coords: true + }; + + // Use this for any attribute in IE6/7 + // This fixes almost every IE6/7 issue + nodeHook = jQuery.valHooks.button = { + get: function( elem, name ) { + var ret; + ret = elem.getAttributeNode( name ); + return ret && ( fixSpecified[ name ] ? ret.nodeValue !== "" : ret.specified ) ? + ret.nodeValue : + undefined; + }, + set: function( elem, value, name ) { + // Set the existing or create a new attribute node + var ret = elem.getAttributeNode( name ); + if ( !ret ) { + ret = document.createAttribute( name ); + elem.setAttributeNode( ret ); + } + return ( ret.nodeValue = value + "" ); + } + }; + + // Apply the nodeHook to tabindex + jQuery.attrHooks.tabindex.set = nodeHook.set; + + // Set width and height to auto instead of 0 on empty string( Bug #8150 ) + // This is for removals + jQuery.each([ "width", "height" ], function( i, name ) { + jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { + set: function( elem, value ) { + if ( value === "" ) { + elem.setAttribute( name, "auto" ); + return value; + } + } + }); + }); + + // Set contenteditable to false on removals(#10429) + // Setting to empty string throws an error as an invalid value + jQuery.attrHooks.contenteditable = { + get: nodeHook.get, + set: function( elem, value, name ) { + if ( value === "" ) { + value = "false"; + } + nodeHook.set( elem, value, name ); + } + }; +} + + +// Some attributes require a special call on IE +if ( !jQuery.support.hrefNormalized ) { + jQuery.each([ "href", "src", "width", "height" ], function( i, name ) { + jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { + get: function( elem ) { + var ret = elem.getAttribute( name, 2 ); + return ret === null ? undefined : ret; + } + }); + }); +} + +if ( !jQuery.support.style ) { + jQuery.attrHooks.style = { + get: function( elem ) { + // Return undefined in the case of empty string + // Normalize to lowercase since IE uppercases css property names + return elem.style.cssText.toLowerCase() || undefined; + }, + set: function( elem, value ) { + return ( elem.style.cssText = "" + value ); + } + }; +} + +// Safari mis-reports the default selected property of an option +// Accessing the parent's selectedIndex property fixes it +if ( !jQuery.support.optSelected ) { + jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, { + get: function( elem ) { + var parent = elem.parentNode; + + if ( parent ) { + parent.selectedIndex; + + // Make sure that it also works with optgroups, see #5701 + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + return null; + } + }); +} + +// IE6/7 call enctype encoding +if ( !jQuery.support.enctype ) { + jQuery.propFix.enctype = "encoding"; +} + +// Radios and checkboxes getter/setter +if ( !jQuery.support.checkOn ) { + jQuery.each([ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = { + get: function( elem ) { + // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified + return elem.getAttribute("value") === null ? "on" : elem.value; + } + }; + }); +} +jQuery.each([ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], { + set: function( elem, value ) { + if ( jQuery.isArray( value ) ) { + return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 ); + } + } + }); +}); + + + + +var rformElems = /^(?:textarea|input|select)$/i, + rtypenamespace = /^([^\.]*)?(?:\.(.+))?$/, + rhoverHack = /(?:^|\s)hover(\.\S+)?\b/, + rkeyEvent = /^key/, + rmouseEvent = /^(?:mouse|contextmenu)|click/, + rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, + rquickIs = /^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/, + quickParse = function( selector ) { + var quick = rquickIs.exec( selector ); + if ( quick ) { + // 0 1 2 3 + // [ _, tag, id, class ] + quick[1] = ( quick[1] || "" ).toLowerCase(); + quick[3] = quick[3] && new RegExp( "(?:^|\\s)" + quick[3] + "(?:\\s|$)" ); + } + return quick; + }, + quickIs = function( elem, m ) { + var attrs = elem.attributes || {}; + return ( + (!m[1] || elem.nodeName.toLowerCase() === m[1]) && + (!m[2] || (attrs.id || {}).value === m[2]) && + (!m[3] || m[3].test( (attrs[ "class" ] || {}).value )) + ); + }, + hoverHack = function( events ) { + return jQuery.event.special.hover ? events : events.replace( rhoverHack, "mouseenter$1 mouseleave$1" ); + }; + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + add: function( elem, types, handler, data, selector ) { + + var elemData, eventHandle, events, + t, tns, type, namespaces, handleObj, + handleObjIn, quick, handlers, special; + + // Don't attach events to noData or text/comment nodes (allow plain objects tho) + if ( elem.nodeType === 3 || elem.nodeType === 8 || !types || !handler || !(elemData = jQuery._data( elem )) ) { + 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 + events = elemData.events; + if ( !events ) { + elemData.events = events = {}; + } + eventHandle = elemData.handle; + if ( !eventHandle ) { + elemData.handle = eventHandle = 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 + // jQuery(...).bind("mouseover mouseout", fn); + types = jQuery.trim( hoverHack(types) ).split( " " ); + for ( t = 0; t < types.length; t++ ) { + + tns = rtypenamespace.exec( types[t] ) || []; + type = tns[1]; + namespaces = ( tns[2] || "" ).split( "." ).sort(); + + // 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: tns[1], + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + quick: selector && quickParse( selector ), + namespace: namespaces.join(".") + }, handleObjIn ); + + // Init the event handler queue if we're the first + handlers = events[ type ]; + if ( !handlers ) { + 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; + }, + + global: {}, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + + var elemData = jQuery.hasData( elem ) && jQuery._data( elem ), + t, tns, type, origType, namespaces, origCount, + j, events, special, handle, eventType, handleObj; + + if ( !elemData || !(events = elemData.events) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = jQuery.trim( hoverHack( types || "" ) ).split(" "); + for ( t = 0; t < types.length; t++ ) { + tns = rtypenamespace.exec( types[t] ) || []; + type = origType = tns[1]; + namespaces = tns[2]; + + // 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; + eventType = events[ type ] || []; + origCount = eventType.length; + namespaces = namespaces ? new RegExp("(^|\\.)" + namespaces.split(".").sort().join("\\.(?:.*\\.)?") + "(\\.|$)") : null; + + // Remove matching events + for ( j = 0; j < eventType.length; j++ ) { + handleObj = eventType[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !namespaces || namespaces.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) { + eventType.splice( j--, 1 ); + + if ( handleObj.selector ) { + eventType.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 ( eventType.length === 0 && origCount !== eventType.length ) { + if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) { + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + handle = elemData.handle; + if ( handle ) { + handle.elem = null; + } + + // removeData also checks for emptiness and clears the expando if empty + // so use it instead of delete + jQuery.removeData( elem, [ "events", "handle" ], true ); + } + }, + + // Events that are safe to short-circuit if no handlers are attached. + // Native DOM events should not be added, they may have inline handlers. + customEvent: { + "getData": true, + "setData": true, + "changeData": true + }, + + trigger: function( event, data, elem, onlyHandlers ) { + // Don't do events on text and comment nodes + if ( elem && (elem.nodeType === 3 || elem.nodeType === 8) ) { + return; + } + + // Event object or event type + var type = event.type || event, + namespaces = [], + cache, exclusive, i, cur, old, ontype, special, handle, eventPath, bubbleType; + + // 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( "!" ) >= 0 ) { + // Exclusive events trigger only for the exact event (no namespaces) + type = type.slice(0, -1); + exclusive = true; + } + + if ( type.indexOf( "." ) >= 0 ) { + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split("."); + type = namespaces.shift(); + namespaces.sort(); + } + + if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) { + // No jQuery handlers for this event type, and it can't have inline handlers + return; + } + + // Caller can pass in an Event, Object, or just an event type string + event = typeof event === "object" ? + // jQuery.Event object + event[ jQuery.expando ] ? event : + // Object literal + new jQuery.Event( type, event ) : + // Just the event type (string) + new jQuery.Event( type ); + + event.type = type; + event.isTrigger = true; + event.exclusive = exclusive; + event.namespace = namespaces.join( "." ); + event.namespace_re = event.namespace? new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.)?") + "(\\.|$)") : null; + ontype = type.indexOf( ":" ) < 0 ? "on" + type : ""; + + // Handle a global trigger + if ( !elem ) { + + // TODO: Stop taunting the data cache; remove global events and always attach to document + cache = jQuery.cache; + for ( i in cache ) { + if ( cache[ i ].events && cache[ i ].events[ type ] ) { + jQuery.event.trigger( event, data, cache[ i ].handle.elem, true ); + } + } + return; + } + + // 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 ? jQuery.makeArray( data ) : []; + data.unshift( event ); + + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( 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) + eventPath = [[ elem, special.bindType || type ]]; + if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + cur = rfocusMorph.test( bubbleType + type ) ? elem : elem.parentNode; + old = null; + for ( ; cur; cur = cur.parentNode ) { + eventPath.push([ cur, bubbleType ]); + old = cur; + } + + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( old && old === elem.ownerDocument ) { + eventPath.push([ old.defaultView || old.parentWindow || window, bubbleType ]); + } + } + + // Fire handlers on the event path + for ( i = 0; i < eventPath.length && !event.isPropagationStopped(); i++ ) { + + cur = eventPath[i][0]; + event.type = eventPath[i][1]; + + handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + // Note that this is a bare JS function and not a jQuery handler + handle = ontype && cur[ ontype ]; + if ( handle && jQuery.acceptData( cur ) && handle.apply( cur, data ) === 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( elem.ownerDocument, data ) === false) && + !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.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) + // IE<9 dies on focus/blur to hidden element (#1486) + if ( ontype && elem[ type ] && ((type !== "focus" && type !== "blur") || event.target.offsetWidth !== 0) && !jQuery.isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + old = elem[ ontype ]; + + if ( old ) { + elem[ ontype ] = null; + } + + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + elem[ type ](); + jQuery.event.triggered = undefined; + + if ( old ) { + elem[ ontype ] = old; + } + } + } + } + + return event.result; + }, + + dispatch: function( event ) { + + // Make a writable jQuery.Event from the native event object + event = jQuery.event.fix( event || window.event ); + + var handlers = ( (jQuery._data( this, "events" ) || {} )[ event.type ] || []), + delegateCount = handlers.delegateCount, + args = [].slice.call( arguments, 0 ), + run_all = !event.exclusive && !event.namespace, + special = jQuery.event.special[ event.type ] || {}, + handlerQueue = [], + i, j, cur, jqcur, ret, selMatch, matched, matches, handleObj, sel, related; + + // 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 that should run if there are delegated events + // Avoid non-left-click bubbling in Firefox (#3861) + if ( delegateCount && !(event.button && event.type === "click") ) { + + // Pregenerate a single jQuery object for reuse with .is() + jqcur = jQuery(this); + jqcur.context = this.ownerDocument || this; + + for ( cur = event.target; cur != this; cur = cur.parentNode || this ) { + + // Don't process events on disabled elements (#6911, #8165) + if ( cur.disabled !== true ) { + selMatch = {}; + matches = []; + jqcur[0] = cur; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + sel = handleObj.selector; + + if ( selMatch[ sel ] === undefined ) { + selMatch[ sel ] = ( + handleObj.quick ? quickIs( cur, handleObj.quick ) : jqcur.is( sel ) + ); + } + if ( selMatch[ sel ] ) { + matches.push( handleObj ); + } + } + if ( matches.length ) { + handlerQueue.push({ elem: cur, matches: matches }); + } + } + } + } + + // Add the remaining (directly-bound) handlers + if ( handlers.length > delegateCount ) { + handlerQueue.push({ elem: this, matches: handlers.slice( delegateCount ) }); + } + + // Run delegates first; they may want to stop propagation beneath us + for ( i = 0; i < handlerQueue.length && !event.isPropagationStopped(); i++ ) { + matched = handlerQueue[ i ]; + event.currentTarget = matched.elem; + + for ( j = 0; j < matched.matches.length && !event.isImmediatePropagationStopped(); j++ ) { + handleObj = matched.matches[ j ]; + + // Triggered event must either 1) be non-exclusive and have no namespace, or + // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace). + if ( run_all || (!event.namespace && !handleObj.namespace) || event.namespace_re && event.namespace_re.test( handleObj.namespace ) ) { + + event.data = handleObj.data; + event.handleObj = handleObj; + + ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler ) + .apply( matched.elem, args ); + + if ( ret !== undefined ) { + event.result = ret; + if ( 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; + }, + + // Includes some event props shared by KeyEvent and MouseEvent + // *** attrChange attrName relatedNode srcElement are not normalized, non-W3C, deprecated, will be removed in 1.8 *** + props: "attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget 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 eventDoc, doc, body, + 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; + } + }, + + fix: function( event ) { + if ( event[ jQuery.expando ] ) { + return event; + } + + // Create a writable copy of the event object and normalize some properties + var i, prop, + originalEvent = event, + fixHook = jQuery.event.fixHooks[ event.type ] || {}, + copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props; + + event = jQuery.Event( originalEvent ); + + for ( i = copy.length; i; ) { + prop = copy[ --i ]; + event[ prop ] = originalEvent[ prop ]; + } + + // Fix target property, if necessary (#1925, IE 6/7/8 & Safari2) + if ( !event.target ) { + event.target = originalEvent.srcElement || document; + } + + // Target should not be a text node (#504, Safari) + if ( event.target.nodeType === 3 ) { + event.target = event.target.parentNode; + } + + // For mouse/key events; add metaKey if it's not there (#3368, IE6/7/8) + if ( event.metaKey === undefined ) { + event.metaKey = event.ctrlKey; + } + + return fixHook.filter? fixHook.filter( event, originalEvent ) : event; + }, + + special: { + ready: { + // Make sure the ready event is setup + setup: jQuery.bindReady + }, + + load: { + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + + focus: { + delegateType: "focusin" + }, + blur: { + delegateType: "focusout" + }, + + beforeunload: { + setup: function( data, namespaces, eventHandle ) { + // We only want to do this special case on windows + if ( jQuery.isWindow( this ) ) { + this.onbeforeunload = eventHandle; + } + }, + + teardown: function( namespaces, eventHandle ) { + if ( this.onbeforeunload === eventHandle ) { + this.onbeforeunload = null; + } + } + } + }, + + simulate: function( type, elem, event, bubble ) { + // Piggyback on a donor event to simulate a different one. + // Fake originalEvent to avoid donor's stopPropagation, but if the + // simulated event prevents default then we do the same on the donor. + var e = jQuery.extend( + new jQuery.Event(), + event, + { type: type, + isSimulated: true, + originalEvent: {} + } + ); + if ( bubble ) { + jQuery.event.trigger( e, null, elem ); + } else { + jQuery.event.dispatch.call( elem, e ); + } + if ( e.isDefaultPrevented() ) { + event.preventDefault(); + } + } +}; + +// Some plugins are using, but it's undocumented/deprecated and will be removed. +// The 1.7 special event interface should provide all the hooks needed now. +jQuery.event.handle = jQuery.event.dispatch; + +jQuery.removeEvent = document.removeEventListener ? + function( elem, type, handle ) { + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle, false ); + } + } : + function( elem, type, handle ) { + if ( elem.detachEvent ) { + elem.detachEvent( "on" + type, 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.returnValue === false || + src.getPreventDefault && src.getPreventDefault() ) ? 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; +}; + +function returnFalse() { + return false; +} +function returnTrue() { + return 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 = { + preventDefault: function() { + this.isDefaultPrevented = returnTrue; + + var e = this.originalEvent; + if ( !e ) { + return; + } + + // if preventDefault exists run it on the original event + if ( e.preventDefault ) { + e.preventDefault(); + + // otherwise set the returnValue property of the original event to false (IE) + } else { + e.returnValue = false; + } + }, + stopPropagation: function() { + this.isPropagationStopped = returnTrue; + + var e = this.originalEvent; + if ( !e ) { + return; + } + // if stopPropagation exists run it on the original event + if ( e.stopPropagation ) { + e.stopPropagation(); + } + // otherwise set the cancelBubble property of the original event to true (IE) + e.cancelBubble = true; + }, + stopImmediatePropagation: function() { + this.isImmediatePropagationStopped = returnTrue; + this.stopPropagation(); + }, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse +}; + +// Create mouseenter/leave events using mouseover/out and event-time checks +jQuery.each({ + mouseenter: "mouseover", + mouseleave: "mouseout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var target = this, + related = event.relatedTarget, + handleObj = event.handleObj, + selector = handleObj.selector, + ret; + + // For mousenter/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 ( !jQuery.support.submitBubbles ) { + + 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" ) ? elem.form : undefined; + if ( form && !form._submit_attached ) { + jQuery.event.add( form, "submit._submit", function( event ) { + event._submit_bubble = true; + }); + form._submit_attached = 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._submit_bubble ) { + delete event._submit_bubble; + if ( this.parentNode && !event.isTrigger ) { + jQuery.event.simulate( "submit", this.parentNode, event, true ); + } + } + }, + + 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 ( !jQuery.support.changeBubbles ) { + + 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._just_changed = true; + } + }); + jQuery.event.add( this, "click._change", function( event ) { + if ( this._just_changed && !event.isTrigger ) { + this._just_changed = false; + jQuery.event.simulate( "change", this, event, true ); + } + }); + } + 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 ) && !elem._change_attached ) { + jQuery.event.add( elem, "change._change", function( event ) { + if ( this.parentNode && !event.isSimulated && !event.isTrigger ) { + jQuery.event.simulate( "change", this.parentNode, event, true ); + } + }); + elem._change_attached = 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 ); + } + }; +} + +// Create "bubbling" focus and blur events +if ( !jQuery.support.focusinBubbles ) { + jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler while someone wants focusin/focusout + var attaches = 0, + handler = function( event ) { + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true ); + }; + + jQuery.event.special[ fix ] = { + setup: function() { + if ( attaches++ === 0 ) { + document.addEventListener( orig, handler, true ); + } + }, + teardown: function() { + if ( --attaches === 0 ) { + document.removeEventListener( orig, handler, true ); + } + } + }; + }); +} + +jQuery.fn.extend({ + + on: function( types, selector, data, fn, /*INTERNAL*/ one ) { + var origFn, type; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { // && selector != null + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + this.on( type, selector, data, types[ type ], one ); + } + return this; + } + + 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 this; + } + + 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 this.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + }); + }, + one: function( types, selector, data, fn ) { + return this.on( types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + if ( types && types.preventDefault && types.handleObj ) { + // ( event ) dispatched jQuery.Event + var 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 ( var 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 ); + }); + }, + + bind: function( types, data, fn ) { + return this.on( types, null, data, fn ); + }, + unbind: function( types, fn ) { + return this.off( types, null, fn ); + }, + + live: function( types, data, fn ) { + jQuery( this.context ).on( types, this.selector, data, fn ); + return this; + }, + die: function( types, fn ) { + jQuery( this.context ).off( types, this.selector || "**", fn ); + return this; + }, + + delegate: function( selector, types, data, fn ) { + return this.on( types, selector, data, fn ); + }, + undelegate: function( selector, types, fn ) { + // ( namespace ) or ( selector, types [, fn] ) + return arguments.length == 1? this.off( selector, "**" ) : this.off( types, selector, fn ); + }, + + trigger: function( type, data ) { + return this.each(function() { + jQuery.event.trigger( type, data, this ); + }); + }, + triggerHandler: function( type, data ) { + if ( this[0] ) { + return jQuery.event.trigger( type, data, this[0], true ); + } + }, + + toggle: function( fn ) { + // Save reference to arguments for access in closure + var args = arguments, + guid = fn.guid || jQuery.guid++, + i = 0, + toggler = function( event ) { + // Figure out which function to execute + var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i; + jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 ); + + // Make sure that clicks stop + event.preventDefault(); + + // and execute the function + return args[ lastToggle ].apply( this, arguments ) || false; + }; + + // link all the functions, so any of them can unbind this click handler + toggler.guid = guid; + while ( i < args.length ) { + args[ i++ ].guid = guid; + } + + return this.click( toggler ); + }, + + hover: function( fnOver, fnOut ) { + return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); + } +}); + +jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " + + "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + + "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) { + + // Handle event binding + jQuery.fn[ name ] = function( data, fn ) { + if ( fn == null ) { + fn = data; + data = null; + } + + return arguments.length > 0 ? + this.on( name, null, data, fn ) : + this.trigger( name ); + }; + + if ( jQuery.attrFn ) { + jQuery.attrFn[ name ] = true; + } + + if ( rkeyEvent.test( name ) ) { + jQuery.event.fixHooks[ name ] = jQuery.event.keyHooks; + } + + if ( rmouseEvent.test( name ) ) { + jQuery.event.fixHooks[ name ] = jQuery.event.mouseHooks; + } +}); + + + +/*! + * Sizzle CSS Selector Engine + * Copyright 2011, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * More information: http://sizzlejs.com/ + */ +(function(){ + +var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, + expando = "sizcache" + (Math.random() + '').replace('.', ''), + done = 0, + toString = Object.prototype.toString, + hasDuplicate = false, + baseHasDuplicate = true, + rBackslash = /\\/g, + rReturn = /\r\n/g, + rNonWord = /\W/; + +// Here we check if the JavaScript engine is using some sort of +// optimization where it does not always call our comparision +// function. If that is the case, discard the hasDuplicate value. +// Thus far that includes Google Chrome. +[0, 0].sort(function() { + baseHasDuplicate = false; + return 0; +}); + +var Sizzle = function( selector, context, results, seed ) { + results = results || []; + context = context || document; + + var origContext = context; + + if ( context.nodeType !== 1 && context.nodeType !== 9 ) { + return []; + } + + if ( !selector || typeof selector !== "string" ) { + return results; + } + + var m, set, checkSet, extra, ret, cur, pop, i, + prune = true, + contextXML = Sizzle.isXML( context ), + parts = [], + soFar = selector; + + // Reset the position of the chunker regexp (start from head) + do { + chunker.exec( "" ); + m = chunker.exec( soFar ); + + if ( m ) { + soFar = m[3]; + + parts.push( m[1] ); + + if ( m[2] ) { + extra = m[3]; + break; + } + } + } while ( m ); + + if ( parts.length > 1 && origPOS.exec( selector ) ) { + + if ( parts.length === 2 && Expr.relative[ parts[0] ] ) { + set = posProcess( parts[0] + parts[1], context, seed ); + + } else { + set = Expr.relative[ parts[0] ] ? + [ context ] : + Sizzle( parts.shift(), context ); + + while ( parts.length ) { + selector = parts.shift(); + + if ( Expr.relative[ selector ] ) { + selector += parts.shift(); + } + + set = posProcess( selector, set, seed ); + } + } + + } else { + // Take a shortcut and set the context if the root selector is an ID + // (but not if it'll be faster if the inner selector is an ID) + if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML && + Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) { + + ret = Sizzle.find( parts.shift(), context, contextXML ); + context = ret.expr ? + Sizzle.filter( ret.expr, ret.set )[0] : + ret.set[0]; + } + + if ( context ) { + ret = seed ? + { expr: parts.pop(), set: makeArray(seed) } : + Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML ); + + set = ret.expr ? + Sizzle.filter( ret.expr, ret.set ) : + ret.set; + + if ( parts.length > 0 ) { + checkSet = makeArray( set ); + + } else { + prune = false; + } + + while ( parts.length ) { + cur = parts.pop(); + pop = cur; + + if ( !Expr.relative[ cur ] ) { + cur = ""; + } else { + pop = parts.pop(); + } + + if ( pop == null ) { + pop = context; + } + + Expr.relative[ cur ]( checkSet, pop, contextXML ); + } + + } else { + checkSet = parts = []; + } + } + + if ( !checkSet ) { + checkSet = set; + } + + if ( !checkSet ) { + Sizzle.error( cur || selector ); + } + + if ( toString.call(checkSet) === "[object Array]" ) { + if ( !prune ) { + results.push.apply( results, checkSet ); + + } else if ( context && context.nodeType === 1 ) { + for ( i = 0; checkSet[i] != null; i++ ) { + if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && Sizzle.contains(context, checkSet[i])) ) { + results.push( set[i] ); + } + } + + } else { + for ( i = 0; checkSet[i] != null; i++ ) { + if ( checkSet[i] && checkSet[i].nodeType === 1 ) { + results.push( set[i] ); + } + } + } + + } else { + makeArray( checkSet, results ); + } + + if ( extra ) { + Sizzle( extra, origContext, results, seed ); + Sizzle.uniqueSort( results ); + } + + return results; +}; + +Sizzle.uniqueSort = function( results ) { + if ( sortOrder ) { + hasDuplicate = baseHasDuplicate; + results.sort( sortOrder ); + + if ( hasDuplicate ) { + for ( var i = 1; i < results.length; i++ ) { + if ( results[i] === results[ i - 1 ] ) { + results.splice( i--, 1 ); + } + } + } + } + + return results; +}; + +Sizzle.matches = function( expr, set ) { + return Sizzle( expr, null, null, set ); +}; + +Sizzle.matchesSelector = function( node, expr ) { + return Sizzle( expr, null, null, [node] ).length > 0; +}; + +Sizzle.find = function( expr, context, isXML ) { + var set, i, len, match, type, left; + + if ( !expr ) { + return []; + } + + for ( i = 0, len = Expr.order.length; i < len; i++ ) { + type = Expr.order[i]; + + if ( (match = Expr.leftMatch[ type ].exec( expr )) ) { + left = match[1]; + match.splice( 1, 1 ); + + if ( left.substr( left.length - 1 ) !== "\\" ) { + match[1] = (match[1] || "").replace( rBackslash, "" ); + set = Expr.find[ type ]( match, context, isXML ); + + if ( set != null ) { + expr = expr.replace( Expr.match[ type ], "" ); + break; + } + } + } + } + + if ( !set ) { + set = typeof context.getElementsByTagName !== "undefined" ? + context.getElementsByTagName( "*" ) : + []; + } + + return { set: set, expr: expr }; +}; + +Sizzle.filter = function( expr, set, inplace, not ) { + var match, anyFound, + type, found, item, filter, left, + i, pass, + old = expr, + result = [], + curLoop = set, + isXMLFilter = set && set[0] && Sizzle.isXML( set[0] ); + + while ( expr && set.length ) { + for ( type in Expr.filter ) { + if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) { + filter = Expr.filter[ type ]; + left = match[1]; + + anyFound = false; + + match.splice(1,1); + + if ( left.substr( left.length - 1 ) === "\\" ) { + continue; + } + + if ( curLoop === result ) { + result = []; + } + + if ( Expr.preFilter[ type ] ) { + match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter ); + + if ( !match ) { + anyFound = found = true; + + } else if ( match === true ) { + continue; + } + } + + if ( match ) { + for ( i = 0; (item = curLoop[i]) != null; i++ ) { + if ( item ) { + found = filter( item, match, i, curLoop ); + pass = not ^ found; + + if ( inplace && found != null ) { + if ( pass ) { + anyFound = true; + + } else { + curLoop[i] = false; + } + + } else if ( pass ) { + result.push( item ); + anyFound = true; + } + } + } + } + + if ( found !== undefined ) { + if ( !inplace ) { + curLoop = result; + } + + expr = expr.replace( Expr.match[ type ], "" ); + + if ( !anyFound ) { + return []; + } + + break; + } + } + } + + // Improper expression + if ( expr === old ) { + if ( anyFound == null ) { + Sizzle.error( expr ); + + } else { + break; + } + } + + old = expr; + } + + return curLoop; +}; + +Sizzle.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +/** + * Utility function for retreiving the text value of an array of DOM nodes + * @param {Array|Element} elem + */ +var getText = Sizzle.getText = function( elem ) { + var i, node, + nodeType = elem.nodeType, + ret = ""; + + if ( nodeType ) { + if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + // Use textContent || innerText for elements + if ( typeof elem.textContent === 'string' ) { + return elem.textContent; + } else if ( typeof elem.innerText === 'string' ) { + // Replace IE's carriage returns + return elem.innerText.replace( rReturn, '' ); + } else { + // Traverse it's children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling) { + ret += getText( elem ); + } + } + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + } else { + + // If no nodeType, this is expected to be an array + for ( i = 0; (node = elem[i]); i++ ) { + // Do not traverse comment nodes + if ( node.nodeType !== 8 ) { + ret += getText( node ); + } + } + } + return ret; +}; + +var Expr = Sizzle.selectors = { + order: [ "ID", "NAME", "TAG" ], + + match: { + ID: /#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/, + CLASS: /\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/, + NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/, + ATTR: /\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/, + TAG: /^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/, + CHILD: /:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/, + POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/, + PSEUDO: /:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/ + }, + + leftMatch: {}, + + attrMap: { + "class": "className", + "for": "htmlFor" + }, + + attrHandle: { + href: function( elem ) { + return elem.getAttribute( "href" ); + }, + type: function( elem ) { + return elem.getAttribute( "type" ); + } + }, + + relative: { + "+": function(checkSet, part){ + var isPartStr = typeof part === "string", + isTag = isPartStr && !rNonWord.test( part ), + isPartStrNotTag = isPartStr && !isTag; + + if ( isTag ) { + part = part.toLowerCase(); + } + + for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) { + if ( (elem = checkSet[i]) ) { + while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {} + + checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ? + elem || false : + elem === part; + } + } + + if ( isPartStrNotTag ) { + Sizzle.filter( part, checkSet, true ); + } + }, + + ">": function( checkSet, part ) { + var elem, + isPartStr = typeof part === "string", + i = 0, + l = checkSet.length; + + if ( isPartStr && !rNonWord.test( part ) ) { + part = part.toLowerCase(); + + for ( ; i < l; i++ ) { + elem = checkSet[i]; + + if ( elem ) { + var parent = elem.parentNode; + checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false; + } + } + + } else { + for ( ; i < l; i++ ) { + elem = checkSet[i]; + + if ( elem ) { + checkSet[i] = isPartStr ? + elem.parentNode : + elem.parentNode === part; + } + } + + if ( isPartStr ) { + Sizzle.filter( part, checkSet, true ); + } + } + }, + + "": function(checkSet, part, isXML){ + var nodeCheck, + doneName = done++, + checkFn = dirCheck; + + if ( typeof part === "string" && !rNonWord.test( part ) ) { + part = part.toLowerCase(); + nodeCheck = part; + checkFn = dirNodeCheck; + } + + checkFn( "parentNode", part, doneName, checkSet, nodeCheck, isXML ); + }, + + "~": function( checkSet, part, isXML ) { + var nodeCheck, + doneName = done++, + checkFn = dirCheck; + + if ( typeof part === "string" && !rNonWord.test( part ) ) { + part = part.toLowerCase(); + nodeCheck = part; + checkFn = dirNodeCheck; + } + + checkFn( "previousSibling", part, doneName, checkSet, nodeCheck, isXML ); + } + }, + + find: { + ID: function( match, context, isXML ) { + if ( typeof context.getElementById !== "undefined" && !isXML ) { + var m = context.getElementById(match[1]); + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + return m && m.parentNode ? [m] : []; + } + }, + + NAME: function( match, context ) { + if ( typeof context.getElementsByName !== "undefined" ) { + var ret = [], + results = context.getElementsByName( match[1] ); + + for ( var i = 0, l = results.length; i < l; i++ ) { + if ( results[i].getAttribute("name") === match[1] ) { + ret.push( results[i] ); + } + } + + return ret.length === 0 ? null : ret; + } + }, + + TAG: function( match, context ) { + if ( typeof context.getElementsByTagName !== "undefined" ) { + return context.getElementsByTagName( match[1] ); + } + } + }, + preFilter: { + CLASS: function( match, curLoop, inplace, result, not, isXML ) { + match = " " + match[1].replace( rBackslash, "" ) + " "; + + if ( isXML ) { + return match; + } + + for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) { + if ( elem ) { + if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n\r]/g, " ").indexOf(match) >= 0) ) { + if ( !inplace ) { + result.push( elem ); + } + + } else if ( inplace ) { + curLoop[i] = false; + } + } + } + + return false; + }, + + ID: function( match ) { + return match[1].replace( rBackslash, "" ); + }, + + TAG: function( match, curLoop ) { + return match[1].replace( rBackslash, "" ).toLowerCase(); + }, + + CHILD: function( match ) { + if ( match[1] === "nth" ) { + if ( !match[2] ) { + Sizzle.error( match[0] ); + } + + match[2] = match[2].replace(/^\+|\s*/g, ''); + + // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6' + var test = /(-?)(\d*)(?:n([+\-]?\d*))?/.exec( + match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" || + !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]); + + // calculate the numbers (first)n+(last) including if they are negative + match[2] = (test[1] + (test[2] || 1)) - 0; + match[3] = test[3] - 0; + } + else if ( match[2] ) { + Sizzle.error( match[0] ); + } + + // TODO: Move to normal caching system + match[0] = done++; + + return match; + }, + + ATTR: function( match, curLoop, inplace, result, not, isXML ) { + var name = match[1] = match[1].replace( rBackslash, "" ); + + if ( !isXML && Expr.attrMap[name] ) { + match[1] = Expr.attrMap[name]; + } + + // Handle if an un-quoted value was used + match[4] = ( match[4] || match[5] || "" ).replace( rBackslash, "" ); + + if ( match[2] === "~=" ) { + match[4] = " " + match[4] + " "; + } + + return match; + }, + + PSEUDO: function( match, curLoop, inplace, result, not ) { + if ( match[1] === "not" ) { + // If we're dealing with a complex expression, or a simple one + if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) { + match[3] = Sizzle(match[3], null, null, curLoop); + + } else { + var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not); + + if ( !inplace ) { + result.push.apply( result, ret ); + } + + return false; + } + + } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) { + return true; + } + + return match; + }, + + POS: function( match ) { + match.unshift( true ); + + return match; + } + }, + + filters: { + enabled: function( elem ) { + return elem.disabled === false && elem.type !== "hidden"; + }, + + disabled: function( elem ) { + return elem.disabled === true; + }, + + checked: function( elem ) { + return elem.checked === true; + }, + + 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; + }, + + parent: function( elem ) { + return !!elem.firstChild; + }, + + empty: function( elem ) { + return !elem.firstChild; + }, + + has: function( elem, i, match ) { + return !!Sizzle( match[3], elem ).length; + }, + + header: function( elem ) { + return (/h\d/i).test( elem.nodeName ); + }, + + text: function( elem ) { + var attr = elem.getAttribute( "type" ), type = elem.type; + // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) + // use getAttribute instead to test this case + return elem.nodeName.toLowerCase() === "input" && "text" === type && ( attr === type || attr === null ); + }, + + radio: function( elem ) { + return elem.nodeName.toLowerCase() === "input" && "radio" === elem.type; + }, + + checkbox: function( elem ) { + return elem.nodeName.toLowerCase() === "input" && "checkbox" === elem.type; + }, + + file: function( elem ) { + return elem.nodeName.toLowerCase() === "input" && "file" === elem.type; + }, + + password: function( elem ) { + return elem.nodeName.toLowerCase() === "input" && "password" === elem.type; + }, + + submit: function( elem ) { + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && "submit" === elem.type; + }, + + image: function( elem ) { + return elem.nodeName.toLowerCase() === "input" && "image" === elem.type; + }, + + reset: function( elem ) { + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && "reset" === elem.type; + }, + + button: function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && "button" === elem.type || name === "button"; + }, + + input: function( elem ) { + return (/input|select|textarea|button/i).test( elem.nodeName ); + }, + + focus: function( elem ) { + return elem === elem.ownerDocument.activeElement; + } + }, + setFilters: { + first: function( elem, i ) { + return i === 0; + }, + + last: function( elem, i, match, array ) { + return i === array.length - 1; + }, + + even: function( elem, i ) { + return i % 2 === 0; + }, + + odd: function( elem, i ) { + return i % 2 === 1; + }, + + lt: function( elem, i, match ) { + return i < match[3] - 0; + }, + + gt: function( elem, i, match ) { + return i > match[3] - 0; + }, + + nth: function( elem, i, match ) { + return match[3] - 0 === i; + }, + + eq: function( elem, i, match ) { + return match[3] - 0 === i; + } + }, + filter: { + PSEUDO: function( elem, match, i, array ) { + var name = match[1], + filter = Expr.filters[ name ]; + + if ( filter ) { + return filter( elem, i, match, array ); + + } else if ( name === "contains" ) { + return (elem.textContent || elem.innerText || getText([ elem ]) || "").indexOf(match[3]) >= 0; + + } else if ( name === "not" ) { + var not = match[3]; + + for ( var j = 0, l = not.length; j < l; j++ ) { + if ( not[j] === elem ) { + return false; + } + } + + return true; + + } else { + Sizzle.error( name ); + } + }, + + CHILD: function( elem, match ) { + var first, last, + doneName, parent, cache, + count, diff, + type = match[1], + node = elem; + + switch ( type ) { + case "only": + case "first": + while ( (node = node.previousSibling) ) { + if ( node.nodeType === 1 ) { + return false; + } + } + + if ( type === "first" ) { + return true; + } + + node = elem; + + /* falls through */ + case "last": + while ( (node = node.nextSibling) ) { + if ( node.nodeType === 1 ) { + return false; + } + } + + return true; + + case "nth": + first = match[2]; + last = match[3]; + + if ( first === 1 && last === 0 ) { + return true; + } + + doneName = match[0]; + parent = elem.parentNode; + + if ( parent && (parent[ expando ] !== doneName || !elem.nodeIndex) ) { + count = 0; + + for ( node = parent.firstChild; node; node = node.nextSibling ) { + if ( node.nodeType === 1 ) { + node.nodeIndex = ++count; + } + } + + parent[ expando ] = doneName; + } + + diff = elem.nodeIndex - last; + + if ( first === 0 ) { + return diff === 0; + + } else { + return ( diff % first === 0 && diff / first >= 0 ); + } + } + }, + + ID: function( elem, match ) { + return elem.nodeType === 1 && elem.getAttribute("id") === match; + }, + + TAG: function( elem, match ) { + return (match === "*" && elem.nodeType === 1) || !!elem.nodeName && elem.nodeName.toLowerCase() === match; + }, + + CLASS: function( elem, match ) { + return (" " + (elem.className || elem.getAttribute("class")) + " ") + .indexOf( match ) > -1; + }, + + ATTR: function( elem, match ) { + var name = match[1], + result = Sizzle.attr ? + Sizzle.attr( elem, name ) : + Expr.attrHandle[ name ] ? + Expr.attrHandle[ name ]( elem ) : + elem[ name ] != null ? + elem[ name ] : + elem.getAttribute( name ), + value = result + "", + type = match[2], + check = match[4]; + + return result == null ? + type === "!=" : + !type && Sizzle.attr ? + result != null : + type === "=" ? + value === check : + type === "*=" ? + value.indexOf(check) >= 0 : + type === "~=" ? + (" " + value + " ").indexOf(check) >= 0 : + !check ? + value && result !== false : + type === "!=" ? + value !== check : + type === "^=" ? + value.indexOf(check) === 0 : + type === "$=" ? + value.substr(value.length - check.length) === check : + type === "|=" ? + value === check || value.substr(0, check.length + 1) === check + "-" : + false; + }, + + POS: function( elem, match, i, array ) { + var name = match[2], + filter = Expr.setFilters[ name ]; + + if ( filter ) { + return filter( elem, i, match, array ); + } + } + } +}; + +var origPOS = Expr.match.POS, + fescape = function(all, num){ + return "\\" + (num - 0 + 1); + }; + +for ( var type in Expr.match ) { + Expr.match[ type ] = new RegExp( Expr.match[ type ].source + (/(?![^\[]*\])(?![^\(]*\))/.source) ); + Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, fescape) ); +} +// Expose origPOS +// "global" as in regardless of relation to brackets/parens +Expr.match.globalPOS = origPOS; + +var makeArray = function( array, results ) { + array = Array.prototype.slice.call( array, 0 ); + + if ( results ) { + results.push.apply( results, array ); + return results; + } + + return array; +}; + +// Perform a simple check to determine if the browser is capable of +// converting a NodeList to an array using builtin methods. +// Also verifies that the returned array holds DOM nodes +// (which is not the case in the Blackberry browser) +try { + Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType; + +// Provide a fallback method if it does not work +} catch( e ) { + makeArray = function( array, results ) { + var i = 0, + ret = results || []; + + if ( toString.call(array) === "[object Array]" ) { + Array.prototype.push.apply( ret, array ); + + } else { + if ( typeof array.length === "number" ) { + for ( var l = array.length; i < l; i++ ) { + ret.push( array[i] ); + } + + } else { + for ( ; array[i]; i++ ) { + ret.push( array[i] ); + } + } + } + + return ret; + }; +} + +var sortOrder, siblingCheck; + +if ( document.documentElement.compareDocumentPosition ) { + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) { + return a.compareDocumentPosition ? -1 : 1; + } + + return a.compareDocumentPosition(b) & 4 ? -1 : 1; + }; + +} else { + sortOrder = function( a, b ) { + // The nodes are identical, we can exit early + if ( a === b ) { + hasDuplicate = true; + return 0; + + // Fallback to using sourceIndex (in IE) if it's available on both nodes + } else if ( a.sourceIndex && b.sourceIndex ) { + return a.sourceIndex - b.sourceIndex; + } + + var al, bl, + ap = [], + bp = [], + aup = a.parentNode, + bup = b.parentNode, + cur = aup; + + // If the nodes are siblings (or identical) we can do a quick check + if ( aup === bup ) { + return siblingCheck( a, b ); + + // If no parents were found then the nodes are disconnected + } else if ( !aup ) { + return -1; + + } else if ( !bup ) { + return 1; + } + + // Otherwise they're somewhere else in the tree so we need + // to build up a full list of the parentNodes for comparison + while ( cur ) { + ap.unshift( cur ); + cur = cur.parentNode; + } + + cur = bup; + + while ( cur ) { + bp.unshift( cur ); + cur = cur.parentNode; + } + + al = ap.length; + bl = bp.length; + + // Start walking down the tree looking for a discrepancy + for ( var i = 0; i < al && i < bl; i++ ) { + if ( ap[i] !== bp[i] ) { + return siblingCheck( ap[i], bp[i] ); + } + } + + // We ended someplace up the tree so do a sibling check + return i === al ? + siblingCheck( a, bp[i], -1 ) : + siblingCheck( ap[i], b, 1 ); + }; + + siblingCheck = function( a, b, ret ) { + if ( a === b ) { + return ret; + } + + var cur = a.nextSibling; + + while ( cur ) { + if ( cur === b ) { + return -1; + } + + cur = cur.nextSibling; + } + + return 1; + }; +} + +// Check to see if the browser returns elements by name when +// querying by getElementById (and provide a workaround) +(function(){ + // We're going to inject a fake input element with a specified name + var form = document.createElement("div"), + id = "script" + (new Date()).getTime(), + root = document.documentElement; + + form.innerHTML = "
      "; + + // Inject it into the root element, check its status, and remove it quickly + root.insertBefore( form, root.firstChild ); + + // The workaround has to do additional checks after a getElementById + // Which slows things down for other browsers (hence the branching) + if ( document.getElementById( id ) ) { + Expr.find.ID = function( match, context, isXML ) { + if ( typeof context.getElementById !== "undefined" && !isXML ) { + var m = context.getElementById(match[1]); + + return m ? + m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? + [m] : + undefined : + []; + } + }; + + Expr.filter.ID = function( elem, match ) { + var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id"); + + return elem.nodeType === 1 && node && node.nodeValue === match; + }; + } + + root.removeChild( form ); + + // release memory in IE + root = form = null; +})(); + +(function(){ + // Check to see if the browser returns only elements + // when doing getElementsByTagName("*") + + // Create a fake element + var div = document.createElement("div"); + div.appendChild( document.createComment("") ); + + // Make sure no comments are found + if ( div.getElementsByTagName("*").length > 0 ) { + Expr.find.TAG = function( match, context ) { + var results = context.getElementsByTagName( match[1] ); + + // Filter out possible comments + if ( match[1] === "*" ) { + var tmp = []; + + for ( var i = 0; results[i]; i++ ) { + if ( results[i].nodeType === 1 ) { + tmp.push( results[i] ); + } + } + + results = tmp; + } + + return results; + }; + } + + // Check to see if an attribute returns normalized href attributes + div.innerHTML = ""; + + if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" && + div.firstChild.getAttribute("href") !== "#" ) { + + Expr.attrHandle.href = function( elem ) { + return elem.getAttribute( "href", 2 ); + }; + } + + // release memory in IE + div = null; +})(); + +if ( document.querySelectorAll ) { + (function(){ + var oldSizzle = Sizzle, + div = document.createElement("div"), + id = "__sizzle__"; + + div.innerHTML = "

      "; + + // Safari can't handle uppercase or unicode characters when + // in quirks mode. + if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) { + return; + } + + Sizzle = function( query, context, extra, seed ) { + context = context || document; + + // Only use querySelectorAll on non-XML documents + // (ID selectors don't work in non-HTML documents) + if ( !seed && !Sizzle.isXML(context) ) { + // See if we find a selector to speed up + var match = /^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec( query ); + + if ( match && (context.nodeType === 1 || context.nodeType === 9) ) { + // Speed-up: Sizzle("TAG") + if ( match[1] ) { + return makeArray( context.getElementsByTagName( query ), extra ); + + // Speed-up: Sizzle(".CLASS") + } else if ( match[2] && Expr.find.CLASS && context.getElementsByClassName ) { + return makeArray( context.getElementsByClassName( match[2] ), extra ); + } + } + + if ( context.nodeType === 9 ) { + // Speed-up: Sizzle("body") + // The body element only exists once, optimize finding it + if ( query === "body" && context.body ) { + return makeArray( [ context.body ], extra ); + + // Speed-up: Sizzle("#ID") + } else if ( match && match[3] ) { + var elem = context.getElementById( match[3] ); + + // 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[3] ) { + return makeArray( [ elem ], extra ); + } + + } else { + return makeArray( [], extra ); + } + } + + try { + return makeArray( context.querySelectorAll(query), extra ); + } catch(qsaError) {} + + // qSA works strangely on Element-rooted queries + // We can work around this by specifying an extra ID on the root + // and working up from there (Thanks to Andrew Dupont for the technique) + // IE 8 doesn't work on object elements + } else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) { + var oldContext = context, + old = context.getAttribute( "id" ), + nid = old || id, + hasParent = context.parentNode, + relativeHierarchySelector = /^\s*[+~]/.test( query ); + + if ( !old ) { + context.setAttribute( "id", nid ); + } else { + nid = nid.replace( /'/g, "\\$&" ); + } + if ( relativeHierarchySelector && hasParent ) { + context = context.parentNode; + } + + try { + if ( !relativeHierarchySelector || hasParent ) { + return makeArray( context.querySelectorAll( "[id='" + nid + "'] " + query ), extra ); + } + + } catch(pseudoError) { + } finally { + if ( !old ) { + oldContext.removeAttribute( "id" ); + } + } + } + } + + return oldSizzle(query, context, extra, seed); + }; + + for ( var prop in oldSizzle ) { + Sizzle[ prop ] = oldSizzle[ prop ]; + } + + // release memory in IE + div = null; + })(); +} + +(function(){ + var html = document.documentElement, + matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector; + + if ( matches ) { + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9 fails this) + var disconnectedMatch = !matches.call( document.createElement( "div" ), "div" ), + pseudoWorks = false; + + try { + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( document.documentElement, "[test!='']:sizzle" ); + + } catch( pseudoError ) { + pseudoWorks = true; + } + + Sizzle.matchesSelector = function( node, expr ) { + // Make sure that attribute selectors are quoted + expr = expr.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']"); + + if ( !Sizzle.isXML( node ) ) { + try { + if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) { + var ret = matches.call( node, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || !disconnectedMatch || + // As well, disconnected nodes are said to be in a document + // fragment in IE 9, so check for that + node.document && node.document.nodeType !== 11 ) { + return ret; + } + } + } catch(e) {} + } + + return Sizzle(expr, null, null, [node]).length > 0; + }; + } +})(); + +(function(){ + var div = document.createElement("div"); + + div.innerHTML = "
      "; + + // Opera can't find a second classname (in 9.6) + // Also, make sure that getElementsByClassName actually exists + if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) { + return; + } + + // Safari caches class attributes, doesn't catch changes (in 3.2) + div.lastChild.className = "e"; + + if ( div.getElementsByClassName("e").length === 1 ) { + return; + } + + Expr.order.splice(1, 0, "CLASS"); + Expr.find.CLASS = function( match, context, isXML ) { + if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) { + return context.getElementsByClassName(match[1]); + } + }; + + // release memory in IE + div = null; +})(); + +function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + + if ( elem ) { + var match = false; + + elem = elem[dir]; + + while ( elem ) { + if ( elem[ expando ] === doneName ) { + match = checkSet[elem.sizset]; + break; + } + + if ( elem.nodeType === 1 && !isXML ){ + elem[ expando ] = doneName; + elem.sizset = i; + } + + if ( elem.nodeName.toLowerCase() === cur ) { + match = elem; + break; + } + + elem = elem[dir]; + } + + checkSet[i] = match; + } + } +} + +function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + + if ( elem ) { + var match = false; + + elem = elem[dir]; + + while ( elem ) { + if ( elem[ expando ] === doneName ) { + match = checkSet[elem.sizset]; + break; + } + + if ( elem.nodeType === 1 ) { + if ( !isXML ) { + elem[ expando ] = doneName; + elem.sizset = i; + } + + if ( typeof cur !== "string" ) { + if ( elem === cur ) { + match = true; + break; + } + + } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) { + match = elem; + break; + } + } + + elem = elem[dir]; + } + + checkSet[i] = match; + } + } +} + +if ( document.documentElement.contains ) { + Sizzle.contains = function( a, b ) { + return a !== b && (a.contains ? a.contains(b) : true); + }; + +} else if ( document.documentElement.compareDocumentPosition ) { + Sizzle.contains = function( a, b ) { + return !!(a.compareDocumentPosition(b) & 16); + }; + +} else { + Sizzle.contains = function() { + return false; + }; +} + +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 : 0).documentElement; + + return documentElement ? documentElement.nodeName !== "HTML" : false; +}; + +var posProcess = function( selector, context, seed ) { + var match, + tmpSet = [], + later = "", + root = context.nodeType ? [context] : context; + + // Position selectors must be done after the filter + // And so must :not(positional) so we move all PSEUDOs to the end + while ( (match = Expr.match.PSEUDO.exec( selector )) ) { + later += match[0]; + selector = selector.replace( Expr.match.PSEUDO, "" ); + } + + selector = Expr.relative[selector] ? selector + "*" : selector; + + for ( var i = 0, l = root.length; i < l; i++ ) { + Sizzle( selector, root[i], tmpSet, seed ); + } + + return Sizzle.filter( later, tmpSet ); +}; + +// EXPOSE +// Override sizzle attribute retrieval +Sizzle.attr = jQuery.attr; +Sizzle.selectors.attrMap = {}; +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; +jQuery.expr[":"] = jQuery.expr.filters; +jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; + + +})(); + + +var runtil = /Until$/, + rparentsprev = /^(?:parents|prevUntil|prevAll)/, + // Note: This RegExp should be improved, or likely pulled from Sizzle + rmultiselector = /,/, + isSimple = /^.[^:#\[\.,]*$/, + slice = Array.prototype.slice, + POS = jQuery.expr.match.globalPOS, + // 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({ + find: function( selector ) { + var self = this, + i, l; + + if ( typeof selector !== "string" ) { + return jQuery( selector ).filter(function() { + for ( i = 0, l = self.length; i < l; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + }); + } + + var ret = this.pushStack( "", "find", selector ), + length, n, r; + + for ( i = 0, l = this.length; i < l; i++ ) { + length = ret.length; + jQuery.find( selector, this[i], ret ); + + if ( i > 0 ) { + // Make sure that the results are unique + for ( n = length; n < ret.length; n++ ) { + for ( r = 0; r < length; r++ ) { + if ( ret[r] === ret[n] ) { + ret.splice(n--, 1); + break; + } + } + } + } + } + + return ret; + }, + + has: function( target ) { + var targets = jQuery( target ); + return this.filter(function() { + for ( var i = 0, l = targets.length; i < l; i++ ) { + if ( jQuery.contains( this, targets[i] ) ) { + return true; + } + } + }); + }, + + not: function( selector ) { + return this.pushStack( winnow(this, selector, false), "not", selector); + }, + + filter: function( selector ) { + return this.pushStack( winnow(this, selector, true), "filter", selector ); + }, + + is: function( selector ) { + return !!selector && ( + typeof selector === "string" ? + // If this is a positional selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + POS.test( selector ) ? + jQuery( selector, this.context ).index( this[0] ) >= 0 : + jQuery.filter( selector, this ).length > 0 : + this.filter( selector ).length > 0 ); + }, + + closest: function( selectors, context ) { + var ret = [], i, l, cur = this[0]; + + // Array (deprecated as of jQuery 1.7) + if ( jQuery.isArray( selectors ) ) { + var level = 1; + + while ( cur && cur.ownerDocument && cur !== context ) { + for ( i = 0; i < selectors.length; i++ ) { + + if ( jQuery( cur ).is( selectors[ i ] ) ) { + ret.push({ selector: selectors[ i ], elem: cur, level: level }); + } + } + + cur = cur.parentNode; + level++; + } + + return ret; + } + + // String + var pos = POS.test( selectors ) || typeof selectors !== "string" ? + jQuery( selectors, context || this.context ) : + 0; + + for ( i = 0, l = this.length; i < l; i++ ) { + cur = this[i]; + + while ( cur ) { + if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) { + ret.push( cur ); + break; + + } else { + cur = cur.parentNode; + if ( !cur || !cur.ownerDocument || cur === context || cur.nodeType === 11 ) { + break; + } + } + } + } + + ret = ret.length > 1 ? jQuery.unique( ret ) : ret; + + return this.pushStack( ret, "closest", selectors ); + }, + + // 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.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 ) { + var set = typeof selector === "string" ? + jQuery( selector, context ) : + jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ), + all = jQuery.merge( this.get(), set ); + + return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ? + all : + jQuery.unique( all ) ); + }, + + andSelf: function() { + return this.add( this.prevObject ); + } +}); + +// A painfully simple check to see if an element is disconnected +// from a document (should be improved, where feasible). +function isDisconnected( node ) { + return !node || !node.parentNode || node.parentNode.nodeType === 11; +} + +jQuery.each({ + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return jQuery.dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, i, until ) { + return jQuery.dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return jQuery.nth( elem, 2, "nextSibling" ); + }, + prev: function( elem ) { + return jQuery.nth( elem, 2, "previousSibling" ); + }, + nextAll: function( elem ) { + return jQuery.dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return jQuery.dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, i, until ) { + return jQuery.dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, i, until ) { + return jQuery.dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem ); + }, + children: function( elem ) { + return jQuery.sibling( elem.firstChild ); + }, + contents: function( elem ) { + return jQuery.nodeName( elem, "iframe" ) ? + elem.contentDocument || elem.contentWindow.document : + jQuery.makeArray( elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var ret = jQuery.map( this, fn, until ); + + if ( !runtil.test( name ) ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + ret = jQuery.filter( selector, ret ); + } + + ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret; + + if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) { + ret = ret.reverse(); + } + + return this.pushStack( ret, name, slice.call( arguments ).join(",") ); + }; +}); + +jQuery.extend({ + filter: function( expr, elems, not ) { + if ( not ) { + expr = ":not(" + expr + ")"; + } + + return elems.length === 1 ? + jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] : + jQuery.find.matches(expr, elems); + }, + + dir: function( elem, dir, until ) { + var matched = [], + cur = elem[ dir ]; + + while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { + if ( cur.nodeType === 1 ) { + matched.push( cur ); + } + cur = cur[dir]; + } + return matched; + }, + + nth: function( cur, result, dir, elem ) { + result = result || 1; + var num = 0; + + for ( ; cur; cur = cur[dir] ) { + if ( cur.nodeType === 1 && ++num === result ) { + break; + } + } + + return cur; + }, + + sibling: function( n, elem ) { + var r = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + r.push( n ); + } + } + + return r; + } +}); + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, keep ) { + + // Can't pass null or undefined to indexOf in Firefox 4 + // Set to 0 to skip string check + qualifier = qualifier || 0; + + if ( jQuery.isFunction( qualifier ) ) { + return jQuery.grep(elements, function( elem, i ) { + var retVal = !!qualifier.call( elem, i, elem ); + return retVal === keep; + }); + + } else if ( qualifier.nodeType ) { + return jQuery.grep(elements, function( elem, i ) { + return ( elem === qualifier ) === keep; + }); + + } else if ( typeof qualifier === "string" ) { + var filtered = jQuery.grep(elements, function( elem ) { + return elem.nodeType === 1; + }); + + if ( isSimple.test( qualifier ) ) { + return jQuery.filter(qualifier, filtered, !keep); + } else { + qualifier = jQuery.filter( qualifier, filtered ); + } + } + + return jQuery.grep(elements, function( elem, i ) { + return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep; + }); +} + + + + +function createSafeFragment( document ) { + var list = nodeNames.split( "|" ), + safeFrag = document.createDocumentFragment(); + + if ( safeFrag.createElement ) { + while ( list.length ) { + safeFrag.createElement( + list.pop() + ); + } + } + return safeFrag; +} + +var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" + + "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video", + rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g, + rleadingWhitespace = /^\s+/, + rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig, + rtagName = /<([\w:]+)/, + rtbody = /]", "i"), + // checked="checked" or checked + rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i, + rscriptType = /\/(java|ecma)script/i, + rcleanScript = /^\s*", "" ], + legend: [ 1, "
      ", "
      " ], + thead: [ 1, "", "
      " ], + tr: [ 2, "", "
      " ], + td: [ 3, "", "
      " ], + col: [ 2, "", "
      " ], + area: [ 1, "", "" ], + _default: [ 0, "", "" ] + }, + safeFragment = createSafeFragment( document ); + +wrapMap.optgroup = wrapMap.option; +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + +// IE can't serialize and + - + diff --git a/feeds/webclipfeed.php b/feeds/webclipfeed.php index 5f8b488..a3d749e 100644 --- a/feeds/webclipfeed.php +++ b/feeds/webclipfeed.php @@ -13,7 +13,7 @@
      KKnowledge ArticlesKKnowledge
      -
      +
      - + ]", "i"), - // checked="checked" or checked - rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i, - rscriptType = /\/(java|ecma)script/i, - rcleanScript = /^\s*", "" ], - legend: [ 1, "
      ", "
      " ], - thead: [ 1, "
      Klips FeedLatest Klips
      diff --git a/grid.php b/grid.php new file mode 100644 index 0000000..a362f10 --- /dev/null +++ b/grid.php @@ -0,0 +1,60 @@ + + + + + + + + +
      +
        +
        + + + + + + + + + + + diff --git a/links/jdownloader.php b/links/jdownloader.php index 67e02e4..30c117e 100644 --- a/links/jdownloader.php +++ b/links/jdownloader.php @@ -1,9 +1,23 @@ "; + echo "
      • "; } else { - echo ""; +echo "
      • "; + } -?> \ No newline at end of file +?> + + + + + + + + + + + + + diff --git a/links/transmission.php b/links/transmission.php index 608371f..151c3e5 100644 --- a/links/transmission.php +++ b/links/transmission.php @@ -1,5 +1,6 @@ "; + echo "
      • "; } -?> \ No newline at end of file +?> + diff --git a/links/utorrent.php b/links/utorrent.php index b25a28c..c2691bf 100644 --- a/links/utorrent.php +++ b/links/utorrent.php @@ -1,9 +1,10 @@ "; + echo "
      • "; } else { - echo ""; + echo "
      • "; } -?> \ No newline at end of file +?> + diff --git a/newtest.php b/newtest.php new file mode 100644 index 0000000..561826d --- /dev/null +++ b/newtest.php @@ -0,0 +1,160 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        +
        + + + + +
        +$yourname's Server Access

        ";?> +
        + +

        +"; ?> +

        +
        + +
        +
          + + "0") { + require "links/jdownloader.php"; + } +?> + "0") { + require "links/torrent.php"; + } +?> + +
        • A
        • +
        • A
        • +
        • A
        • +
        • F
        • + +
        • + +
        +
        + +
        + +
        +

        +Adults"; ?> - Kids"; ?> +

        +
        +
        +
        +"; ?> +"; ?> +"; ?> +"; ?> +"; ?> +"; ?> +"; ?> +"; ?> +"; ?> +"; ?> +"; ?> + + + +
        + + + + + \ No newline at end of file diff --git a/right.php b/right.php index d1b7773..cca70d7 100644 --- a/right.php +++ b/right.php @@ -105,7 +105,7 @@ if ($customfeed3visible > "0") { - + diff --git a/robots.txt b/robots.txt new file mode 100644 index 0000000..f783256 --- /dev/null +++ b/robots.txt @@ -0,0 +1,5 @@ + +# This file can be used to affect how search engines and other web site crawlers see your site. +# For more information, please see http://www.w3.org/TR/html4/appendix/notes.html#h-B.4.1.1 +# WebMatrix 2.0 + From 2b4d15e26c9a60bc432a456c74cef84d0708abd7 Mon Sep 17 00:00:00 2001 From: Karl Hudgell Date: Fri, 29 Jan 2016 11:20:36 +0000 Subject: [PATCH 2/5] Grid layout, Headphones --- GRID/.bowerrc | 4 - GRID/.gitignore | 7 - GRID/CHANGELOG.md | 185 - GRID/CONTRIBUTING.md | 143 - GRID/Gruntfile.js | 183 - GRID/LICENSE | 19 - GRID/README.md | 50 - GRID/assets/demo.css | 69 - GRID/assets/gridster_new.js | 104 - GRID/assets/jquery.gridster.js | 3232 ------ GRID/assets/jquery.js | 9404 ------------------ GRID/dist/jquery.gridster.css | 121 - GRID/dist/jquery.gridster.js | 3987 -------- GRID/dist/jquery.gridster.min.css | 2 - GRID/dist/jquery.gridster.min.js | 2 - GRID/dist/jquery.gridster.with-extras.js | 4163 -------- GRID/dist/jquery.gridster.with-extras.min.js | 2 - GRID/grid.php | 46 - GRID/jquery.gridder.html | 46 - GRID/jquery.gridder_test.js | 38 - GRID/package.json | 41 - GRID/src/jquery.collision.js | 242 - GRID/src/jquery.coords.js | 125 - GRID/src/jquery.draggable.js | 432 - GRID/src/jquery.gridster.css | 117 - GRID/src/jquery.gridster.extras.js | 175 - GRID/src/jquery.gridster.js | 3140 ------ GRID/src/utils.js | 72 - Pic/Upload/couch.png | Bin 0 -> 18162 bytes assets/gridster_new.js | 5 +- config/TEST.php | 15 + config/set1.php | 8 + config/set2.php | 18 +- config/write2.php | 2 +- grid.php | 60 - links/cpdual.php | 7 +- links/cpsingle.php | 7 +- links/ftp.php | 7 +- links/headphones.php | 10 + links/jdownloader.php | 4 +- links/kodi.php | 4 +- links/madsonic.php | 7 +- links/plex.php | 8 +- links/sab.php | 7 +- links/sickbeard.php | 7 +- links/sickrage.php | 7 +- links/squeeze.php | 8 +- links/transmission.php | 2 +- links/utorrent.php | 4 +- main.php | 90 +- newtest.php => main.phpold | 112 +- 51 files changed, 223 insertions(+), 26327 deletions(-) delete mode 100644 GRID/.bowerrc delete mode 100644 GRID/.gitignore delete mode 100644 GRID/CHANGELOG.md delete mode 100644 GRID/CONTRIBUTING.md delete mode 100644 GRID/Gruntfile.js delete mode 100644 GRID/LICENSE delete mode 100644 GRID/README.md delete mode 100644 GRID/assets/demo.css delete mode 100644 GRID/assets/gridster_new.js delete mode 100644 GRID/assets/jquery.gridster.js delete mode 100644 GRID/assets/jquery.js delete mode 100644 GRID/dist/jquery.gridster.css delete mode 100644 GRID/dist/jquery.gridster.js delete mode 100644 GRID/dist/jquery.gridster.min.css delete mode 100644 GRID/dist/jquery.gridster.min.js delete mode 100644 GRID/dist/jquery.gridster.with-extras.js delete mode 100644 GRID/dist/jquery.gridster.with-extras.min.js delete mode 100644 GRID/grid.php delete mode 100644 GRID/jquery.gridder.html delete mode 100644 GRID/jquery.gridder_test.js delete mode 100644 GRID/package.json delete mode 100644 GRID/src/jquery.collision.js delete mode 100644 GRID/src/jquery.coords.js delete mode 100644 GRID/src/jquery.draggable.js delete mode 100644 GRID/src/jquery.gridster.css delete mode 100644 GRID/src/jquery.gridster.extras.js delete mode 100644 GRID/src/jquery.gridster.js delete mode 100644 GRID/src/utils.js create mode 100644 Pic/Upload/couch.png create mode 100644 config/TEST.php delete mode 100644 grid.php create mode 100644 links/headphones.php rename newtest.php => main.phpold (77%) diff --git a/GRID/.bowerrc b/GRID/.bowerrc deleted file mode 100644 index a33fd7a..0000000 --- a/GRID/.bowerrc +++ /dev/null @@ -1,4 +0,0 @@ -{ - "directory": "libs", - "json": "package.json" -} \ No newline at end of file diff --git a/GRID/.gitignore b/GRID/.gitignore deleted file mode 100644 index 440a178..0000000 --- a/GRID/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -node_modules/ -libs/ -gh-pages/ -demo/ -.idea -.DS_Store -.idea diff --git a/GRID/CHANGELOG.md b/GRID/CHANGELOG.md deleted file mode 100644 index 6d6f1a2..0000000 --- a/GRID/CHANGELOG.md +++ /dev/null @@ -1,185 +0,0 @@ - -### v0.5.6 (2014-09-25) - - -#### Bug Fixes - -* **draggable:** namespace events with unique ids ([79aff38c](http://github.com/ducksboard/gridster.js/commit/79aff38c60cc6ce2c0f0160bd3c6f93cb2511642)) - - -### v0.5.5 (2014-07-25) - - -#### Bug Fixes - -* **gridster:** fire `positionschanged` when widget orig position changes ([9926ceff](http://github.com/ducksboard/gridster.js/commit/9926ceff59cba49c71542e45aa095be35eb1df58)) - - -### v0.5.4 (2014-07-16) - - -#### Bug Fixes - -* **gridster:** serialize returns an Array object, not a jQuery object ([93df6cf6](http://github.com/ducksboard/gridster.js/commit/93df6cf6907fd0fb8787b3d068c9a9c467dcc020), closes [#394](http://github.com/ducksboard/gridster.js/issues/394)) - - -### v0.5.3 (2014-07-04) - - -#### Bug Fixes - -* **gridster:** - * custom `ignore_dragging` overwrites the default value ([6bcfa6e1](http://github.com/ducksboard/gridster.js/commit/6bcfa6e16e4a88cbb5efff1ce29308737884a89d)) - * sort widgets appropriately when reading them from DOM ([5c6d25cb](http://github.com/ducksboard/gridster.js/commit/5c6d25cbbe3de021806408f3cff6cb1e139c0a25)) - - -#### Features - -* make gridster AMD compatible ([589d7fd5](http://github.com/ducksboard/gridster.js/commit/589d7fd509a570fd02666c2f8231545211d6c83f)) -* **gridster:** move widget up when added if there is space available ([8ec307b6](http://github.com/ducksboard/gridster.js/commit/8ec307b6f7173e94610409adcb1671372cc2c67d)) - - -### v0.5.2 (2014-06-16) - - -#### Bug Fixes - -* **draggable:** - * handle both touch and click events ([021a6c23](http://github.com/ducksboard/gridster.js/commit/021a6c23e851210c1b817bd353a1e5e19ce10b90), closes [#207](http://github.com/ducksboard/gridster.js/issues/207), [#236](http://github.com/ducksboard/gridster.js/issues/236), [#329](http://github.com/ducksboard/gridster.js/issues/329), [#380](http://github.com/ducksboard/gridster.js/issues/380)) - * replaced scrollX/Y with scrollLeft/Top ([bb7463a3](http://github.com/ducksboard/gridster.js/commit/bb7463a3241750397492dfbac133cea193f0254f)) - * fix offset during drag ([c726c4ad](http://github.com/ducksboard/gridster.js/commit/c726c4ad9c18fea95e4b46b9bacd36c42aa9691c)) - * bind drag events to $document ([dd6c7420](http://github.com/ducksboard/gridster.js/commit/dd6c7420087d5810a9f6b02bf9d81a04a60ae840)) -* **gridster:** - * fix add_widget to use correct size_y when adding rows ([7d22e6c8](http://github.com/ducksboard/gridster.js/commit/7d22e6c8b201de33e33def77a93dc9009d0aa4cb)) - * Removing previously added style tags before adding new one. ([93c46ff4](http://github.com/ducksboard/gridster.js/commit/93c46ff45ebe59f3658b7f32f05b67109aa87311)) - - -#### Features - -* **draggable:** - * allow ignore_dragging config option to be a function ([69fcfe45](http://github.com/ducksboard/gridster.js/commit/69fcfe459678e833cb53de040b9fbc96dd687543)) - * option to not remove helper on drag stop ([03910df9](http://github.com/ducksboard/gridster.js/commit/03910df967a1ae7bcb2fa3aadd58255e0bcbf327)) - - -### v0.5.1 (2014-03-05) - - -#### Features - -* **collision:** overlapping region as a config option ([720d487e](http://github.com/ducksboard/gridster.js/commit/720d487e3988593e2c60909c88aaff13fbd4f842)) -* **coords:** - * allow both (left/x1) and (top/y1) attr keys ([6f22217f](http://github.com/ducksboard/gridster.js/commit/6f22217f056e4fc52f6405f2af49596105aae150)) - * add destroy method ([fdeee4f6](http://github.com/ducksboard/gridster.js/commit/fdeee4f636266c7a0579ced833f04fec013b6863)) -* **draggable:** keep container position prop if different than static ([04868a38](http://github.com/ducksboard/gridster.js/commit/04868a384d655d110f2d153d2fddb94b1c6d54a9)) -* **gridster:** destroy element's data and optionally remove from DOM ([dc09f191](http://github.com/ducksboard/gridster.js/commit/dc09f191d8503669cfa4737122c77cb0f5b9c3d2)) - - -## v0.5.0 (2014-02-14) - - -#### Bug Fixes - -* **autogrow:** refining autogrow_cols behavior and grid width issues ([835c2df8](http://github.com/ducksboard/gridster.js/commit/835c2df84419a92b1641b687fcf083f3ff102627)) -* **resize.stop:** Call resize.stop at the latest possible moment ([e21f63a0](http://github.com/ducksboard/gridster.js/commit/e21f63a05a539f5c611eb49cd6861b1e38b36531)) - - -#### Features - -* **draggable:** Add toggle draggable method. ([073fdc40](http://github.com/ducksboard/gridster.js/commit/073fdc40e0a94dd371646fc54cd420e3ddab0254)) - - -### v0.4.4 (2014-02-13) - - -#### Features - -* **resize:** add start/stop/resize event triggers ([7ca8deec](http://github.com/ducksboard/gridster.js/commit/7ca8deec8559d950097a6dc351cb0c6fcef3458d)) - - -### v0.4.3 (2014-02-11) - - -#### Bug Fixes - -* **generated-styles:** cleaning cached serializations properly ([f8b04f29](http://github.com/ducksboard/gridster.js/commit/f8b04f298e12e46ca9b07f0bae0abc6b08ed6e18)) - - -### v0.4.2 (2014-02-07) - - -#### Bug Fixes - -* recalculate grid width when adding widgets ([47745978](http://github.com/ducksboard/gridster.js/commit/4774597834300601fc81d5111a31a8c1672c55e1)) - - -### v0.4.1 (2014-02-07) - -#### Bug Fixes - -* add resize.min_size option to default config object ([5672edb0](http://github.com/ducksboard/gridster.js/commit/5672edb05e39c6b9ff5e3ca31d68c9e94dfaa617)) - - -## v0.4.0 (2014-02-07) - - -#### Bug Fixes - -* **gridster:** - * leaking options with multiple Gridster instances ([07c71097](http://github.com/ducksboard/gridster.js/commit/07c7109771094d98be51d68448a20e1d2987b35d)) - * resize.axes default option only 'both' ([62988780](http://github.com/ducksboard/gridster.js/commit/6298878077d5db129daa9780939fec5237b82af9)) -* **licenses:** add required copyright message for underscore ([b563c094](http://github.com/ducksboard/gridster.js/commit/b563c094cf0f3a5da2288492f95759ae32e8967c)) -* **readme:** link title jsfiddle -> jsbin, edit 5) of process steps ([0641aa89](http://github.com/ducksboard/gridster.js/commit/0641aa89833ecf9d167f7d8e89ee8bd5b4304248)) - - -#### Features - -* **draggable:** - * method to set drag limits dynamically ([d4482ec1](http://github.com/ducksboard/gridster.js/commit/d4482ec1476f8a0b6fb6cdeb25b7774ef678d81c)) - * support horizontal scrolling while dragging ([ae4921b7](http://github.com/ducksboard/gridster.js/commit/ae4921b70798944211267cacf8a89e62d0818369)) -* **gridster:** increase grid width when dragging or resizing ([37c4e943](http://github.com/ducksboard/gridster.js/commit/37c4e94358b9392710452b9e7f96454837bf9845)) -* **resize:** add option to set min_size of a widget ([ff511872](http://github.com/ducksboard/gridster.js/commit/ff511872e65992ee89bd2a88d862caaf99733f38)) - - -## v0.3.0 (2013-11-18) - - -#### Features - -* **draggable:** - * method to set drag limits dynamically ([d4482ec1](http://github.com/ducksboard/gridster.js/commit/d4482ec1476f8a0b6fb6cdeb25b7774ef678d81c)) - * support horizontal scrolling while dragging ([ae4921b7](http://github.com/ducksboard/gridster.js/commit/ae4921b70798944211267cacf8a89e62d0818369)) -* **gridster:** increase grid width when dragging or resizing ([b61df653](http://github.com/ducksboard/gridster.js/commit/b61df6535f728970fb8c6f25a208275dbde66550)) - - -### v0.2.1 (2013-10-28) - - -#### Features - -* **resize:** Add start/stop/resize callbacks ([d4ec7140](http://github.com/ducksboard/gridster.js/commit/d4ec7140f736bc30697c75b54ed3242ddf1d75b9)) - - -## v0.2.0 (2013-10-26) - - -#### Bug Fixes - -* fixes and improvements in widget-resizing. ([ae02b32b](http://github.com/ducksboard/gridster.js/commit/ae02b32b9210c6328f4acc339e215ae50c134f77), closes [#32](http://github.com/ducksboard/gridster.js/issues/32)) -* **gridster:** - * the preview holder should not always use `li` ([1ade74e2](http://github.com/ducksboard/gridster.js/commit/1ade74e239485b07e870fca44e1eafb3ff1ae283)) - * overlapping widget problem ([31fd8d6b](http://github.com/ducksboard/gridster.js/commit/31fd8d6ba893e4c39b91ba30d429e37f3da30b24)) - * Orphan preview holder when dragging is interrupted ([1b13617d](http://github.com/ducksboard/gridster.js/commit/1b13617df2ce53235bdf3a1e38f1555f529663c3)) - * remove_widget Returns the instance of the Gridster Class ([5bfbc5c0](http://github.com/ducksboard/gridster.js/commit/5bfbc5c0b5ab49c2a7c651327ce2e0f30f594985)) - - -#### Features - -* **draggable:** - * new config option to move or not the dragged element ([4d9b2a84](http://github.com/ducksboard/gridster.js/commit/4d9b2a84f11cb7cb2ddad51c158d92b82e7bc447)) - * CSS selectors support in `ignore_dragging` config opt ([0f956249](http://github.com/ducksboard/gridster.js/commit/0f95624925be97aee7a8450707e04e887e4dac58)) - * pass previous position to the drag callback ([055cc0e4](http://github.com/ducksboard/gridster.js/commit/055cc0e4f6f9de5721986515656ac894855f9e02)) - * Don't start new drag if previous one hasn't stopped ([91ca6572](http://github.com/ducksboard/gridster.js/commit/91ca65721c2eb32b5dec82cdc5e5e7f81dac329e)) - * pass useful data to all drag callbacks ([8dda2410](http://github.com/ducksboard/gridster.js/commit/8dda2410f300592706985c05141ca6b702977dc0)) -* **gridster:** drag-and-drop widget resizing ([e1924053](http://github.com/ducksboard/gridster.js/commit/e19240532de0bad35ffe6e5fc63934819390adc5)) -* **utils:** add delay helper to utils ([faa6c5db](http://github.com/ducksboard/gridster.js/commit/faa6c5db0002feccf681e9f919ed583eef152773)) - diff --git a/GRID/CONTRIBUTING.md b/GRID/CONTRIBUTING.md deleted file mode 100644 index 032a9fa..0000000 --- a/GRID/CONTRIBUTING.md +++ /dev/null @@ -1,143 +0,0 @@ -# Contributing to this project - -Please take a moment to review this document in order to make the contribution -process easy and effective for everyone involved. - -Following these guidelines helps to communicate that you respect the time of -the developers managing and developing this open source project. In return, -they should reciprocate that respect in addressing your issue or assessing -patches and features. - - -## Using the issue tracker - -The issue tracker is the preferred channel for [bug reports](#bugs), -[features requests](#features) and [submitting pull -requests](#pull-requests), but please respect the following restrictions: - -* Please **do not** use the issue tracker for personal support requests (use - [Stack Overflow](http://stackoverflow.com)). - -* Please **do not** derail or troll issues. Keep the discussion on topic and - respect the opinions of others. - - - -## Bug reports - -A bug is a _demonstrable problem_ that is caused by the code in the repository. -Good bug reports are extremely helpful - thank you! - -Guidelines for bug reports: - -1. **Use the GitHub issue search** — check if the issue has already been - reported. - -2. **Check if the issue has been fixed** — try to reproduce it using the - latest `master` or development branch in the repository. - -3. **Isolate the problem** — ideally create a [reduced test - case](http://css-tricks.com/6263-reduced-test-cases/) and a live example (you can use something like [jsfiddle](http://jsfiddle.net/) or [jsbin](http://jsbin.com/)) . - -A good bug report shouldn't leave others needing to chase you up for more -information. Please try to be as detailed as possible in your report. What is -your environment? What steps will reproduce the issue? What browser(s) and OS -experience the problem? What would you expect to be the outcome? All these -details will help people to fix any potential bugs. - -Example: - -> Short and descriptive example bug report title -> -> A summary of the issue and the browser/OS environment in which it occurs. If -> suitable, include the steps required to reproduce the bug. -> -> 1. This is the first step -> 2. This is the second step -> 3. Further steps, etc. -> -> `` - a link to the reduced test case -> -> Any other information you want to share that is relevant to the issue being -> reported. This might include the lines of code that you have identified as -> causing the bug, and potential solutions (and your opinions on their -> merits). - - - -## Feature requests - -Feature requests are welcome. But take a moment to find out whether your idea -fits with the scope and aims of the project. It's up to *you* to make a strong -case to convince the project's developers of the merits of this feature. Please -provide as much detail and context as possible. - -**Please, use the GitHub issue search** to check if the feature has already been requested. - - - -## Pull requests - -Good pull requests - patches, improvements, new features - are a fantastic -help. They should remain focused in scope and avoid containing unrelated -commits. - -**Please ask first** before embarking on any significant pull request (e.g. -implementing features, refactoring code, porting to a different language), -otherwise you risk spending a lot of time working on something that the -project's developers might not want to merge into the project. - -Code must follow, mostly, these [coding conventions](http://javascript.crockford.com/code.html) . - -Adhering to the following this process is the best way to get your work -included in the project: - -1. [Fork](http://help.github.com/fork-a-repo/) the project, clone your fork, - and configure the remotes: - - ```bash - # Clone your fork of the repo into the current directory - git clone https://github.com//gridster.js - # Navigate to the newly cloned directory - cd gridster.js - # Assign the original repo to a remote called "upstream" - git remote add upstream https://github.com/ducksboard/gridster.js - ``` - -2. If you cloned a while ago, get the latest changes from upstream: - - ```bash - git checkout master - git pull upstream master - ``` - -3. Create a new topic branch (off the main project development branch) to - contain your feature, change, or fix: - - ```bash - git checkout -b - ``` - -4. Commit your changes in logical chunks. Please adhere to these [git commit - message guidelines](https://docs.google.com/document/d/1QrDFcIiPjSLDn3EL15IJygNPiHORgU1_OOAqWjiDU5Y) - or your code is unlikely be merged into the main project. Use Git's - [interactive rebase](https://help.github.com/articles/interactive-rebase) - feature to tidy up your commits before making them public. - -5. Merge or rebase the upstream development branch into your topic branch: - - ```bash - git pull --rebase upstream master - ``` - -6. Push your topic branch up to your fork: - - ```bash - git push origin - ``` - -7. [Open a Pull Request](https://help.github.com/articles/using-pull-requests/) - with a clear title and description. - -**IMPORTANT**: By submitting a patch, you agree to allow the project owner to -license your work under the same license as that used by the project. diff --git a/GRID/Gruntfile.js b/GRID/Gruntfile.js deleted file mode 100644 index 48be913..0000000 --- a/GRID/Gruntfile.js +++ /dev/null @@ -1,183 +0,0 @@ -/*global module:false*/ -module.exports = function(grunt) { - - // Project configuration. - grunt.initConfig({ - pkg: grunt.file.readJSON('package.json'), - meta: { - banner: '/*! <%= pkg.title || pkg.name %> - v<%= pkg.version %> - ' + - '<%= grunt.template.today("yyyy-mm-dd") %>\n' + - '<%= pkg.homepage ? "* " + pkg.homepage : "" %>\n' + - '* Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>;' + - ' Licensed <%= _.pluck(pkg.licenses, "type").join(", ") %> */\n\n', - - minibanner: '/*! <%= pkg.title || pkg.name %> - v<%= pkg.version %> - ' + - '<%= grunt.template.today("yyyy-mm-dd") %> - ' + - '<%= pkg.homepage ? "* " + pkg.homepage + " - " : "" %>' + - 'Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>;' + - ' Licensed <%= _.pluck(pkg.licenses, "type").join(", ") %> */ ' - }, - concat: { - options: { - stripBanners: true, - banner: '<%= meta.banner %>' - }, - dist_js: { - src: ['src/jquery.coords.js', 'src/jquery.collision.js', 'src/utils.js', 'src/jquery.draggable.js', 'src/jquery.<%= pkg.name %>.js'], - dest: 'dist/jquery.<%= pkg.name %>.js' - }, - - dist_extras_js: { - src: ['src/jquery.coords.js', 'src/jquery.collision.js', 'src/utils.js', 'src/jquery.draggable.js', 'src/jquery.<%= pkg.name %>.js', 'src/jquery.<%= pkg.name %>.extras.js'], - dest: 'dist/jquery.<%= pkg.name %>.with-extras.js' - }, - - dist_css: { - src: ['src/jquery.<%= pkg.name %>.css'], - dest: 'dist/jquery.<%= pkg.name %>.css' - }, - - dist_demo_js: { - src: ['src/jquery.coords.js', 'src/jquery.collision.js', 'src/utils.js', 'src/jquery.draggable.js', 'src/jquery.<%= pkg.name %>.js'], - dest: 'gh-pages/dist/jquery.<%= pkg.name %>.js' - }, - - dist_extras_demo_js: { - src: ['src/jquery.coords.js', 'src/jquery.collision.js', 'src/utils.js', 'src/jquery.draggable.js', 'src/jquery.<%= pkg.name %>.js', 'src/jquery.<%= pkg.name %>.extras.js'], - dest: 'gh-pages/dist/jquery.<%= pkg.name %>.with-extras.js' - }, - - dist_demo_css: { - src: ['src/jquery.<%= pkg.name %>.css'], - dest: 'gh-pages/dist/jquery.<%= pkg.name %>.css' - } - }, - uglify: { - options: { - banner: '<%= meta.minibanner %>' - }, - dist: { - files: { - 'dist/jquery.<%= pkg.name %>.min.js': ['<%= concat.dist_js.dest %>'] - } - }, - - dist_extras: { - files: { - 'dist/jquery.<%= pkg.name %>.with-extras.min.js': ['<%= concat.dist_extras_js.dest %>'] - } - }, - - dist_demo: { - files: { - 'gh-pages/dist/jquery.<%= pkg.name %>.min.js': ['<%= concat.dist_js.dest %>'], - } - }, - - dist_extras_demo: { - files: { - 'gh-pages/dist/jquery.<%= pkg.name %>.with-extras.min.js': ['<%= concat.dist_extras_js.dest %>'] - } - } - }, - cssmin: { - compress: { - options: { - keepSpecialComments: 0, - banner: '<%= meta.minibanner %>' - }, - files: { - "dist/jquery.<%= pkg.name %>.min.css": ["dist/jquery.<%= pkg.name %>.css"], - "gh-pages/dist/jquery.<%= pkg.name %>.min.css": ["dist/jquery.<%= pkg.name %>.css"] - } - } - }, - jshint: { - files: ['grunt.js', 'src/**/*.js', 'test/**/*.js'] - }, - watch: { - files: ['<%= lint.files %>', 'src/jquery.<%= pkg.name %>.css'], - tasks: 'min concat' - }, - jshint: { - options: { - curly: true, - eqeqeq: true, - immed: true, - latedef: true, - newcap: true, - noarg: true, - sub: true, - undef: true, - boss: true, - eqnull: true, - browser: true - }, - globals: { - jQuery: true - } - }, - yuidoc: { - compile: { - "name": 'gridster.js', - "description": 'gridster.js, a drag-and-drop multi-column jQuery grid plugin', - "version": '0.1.0', - "url": 'http://gridster.net/', - "logo": 'https://ducksboard.com/static/images/svg/logo-ducksboard-black-small.svg', - options: { - paths: "src/", - outdir: "gh-pages/docs/" - } - } - }, - - bump: { - options: { - files: ['package.json'], - updateConfigs: ['pkg'], - commit: true, - commitMessage: 'Release v%VERSION%', - commitFiles: ['package.json', 'CHANGELOG.md', 'dist/'], // '-a' for all files - createTag: true, - tagName: 'v%VERSION%', - tagMessage: 'Version %VERSION%', - push: false, - pushTo: 'origin', - gitDescribeOptions: '--tags --always --abbrev=1 --dirty=-d' // options to use with '$ git describe' - } - }, - - changelog: { - options: { - dest: 'CHANGELOG.md' - } - }, - - watch: { - files: ['libs/*.js', 'src/*.js', 'src/*.css', 'Gruntfile.js'], - tasks: ['concat', 'uglify', 'cssmin'] - } - }); - - - grunt.loadNpmTasks('grunt-contrib-watch'); - grunt.loadNpmTasks('grunt-contrib-jshint'); - grunt.loadNpmTasks('grunt-contrib-concat'); - grunt.loadNpmTasks('grunt-contrib-uglify'); - grunt.loadNpmTasks('grunt-contrib-cssmin'); - grunt.loadNpmTasks('grunt-contrib-yuidoc'); - grunt.loadNpmTasks('grunt-bump'); - grunt.loadNpmTasks('grunt-conventional-changelog'); - - // Default task. - grunt.registerTask('default', ['jshint', 'concat', 'uglify', 'cssmin']); - grunt.registerTask('build', ['default']); - grunt.registerTask('docs', ['yuidoc']); - - grunt.registerTask('release', ['build', 'bump-only:patch', 'build', 'docs', 'changelog']); - grunt.registerTask('release:minor', ['build', 'bump-only:minor', 'build', 'docs', 'changelog']); - grunt.registerTask('release:major', ['build', 'bump-only:major', 'build', 'docs', 'changelog']); - grunt.registerTask('release:git', ['build', 'bump-only:git', 'build', 'docs', 'changelog', 'bump-commit']); - grunt.registerTask('release:commit', ['bump-commit']); - -}; diff --git a/GRID/LICENSE b/GRID/LICENSE deleted file mode 100644 index 869f81f..0000000 --- a/GRID/LICENSE +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2012 Ducksboard - -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/GRID/README.md b/GRID/README.md deleted file mode 100644 index 00eff37..0000000 --- a/GRID/README.md +++ /dev/null @@ -1,50 +0,0 @@ -Gridster.js -=========== - -[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/ducksboard/gridster.js/trend.png)](https://bitdeli.com/free "Bitdeli Badge") - -Gridster is a jQuery plugin that makes building intuitive draggable -layouts from elements spanning multiple columns. You can even -dynamically add and remove elements from the grid. - -More at [http://gridster.net/](http://gridster.net/). - -[Releases](https://github.com/ducksboard/gridster.js/releases) - -[CHANGELOG](https://github.com/ducksboard/gridster.js/blob/master/CHANGELOG.md) - -Gridster is maintained by Ducksboard occasionally but not actively. -@dustmoo and @pushmatrix have also write permissions as Gridster maintainers -they are. Thank you guys! - -## Forks - -Mr @dustmoo (maintainer of Gridster) has his own fork of gridster.js -with some new interesting features like widget-swapping and static widgets. - -Can be found here: [dustmoo/gridster.js](https://github.com/dustmoo/gridster.js) - -@dustmoo is working in his spare time to merge all these changes into -ducksboard/gridster.js - -If anyone would like to help @dustmoo improve his fork and reconcile -it with the main library he would be happy for the help. - - -## Contributing to this project - -Anyone and everyone is welcome to contribute. Please take a moment to review the guidelines for contributing. - -* [Bug reports](CONTRIBUTING.md#bugs) -* [Feature requests](CONTRIBUTING.md#features) -* [Pull requests](CONTRIBUTING.md#pull-requests) - - -## License - -Distributed under the MIT license. - -## Whodunit - -Gridster is built by [Ducksboard](http://ducksboard.com/) with the help of all -these [wonderful people](https://github.com/ducksboard/gridster.js/graphs/contributors). diff --git a/GRID/assets/demo.css b/GRID/assets/demo.css deleted file mode 100644 index c64eef7..0000000 --- a/GRID/assets/demo.css +++ /dev/null @@ -1,69 +0,0 @@ -.gridster * { - margin:0; - padding:0; -} - -ul { - list-style-type: none; -} - - -/*/ -/* demo -/*/ - - -body { - font-size: 16px; - font-family: 'Helvetica Neue', Arial, sans-serif; - color: #444; - margin: 30px 40px; -} - -.controls { - margin-bottom: 20px; -} - -/*/ -/* gridster -/*/ - -.gridster ul { - background-color: #EFEFEF; -} - -.gridster li { - font-size: 1em; - font-weight: bold; - text-align: center; - line-height: 100%; -} - - -.gridster { - margin: 0 auto; - - opacity: .8; - - -webkit-transition: opacity .6s; - -moz-transition: opacity .6s; - -o-transition: opacity .6s; - -ms-transition: opacity .6s; - transition: opacity .6s; -} - -.gridster .gs-w { - background: #DDD; - cursor: pointer; -} - -.gridster .player { - background: #BBB; -} - - -.gridster .preview-holder { - border: none!important; - background: red!important; -} - diff --git a/GRID/assets/gridster_new.js b/GRID/assets/gridster_new.js deleted file mode 100644 index c4a06af..0000000 --- a/GRID/assets/gridster_new.js +++ /dev/null @@ -1,104 +0,0 @@ - - $(window).ready(function () { - var localData = JSON.parse(localStorage.getItem('positions')); - - if(localData!=null) - { - $.each(localData, function(i,value){ - - var id_name; - - id_name="#"; - id_name = id_name + value.id; - console.log(id_name); - - $(id_name).attr({"data-col":value.col, "data-row":value.row, "data-sizex":value.size_x, "data-sizey":value.size_y}); - - -}); - } - else{ - console.log('No data returned by the server'); - } - - - // widget_selector: "> ul" - // Define which elements are the widgets. Can be a CSS Selector string or a jQuery collection of HTMLElements. - - // widget_margins: [3, 3] - // Horizontal and vertical margins respectively for widgets. - - // widget_base_dimensions: [110, 110] - // Base widget dimensions in pixels. The first index is the width, the second is the height. - - var grid_canvas = $(".gridster > ul").gridster({ - widget_margins: [3, 3], - widget_base_dimensions: [110, 110], - - // serialize_params: function($w, wgd) { return { id: $($w).attr('id'),col: wgd.col, row: wgd.row,size_x: wgd.size_x,size_y: wgd.size_y } - // A function to return serialized data for each each widget, used when calling the serialize method. Two arguments are passed: - // $w: the jQuery wrapped HTMLElement which is used to get the id, and wgd: the grid coords object with keys col, row, size_x and size_y. - - - serialize_params: function($w, wgd) - { - return { - id: $($w).attr('id'), - col: wgd.col, - row: wgd.row, - size_x: wgd.size_x, - size_y: wgd.size_y, - - }; - }, - - // draggable.stop: function(event, ui){} -- A callback for when dragging stops. - // You can also implement other draggable options based on your requirements - // draggable.start: function(event, ui){} -- A callback for when dragging starts. - // draggable.drag: function(event, ui){} -- A callback for when the mouse is moved during the dragging. - - draggable: - { - stop: function(event, ui) { - - // .serialize( ) - // Creates an array of objects representing the current position of all widgets in the grid. - // Returns an Array of Objects (ready to be encoded as a JSON string) with the data specified by the serialize_params option - // JSON.stringify() converts a primitive value, object or array to a JSON-formatted string that can later be parsed with JSON.parse(). - - var positions = JSON.stringify(this.serialize()); - - // With HTML5, web pages can store data locally within the user's browser. - // Earlier, this was done with cookies. However, Web Storage is more secure and faster. - // The data is not included with every server request, but used ONLY when asked for. - // It is also possible to store large amounts of data, without affecting the website's performance. - // The data is stored in key/value pairs, and a web page can only access data stored by itself. - - localStorage.setItem('positions', positions); - - - $.post( - "process.php", - {"positions": positions}, - function(data) - { - - // this is where you can check if your data is sent to the server or not. - // A status of 200 implies success - - console.log(data); - if(data==200) - console.log("Data successfully sent to the server"); - else - console.log - } - ); - - } - } - }).data('gridster'); - - - -}); - \ No newline at end of file diff --git a/GRID/assets/jquery.gridster.js b/GRID/assets/jquery.gridster.js deleted file mode 100644 index 947f4bb..0000000 --- a/GRID/assets/jquery.gridster.js +++ /dev/null @@ -1,3232 +0,0 @@ -/*! gridster.js - v0.1.0 - 2012-10-20 -* http://gridster.net/ -* Copyright (c) 2012 ducksboard; Licensed MIT */ - -;(function($, window, document, undefined){ - /** - * Creates objects with coordinates (x1, y1, x2, y2, cx, cy, width, height) - * to simulate DOM elements on the screen. - * Coords is used by Gridster to create a faux grid with any DOM element can - * collide. - * - * @class Coords - * @param {HTMLElement|Object} obj The jQuery HTMLElement or a object with: left, - * top, width and height properties. - * @return {Object} Coords instance. - * @constructor - */ - function Coords(obj) { - if (obj[0] && $.isPlainObject(obj[0])) { - this.data = obj[0]; - }else { - this.el = obj; - } - - this.isCoords = true; - this.coords = {}; - this.init(); - return this; - } - - - var fn = Coords.prototype; - - - fn.init = function(){ - this.set(); - this.original_coords = this.get(); - }; - - - fn.set = function(update, not_update_offsets) { - var el = this.el; - - if (el && !update) { - this.data = el.offset(); - this.data.width = el.width(); - this.data.height = el.height(); - } - - if (el && update && !not_update_offsets) { - var offset = el.offset(); - this.data.top = offset.top; - this.data.left = offset.left; - } - - var d = this.data; - - this.coords.x1 = d.left; - this.coords.y1 = d.top; - this.coords.x2 = d.left + d.width; - this.coords.y2 = d.top + d.height; - this.coords.cx = d.left + (d.width / 2); - this.coords.cy = d.top + (d.height / 2); - this.coords.width = d.width; - this.coords.height = d.height; - this.coords.el = el || false ; - - return this; - }; - - - fn.update = function(data){ - if (!data && !this.el) { - return this; - } - - if (data) { - var new_data = $.extend({}, this.data, data); - this.data = new_data; - return this.set(true, true); - } - - this.set(true); - return this; - }; - - - fn.get = function(){ - return this.coords; - }; - - - //jQuery adapter - $.fn.coords = function() { - if (this.data('coords') ) { - return this.data('coords'); - } - - var ins = new Coords(this, arguments[0]); - this.data('coords', ins); - return ins; - }; - -}(jQuery, window, document)); - -;(function($, window, document, undefined){ - - var defaults = { - colliders_context: document.body - // ,on_overlap: function(collider_data){}, - // on_overlap_start : function(collider_data){}, - // on_overlap_stop : function(collider_data){} - }; - - - /** - * Detects collisions between a DOM element against other DOM elements or - * Coords objects. - * - * @class Collision - * @uses Coords - * @param {HTMLElement} el The jQuery wrapped HTMLElement. - * @param {HTMLElement|Array} colliders Can be a jQuery collection - * of HTMLElements or an Array of Coords instances. - * @param {Object} [options] An Object with all options you want to - * overwrite: - * @param {Function} [options.on_overlap_start] Executes a function the first - * time each `collider ` is overlapped. - * @param {Function} [options.on_overlap_stop] Executes a function when a - * `collider` is no longer collided. - * @param {Function} [options.on_overlap] Executes a function when the - * mouse is moved during the collision. - * @return {Object} Collision instance. - * @constructor - */ - function Collision(el, colliders, options) { - this.options = $.extend(defaults, options); - this.$element = el; - this.last_colliders = []; - this.last_colliders_coords = []; - if (typeof colliders === 'string' || colliders instanceof jQuery) { - this.$colliders = $(colliders, - this.options.colliders_context).not(this.$element); - }else{ - this.colliders = $(colliders); - } - - this.init(); - } - - - var fn = Collision.prototype; - - - fn.init = function() { - this.find_collisions(); - }; - - - fn.overlaps = function(a, b) { - var x = false; - var y = false; - - if ((b.x1 >= a.x1 && b.x1 <= a.x2) || - (b.x2 >= a.x1 && b.x2 <= a.x2) || - (a.x1 >= b.x1 && a.x2 <= b.x2) - ) { x = true; } - - if ((b.y1 >= a.y1 && b.y1 <= a.y2) || - (b.y2 >= a.y1 && b.y2 <= a.y2) || - (a.y1 >= b.y1 && a.y2 <= b.y2) - ) { y = true; } - - return (x && y); - }; - - - fn.detect_overlapping_region = function(a, b){ - var regionX = ''; - var regionY = ''; - - if (a.y1 > b.cy && a.y1 < b.y2) { regionX = 'N'; } - if (a.y2 > b.y1 && a.y2 < b.cy) { regionX = 'S'; } - if (a.x1 > b.cx && a.x1 < b.x2) { regionY = 'W'; } - if (a.x2 > b.x1 && a.x2 < b.cx) { regionY = 'E'; } - - return (regionX + regionY) || 'C'; - }; - - - fn.calculate_overlapped_area_coords = function(a, b){ - var x1 = Math.max(a.x1, b.x1); - var y1 = Math.max(a.y1, b.y1); - var x2 = Math.min(a.x2, b.x2); - var y2 = Math.min(a.y2, b.y2); - - return $({ - left: x1, - top: y1, - width : (x2 - x1), - height: (y2 - y1) - }).coords().get(); - }; - - - fn.calculate_overlapped_area = function(coords){ - return (coords.width * coords.height); - }; - - - fn.manage_colliders_start_stop = function(new_colliders_coords, start_callback, stop_callback){ - var last = this.last_colliders_coords; - - for (var i = 0, il = last.length; i < il; i++) { - if ($.inArray(last[i], new_colliders_coords) === -1) { - start_callback.call(this, last[i]); - } - } - - for (var j = 0, jl = new_colliders_coords.length; j < jl; j++) { - if ($.inArray(new_colliders_coords[j], last) === -1) { - stop_callback.call(this, new_colliders_coords[j]); - } - - } - }; - - - fn.find_collisions = function(player_data_coords){ - var self = this; - var colliders_coords = []; - var colliders_data = []; - var $colliders = (this.colliders || this.$colliders); - var count = $colliders.length; - var player_coords = self.$element.coords() - .update(player_data_coords || false).get(); - - while(count--){ - var $collider = self.$colliders ? - $($colliders[count]) : $colliders[count]; - var $collider_coords_ins = ($collider.isCoords) ? - $collider : $collider.coords(); - var collider_coords = $collider_coords_ins.get(); - var overlaps = self.overlaps(player_coords, collider_coords); - - if (!overlaps) { - continue; - } - - var region = self.detect_overlapping_region( - player_coords, collider_coords); - - //todo: make this an option - if (region === 'C'){ - var area_coords = self.calculate_overlapped_area_coords( - player_coords, collider_coords); - var area = self.calculate_overlapped_area(area_coords); - var collider_data = { - area: area, - area_coords : area_coords, - region: region, - coords: collider_coords, - player_coords: player_coords, - el: $collider - }; - - if (self.options.on_overlap) { - self.options.on_overlap.call(this, collider_data); - } - colliders_coords.push($collider_coords_ins); - colliders_data.push(collider_data); - } - } - - if (self.options.on_overlap_stop || self.options.on_overlap_start) { - this.manage_colliders_start_stop(colliders_coords, - self.options.on_overlap_stop, self.options.on_overlap_start); - } - - this.last_colliders_coords = colliders_coords; - - return colliders_data; - }; - - - fn.get_closest_colliders = function(player_data_coords){ - var colliders = this.find_collisions(player_data_coords); - - colliders.sort(function(a, b) { - /* if colliders are being overlapped by the "C" (center) region, - * we have to set a lower index in the array to which they are placed - * above in the grid. */ - if (a.region === 'C' && b.region === 'C') { - if (a.coords.y1 < b.coords.y1 || a.coords.x1 < b.coords.x1) { - return - 1; - }else{ - return 1; - } - } - - if (a.area < b.area) { - return 1; - } - - return 1; - }); - return colliders; - }; - - - //jQuery adapter - $.fn.collision = function(collider, options) { - return new Collision( this, collider, options ); - }; - - -}(jQuery, window, document)); - -;(function(window, undefined) { - /* Debounce and throttle functions taken from underscore.js */ - window.debounce = function(func, wait, immediate) { - var timeout; - return function() { - var context = this, args = arguments; - var later = function() { - timeout = null; - if (!immediate) func.apply(context, args); - }; - if (immediate && !timeout) func.apply(context, args); - clearTimeout(timeout); - timeout = setTimeout(later, wait); - }; - }; - - - window.throttle = function(func, wait) { - var context, args, timeout, throttling, more, result; - var whenDone = debounce( - function(){ more = throttling = false; }, wait); - return function() { - context = this; args = arguments; - var later = function() { - timeout = null; - if (more) func.apply(context, args); - whenDone(); - }; - if (!timeout) timeout = setTimeout(later, wait); - if (throttling) { - more = true; - } else { - result = func.apply(context, args); - } - whenDone(); - throttling = true; - return result; - }; - }; - -})(window); - -;(function($, window, document, undefined){ - - var defaults = { - items: '.gs_w', - distance: 1, - limit: true, - offset_left: 0, - autoscroll: true, - ignore_dragging: ['INPUT', 'TEXTAREA', 'SELECT', 'BUTTON'], - handle: null - // ,drag: function(e){}, - // start : function(e, ui){}, - // stop : function(e){} - }; - - var $window = $(window); - var isTouch = !!('ontouchstart' in window); - var pointer_events = { - start: isTouch ? 'touchstart' : 'mousedown.draggable', - move: isTouch ? 'touchmove' : 'mousemove.draggable', - end: isTouch ? 'touchend' : 'mouseup.draggable' - }; - - /** - * Basic drag implementation for DOM elements inside a container. - * Provide start/stop/drag callbacks. - * - * @class Draggable - * @param {HTMLElement} el The HTMLelement that contains all the widgets - * to be dragged. - * @param {Object} [options] An Object with all options you want to - * overwrite: - * @param {HTMLElement|String} [options.items] Define who will - * be the draggable items. Can be a CSS Selector String or a - * collection of HTMLElements. - * @param {Number} [options.distance] Distance in pixels after mousedown - * the mouse must move before dragging should start. - * @param {Boolean} [options.limit] Constrains dragging to the width of - * the container - * @param {offset_left} [options.offset_left] Offset added to the item - * that is being dragged. - * @param {Number} [options.drag] Executes a callback when the mouse is - * moved during the dragging. - * @param {Number} [options.start] Executes a callback when the drag - * starts. - * @param {Number} [options.stop] Executes a callback when the drag stops. - * @return {Object} Returns `el`. - * @constructor - */ - function Draggable(el, options) { - this.options = $.extend({}, defaults, options); - this.$body = $(document.body); - this.$container = $(el); - this.$dragitems = $(this.options.items, this.$container); - this.is_dragging = false; - this.player_min_left = 0 + this.options.offset_left; - this.init(); - } - - var fn = Draggable.prototype; - - fn.init = function() { - this.calculate_positions(); - this.$container.css('position', 'relative'); - this.disabled = false; - this.events(); - - $(window).bind('resize', - throttle($.proxy(this.calculate_positions, this), 200)); - }; - - fn.events = function() { - this.$container.on('selectstart', $.proxy(this.on_select_start, this)); - - this.$container.on(pointer_events.start, this.options.items, $.proxy( - this.drag_handler, this)); - - this.$body.on(pointer_events.end, $.proxy(function(e) { - this.is_dragging = false; - if (this.disabled) { return; } - this.$body.off(pointer_events.move); - if (this.drag_start) { - this.on_dragstop(e); - } - }, this)); - }; - - fn.get_actual_pos = function($el) { - var pos = $el.position(); - return pos; - }; - - - fn.get_mouse_pos = function(e) { - if (isTouch) { - var oe = e.originalEvent; - e = oe.touches.length ? oe.touches[0] : oe.changedTouches[0]; - } - - return { - left: e.clientX, - top: e.clientY - }; - }; - - - fn.get_offset = function(e) { - e.preventDefault(); - var mouse_actual_pos = this.get_mouse_pos(e); - var diff_x = Math.round( - mouse_actual_pos.left - this.mouse_init_pos.left); - var diff_y = Math.round(mouse_actual_pos.top - this.mouse_init_pos.top); - - var left = Math.round(this.el_init_offset.left + diff_x - this.baseX); - var top = Math.round( - this.el_init_offset.top + diff_y - this.baseY + this.scrollOffset); - - if (this.options.limit) { - if (left > this.player_max_left) { - left = this.player_max_left; - }else if(left < this.player_min_left) { - left = this.player_min_left; - } - } - - return { - left: left, - top: top, - mouse_left: mouse_actual_pos.left, - mouse_top: mouse_actual_pos.top - }; - }; - - - fn.manage_scroll = function(offset) { - /* scroll document */ - var nextScrollTop; - var scrollTop = $window.scrollTop(); - var min_window_y = scrollTop; - var max_window_y = min_window_y + this.window_height; - - var mouse_down_zone = max_window_y - 50; - var mouse_up_zone = min_window_y + 50; - - var abs_mouse_left = offset.mouse_left; - var abs_mouse_top = min_window_y + offset.mouse_top; - - var max_player_y = (this.doc_height - this.window_height + - this.player_height); - - if (abs_mouse_top >= mouse_down_zone) { - nextScrollTop = scrollTop + 30; - if (nextScrollTop < max_player_y) { - $window.scrollTop(nextScrollTop); - this.scrollOffset = this.scrollOffset + 30; - } - } - - if (abs_mouse_top <= mouse_up_zone) { - nextScrollTop = scrollTop - 30; - if (nextScrollTop > 0) { - $window.scrollTop(nextScrollTop); - this.scrollOffset = this.scrollOffset - 30; - } - } - }; - - - fn.calculate_positions = function(e) { - this.window_height = $window.height(); - }; - - - fn.drag_handler = function(e) { - var node = e.target.nodeName; - if (this.disabled || e.which !== 1 && !isTouch) { - return; - } - - if (this.ignore_drag(e)) { - return; - } - - var self = this; - var first = true; - this.$player = $(e.currentTarget); - - this.el_init_pos = this.get_actual_pos(this.$player); - this.mouse_init_pos = this.get_mouse_pos(e); - this.offsetY = this.mouse_init_pos.top - this.el_init_pos.top; - - this.$body.on(pointer_events.move, function(mme){ - var mouse_actual_pos = self.get_mouse_pos(mme); - var diff_x = Math.abs( - mouse_actual_pos.left - self.mouse_init_pos.left); - var diff_y = Math.abs( - mouse_actual_pos.top - self.mouse_init_pos.top); - if (!(diff_x > self.options.distance || - diff_y > self.options.distance) - ) { - return false; - } - - if (first) { - first = false; - self.on_dragstart.call(self, mme); - return false; - } - - if (self.is_dragging === true) { - self.on_dragmove.call(self, mme); - } - - return false; - }); - - return false; - }; - - - fn.on_dragstart = function(e) { - e.preventDefault(); - this.drag_start = true; - this.is_dragging = true; - var offset = this.$container.offset(); - this.baseX = Math.round(offset.left); - this.baseY = Math.round(offset.top); - this.doc_height = $(document).height(); - - if (this.options.helper === 'clone') { - this.$helper = this.$player.clone() - .appendTo(this.$container).addClass('helper'); - this.helper = true; - }else{ - this.helper = false; - } - this.scrollOffset = 0; - this.el_init_offset = this.$player.offset(); - this.player_width = this.$player.width(); - this.player_height = this.$player.height(); - this.player_max_left = (this.$container.width() - this.player_width + - this.options.offset_left); - - if (this.options.start) { - this.options.start.call(this.$player, e, { - helper: this.helper ? this.$helper : this.$player - }); - } - return false; - }; - - - fn.on_dragmove = function(e) { - var offset = this.get_offset(e); - - this.options.autoscroll && this.manage_scroll(offset); - - (this.helper ? this.$helper : this.$player).css({ - 'position': 'absolute', - 'left' : offset.left, - 'top' : offset.top - }); - - var ui = { - 'position': { - 'left': offset.left, - 'top': offset.top - } - }; - - if (this.options.drag) { - this.options.drag.call(this.$player, e, ui); - } - return false; - }; - - - fn.on_dragstop = function(e) { - var offset = this.get_offset(e); - this.drag_start = false; - - var ui = { - 'position': { - 'left': offset.left, - 'top': offset.top - } - }; - - if (this.options.stop) { - this.options.stop.call(this.$player, e, ui); - } - - if (this.helper) { - this.$helper.remove(); - } - - return false; - }; - - fn.on_select_start = function(e) { - if (this.disabled) { return; } - - if (this.ignore_drag(e)) { - return; - } - - return false; - }; - - fn.enable = function() { - this.disabled = false; - }; - - fn.disable = function() { - this.disabled = true; - }; - - - fn.destroy = function(){ - this.disable(); - $.removeData(this.$container, 'drag'); - }; - - fn.ignore_drag = function(event) { - if (this.options.handle) { - return !$(event.target).is(this.options.handle); - } - - return $.inArray(event.target.nodeName, this.options.ignore_dragging) >= 0; - }; - - //jQuery adapter - $.fn.drag = function ( options ) { - return this.each(function () { - if (!$.data(this, 'drag')) { - $.data(this, 'drag', new Draggable( this, options )); - } - }); - }; - - -}(jQuery, window, document)); - -;(function($, window, document, undefined) { - - var defaults = { - namespace: '', - widget_selector: 'li', - widget_margins: [10, 10], - widget_base_dimensions: [400, 225], - extra_rows: 0, - extra_cols: 0, - min_cols: 1, - min_rows: 15, - max_size_x: 6, - autogenerate_stylesheet: true, - avoid_overlapped_widgets: true, - serialize_params: function($w, wgd) { - return { - col: wgd.col, - row: wgd.row, - size_x: wgd.size_x, - size_y: wgd.size_y - }; - }, - collision: {}, - draggable: { - distance: 4 - } - }; - - - /** - * @class Gridster - * @uses Draggable - * @uses Collision - * @param {HTMLElement} el The HTMLelement that contains all the widgets. - * @param {Object} [options] An Object with all options you want to - * overwrite: - * @param {HTMLElement|String} [options.widget_selector] Define who will - * be the draggable widgets. Can be a CSS Selector String or a - * collection of HTMLElements - * @param {Array} [options.widget_margins] Margin between widgets. - * The first index for the horizontal margin (left, right) and - * the second for the vertical margin (top, bottom). - * @param {Array} [options.widget_base_dimensions] Base widget dimensions - * in pixels. The first index for the width and the second for the - * height. - * @param {Number} [options.extra_cols] Add more columns in addition to - * those that have been calculated. - * @param {Number} [options.extra_rows] Add more rows in addition to - * those that have been calculated. - * @param {Number} [options.min_cols] The minimum required columns. - * @param {Number} [options.min_rows] The minimum required rows. - * @param {Number} [options.max_size_x] The maximum number of columns - * that a widget can span. - * @param {Boolean} [options.autogenerate_stylesheet] If true, all the - * CSS required to position all widgets in their respective columns - * and rows will be generated automatically and injected to the - * `` of the document. You can set this to false, and write - * your own CSS targeting rows and cols via data-attributes like so: - * `[data-col="1"] { left: 10px; }` - * @param {Boolean} [options.avoid_overlapped_widgets] Avoid that widgets loaded - * from the DOM can be overlapped. It is helpful if the positions were - * bad stored in the database or if there was any conflict. - * @param {Function} [options.serialize_params] Return the data you want - * for each widget in the serialization. Two arguments are passed: - * `$w`: the jQuery wrapped HTMLElement, and `wgd`: the grid - * coords object (`col`, `row`, `size_x`, `size_y`). - * @param {Object} [options.collision] An Object with all options for - * Collision class you want to overwrite. See Collision docs for - * more info. - * @param {Object} [options.draggable] An Object with all options for - * Draggable class you want to overwrite. See Draggable docs for more - * info. - * - * @constructor - */ - function Gridster(el, options) { - this.options = $.extend(true, defaults, options); - this.$el = $(el); - this.$wrapper = this.$el.parent(); - this.$widgets = this.$el.children(this.options.widget_selector).addClass('gs_w'); - this.widgets = []; - this.$changed = $([]); - this.wrapper_width = this.$wrapper.width(); - this.min_widget_width = (this.options.widget_margins[0] * 2) + - this.options.widget_base_dimensions[0]; - this.min_widget_height = (this.options.widget_margins[1] * 2) + - this.options.widget_base_dimensions[1]; - this.init(); - } - - Gridster.generated_stylesheets = []; - - var fn = Gridster.prototype; - - fn.init = function() { - this.generate_grid_and_stylesheet(); - this.get_widgets_from_DOM(); - this.set_dom_grid_height(); - this.$wrapper.addClass('ready'); - this.draggable(); - - $(window).bind( - 'resize', throttle($.proxy(this.recalculate_faux_grid, this), 200)); - }; - - - /** - * Disables dragging. - * - * @method disable - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.disable = function() { - this.$wrapper.find('.player-revert').removeClass('player-revert'); - this.drag_api.disable(); - return this; - }; - - - /** - * Enables dragging. - * - * @method enable - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.enable = function() { - this.drag_api.enable(); - return this; - }; - - - /** - * Add a new widget to the grid. - * - * @method add_widget - * @param {String|HTMLElement} html The string representing the HTML of the widget - * or the HTMLElement. - * @param {Number} [size_x] The nº of rows the widget occupies horizontally. - * @param {Number} [size_y] The nº of columns the widget occupies vertically. - * @param {Number} [col] The column the widget should start in. - * @param {Number} [row] The row the widget should start in. - * @return {HTMLElement} Returns the jQuery wrapped HTMLElement representing. - * the widget that was just created. - */ - fn.add_widget = function(html, size_x, size_y, col, row) { - var pos; - size_x || (size_x = 1); - size_y || (size_y = 1); - - if (!col & !row) { - pos = this.next_position(size_x, size_y); - }else{ - pos = { - col: col, - row: row - }; - - this.empty_cells(col, row, size_x, size_y); - } - - var $w = $(html).attr({ - 'data-col': pos.col, - 'data-row': pos.row, - 'data-sizex' : size_x, - 'data-sizey' : size_y - }).addClass('gs_w').appendTo(this.$el).hide(); - - this.$widgets = this.$widgets.add($w); - - this.register_widget($w); - - this.add_faux_rows(pos.size_y); - //this.add_faux_cols(pos.size_x); - - this.set_dom_grid_height(); - - return $w.fadeIn(); - }; - - - - /** - * Change the size of a widget. - * - * @method resize_widget - * @param {HTMLElement} $widget The jQuery wrapped HTMLElement - * representing the widget. - * @param {Number} size_x The number of columns that will occupy the widget. - * @param {Number} size_y The number of rows that will occupy the widget. - * @return {HTMLElement} Returns $widget. - */ - fn.resize_widget = function($widget, size_x, size_y) { - var wgd = $widget.coords().grid; - size_x || (size_x = wgd.size_x); - size_y || (size_y = wgd.size_y); - - if (size_x > this.cols) { - size_x = this.cols; - } - - var old_cells_occupied = this.get_cells_occupied(wgd); - var old_size_x = wgd.size_x; - var old_size_y = wgd.size_y; - var old_col = wgd.col; - var new_col = old_col; - var wider = size_x > old_size_x; - var taller = size_y > old_size_y; - - if (old_col + size_x - 1 > this.cols) { - var diff = old_col + (size_x - 1) - this.cols; - var c = old_col - diff; - new_col = Math.max(1, c); - } - - var new_grid_data = { - col: new_col, - row: wgd.row, - size_x: size_x, - size_y: size_y - }; - - var new_cells_occupied = this.get_cells_occupied(new_grid_data); - - var empty_cols = []; - $.each(old_cells_occupied.cols, function(i, col) { - if ($.inArray(col, new_cells_occupied.cols) === -1) { - empty_cols.push(col); - } - }); - - var occupied_cols = []; - $.each(new_cells_occupied.cols, function(i, col) { - if ($.inArray(col, old_cells_occupied.cols) === -1) { - occupied_cols.push(col); - } - }); - - var empty_rows = []; - $.each(old_cells_occupied.rows, function(i, row) { - if ($.inArray(row, new_cells_occupied.rows) === -1) { - empty_rows.push(row); - } - }); - - var occupied_rows = []; - $.each(new_cells_occupied.rows, function(i, row) { - if ($.inArray(row, old_cells_occupied.rows) === -1) { - occupied_rows.push(row); - } - }); - - this.remove_from_gridmap(wgd); - - if (occupied_cols.length) { - var cols_to_empty = [ - new_col, wgd.row, size_x, Math.min(old_size_y, size_y), $widget - ]; - this.empty_cells.apply(this, cols_to_empty); - } - - if (occupied_rows.length) { - var rows_to_empty = [new_col, wgd.row, size_x, size_y, $widget]; - this.empty_cells.apply(this, rows_to_empty); - } - - wgd.col = new_col; - wgd.size_x = size_x; - wgd.size_y = size_y; - this.add_to_gridmap(new_grid_data, $widget); - - //update coords instance attributes - $widget.data('coords').update({ - width: (size_x * this.options.widget_base_dimensions[0] + - ((size_x - 1) * this.options.widget_margins[0]) * 2), - height: (size_y * this.options.widget_base_dimensions[1] + - ((size_y - 1) * this.options.widget_margins[1]) * 2) - }); - - if (size_y > old_size_y) { - this.add_faux_rows(size_y - old_size_y); - } - - if (size_x > old_size_x) { - this.add_faux_cols(size_x - old_size_x); - } - - $widget.attr({ - 'data-col': new_col, - 'data-sizex': size_x, - 'data-sizey': size_y - }); - - if (empty_cols.length) { - var cols_to_remove_holes = [ - empty_cols[0], wgd.row, - empty_cols.length, - Math.min(old_size_y, size_y), - $widget - ]; - - this.remove_empty_cells.apply(this, cols_to_remove_holes); - } - - if (empty_rows.length) { - var rows_to_remove_holes = [ - new_col, wgd.row, size_x, size_y, $widget - ]; - this.remove_empty_cells.apply(this, rows_to_remove_holes); - } - - return $widget; - }; - - /** - * Move down widgets in cells represented by the arguments col, row, size_x, - * size_y - * - * @method empty_cells - * @param {Number} col The column where the group of cells begin. - * @param {Number} row The row where the group of cells begin. - * @param {Number} size_x The number of columns that the group of cells - * occupy. - * @param {Number} size_y The number of rows that the group of cells - * occupy. - * @param {HTMLElement} $exclude Exclude widgets from being moved. - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.empty_cells = function(col, row, size_x, size_y, $exclude) { - var $nexts = this.widgets_below({ - col: col, - row: row - size_y, - size_x: size_x, - size_y: size_y - }); - - $nexts.not($exclude).each($.proxy(function(i, w) { - var wgd = $(w).coords().grid; - if (!(wgd.row <= (row + size_y - 1))) { return; } - var diff = (row + size_y) - wgd.row; - this.move_widget_down($(w), diff); - }, this)); - - this.set_dom_grid_height(); - - return this; - }; - - - /** - * Move up widgets below cells represented by the arguments col, row, size_x, - * size_y. - * - * @method remove_empty_cells - * @param {Number} col The column where the group of cells begin. - * @param {Number} row The row where the group of cells begin. - * @param {Number} size_x The number of columns that the group of cells - * occupy. - * @param {Number} size_y The number of rows that the group of cells - * occupy. - * @param {HTMLElement} $exclude Exclude widgets from being moved. - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.remove_empty_cells = function(col, row, size_x, size_y, exclude) { - var $nexts = this.widgets_below({ - col: col, - row: row, - size_x: size_x, - size_y: size_y - }); - - $nexts.not(exclude).each($.proxy(function(i, widget) { - this.move_widget_up( $(widget), size_y ); - }, this)); - - this.set_dom_grid_height(); - - return this; - }; - - - /** - * Get the most left column below to add a new widget. - * - * @method next_position - * @param {Number} size_x The nº of rows the widget occupies horizontally. - * @param {Number} size_y The nº of columns the widget occupies vertically. - * @return {Object} Returns a grid coords object representing the future - * widget coords. - */ - fn.next_position = function(size_x, size_y) { - size_x || (size_x = 1); - size_y || (size_y = 1); - var ga = this.gridmap; - var cols_l = ga.length; - var valid_pos = []; - var rows_l; - - for (var c = 1; c < cols_l; c++) { - rows_l = ga[c].length; - for (var r = 1; r <= rows_l; r++) { - var can_move_to = this.can_move_to({ - size_x: size_x, - size_y: size_y - }, c, r); - - if (can_move_to) { - valid_pos.push({ - col: c, - row: r, - size_y: size_y, - size_x: size_x - }); - } - } - } - - if (valid_pos.length) { - return this.sort_by_row_and_col_asc(valid_pos)[0]; - } - return false; - }; - - - /** - * Remove a widget from the grid. - * - * @method remove_widget - * @param {HTMLElement} el The jQuery wrapped HTMLElement you want to remove. - * @param {Boolean|Function} silent If true, widgets below the removed one - * will not move up. If a Function is passed it will be used as callback. - * @param {Function} callback Function executed when the widget is removed. - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.remove_widget = function(el, silent, callback) { - var $el = el instanceof jQuery ? el : $(el); - var wgd = $el.coords().grid; - - // if silent is a function assume it's a callback - if ($.isFunction(silent)) { - callback = silent; - silent = false; - } - - this.cells_occupied_by_placeholder = {}; - this.$widgets = this.$widgets.not($el); - - var $nexts = this.widgets_below($el); - - this.remove_from_gridmap(wgd); - - $el.fadeOut($.proxy(function() { - $el.remove(); - - if (!silent) { - $nexts.each($.proxy(function(i, widget) { - this.move_widget_up( $(widget), wgd.size_y ); - }, this)); - } - - this.set_dom_grid_height(); - - if (callback) { - callback.call(this, el); - } - }, this)); - }; - - - /** - * Remove all widgets from the grid. - * - * @method remove_all_widgets - * @param {Function} callback Function executed for each widget removed. - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.remove_all_widgets = function(callback) { - this.$widgets.each($.proxy(function(i, el){ - this.remove_widget(el, true, callback); - }, this)); - - return this; - }; - - - /** - * Returns a serialized array of the widgets in the grid. - * - * @method serialize - * @param {HTMLElement} [$widgets] The collection of jQuery wrapped - * HTMLElements you want to serialize. If no argument is passed all widgets - * will be serialized. - * @return {Array} Returns an Array of Objects with the data specified in - * the serialize_params option. - */ - fn.serialize = function($widgets) { - $widgets || ($widgets = this.$widgets); - var result = []; - $widgets.each($.proxy(function(i, widget) { - result.push(this.options.serialize_params( - $(widget), $(widget).coords().grid ) ); - }, this)); - - return result; - }; - - - /** - * Returns a serialized array of the widgets that have changed their - * position. - * - * @method serialize_changed - * @return {Array} Returns an Array of Objects with the data specified in - * the serialize_params option. - */ - fn.serialize_changed = function() { - return this.serialize(this.$changed); - }; - - - /** - * Creates the grid coords object representing the widget a add it to the - * mapped array of positions. - * - * @method register_widget - * @return {Array} Returns the instance of the Gridster class. - */ - fn.register_widget = function($el) { - - var wgd = { - 'col': parseInt($el.attr('data-col'), 10), - 'row': parseInt($el.attr('data-row'), 10), - 'size_x': parseInt($el.attr('data-sizex'), 10), - 'size_y': parseInt($el.attr('data-sizey'), 10), - 'el': $el - }; - - if (this.options.avoid_overlapped_widgets && - !this.can_move_to( - {size_x: wgd.size_x, size_y: wgd.size_y}, wgd.col, wgd.row) - ) { - wgd = this.next_position(wgd.size_x, wgd.size_y); - wgd.el = $el; - $el.attr({ - 'data-col': wgd.col, - 'data-row': wgd.row, - 'data-sizex': wgd.size_x, - 'data-sizey': wgd.size_y - }); - } - - // attach Coord object to player data-coord attribute - $el.data('coords', $el.coords()); - - // Extend Coord object with grid position info - $el.data('coords').grid = wgd; - - this.add_to_gridmap(wgd, $el); - - return this; - }; - - - /** - * Update in the mapped array of positions the value of cells represented by - * the grid coords object passed in the `grid_data` param. - * - * @param {Object} grid_data The grid coords object representing the cells - * to update in the mapped array. - * @param {HTMLElement|Boolean} value Pass `false` or the jQuery wrapped - * HTMLElement, depends if you want to delete an existing position or add - * a new one. - * @method update_widget_position - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.update_widget_position = function(grid_data, value) { - this.for_each_cell_occupied(grid_data, function(col, row) { - if (!this.gridmap[col]) { return this; } - this.gridmap[col][row] = value; - }); - return this; - }; - - - /** - * Remove a widget from the mapped array of positions. - * - * @method remove_from_gridmap - * @param {Object} grid_data The grid coords object representing the cells - * to update in the mapped array. - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.remove_from_gridmap = function(grid_data) { - return this.update_widget_position(grid_data, false); - }; - - - /** - * Add a widget to the mapped array of positions. - * - * @method add_to_gridmap - * @param {Object} grid_data The grid coords object representing the cells - * to update in the mapped array. - * @param {HTMLElement|Boolean} value The value to set in the specified - * position . - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.add_to_gridmap = function(grid_data, value) { - this.update_widget_position(grid_data, value || grid_data.el); - - if (grid_data.el) { - var $widgets = this.widgets_below(grid_data.el); - $widgets.each($.proxy(function(i, widget) { - this.move_widget_up( $(widget)); - }, this)); - } - }; - - - /** - * Make widgets draggable. - * - * @uses Draggable - * @method draggable - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.draggable = function() { - var self = this; - var draggable_options = $.extend(true, {}, this.options.draggable, { - offset_left: this.options.widget_margins[0], - start: function(event, ui) { - self.$widgets.filter('.player-revert') - .removeClass('player-revert'); - - self.$player = $(this); - self.$helper = self.options.draggable.helper === 'clone' ? - $(ui.helper) : self.$player; - self.helper = !self.$helper.is(self.$player); - - self.on_start_drag.call(self, event, ui); - self.$el.trigger('gridster:dragstart'); - }, - stop: function(event, ui) { - self.on_stop_drag.call(self, event, ui); - self.$el.trigger('gridster:dragstop'); - }, - drag: throttle(function(event, ui) { - self.on_drag.call(self, event, ui); - self.$el.trigger('gridster:drag'); - }, 60) - }); - - this.drag_api = this.$el.drag(draggable_options).data('drag'); - return this; - }; - - - /** - * This function is executed when the player begins to be dragged. - * - * @method on_start_drag - * @param {Event} The original browser event - * @param {Object} A prepared ui object. - */ - fn.on_start_drag = function(event, ui) { - - this.$helper.add(this.$player).add(this.$wrapper).addClass('dragging'); - - this.$player.addClass('player'); - this.player_grid_data = this.$player.coords().grid; - this.placeholder_grid_data = $.extend({}, this.player_grid_data); - - //set new grid height along the dragging period - this.$el.css('height', this.$el.height() + - (this.player_grid_data.size_y * this.min_widget_height)); - - var colliders = this.faux_grid; - var coords = this.$player.data('coords').coords; - - this.cells_occupied_by_player = this.get_cells_occupied( - this.player_grid_data); - this.cells_occupied_by_placeholder = this.get_cells_occupied( - this.placeholder_grid_data); - - this.last_cols = []; - this.last_rows = []; - - - // see jquery.collision.js - this.collision_api = this.$helper.collision( - colliders, this.options.collision); - - this.$preview_holder = $('
      • ', { - 'class': 'preview-holder', - 'data-row': this.$player.attr('data-row'), - 'data-col': this.$player.attr('data-col'), - css: { - width: coords.width, - height: coords.height - } - }).appendTo(this.$el); - - if (this.options.draggable.start) { - this.options.draggable.start.call(this, event, ui); - } - }; - - - /** - * This function is executed when the player is being dragged. - * - * @method on_drag - * @param {Event} The original browser event - * @param {Object} A prepared ui object. - */ - fn.on_drag = function(event, ui) { - //break if dragstop has been fired - if (this.$player === null) { - return false; - } - - var abs_offset = { - left: ui.position.left + this.baseX, - top: ui.position.top + this.baseY - }; - - this.colliders_data = this.collision_api.get_closest_colliders( - abs_offset); - - this.on_overlapped_column_change( - this.on_start_overlapping_column, - this.on_stop_overlapping_column - ); - - this.on_overlapped_row_change( - this.on_start_overlapping_row, - this.on_stop_overlapping_row - ); - - if (this.helper && this.$player) { - this.$player.css({ - 'left': ui.position.left, - 'top': ui.position.top - }); - } - - if (this.options.draggable.drag) { - this.options.draggable.drag.call(this, event, ui); - } - }; - - /** - * This function is executed when the player stops being dragged. - * - * @method on_stop_drag - * @param {Event} The original browser event - * @param {Object} A prepared ui object. - */ - fn.on_stop_drag = function(event, ui) { - this.$helper.add(this.$player).add(this.$wrapper) - .removeClass('dragging'); - - ui.position.left = ui.position.left + this.baseX; - ui.position.top = ui.position.top + this.baseY; - this.colliders_data = this.collision_api.get_closest_colliders(ui.position); - - this.on_overlapped_column_change( - this.on_start_overlapping_column, - this.on_stop_overlapping_column - ); - - this.on_overlapped_row_change( - this.on_start_overlapping_row, - this.on_stop_overlapping_row - ); - - this.$player.addClass('player-revert').removeClass('player') - .attr({ - 'data-col': this.placeholder_grid_data.col, - 'data-row': this.placeholder_grid_data.row - }).css({ - 'left': '', - 'top': '' - }); - - this.$changed = this.$changed.add(this.$player); - - this.cells_occupied_by_player = this.get_cells_occupied( - this.placeholder_grid_data); - this.set_cells_player_occupies( - this.placeholder_grid_data.col, this.placeholder_grid_data.row); - - this.$player.coords().grid.row = this.placeholder_grid_data.row; - this.$player.coords().grid.col = this.placeholder_grid_data.col; - - if (this.options.draggable.stop) { - this.options.draggable.stop.call(this, event, ui); - } - - this.$preview_holder.remove(); - - this.$player = null; - this.$helper = null; - this.placeholder_grid_data = {}; - this.player_grid_data = {}; - this.cells_occupied_by_placeholder = {}; - this.cells_occupied_by_player = {}; - - this.set_dom_grid_height(); - }; - - - /** - * Executes the callbacks passed as arguments when a column begins to be - * overlapped or stops being overlapped. - * - * @param {Function} start_callback Function executed when a new column - * begins to be overlapped. The column is passed as first argument. - * @param {Function} stop_callback Function executed when a column stops - * being overlapped. The column is passed as first argument. - * @method on_overlapped_column_change - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.on_overlapped_column_change = function(start_callback, stop_callback) { - if (!this.colliders_data.length) { - return; - } - var cols = this.get_targeted_columns( - this.colliders_data[0].el.data.col); - - var last_n_cols = this.last_cols.length; - var n_cols = cols.length; - var i; - - for (i = 0; i < n_cols; i++) { - if ($.inArray(cols[i], this.last_cols) === -1) { - (start_callback || $.noop).call(this, cols[i]); - } - } - - for (i = 0; i< last_n_cols; i++) { - if ($.inArray(this.last_cols[i], cols) === -1) { - (stop_callback || $.noop).call(this, this.last_cols[i]); - } - } - - this.last_cols = cols; - - return this; - }; - - - /** - * Executes the callbacks passed as arguments when a row starts to be - * overlapped or stops being overlapped. - * - * @param {Function} start_callback Function executed when a new row begins - * to be overlapped. The row is passed as first argument. - * @param {Function} stop_callback Function executed when a row stops being - * overlapped. The row is passed as first argument. - * @method on_overlapped_row_change - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.on_overlapped_row_change = function(start_callback, end_callback) { - if (!this.colliders_data.length) { - return; - } - var rows = this.get_targeted_rows(this.colliders_data[0].el.data.row); - var last_n_rows = this.last_rows.length; - var n_rows = rows.length; - var i; - - for (i = 0; i < n_rows; i++) { - if ($.inArray(rows[i], this.last_rows) === -1) { - (start_callback || $.noop).call(this, rows[i]); - } - } - - for (i = 0; i < last_n_rows; i++) { - if ($.inArray(this.last_rows[i], rows) === -1) { - (end_callback || $.noop).call(this, this.last_rows[i]); - } - } - - this.last_rows = rows; - }; - - - /** - * Sets the current position of the player - * - * @param {Function} start_callback Function executed when a new row begins - * to be overlapped. The row is passed as first argument. - * @param {Function} stop_callback Function executed when a row stops being - * overlapped. The row is passed as first argument. - * @method set_player - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.set_player = function(col, row, no_player) { - var self = this; - if (!no_player) { - this.empty_cells_player_occupies(); - } - var cell = !no_player ? self.colliders_data[0].el.data : {col: col}; - var to_col = cell.col; - var to_row = row || cell.row; - - this.player_grid_data = { - col: to_col, - row: to_row, - size_y : this.player_grid_data.size_y, - size_x : this.player_grid_data.size_x - }; - - this.cells_occupied_by_player = this.get_cells_occupied( - this.player_grid_data); - - var $overlapped_widgets = this.get_widgets_overlapped( - this.player_grid_data); - - var constraints = this.widgets_constraints($overlapped_widgets); - - this.manage_movements(constraints.can_go_up, to_col, to_row); - this.manage_movements(constraints.can_not_go_up, to_col, to_row); - - /* if there is not widgets overlapping in the new player position, - * update the new placeholder position. */ - if (!$overlapped_widgets.length) { - var pp = this.can_go_player_up(this.player_grid_data); - if (pp !== false) { - to_row = pp; - } - this.set_placeholder(to_col, to_row); - } - - return { - col: to_col, - row: to_row - }; - }; - - - /** - * See which of the widgets in the $widgets param collection can go to - * a upper row and which not. - * - * @method widgets_contraints - * @param {HTMLElements} $widgets A jQuery wrapped collection of - * HTMLElements. - * @return {Array} Returns a literal Object with two keys: `can_go_up` & - * `can_not_go_up`. Each contains a set of HTMLElements. - */ - fn.widgets_constraints = function($widgets) { - var $widgets_can_go_up = $([]); - var $widgets_can_not_go_up; - var wgd_can_go_up = []; - var wgd_can_not_go_up = []; - - $widgets.each($.proxy(function(i, w) { - var $w = $(w); - var wgd = $w.coords().grid; - if (this.can_go_widget_up(wgd)) { - $widgets_can_go_up = $widgets_can_go_up.add($w); - wgd_can_go_up.push(wgd); - }else{ - wgd_can_not_go_up.push(wgd); - } - }, this)); - - $widgets_can_not_go_up = $widgets.not($widgets_can_go_up); - - return { - can_go_up: this.sort_by_row_asc(wgd_can_go_up), - can_not_go_up: this.sort_by_row_desc(wgd_can_not_go_up) - }; - }; - - - /** - * Sorts an Array of grid coords objects (representing the grid coords of - * each widget) in ascending way. - * - * @method sort_by_row_asc - * @param {Array} widgets Array of grid coords objects - * @return {Array} Returns the array sorted. - */ - fn.sort_by_row_asc = function(widgets) { - widgets = widgets.sort(function(a, b) { - if (!a.row) { - a = $(a).coords().grid; - b = $(b).coords().grid; - } - - if (a.row > b.row) { - return 1; - } - return -1; - }); - - return widgets; - }; - - - /** - * Sorts an Array of grid coords objects (representing the grid coords of - * each widget) placing first the empty cells upper left. - * - * @method sort_by_row_and_col_asc - * @param {Array} widgets Array of grid coords objects - * @return {Array} Returns the array sorted. - */ - fn.sort_by_row_and_col_asc = function(widgets) { - widgets = widgets.sort(function(a, b) { - if (a.row > b.row || a.row === b.row && a.col > b.col) { - return 1; - } - return -1; - }); - - return widgets; - }; - - - /** - * Sorts an Array of grid coords objects by column (representing the grid - * coords of each widget) in ascending way. - * - * @method sort_by_col_asc - * @param {Array} widgets Array of grid coords objects - * @return {Array} Returns the array sorted. - */ - fn.sort_by_col_asc = function(widgets) { - widgets = widgets.sort(function(a, b) { - if (a.col > b.col) { - return 1; - } - return -1; - }); - - return widgets; - }; - - - /** - * Sorts an Array of grid coords objects (representing the grid coords of - * each widget) in descending way. - * - * @method sort_by_row_desc - * @param {Array} widgets Array of grid coords objects - * @return {Array} Returns the array sorted. - */ - fn.sort_by_row_desc = function(widgets) { - widgets = widgets.sort(function(a, b) { - if (a.row + a.size_y < b.row + b.size_y) { - return 1; - } - return -1; - }); - return widgets; - }; - - - /** - * Sorts an Array of grid coords objects (representing the grid coords of - * each widget) in descending way. - * - * @method manage_movements - * @param {HTMLElements} $widgets A jQuery collection of HTMLElements - * representing the widgets you want to move. - * @param {Number} to_col The column to which we want to move the widgets. - * @param {Number} to_row The row to which we want to move the widgets. - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.manage_movements = function($widgets, to_col, to_row) { - $.each($widgets, $.proxy(function(i, w) { - var wgd = w; - var $w = wgd.el; - - var can_go_widget_up = this.can_go_widget_up(wgd); - - if (can_go_widget_up) { - //target CAN go up - //so move widget up - this.move_widget_to($w, can_go_widget_up); - this.set_placeholder(to_col, can_go_widget_up + wgd.size_y); - - } else { - //target can't go up - var can_go_player_up = this.can_go_player_up( - this.player_grid_data); - - if (!can_go_player_up) { - // target can't go up - // player cant't go up - // so we need to move widget down to a position that dont - // overlaps player - var y = (to_row + this.player_grid_data.size_y) - wgd.row; - - this.move_widget_down($w, y); - this.set_placeholder(to_col, to_row); - } - } - }, this)); - - return this; - }; - - /** - * Determines if there is a widget in the row and col given. Or if the - * HTMLElement passed as first argument is the player. - * - * @method is_player - * @param {Number|HTMLElement} col_or_el A jQuery wrapped collection of - * HTMLElements. - * @param {Number} [row] The column to which we want to move the widgets. - * @return {Boolean} Returns true or false. - */ - fn.is_player = function(col_or_el, row) { - if (row && !this.gridmap[col_or_el]) { return false; } - var $w = row ? this.gridmap[col_or_el][row] : col_or_el; - return $w && ($w.is(this.$player) || $w.is(this.$helper)); - }; - - - /** - * Determines if the widget that is being dragged is currently over the row - * and col given. - * - * @method is_player_in - * @param {Number} col The column to check. - * @param {Number} row The row to check. - * @return {Boolean} Returns true or false. - */ - fn.is_player_in = function(col, row) { - var c = this.cells_occupied_by_player || {}; - return $.inArray(col, c.cols) >= 0 && $.inArray(row, c.rows) >= 0; - }; - - - /** - * Determines if the placeholder is currently over the row and col given. - * - * @method is_placeholder_in - * @param {Number} col The column to check. - * @param {Number} row The row to check. - * @return {Boolean} Returns true or false. - */ - fn.is_placeholder_in = function(col, row) { - var c = this.cells_occupied_by_placeholder || {}; - return this.is_placeholder_in_col(col) && $.inArray(row, c.rows) >= 0; - }; - - - /** - * Determines if the placeholder is currently over the column given. - * - * @method is_placeholder_in_col - * @param {Number} col The column to check. - * @return {Boolean} Returns true or false. - */ - fn.is_placeholder_in_col = function(col) { - var c = this.cells_occupied_by_placeholder || []; - return $.inArray(col, c.cols) >= 0; - }; - - - /** - * Determines if the cell represented by col and row params is empty. - * - * @method is_empty - * @param {Number} col The column to check. - * @param {Number} row The row to check. - * @return {Boolean} Returns true or false. - */ - fn.is_empty = function(col, row) { - if (typeof this.gridmap[col] !== 'undefined' && - typeof this.gridmap[col][row] !== 'undefined' && - this.gridmap[col][row] === false - ) { - return true; - } - return false; - }; - - - /** - * Determines if the cell represented by col and row params is occupied. - * - * @method is_occupied - * @param {Number} col The column to check. - * @param {Number} row The row to check. - * @return {Boolean} Returns true or false. - */ - fn.is_occupied = function(col, row) { - if (!this.gridmap[col]) { - return false; - } - - if (this.gridmap[col][row]) { - return true; - } - return false; - }; - - - /** - * Determines if there is a widget in the cell represented by col/row params. - * - * @method is_widget - * @param {Number} col The column to check. - * @param {Number} row The row to check. - * @return {Boolean|HTMLElement} Returns false if there is no widget, - * else returns the jQuery HTMLElement - */ - fn.is_widget = function(col, row) { - var cell = this.gridmap[col]; - if (!cell) { - return false; - } - - cell = cell[row]; - - if (cell) { - return cell; - } - - return false; - }; - - - /** - * Determines if there is a widget in the cell represented by col/row - * params and if this is under the widget that is being dragged. - * - * @method is_widget_under_player - * @param {Number} col The column to check. - * @param {Number} row The row to check. - * @return {Boolean} Returns true or false. - */ - fn.is_widget_under_player = function(col, row) { - if (this.is_widget(col, row)) { - return this.is_player_in(col, row); - } - return false; - }; - - - /** - * Get widgets overlapping with the player or with the object passed - * representing the grid cells. - * - * @method get_widgets_under_player - * @return {HTMLElement} Returns a jQuery collection of HTMLElements - */ - fn.get_widgets_under_player = function(cells) { - cells || (cells = this.cells_occupied_by_player || {cols: [], rows: []}); - var $widgets = $([]); - - $.each(cells.cols, $.proxy(function(i, col) { - $.each(cells.rows, $.proxy(function(i, row) { - if(this.is_widget(col, row)) { - $widgets = $widgets.add(this.gridmap[col][row]); - } - }, this)); - }, this)); - - return $widgets; - }; - - - /** - * Put placeholder at the row and column specified. - * - * @method set_placeholder - * @param {Number} col The column to which we want to move the - * placeholder. - * @param {Number} row The row to which we want to move the - * placeholder. - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.set_placeholder = function(col, row) { - var phgd = $.extend({}, this.placeholder_grid_data); - var $nexts = this.widgets_below({ - col: phgd.col, - row: phgd.row, - size_y: phgd.size_y, - size_x: phgd.size_x - }); - - // Prevents widgets go out of the grid - var right_col = (col + phgd.size_x - 1); - if (right_col > this.cols) { - col = col - (right_col - col); - } - - var moved_down = this.placeholder_grid_data.row < row; - var changed_column = this.placeholder_grid_data.col !== col; - - this.placeholder_grid_data.col = col; - this.placeholder_grid_data.row = row; - - this.cells_occupied_by_placeholder = this.get_cells_occupied( - this.placeholder_grid_data); - - this.$preview_holder.attr({ - 'data-row' : row, - 'data-col' : col - }); - - if (moved_down || changed_column) { - $nexts.each($.proxy(function(i, widget) { - this.move_widget_up( - $(widget), this.placeholder_grid_data.col - col + phgd.size_y); - }, this)); - } - - - var $widgets_under_ph = this.get_widgets_under_player(this.cells_occupied_by_placeholder); - if ($widgets_under_ph.length) { - $widgets_under_ph.each($.proxy(function(i, widget) { - var $w = $(widget); - this.move_widget_down( - $w, row + phgd.size_y - $w.data('coords').grid.row); - }, this)); - } - - }; - - - /** - * Determines whether the player can move to a position above. - * - * @method can_go_player_up - * @param {Object} widget_grid_data The actual grid coords object of the - * player. - * @return {Number|Boolean} If the player can be moved to an upper row - * returns the row number, else returns false. - */ - fn.can_go_player_up = function(widget_grid_data) { - var p_bottom_row = widget_grid_data.row + widget_grid_data.size_y - 1; - var result = true; - var upper_rows = []; - var min_row = 10000; - var $widgets_under_player = this.get_widgets_under_player(); - - /* generate an array with columns as index and array with upper rows - * empty as value */ - this.for_each_column_occupied(widget_grid_data, function(tcol) { - var grid_col = this.gridmap[tcol]; - var r = p_bottom_row + 1; - upper_rows[tcol] = []; - - while (--r > 0) { - if (this.is_empty(tcol, r) || this.is_player(tcol, r) || - this.is_widget(tcol, r) && - grid_col[r].is($widgets_under_player) - ) { - upper_rows[tcol].push(r); - min_row = r < min_row ? r : min_row; - }else{ - break; - } - } - - if (upper_rows[tcol].length === 0) { - result = false; - return true; //break - } - - upper_rows[tcol].sort(); - }); - - if (!result) { return false; } - - return this.get_valid_rows(widget_grid_data, upper_rows, min_row); - }; - - - /** - * Determines whether a widget can move to a position above. - * - * @method can_go_widget_up - * @param {Object} widget_grid_data The actual grid coords object of the - * widget we want to check. - * @return {Number|Boolean} If the widget can be moved to an upper row - * returns the row number, else returns false. - */ - fn.can_go_widget_up = function(widget_grid_data) { - var p_bottom_row = widget_grid_data.row + widget_grid_data.size_y - 1; - var result = true; - var upper_rows = []; - var min_row = 10000; - - /* generate an array with columns as index and array with topmost rows - * empty as value */ - this.for_each_column_occupied(widget_grid_data, function(tcol) { - var grid_col = this.gridmap[tcol]; - upper_rows[tcol] = []; - - var r = p_bottom_row + 1; - // iterate over each row - while (--r > 0) { - if (this.is_widget(tcol, r) && !this.is_player_in(tcol, r)) { - if (!grid_col[r].is(widget_grid_data.el)) { - break; - } - } - - if (!this.is_player(tcol, r) && - !this.is_placeholder_in(tcol, r) && - !this.is_player_in(tcol, r)) { - upper_rows[tcol].push(r); - } - - if (r < min_row) { - min_row = r; - } - } - - if (upper_rows[tcol].length === 0) { - result = false; - return true; //break - } - - upper_rows[tcol].sort(); - }); - - if (!result) { return false; } - - return this.get_valid_rows(widget_grid_data, upper_rows, min_row); - }; - - - /** - * Search a valid row for the widget represented by `widget_grid_data' in - * the `upper_rows` array. Iteration starts from row specified in `min_row`. - * - * @method get_valid_rows - * @param {Object} widget_grid_data The actual grid coords object of the - * player. - * @param {Array} upper_rows An array with columns as index and arrays - * of valid rows as values. - * @param {Number} min_row The upper row from which the iteration will start. - * @return {Number|Boolean} Returns the upper row valid from the `upper_rows` - * for the widget in question. - */ - fn.get_valid_rows = function(widget_grid_data, upper_rows, min_row) { - var p_top_row = widget_grid_data.row; - var p_bottom_row = widget_grid_data.row + widget_grid_data.size_y - 1; - var size_y = widget_grid_data.size_y; - var r = min_row - 1; - var valid_rows = []; - - while (++r <= p_bottom_row ) { - var common = true; - $.each(upper_rows, function(col, rows) { - if ($.isArray(rows) && $.inArray(r, rows) === -1) { - common = false; - } - }); - - if (common === true) { - valid_rows.push(r); - if (valid_rows.length === size_y) { - break; - } - } - } - - var new_row = false; - if (size_y === 1) { - if (valid_rows[0] !== p_top_row) { - new_row = valid_rows[0] || false; - } - }else{ - if (valid_rows[0] !== p_top_row) { - new_row = this.get_consecutive_numbers_index( - valid_rows, size_y); - } - } - - return new_row; - }; - - - fn.get_consecutive_numbers_index = function(arr, size_y) { - var max = arr.length; - var result = []; - var first = true; - var prev = -1; // or null? - - for (var i=0; i < max; i++) { - if (first || arr[i] === prev + 1) { - result.push(i); - if (result.length === size_y) { - break; - } - first = false; - }else{ - result = []; - first = true; - } - - prev = arr[i]; - } - - return result.length >= size_y ? arr[result[0]] : false; - }; - - - /** - * Get widgets overlapping with the player. - * - * @method get_widgets_overlapped - * @return {HTMLElements} Returns a jQuery collection of HTMLElements. - */ - fn.get_widgets_overlapped = function() { - var $w; - var $widgets = $([]); - var used = []; - var rows_from_bottom = this.cells_occupied_by_player.rows.slice(0); - rows_from_bottom.reverse(); - - $.each(this.cells_occupied_by_player.cols, $.proxy(function(i, col) { - $.each(rows_from_bottom, $.proxy(function(i, row) { - // if there is a widget in the player position - if (!this.gridmap[col]) { return true; } //next iteration - var $w = this.gridmap[col][row]; - if (this.is_occupied(col, row) && !this.is_player($w) && - $.inArray($w, used) === -1 - ) { - $widgets = $widgets.add($w); - used.push($w); - } - - }, this)); - }, this)); - - return $widgets; - }; - - - /** - * This callback is executed when the player begins to collide with a column. - * - * @method on_start_overlapping_column - * @param {Number} col The collided column. - * @return {HTMLElements} Returns a jQuery collection of HTMLElements. - */ - fn.on_start_overlapping_column = function(col) { - this.set_player(col, false); - }; - - - /** - * A callback executed when the player begins to collide with a row. - * - * @method on_start_overlapping_row - * @param {Number} col The collided row. - * @return {HTMLElements} Returns a jQuery collection of HTMLElements. - */ - fn.on_start_overlapping_row = function(row) { - this.set_player(false, row); - }; - - - /** - * A callback executed when the the player ends to collide with a column. - * - * @method on_stop_overlapping_column - * @param {Number} col The collided row. - * @return {HTMLElements} Returns a jQuery collection of HTMLElements. - */ - fn.on_stop_overlapping_column = function(col) { - this.set_player(col, false); - - var self = this; - this.for_each_widget_below(col, this.cells_occupied_by_player.rows[0], - function(tcol, trow) { - self.move_widget_up(this, self.player_grid_data.size_y); - }); - }; - - - /** - * This callback is executed when the player ends to collide with a row. - * - * @method on_stop_overlapping_row - * @param {Number} row The collided row. - * @return {HTMLElements} Returns a jQuery collection of HTMLElements. - */ - fn.on_stop_overlapping_row = function(row) { - this.set_player(false, row); - - var self = this; - var cols = this.cells_occupied_by_player.cols; - for (var c = 0, cl = cols.length; c < cl; c++) { - this.for_each_widget_below(cols[c], row, function(tcol, trow) { - self.move_widget_up(this, self.player_grid_data.size_y); - }); - } - }; - - - /** - * Move a widget to a specific row. The cell or cells must be empty. - * If the widget has widgets below, all of these widgets will be moved also - * if they can. - * - * @method move_widget_to - * @param {HTMLElement} $widget The jQuery wrapped HTMLElement of the - * widget is going to be moved. - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.move_widget_to = function($widget, row) { - var self = this; - var widget_grid_data = $widget.coords().grid; - var diff = row - widget_grid_data.row; - var $next_widgets = this.widgets_below($widget); - - var can_move_to_new_cell = this.can_move_to( - widget_grid_data, widget_grid_data.col, row, $widget); - - if (can_move_to_new_cell === false) { - return false; - } - - this.remove_from_gridmap(widget_grid_data); - widget_grid_data.row = row; - this.add_to_gridmap(widget_grid_data); - $widget.attr('data-row', row); - this.$changed = this.$changed.add($widget); - - - $next_widgets.each(function(i, widget) { - var $w = $(widget); - var wgd = $w.coords().grid; - var can_go_up = self.can_go_widget_up(wgd); - if (can_go_up && can_go_up !== wgd.row) { - self.move_widget_to($w, can_go_up); - } - }); - - return this; - }; - - - /** - * Move up the specified widget and all below it. - * - * @method move_widget_up - * @param {HTMLElement} $widget The widget you want to move. - * @param {Number} [y_units] The number of cells that the widget has to move. - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.move_widget_up = function($widget, y_units) { - var el_grid_data = $widget.coords().grid; - var actual_row = el_grid_data.row; - var moved = []; - var can_go_up = true; - y_units || (y_units = 1); - - if (!this.can_go_up($widget)) { return false; } //break; - - this.for_each_column_occupied(el_grid_data, function(col) { - // can_go_up - if ($.inArray($widget, moved) === -1) { - var widget_grid_data = $widget.coords().grid; - var next_row = actual_row - y_units; - next_row = this.can_go_up_to_row( - widget_grid_data, col, next_row); - - if (!next_row) { - return true; - } - - var $next_widgets = this.widgets_below($widget); - - this.remove_from_gridmap(widget_grid_data); - widget_grid_data.row = next_row; - this.add_to_gridmap(widget_grid_data); - $widget.attr('data-row', widget_grid_data.row); - this.$changed = this.$changed.add($widget); - - moved.push($widget); - - $next_widgets.each($.proxy(function(i, widget) { - this.move_widget_up($(widget), y_units); - }, this)); - } - }); - - }; - - - /** - * Move down the specified widget and all below it. - * - * @method move_widget_down - * @param {HTMLElement} $widget The jQuery object representing the widget - * you want to move. - * @param {Number} The number of cells that the widget has to move. - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.move_widget_down = function($widget, y_units) { - var el_grid_data = $widget.coords().grid; - var actual_row = el_grid_data.row; - var moved = []; - var y_diff = y_units; - - if (!$widget) { return false; } - - if ($.inArray($widget, moved) === -1) { - - var widget_grid_data = $widget.coords().grid; - var next_row = actual_row + y_units; - var $next_widgets = this.widgets_below($widget); - - this.remove_from_gridmap(widget_grid_data); - - $next_widgets.each($.proxy(function(i, widget) { - var $w = $(widget); - var wd = $w.coords().grid; - var tmp_y = this.displacement_diff( - wd, widget_grid_data, y_diff); - - if (tmp_y > 0) { - this.move_widget_down($w, tmp_y); - } - }, this)); - - widget_grid_data.row = next_row; - this.update_widget_position(widget_grid_data, $widget); - $widget.attr('data-row', widget_grid_data.row); - this.$changed = this.$changed.add($widget); - - moved.push($widget); - } - }; - - - /** - * Check if the widget can move to the specified row, else returns the - * upper row possible. - * - * @method can_go_up_to_row - * @param {Number} widget_grid_data The current grid coords object of the - * widget. - * @param {Number} col The target column. - * @param {Number} row The target row. - * @return {Boolean|Number} Returns the row number if the widget can move - * to the target position, else returns false. - */ - fn.can_go_up_to_row = function(widget_grid_data, col, row) { - var ga = this.gridmap; - var result = true; - var urc = []; // upper_rows_in_columns - var actual_row = widget_grid_data.row; - var r; - - /* generate an array with columns as index and array with - * upper rows empty in the column */ - this.for_each_column_occupied(widget_grid_data, function(tcol) { - var grid_col = ga[tcol]; - urc[tcol] = []; - - r = actual_row; - while (r--) { - if (this.is_empty(tcol, r) && - !this.is_placeholder_in(tcol, r) - ) { - urc[tcol].push(r); - }else{ - break; - } - } - - if (!urc[tcol].length) { - result = false; - return true; - } - - }); - - if (!result) { return false; } - - /* get common rows starting from upper position in all the columns - * that widget occupies */ - r = row; - for (r = 1; r < actual_row; r++) { - var common = true; - - for (var uc = 0, ucl = urc.length; uc < ucl; uc++) { - if (urc[uc] && $.inArray(r, urc[uc]) === -1) { - common = false; - } - } - - if (common === true) { - result = r; - break; - } - } - - return result; - }; - - - fn.displacement_diff = function(widget_grid_data, parent_bgd, y_units) { - var actual_row = widget_grid_data.row; - var diffs = []; - var parent_max_y = parent_bgd.row + parent_bgd.size_y; - - this.for_each_column_occupied(widget_grid_data, function(col) { - var temp_y_units = 0; - - for (var r = parent_max_y; r < actual_row; r++) { - if (this.is_empty(col, r)) { - temp_y_units = temp_y_units + 1; - } - } - - diffs.push(temp_y_units); - }); - - var max_diff = Math.max.apply(Math, diffs); - y_units = (y_units - max_diff); - - return y_units > 0 ? y_units : 0; - }; - - - /** - * Get widgets below a widget. - * - * @method widgets_below - * @param {HTMLElement} $el The jQuery wrapped HTMLElement. - * @return {HTMLElements} A jQuery collection of HTMLElements. - */ - fn.widgets_below = function($el) { - var el_grid_data = $.isPlainObject($el) ? $el : $el.coords().grid; - var self = this; - var ga = this.gridmap; - var next_row = el_grid_data.row + el_grid_data.size_y - 1; - var $nexts = $([]); - - this.for_each_column_occupied(el_grid_data, function(col) { - self.for_each_widget_below(col, next_row, function(tcol, trow) { - if (!self.is_player(this) && $.inArray(this, $nexts) === -1) { - $nexts = $nexts.add(this); - return true; // break - } - }); - }); - - return this.sort_by_row_asc($nexts); - }; - - - /** - * Update the array of mapped positions with the new player position. - * - * @method set_cells_player_occupies - * @param {Number} col The new player col. - * @param {Number} col The new player row. - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.set_cells_player_occupies = function(col, row) { - this.remove_from_gridmap(this.placeholder_grid_data); - this.placeholder_grid_data.col = col; - this.placeholder_grid_data.row = row; - this.add_to_gridmap(this.placeholder_grid_data, this.$player); - return this; - }; - - - /** - * Remove from the array of mapped positions the reference to the player. - * - * @method empty_cells_player_occupies - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.empty_cells_player_occupies = function() { - this.remove_from_gridmap(this.placeholder_grid_data); - return this; - }; - - - fn.can_go_up = function($el) { - var el_grid_data = $el.coords().grid; - var initial_row = el_grid_data.row; - var prev_row = initial_row - 1; - var ga = this.gridmap; - var upper_rows_by_column = []; - - var result = true; - if (initial_row === 1) { return false; } - - this.for_each_column_occupied(el_grid_data, function(col) { - var $w = this.is_widget(col, prev_row); - - if (this.is_occupied(col, prev_row) || - this.is_player(col, prev_row) || - this.is_placeholder_in(col, prev_row) || - this.is_player_in(col, prev_row) - ) { - result = false; - return true; //break - } - }); - - return result; - }; - - - - /** - * Check if it's possible to move a widget to a specific col/row. It takes - * into account the dimensions (`size_y` and `size_x` attrs. of the grid - * coords object) the widget occupies. - * - * @method can_move_to - * @param {Object} widget_grid_data The grid coords object that represents - * the widget. - * @param {Object} col The col to check. - * @param {Object} row The row to check. - * @param {Number} [max_row] The max row allowed. - * @return {Boolean} Returns true if all cells are empty, else return false. - */ - fn.can_move_to = function(widget_grid_data, col, row, max_row) { - var ga = this.gridmap; - var $w = widget_grid_data.el; - var future_wd = { - size_y: widget_grid_data.size_y, - size_x: widget_grid_data.size_x, - col: col, - row: row - }; - var result = true; - - //Prevents widgets go out of the grid - var right_col = col + widget_grid_data.size_x - 1; - if (right_col > this.cols) { - return false; - } - - if (max_row && max_row < row + widget_grid_data.size_y - 1) { - return false; - } - - this.for_each_cell_occupied(future_wd, function(tcol, trow) { - var $tw = this.is_widget(tcol, trow); - if ($tw && (!widget_grid_data.el || $tw.is($w))) { - result = false; - } - }); - - return result; - }; - - - /** - * Given the leftmost column returns all columns that are overlapping - * with the player. - * - * @method get_targeted_columns - * @param {Number} [from_col] The leftmost column. - * @return {Array} Returns an array with column numbers. - */ - fn.get_targeted_columns = function(from_col) { - var max = (from_col || this.player_grid_data.col) + - (this.player_grid_data.size_x - 1); - var cols = []; - for (var col = from_col; col <= max; col++) { - cols.push(col); - } - return cols; - }; - - - /** - * Given the upper row returns all rows that are overlapping with the player. - * - * @method get_targeted_rows - * @param {Number} [from_row] The upper row. - * @return {Array} Returns an array with row numbers. - */ - fn.get_targeted_rows = function(from_row) { - var max = (from_row || this.player_grid_data.row) + - (this.player_grid_data.size_y - 1); - var rows = []; - for (var row = from_row; row <= max; row++) { - rows.push(row); - } - return rows; - }; - - /** - * Get all columns and rows that a widget occupies. - * - * @method get_cells_occupied - * @param {Object} el_grid_data The grid coords object of the widget. - * @return {Object} Returns an object like `{ cols: [], rows: []}`. - */ - fn.get_cells_occupied = function(el_grid_data) { - var cells = { cols: [], rows: []}; - var i; - if (arguments[1] instanceof jQuery) { - el_grid_data = arguments[1].coords().grid; - } - - for (i = 0; i < el_grid_data.size_x; i++) { - var col = el_grid_data.col + i; - cells.cols.push(col); - } - - for (i = 0; i < el_grid_data.size_y; i++) { - var row = el_grid_data.row + i; - cells.rows.push(row); - } - - return cells; - }; - - - /** - * Iterate over the cells occupied by a widget executing a function for - * each one. - * - * @method for_each_cell_occupied - * @param {Object} el_grid_data The grid coords object that represents the - * widget. - * @param {Function} callback The function to execute on each column - * iteration. Column and row are passed as arguments. - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.for_each_cell_occupied = function(grid_data, callback) { - this.for_each_column_occupied(grid_data, function(col) { - this.for_each_row_occupied(grid_data, function(row) { - callback.call(this, col, row); - }); - }); - return this; - }; - - - /** - * Iterate over the columns occupied by a widget executing a function for - * each one. - * - * @method for_each_column_occupied - * @param {Object} el_grid_data The grid coords object that represents - * the widget. - * @param {Function} callback The function to execute on each column - * iteration. The column number is passed as first argument. - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.for_each_column_occupied = function(el_grid_data, callback) { - for (var i = 0; i < el_grid_data.size_x; i++) { - var col = el_grid_data.col + i; - callback.call(this, col, el_grid_data); - } - }; - - - /** - * Iterate over the rows occupied by a widget executing a function for - * each one. - * - * @method for_each_row_occupied - * @param {Object} el_grid_data The grid coords object that represents - * the widget. - * @param {Function} callback The function to execute on each column - * iteration. The row number is passed as first argument. - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.for_each_row_occupied = function(el_grid_data, callback) { - for (var i = 0; i < el_grid_data.size_y; i++) { - var row = el_grid_data.row + i; - callback.call(this, row, el_grid_data); - } - }; - - - - fn._traversing_widgets = function(type, direction, col, row, callback) { - var ga = this.gridmap; - if (!ga[col]) { return; } - - var cr, max; - var action = type + '/' + direction; - if (arguments[2] instanceof jQuery) { - var el_grid_data = arguments[2].coords().grid; - col = el_grid_data.col; - row = el_grid_data.row; - callback = arguments[3]; - } - var matched = []; - var trow = row; - - - var methods = { - 'for_each/above': function() { - while (trow--) { - if (trow > 0 && this.is_widget(col, trow) && - $.inArray(ga[col][trow], matched) === -1 - ) { - cr = callback.call(ga[col][trow], col, trow); - matched.push(ga[col][trow]); - if (cr) { break; } - } - } - }, - 'for_each/below': function() { - for (trow = row + 1, max = ga[col].length; trow < max; trow++) { - if (this.is_widget(col, trow) && - $.inArray(ga[col][trow], matched) === -1 - ) { - cr = callback.call(ga[col][trow], col, trow); - matched.push(ga[col][trow]); - if (cr) { break; } - } - } - } - }; - - if (methods[action]) { - methods[action].call(this); - } - }; - - - /** - * Iterate over each widget above the column and row specified. - * - * @method for_each_widget_above - * @param {Number} col The column to start iterating. - * @param {Number} row The row to start iterating. - * @param {Function} callback The function to execute on each widget - * iteration. The value of `this` inside the function is the jQuery - * wrapped HTMLElement. - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.for_each_widget_above = function(col, row, callback) { - this._traversing_widgets('for_each', 'above', col, row, callback); - return this; - }; - - - /** - * Iterate over each widget below the column and row specified. - * - * @method for_each_widget_below - * @param {Number} col The column to start iterating. - * @param {Number} row The row to start iterating. - * @param {Function} callback The function to execute on each widget - * iteration. The value of `this` inside the function is the jQuery wrapped - * HTMLElement. - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.for_each_widget_below = function(col, row, callback) { - this._traversing_widgets('for_each', 'below', col, row, callback); - return this; - }; - - - /** - * Returns the highest occupied cell in the grid. - * - * @method get_highest_occupied_cell - * @return {Object} Returns an object with `col` and `row` numbers. - */ - fn.get_highest_occupied_cell = function() { - var r; - var gm = this.gridmap; - var rows = []; - var row_in_col = []; - for (var c = gm.length - 1; c >= 1; c--) { - for (r = gm[c].length - 1; r >= 1; r--) { - if (this.is_widget(c, r)) { - rows.push(r); - row_in_col[r] = c; - break; - } - } - } - - var highest_row = Math.max.apply(Math, rows); - - this.highest_occupied_cell = { - col: row_in_col[highest_row], - row: highest_row - }; - - return this.highest_occupied_cell; - }; - - - fn.get_widgets_from = function(col, row) { - var ga = this.gridmap; - var $widgets = $(); - - if (col) { - $widgets = $widgets.add( - this.$widgets.filter(function() { - var tcol = $(this).attr('data-col'); - return (tcol === col || tcol > col); - }) - ); - } - - if (row) { - $widgets = $widgets.add( - this.$widgets.filter(function() { - var trow = $(this).attr('data-row'); - return (trow === row || trow > row); - }) - ); - } - - return $widgets; - }; - - - /** - * Set the current height of the parent grid. - * - * @method set_dom_grid_height - * @return {Object} Returns the instance of the Gridster class. - */ - fn.set_dom_grid_height = function() { - var r = this.get_highest_occupied_cell().row; - this.$el.css('height', r * this.min_widget_height); - return this; - }; - - - /** - * It generates the neccessary styles to position the widgets. - * - * @method generate_stylesheet - * @param {Number} rows Number of columns. - * @param {Number} cols Number of rows. - * @return {Object} Returns the instance of the Gridster class. - */ - fn.generate_stylesheet = function(opts) { - var styles = ''; - var max_size_x = this.options.max_size_x; - var max_rows = 0; - var max_cols = 0; - var i; - var rules; - - opts || (opts = {}); - opts.cols || (opts.cols = this.cols); - opts.rows || (opts.rows = this.rows); - opts.namespace || (opts.namespace = this.options.namespace); - opts.widget_base_dimensions || - (opts.widget_base_dimensions = this.options.widget_base_dimensions); - opts.widget_margins || - (opts.widget_margins = this.options.widget_margins); - opts.min_widget_width = (opts.widget_margins[0] * 2) + - opts.widget_base_dimensions[0]; - opts.min_widget_height = (opts.widget_margins[1] * 2) + - opts.widget_base_dimensions[1]; - - // don't duplicate stylesheets for the same configuration - var serialized_opts = $.param(opts); - if ($.inArray(serialized_opts, Gridster.generated_stylesheets) >= 0) { - return false; - } - - Gridster.generated_stylesheets.push(serialized_opts); - - /* generate CSS styles for cols */ - for (i = opts.cols; i >= 0; i--) { - styles += (opts.namespace + ' [data-col="'+ (i + 1) + '"] { left:' + - ((i * opts.widget_base_dimensions[0]) + - (i * opts.widget_margins[0]) + - ((i + 1) * opts.widget_margins[0])) + 'px;} '); - } - - /* generate CSS styles for rows */ - for (i = opts.rows; i >= 0; i--) { - styles += (opts.namespace + ' [data-row="' + (i + 1) + '"] { top:' + - ((i * opts.widget_base_dimensions[1]) + - (i * opts.widget_margins[1]) + - ((i + 1) * opts.widget_margins[1]) ) + 'px;} '); - } - - for (var y = 1; y <= opts.rows; y++) { - styles += (opts.namespace + ' [data-sizey="' + y + '"] { height:' + - (y * opts.widget_base_dimensions[1] + - (y - 1) * (opts.widget_margins[1] * 2)) + 'px;}'); - } - - for (var x = 1; x <= max_size_x; x++) { - styles += (opts.namespace + ' [data-sizex="' + x + '"] { width:' + - (x * opts.widget_base_dimensions[0] + - (x - 1) * (opts.widget_margins[0] * 2)) + 'px;}'); - } - - return this.add_style_tag(styles); - }; - - - /** - * Injects the given CSS as string to the head of the document. - * - * @method add_style_tag - * @param {String} css The styles to apply. - * @return {Object} Returns the instance of the Gridster class. - */ - fn.add_style_tag = function(css) { - var d = document; - var tag = d.createElement('style'); - - d.getElementsByTagName('head')[0].appendChild(tag); - tag.setAttribute('type', 'text/css'); - - if (tag.styleSheet) { - tag.styleSheet.cssText = css; - }else{ - tag.appendChild(document.createTextNode(css)); - } - return this; - }; - - - /** - * Generates a faux grid to collide with it when a widget is dragged and - * detect row or column that we want to go. - * - * @method generate_faux_grid - * @param {Number} rows Number of columns. - * @param {Number} cols Number of rows. - * @return {Object} Returns the instance of the Gridster class. - */ - fn.generate_faux_grid = function(rows, cols) { - this.faux_grid = []; - this.gridmap = []; - var col; - var row; - for (col = cols; col > 0; col--) { - this.gridmap[col] = []; - for (row = rows; row > 0; row--) { - this.add_faux_cell(row, col); - } - } - return this; - }; - - - /** - * Add cell to the faux grid. - * - * @method add_faux_cell - * @param {Number} row The row for the new faux cell. - * @param {Number} col The col for the new faux cell. - * @return {Object} Returns the instance of the Gridster class. - */ - fn.add_faux_cell = function(row, col) { - var coords = $({ - left: this.baseX + ((col - 1) * this.min_widget_width), - top: this.baseY + (row -1) * this.min_widget_height, - width: this.min_widget_width, - height: this.min_widget_height, - col: col, - row: row, - original_col: col, - original_row: row - }).coords(); - - if (!$.isArray(this.gridmap[col])) { - this.gridmap[col] = []; - } - - this.gridmap[col][row] = false; - this.faux_grid.push(coords); - - return this; - }; - - - /** - * Add rows to the faux grid. - * - * @method add_faux_rows - * @param {Number} rows The number of rows you want to add to the faux grid. - * @return {Object} Returns the instance of the Gridster class. - */ - fn.add_faux_rows = function(rows) { - var actual_rows = this.rows; - var max_rows = actual_rows + (rows || 1); - - for (var r = max_rows; r > actual_rows; r--) { - for (var c = this.cols; c >= 1; c--) { - this.add_faux_cell(r, c); - } - } - - this.rows = max_rows; - - if (this.options.autogenerate_stylesheet) { - this.generate_stylesheet(); - } - - return this; - }; - - /** - * Add cols to the faux grid. - * - * @method add_faux_cols - * @param {Number} cols The number of cols you want to add to the faux grid. - * @return {Object} Returns the instance of the Gridster class. - */ - fn.add_faux_cols = function(cols) { - var actual_cols = this.cols; - var max_cols = actual_cols + (cols || 1); - - for (var c = actual_cols; c < max_cols; c++) { - for (var r = this.rows; r >= 1; r--) { - this.add_faux_cell(r, c); - } - } - - this.cols = max_cols; - - if (this.options.autogenerate_stylesheet) { - this.generate_stylesheet(); - } - - return this; - }; - - - /** - * Recalculates the offsets for the faux grid. You need to use it when - * the browser is resized. - * - * @method recalculate_faux_grid - * @return {Object} Returns the instance of the Gridster class. - */ - fn.recalculate_faux_grid = function() { - var aw = this.$wrapper.width(); - this.baseX = ($(window).width() - aw) / 2; - this.baseY = this.$wrapper.offset().top; - - $.each(this.faux_grid, $.proxy(function(i, coords) { - this.faux_grid[i] = coords.update({ - left: this.baseX + (coords.data.col -1) * this.min_widget_width, - top: this.baseY + (coords.data.row -1) * this.min_widget_height - }); - - }, this)); - - return this; - }; - - - /** - * Get all widgets in the DOM and register them. - * - * @method get_widgets_from_DOM - * @return {Object} Returns the instance of the Gridster class. - */ - fn.get_widgets_from_DOM = function() { - this.$widgets.each($.proxy(function(i, widget) { - this.register_widget($(widget)); - }, this)); - return this; - }; - - - /** - * Calculate columns and rows to be set based on the configuration - * parameters, grid dimensions, etc ... - * - * @method generate_grid_and_stylesheet - * @return {Object} Returns the instance of the Gridster class. - */ - fn.generate_grid_and_stylesheet = function() { - var aw = this.$wrapper.width(); - var ah = this.$wrapper.height(); - - var cols = Math.floor(aw / this.min_widget_width) + - this.options.extra_cols; - - var actual_cols = this.$widgets.map(function() { - return $(this).attr('data-col'); - }); - actual_cols = Array.prototype.slice.call(actual_cols, 0); - //needed to pass tests with phantomjs - actual_cols.length || (actual_cols = [0]); - - var min_cols = Math.max.apply(Math, actual_cols); - - // get all rows that could be occupied by the current widgets - var max_rows = this.options.extra_rows; - this.$widgets.each(function(i, w) { - max_rows += (+$(w).attr('data-sizey')); - }); - - this.cols = Math.max(min_cols, cols, this.options.min_cols); - this.rows = Math.max(max_rows, this.options.min_rows); - - this.baseX = ($(window).width() - aw) / 2; - this.baseY = this.$wrapper.offset().top; - - if (this.options.autogenerate_stylesheet) { - this.generate_stylesheet(); - } - - return this.generate_faux_grid(this.rows, this.cols); - }; - - - //jQuery adapter - $.fn.gridster = function(options) { - return this.each(function() { - if (!$(this).data('gridster')) { - $(this).data('gridster', new Gridster( this, options )); - } - }); - }; - - $.Gridster = fn; - -}(jQuery, window, document)); diff --git a/GRID/assets/jquery.js b/GRID/assets/jquery.js deleted file mode 100644 index 3774ff9..0000000 --- a/GRID/assets/jquery.js +++ /dev/null @@ -1,9404 +0,0 @@ -/*! - * jQuery JavaScript Library v1.7.2 - * http://jquery.com/ - * - * Copyright 2011, John Resig - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * Includes Sizzle.js - * http://sizzlejs.com/ - * Copyright 2011, The Dojo Foundation - * Released under the MIT, BSD, and GPL Licenses. - * - * Date: Wed Mar 21 12:46:34 2012 -0700 - */ -(function( window, undefined ) { - -// Use the correct document accordingly with window argument (sandbox) -var document = window.document, - navigator = window.navigator, - location = window.location; -var jQuery = (function() { - -// Define a local copy of jQuery -var jQuery = function( selector, context ) { - // The jQuery object is actually just the init constructor 'enhanced' - return new jQuery.fn.init( selector, context, rootjQuery ); - }, - - // Map over jQuery in case of overwrite - _jQuery = window.jQuery, - - // Map over the $ in case of overwrite - _$ = window.$, - - // A central reference to the root jQuery(document) - rootjQuery, - - // A simple way to check for HTML strings or ID strings - // Prioritize #id over to avoid XSS via location.hash (#9521) - quickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/, - - // Check if a string has a non-whitespace character in it - rnotwhite = /\S/, - - // Used for trimming whitespace - trimLeft = /^\s+/, - trimRight = /\s+$/, - - // Match a standalone tag - rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/, - - // JSON RegExp - rvalidchars = /^[\],:{}\s]*$/, - rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, - rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, - rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g, - - // Useragent RegExp - rwebkit = /(webkit)[ \/]([\w.]+)/, - ropera = /(opera)(?:.*version)?[ \/]([\w.]+)/, - rmsie = /(msie) ([\w.]+)/, - rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/, - - // Matches dashed string for camelizing - rdashAlpha = /-([a-z]|[0-9])/ig, - rmsPrefix = /^-ms-/, - - // Used by jQuery.camelCase as callback to replace() - fcamelCase = function( all, letter ) { - return ( letter + "" ).toUpperCase(); - }, - - // Keep a UserAgent string for use with jQuery.browser - userAgent = navigator.userAgent, - - // For matching the engine and version of the browser - browserMatch, - - // The deferred used on DOM ready - readyList, - - // The ready event handler - DOMContentLoaded, - - // Save a reference to some core methods - toString = Object.prototype.toString, - hasOwn = Object.prototype.hasOwnProperty, - push = Array.prototype.push, - slice = Array.prototype.slice, - trim = String.prototype.trim, - indexOf = Array.prototype.indexOf, - - // [[Class]] -> type pairs - class2type = {}; - -jQuery.fn = jQuery.prototype = { - constructor: jQuery, - init: function( selector, context, rootjQuery ) { - var match, elem, ret, doc; - - // Handle $(""), $(null), or $(undefined) - if ( !selector ) { - return this; - } - - // Handle $(DOMElement) - if ( selector.nodeType ) { - this.context = this[0] = selector; - this.length = 1; - return this; - } - - // The body element only exists once, optimize finding it - if ( selector === "body" && !context && document.body ) { - this.context = document; - this[0] = document.body; - this.selector = selector; - this.length = 1; - return this; - } - - // Handle HTML strings - if ( typeof selector === "string" ) { - // Are we dealing with HTML string or an ID? - 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 = quickExpr.exec( selector ); - } - - // Verify a match, and that no context was specified for #id - if ( match && (match[1] || !context) ) { - - // HANDLE: $(html) -> $(array) - if ( match[1] ) { - context = context instanceof jQuery ? context[0] : context; - doc = ( context ? context.ownerDocument || context : document ); - - // If a single string is passed in and it's a single tag - // just do a createElement and skip the rest - ret = rsingleTag.exec( selector ); - - if ( ret ) { - if ( jQuery.isPlainObject( context ) ) { - selector = [ document.createElement( ret[1] ) ]; - jQuery.fn.attr.call( selector, context, true ); - - } else { - selector = [ doc.createElement( ret[1] ) ]; - } - - } else { - ret = jQuery.buildFragment( [ match[1] ], [ doc ] ); - selector = ( ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment ).childNodes; - } - - return jQuery.merge( this, selector ); - - // 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 || rootjQuery ).find( selector ); - - // HANDLE: $(expr, context) - // (which is just equivalent to: $(context).find(expr) - } else { - return this.constructor( context ).find( selector ); - } - - // HANDLE: $(function) - // Shortcut for document ready - } else if ( jQuery.isFunction( selector ) ) { - return rootjQuery.ready( selector ); - } - - if ( selector.selector !== undefined ) { - this.selector = selector.selector; - this.context = selector.context; - } - - return jQuery.makeArray( selector, this ); - }, - - // Start with an empty selector - selector: "", - - // The current version of jQuery being used - jquery: "1.7.2", - - // The default length of a jQuery object is 0 - length: 0, - - // The number of elements contained in the matched element set - size: function() { - return this.length; - }, - - toArray: function() { - return slice.call( this, 0 ); - }, - - // 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 a 'clean' array - this.toArray() : - - // Return just the object - ( num < 0 ? this[ this.length + num ] : this[ num ] ); - }, - - // Take an array of elements and push it onto the stack - // (returning the new matched element set) - pushStack: function( elems, name, selector ) { - // Build a new jQuery matched element set - var ret = this.constructor(); - - if ( jQuery.isArray( elems ) ) { - push.apply( ret, elems ); - - } else { - jQuery.merge( ret, elems ); - } - - // Add the old object onto the stack (as a reference) - ret.prevObject = this; - - ret.context = this.context; - - if ( name === "find" ) { - ret.selector = this.selector + ( this.selector ? " " : "" ) + selector; - } else if ( name ) { - ret.selector = this.selector + "." + name + "(" + selector + ")"; - } - - // Return the newly-formed element set - return ret; - }, - - // Execute a callback for every element in the matched set. - // (You can seed the arguments with an array of args, but this is - // only used internally.) - each: function( callback, args ) { - return jQuery.each( this, callback, args ); - }, - - ready: function( fn ) { - // Attach the listeners - jQuery.bindReady(); - - // Add the callback - readyList.add( fn ); - - return this; - }, - - eq: function( i ) { - i = +i; - return i === -1 ? - this.slice( i ) : - this.slice( i, i + 1 ); - }, - - first: function() { - return this.eq( 0 ); - }, - - last: function() { - return this.eq( -1 ); - }, - - slice: function() { - return this.pushStack( slice.apply( this, arguments ), - "slice", slice.call(arguments).join(",") ); - }, - - map: function( callback ) { - return this.pushStack( jQuery.map(this, function( elem, i ) { - return callback.call( elem, i, elem ); - })); - }, - - end: function() { - return this.prevObject || this.constructor(null); - }, - - // For internal use only. - // Behaves like an Array's method, not like a jQuery method. - push: push, - sort: [].sort, - splice: [].splice -}; - -// Give the init function the jQuery prototype for later instantiation -jQuery.fn.init.prototype = jQuery.fn; - -jQuery.extend = jQuery.fn.extend = function() { - var options, name, src, copy, copyIsArray, clone, - target = arguments[0] || {}, - i = 1, - length = arguments.length, - deep = false; - - // Handle a deep copy situation - if ( typeof target === "boolean" ) { - deep = target; - 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" && !jQuery.isFunction(target) ) { - target = {}; - } - - // extend jQuery itself if only one argument is passed - if ( length === i ) { - 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({ - noConflict: function( deep ) { - if ( window.$ === jQuery ) { - window.$ = _$; - } - - if ( deep && window.jQuery === jQuery ) { - window.jQuery = _jQuery; - } - - return jQuery; - }, - - // 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 ) { - // Either a released hold or an DOMready/load event and not yet ready - if ( (wait === true && !--jQuery.readyWait) || (wait !== true && !jQuery.isReady) ) { - // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). - if ( !document.body ) { - return setTimeout( jQuery.ready, 1 ); - } - - // 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.fireWith( document, [ jQuery ] ); - - // Trigger any bound ready events - if ( jQuery.fn.trigger ) { - jQuery( document ).trigger( "ready" ).off( "ready" ); - } - } - }, - - bindReady: function() { - if ( readyList ) { - return; - } - - readyList = jQuery.Callbacks( "once memory" ); - - // Catch cases where $(document).ready() is called after the - // browser event has already occurred. - if ( document.readyState === "complete" ) { - // Handle it asynchronously to allow scripts the opportunity to delay ready - return setTimeout( jQuery.ready, 1 ); - } - - // Mozilla, Opera and webkit nightlies currently support this event - if ( document.addEventListener ) { - // Use the handy event callback - document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false ); - - // A fallback to window.onload, that will always work - window.addEventListener( "load", jQuery.ready, false ); - - // If IE event model is used - } else if ( document.attachEvent ) { - // ensure firing before onload, - // maybe late but safe also for iframes - document.attachEvent( "onreadystatechange", DOMContentLoaded ); - - // A fallback to window.onload, that will always work - window.attachEvent( "onload", jQuery.ready ); - - // If IE and not a frame - // continually check to see if the document is ready - var toplevel = false; - - try { - toplevel = window.frameElement == null; - } catch(e) {} - - if ( document.documentElement.doScroll && toplevel ) { - doScrollCheck(); - } - } - }, - - // 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 ) { - return obj != null && obj == obj.window; - }, - - isNumeric: function( obj ) { - return !isNaN( parseFloat(obj) ) && isFinite( obj ); - }, - - type: function( obj ) { - return obj == null ? - String( obj ) : - class2type[ toString.call(obj) ] || "object"; - }, - - isPlainObject: function( obj ) { - // 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; - } - - // Own properties are enumerated firstly, so to speed up, - // if last one is own, then all properties are own. - - var key; - for ( key in obj ) {} - - return key === undefined || hasOwn.call( obj, key ); - }, - - isEmptyObject: function( obj ) { - for ( var name in obj ) { - return false; - } - return true; - }, - - error: function( msg ) { - throw new Error( msg ); - }, - - parseJSON: function( data ) { - if ( typeof data !== "string" || !data ) { - return null; - } - - // Make sure leading/trailing whitespace is removed (IE can't handle it) - data = jQuery.trim( data ); - - // Attempt to parse using the native JSON parser first - if ( window.JSON && window.JSON.parse ) { - return window.JSON.parse( data ); - } - - // Make sure the incoming data is actual JSON - // Logic borrowed from http://json.org/json2.js - if ( rvalidchars.test( data.replace( rvalidescape, "@" ) - .replace( rvalidtokens, "]" ) - .replace( rvalidbraces, "")) ) { - - return ( new Function( "return " + data ) )(); - - } - jQuery.error( "Invalid JSON: " + data ); - }, - - // Cross-browser xml parsing - parseXML: function( data ) { - if ( typeof data !== "string" || !data ) { - return null; - } - var xml, tmp; - try { - if ( window.DOMParser ) { // Standard - tmp = new DOMParser(); - xml = tmp.parseFromString( data , "text/xml" ); - } else { // IE - xml = new ActiveXObject( "Microsoft.XMLDOM" ); - xml.async = "false"; - xml.loadXML( data ); - } - } catch( e ) { - xml = undefined; - } - if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) { - jQuery.error( "Invalid XML: " + data ); - } - return xml; - }, - - noop: function() {}, - - // Evaluates a script in a global context - // 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 && rnotwhite.test( 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 ); - } )( 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.toUpperCase() === name.toUpperCase(); - }, - - // args is for internal usage only - each: function( object, callback, args ) { - var name, i = 0, - length = object.length, - isObj = length === undefined || jQuery.isFunction( object ); - - if ( args ) { - if ( isObj ) { - for ( name in object ) { - if ( callback.apply( object[ name ], args ) === false ) { - break; - } - } - } else { - for ( ; i < length; ) { - if ( callback.apply( object[ i++ ], args ) === false ) { - break; - } - } - } - - // A special, fast, case for the most common use of each - } else { - if ( isObj ) { - for ( name in object ) { - if ( callback.call( object[ name ], name, object[ name ] ) === false ) { - break; - } - } - } else { - for ( ; i < length; ) { - if ( callback.call( object[ i ], i, object[ i++ ] ) === false ) { - break; - } - } - } - } - - return object; - }, - - // Use native String.trim function wherever possible - trim: trim ? - function( text ) { - return text == null ? - "" : - trim.call( text ); - } : - - // Otherwise use our own trimming functionality - function( text ) { - return text == null ? - "" : - text.toString().replace( trimLeft, "" ).replace( trimRight, "" ); - }, - - // results is for internal usage only - makeArray: function( array, results ) { - var ret = results || []; - - if ( array != null ) { - // The window, strings (and functions) also have 'length' - // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930 - var type = jQuery.type( array ); - - if ( array.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( array ) ) { - push.call( ret, array ); - } else { - jQuery.merge( ret, array ); - } - } - - return ret; - }, - - inArray: function( elem, array, i ) { - var len; - - if ( array ) { - if ( indexOf ) { - return indexOf.call( array, elem, i ); - } - - len = array.length; - i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0; - - for ( ; i < len; i++ ) { - // Skip accessing in sparse arrays - if ( i in array && array[ i ] === elem ) { - return i; - } - } - } - - return -1; - }, - - merge: function( first, second ) { - var i = first.length, - j = 0; - - if ( typeof second.length === "number" ) { - for ( var l = second.length; j < l; j++ ) { - first[ i++ ] = second[ j ]; - } - - } else { - while ( second[j] !== undefined ) { - first[ i++ ] = second[ j++ ]; - } - } - - first.length = i; - - return first; - }, - - grep: function( elems, callback, inv ) { - var ret = [], retVal; - inv = !!inv; - - // Go through the array, only saving the items - // that pass the validator function - for ( var i = 0, length = elems.length; i < length; i++ ) { - retVal = !!callback( elems[ i ], i ); - if ( inv !== retVal ) { - ret.push( elems[ i ] ); - } - } - - return ret; - }, - - // arg is for internal usage only - map: function( elems, callback, arg ) { - var value, key, ret = [], - i = 0, - length = elems.length, - // jquery objects are treated as arrays - isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ; - - // Go through the array, translating each of the items to their - if ( isArray ) { - for ( ; i < length; i++ ) { - value = callback( elems[ i ], i, arg ); - - if ( value != null ) { - ret[ ret.length ] = value; - } - } - - // Go through every key on the object, - } else { - for ( key in elems ) { - value = callback( elems[ key ], key, arg ); - - if ( value != null ) { - ret[ ret.length ] = value; - } - } - } - - // Flatten any nested arrays - return ret.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 ) { - if ( typeof context === "string" ) { - var 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 - var args = slice.call( arguments, 2 ), - proxy = function() { - return fn.apply( context, 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 || proxy.guid || jQuery.guid++; - - return proxy; - }, - - // Mutifunctional method to get and set values to a collection - // The value/s can optionally be executed if it's a function - access: function( elems, fn, key, value, chainable, emptyGet, pass ) { - var exec, - bulk = key == null, - i = 0, - length = elems.length; - - // Sets many values - if ( key && typeof key === "object" ) { - for ( i in key ) { - jQuery.access( elems, fn, i, key[i], 1, emptyGet, value ); - } - chainable = 1; - - // Sets one value - } else if ( value !== undefined ) { - // Optionally, function values get executed if exec is true - exec = pass === undefined && jQuery.isFunction( value ); - - if ( bulk ) { - // Bulk operations only iterate when executing function values - if ( exec ) { - exec = fn; - fn = function( elem, key, value ) { - return exec.call( jQuery( elem ), value ); - }; - - // Otherwise they run against the entire set - } else { - fn.call( elems, value ); - fn = null; - } - } - - if ( fn ) { - for (; i < length; i++ ) { - fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass ); - } - } - - chainable = 1; - } - - return chainable ? - elems : - - // Gets - bulk ? - fn.call( elems ) : - length ? fn( elems[0], key ) : emptyGet; - }, - - now: function() { - return ( new Date() ).getTime(); - }, - - // Use of jQuery.browser is frowned upon. - // More details: http://docs.jquery.com/Utilities/jQuery.browser - uaMatch: function( ua ) { - ua = ua.toLowerCase(); - - var match = rwebkit.exec( ua ) || - ropera.exec( ua ) || - rmsie.exec( ua ) || - ua.indexOf("compatible") < 0 && rmozilla.exec( ua ) || - []; - - return { browser: match[1] || "", version: match[2] || "0" }; - }, - - sub: function() { - function jQuerySub( selector, context ) { - return new jQuerySub.fn.init( selector, context ); - } - jQuery.extend( true, jQuerySub, this ); - jQuerySub.superclass = this; - jQuerySub.fn = jQuerySub.prototype = this(); - jQuerySub.fn.constructor = jQuerySub; - jQuerySub.sub = this.sub; - jQuerySub.fn.init = function init( selector, context ) { - if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) { - context = jQuerySub( context ); - } - - return jQuery.fn.init.call( this, selector, context, rootjQuerySub ); - }; - jQuerySub.fn.init.prototype = jQuerySub.fn; - var rootjQuerySub = jQuerySub(document); - return jQuerySub; - }, - - browser: {} -}); - -// Populate the class2type map -jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) { - class2type[ "[object " + name + "]" ] = name.toLowerCase(); -}); - -browserMatch = jQuery.uaMatch( userAgent ); -if ( browserMatch.browser ) { - jQuery.browser[ browserMatch.browser ] = true; - jQuery.browser.version = browserMatch.version; -} - -// Deprecated, use jQuery.browser.webkit instead -if ( jQuery.browser.webkit ) { - jQuery.browser.safari = true; -} - -// IE doesn't match non-breaking spaces with \s -if ( rnotwhite.test( "\xA0" ) ) { - trimLeft = /^[\s\xA0]+/; - trimRight = /[\s\xA0]+$/; -} - -// All jQuery objects should point back to these -rootjQuery = jQuery(document); - -// Cleanup functions for the document ready method -if ( document.addEventListener ) { - DOMContentLoaded = function() { - document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false ); - jQuery.ready(); - }; - -} else if ( document.attachEvent ) { - DOMContentLoaded = function() { - // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). - if ( document.readyState === "complete" ) { - document.detachEvent( "onreadystatechange", DOMContentLoaded ); - jQuery.ready(); - } - }; -} - -// The DOM ready check for Internet Explorer -function doScrollCheck() { - if ( jQuery.isReady ) { - return; - } - - try { - // If IE is used, use the trick by Diego Perini - // http://javascript.nwbox.com/IEContentLoaded/ - document.documentElement.doScroll("left"); - } catch(e) { - setTimeout( doScrollCheck, 1 ); - return; - } - - // and execute any waiting functions - jQuery.ready(); -} - -return jQuery; - -})(); - - -// String to Object flags format cache -var flagsCache = {}; - -// Convert String-formatted flags into Object-formatted ones and store in cache -function createFlags( flags ) { - var object = flagsCache[ flags ] = {}, - i, length; - flags = flags.split( /\s+/ ); - for ( i = 0, length = flags.length; i < length; i++ ) { - object[ flags[i] ] = true; - } - return object; -} - -/* - * Create a callback list using the following parameters: - * - * flags: an optional list of space-separated flags that will change how - * the callback list behaves - * - * By default a callback list will act like an event callback list and can be - * "fired" multiple times. - * - * Possible flags: - * - * 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( flags ) { - - // Convert flags from String-formatted to Object-formatted - // (we check in cache first) - flags = flags ? ( flagsCache[ flags ] || createFlags( flags ) ) : {}; - - var // Actual callback list - list = [], - // Stack of fire calls for repeatable lists - stack = [], - // Last fire value (for non-forgettable lists) - memory, - // Flag to know if list was already fired - fired, - // Flag to know if list is currently firing - firing, - // First callback to fire (used internally by add and fireWith) - firingStart, - // End of the loop when firing - firingLength, - // Index of currently firing callback (modified by remove if needed) - firingIndex, - // Add one or several callbacks to the list - add = function( args ) { - var i, - length, - elem, - type, - actual; - for ( i = 0, length = args.length; i < length; i++ ) { - elem = args[ i ]; - type = jQuery.type( elem ); - if ( type === "array" ) { - // Inspect recursively - add( elem ); - } else if ( type === "function" ) { - // Add if not in unique mode and callback is not in - if ( !flags.unique || !self.has( elem ) ) { - list.push( elem ); - } - } - } - }, - // Fire callbacks - fire = function( context, args ) { - args = args || []; - memory = !flags.memory || [ context, args ]; - fired = true; - firing = true; - firingIndex = firingStart || 0; - firingStart = 0; - firingLength = list.length; - for ( ; list && firingIndex < firingLength; firingIndex++ ) { - if ( list[ firingIndex ].apply( context, args ) === false && flags.stopOnFalse ) { - memory = true; // Mark as halted - break; - } - } - firing = false; - if ( list ) { - if ( !flags.once ) { - if ( stack && stack.length ) { - memory = stack.shift(); - self.fireWith( memory[ 0 ], memory[ 1 ] ); - } - } else if ( memory === true ) { - self.disable(); - } else { - list = []; - } - } - }, - // Actual Callbacks object - self = { - // Add a callback or a collection of callbacks to the list - add: function() { - if ( list ) { - var length = list.length; - add( arguments ); - // Do we need to add the callbacks to the - // current firing batch? - if ( firing ) { - firingLength = list.length; - // With memory, if we're not firing then - // we should call right away, unless previous - // firing was halted (stopOnFalse) - } else if ( memory && memory !== true ) { - firingStart = length; - fire( memory[ 0 ], memory[ 1 ] ); - } - } - return this; - }, - // Remove a callback from the list - remove: function() { - if ( list ) { - var args = arguments, - argIndex = 0, - argLength = args.length; - for ( ; argIndex < argLength ; argIndex++ ) { - for ( var i = 0; i < list.length; i++ ) { - if ( args[ argIndex ] === list[ i ] ) { - // Handle firingIndex and firingLength - if ( firing ) { - if ( i <= firingLength ) { - firingLength--; - if ( i <= firingIndex ) { - firingIndex--; - } - } - } - // Remove the element - list.splice( i--, 1 ); - // If we have some unicity property then - // we only need to do this once - if ( flags.unique ) { - break; - } - } - } - } - } - return this; - }, - // Control if a given callback is in the list - has: function( fn ) { - if ( list ) { - var i = 0, - length = list.length; - for ( ; i < length; i++ ) { - if ( fn === list[ i ] ) { - return true; - } - } - } - return false; - }, - // Remove all callbacks from the list - empty: function() { - list = []; - return this; - }, - // Have the list do nothing anymore - disable: function() { - list = stack = memory = undefined; - return this; - }, - // Is it disabled? - disabled: function() { - return !list; - }, - // Lock the list in its current state - lock: function() { - stack = undefined; - if ( !memory || memory === true ) { - self.disable(); - } - return this; - }, - // Is it locked? - locked: function() { - return !stack; - }, - // Call all callbacks with the given context and arguments - fireWith: function( context, args ) { - if ( stack ) { - if ( firing ) { - if ( !flags.once ) { - stack.push( [ context, args ] ); - } - } else if ( !( flags.once && memory ) ) { - fire( context, args ); - } - } - 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; -}; - - - - -var // Static reference to slice - sliceDeferred = [].slice; - -jQuery.extend({ - - Deferred: function( func ) { - var doneList = jQuery.Callbacks( "once memory" ), - failList = jQuery.Callbacks( "once memory" ), - progressList = jQuery.Callbacks( "memory" ), - state = "pending", - lists = { - resolve: doneList, - reject: failList, - notify: progressList - }, - promise = { - done: doneList.add, - fail: failList.add, - progress: progressList.add, - - state: function() { - return state; - }, - - // Deprecated - isResolved: doneList.fired, - isRejected: failList.fired, - - then: function( doneCallbacks, failCallbacks, progressCallbacks ) { - deferred.done( doneCallbacks ).fail( failCallbacks ).progress( progressCallbacks ); - return this; - }, - always: function() { - deferred.done.apply( deferred, arguments ).fail.apply( deferred, arguments ); - return this; - }, - pipe: function( fnDone, fnFail, fnProgress ) { - return jQuery.Deferred(function( newDefer ) { - jQuery.each( { - done: [ fnDone, "resolve" ], - fail: [ fnFail, "reject" ], - progress: [ fnProgress, "notify" ] - }, function( handler, data ) { - var fn = data[ 0 ], - action = data[ 1 ], - returned; - if ( jQuery.isFunction( fn ) ) { - deferred[ handler ](function() { - returned = fn.apply( this, arguments ); - if ( returned && jQuery.isFunction( returned.promise ) ) { - returned.promise().then( newDefer.resolve, newDefer.reject, newDefer.notify ); - } else { - newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] ); - } - }); - } else { - deferred[ handler ]( newDefer[ action ] ); - } - }); - }).promise(); - }, - // Get a promise for this deferred - // If obj is provided, the promise aspect is added to the object - promise: function( obj ) { - if ( obj == null ) { - obj = promise; - } else { - for ( var key in promise ) { - obj[ key ] = promise[ key ]; - } - } - return obj; - } - }, - deferred = promise.promise({}), - key; - - for ( key in lists ) { - deferred[ key ] = lists[ key ].fire; - deferred[ key + "With" ] = lists[ key ].fireWith; - } - - // Handle state - deferred.done( function() { - state = "resolved"; - }, failList.disable, progressList.lock ).fail( function() { - state = "rejected"; - }, doneList.disable, progressList.lock ); - - // Call given func if any - if ( func ) { - func.call( deferred, deferred ); - } - - // All done! - return deferred; - }, - - // Deferred helper - when: function( firstParam ) { - var args = sliceDeferred.call( arguments, 0 ), - i = 0, - length = args.length, - pValues = new Array( length ), - count = length, - pCount = length, - deferred = length <= 1 && firstParam && jQuery.isFunction( firstParam.promise ) ? - firstParam : - jQuery.Deferred(), - promise = deferred.promise(); - function resolveFunc( i ) { - return function( value ) { - args[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value; - if ( !( --count ) ) { - deferred.resolveWith( deferred, args ); - } - }; - } - function progressFunc( i ) { - return function( value ) { - pValues[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value; - deferred.notifyWith( promise, pValues ); - }; - } - if ( length > 1 ) { - for ( ; i < length; i++ ) { - if ( args[ i ] && args[ i ].promise && jQuery.isFunction( args[ i ].promise ) ) { - args[ i ].promise().then( resolveFunc(i), deferred.reject, progressFunc(i) ); - } else { - --count; - } - } - if ( !count ) { - deferred.resolveWith( deferred, args ); - } - } else if ( deferred !== firstParam ) { - deferred.resolveWith( deferred, length ? [ firstParam ] : [] ); - } - return promise; - } -}); - - - - -jQuery.support = (function() { - - var support, - all, - a, - select, - opt, - input, - fragment, - tds, - events, - eventName, - i, - isSupported, - div = document.createElement( "div" ), - documentElement = document.documentElement; - - // Preliminary tests - div.setAttribute("className", "t"); - div.innerHTML = "
      • ThemeTheme      
        a"; - - all = div.getElementsByTagName( "*" ); - a = div.getElementsByTagName( "a" )[ 0 ]; - - // Can't get basic test support - if ( !all || !all.length || !a ) { - return {}; - } - - // First batch of supports tests - select = document.createElement( "select" ); - opt = select.appendChild( document.createElement("option") ); - input = div.getElementsByTagName( "input" )[ 0 ]; - - support = { - // IE strips leading whitespace when .innerHTML is used - leadingWhitespace: ( div.firstChild.nodeType === 3 ), - - // Make sure that tbody elements aren't automatically inserted - // IE will insert them into empty tables - tbody: !div.getElementsByTagName("tbody").length, - - // Make sure that link elements get serialized correctly by innerHTML - // This requires a wrapper element in IE - htmlSerialize: !!div.getElementsByTagName("link").length, - - // Get the style information from getAttribute - // (IE uses .cssText instead) - style: /top/.test( a.getAttribute("style") ), - - // Make sure that URLs aren't manipulated - // (IE normalizes it by default) - hrefNormalized: ( a.getAttribute("href") === "/a" ), - - // Make sure that element opacity exists - // (IE uses filter instead) - // Use a regex to work around a WebKit issue. See #5145 - opacity: /^0.55/.test( a.style.opacity ), - - // Verify style float existence - // (IE uses styleFloat instead of cssFloat) - cssFloat: !!a.style.cssFloat, - - // Make sure that if no value is specified for a checkbox - // that it defaults to "on". - // (WebKit defaults to "" instead) - checkOn: ( input.value === "on" ), - - // Make sure that a selected-by-default option has a working selected property. - // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) - optSelected: opt.selected, - - // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7) - getSetAttribute: div.className !== "t", - - // Tests for enctype support on a form(#6743) - enctype: !!document.createElement("form").enctype, - - // Makes sure cloning an html5 element does not cause problems - // Where outerHTML is undefined, this still works - html5Clone: document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav>", - - // Will be defined later - submitBubbles: true, - changeBubbles: true, - focusinBubbles: false, - deleteExpando: true, - noCloneEvent: true, - inlineBlockNeedsLayout: false, - shrinkWrapBlocks: false, - reliableMarginRight: true, - pixelMargin: true - }; - - // jQuery.boxModel DEPRECATED in 1.3, use jQuery.support.boxModel instead - jQuery.boxModel = support.boxModel = (document.compatMode === "CSS1Compat"); - - // Make sure checked status is properly cloned - input.checked = true; - support.noCloneChecked = input.cloneNode( true ).checked; - - // Make sure that the options inside disabled selects aren't marked as disabled - // (WebKit marks them as disabled) - select.disabled = true; - support.optDisabled = !opt.disabled; - - // Test to see if it's possible to delete an expando from an element - // Fails in Internet Explorer - try { - delete div.test; - } catch( e ) { - support.deleteExpando = false; - } - - if ( !div.addEventListener && div.attachEvent && div.fireEvent ) { - div.attachEvent( "onclick", function() { - // Cloning a node shouldn't copy over any - // bound event handlers (IE does this) - support.noCloneEvent = false; - }); - div.cloneNode( true ).fireEvent( "onclick" ); - } - - // Check if a radio maintains its value - // after being appended to the DOM - input = document.createElement("input"); - input.value = "t"; - input.setAttribute("type", "radio"); - support.radioValue = input.value === "t"; - - input.setAttribute("checked", "checked"); - - // #11217 - WebKit loses check when the name is after the checked attribute - input.setAttribute( "name", "t" ); - - div.appendChild( input ); - fragment = document.createDocumentFragment(); - fragment.appendChild( div.lastChild ); - - // WebKit doesn't clone checked state correctly in fragments - support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked; - - // Check if a disconnected checkbox will retain its checked - // value of true after appended to the DOM (IE6/7) - support.appendChecked = input.checked; - - fragment.removeChild( input ); - fragment.appendChild( div ); - - // Technique from Juriy Zaytsev - // http://perfectionkills.com/detecting-event-support-without-browser-sniffing/ - // We only care about the case where non-standard event systems - // are used, namely in IE. Short-circuiting here helps us to - // avoid an eval call (in setAttribute) which can cause CSP - // to go haywire. See: https://developer.mozilla.org/en/Security/CSP - if ( div.attachEvent ) { - for ( i in { - submit: 1, - change: 1, - focusin: 1 - }) { - eventName = "on" + i; - isSupported = ( eventName in div ); - if ( !isSupported ) { - div.setAttribute( eventName, "return;" ); - isSupported = ( typeof div[ eventName ] === "function" ); - } - support[ i + "Bubbles" ] = isSupported; - } - } - - fragment.removeChild( div ); - - // Null elements to avoid leaks in IE - fragment = select = opt = div = input = null; - - // Run tests that need a body at doc ready - jQuery(function() { - var container, outer, inner, table, td, offsetSupport, - marginDiv, conMarginTop, style, html, positionTopLeftWidthHeight, - paddingMarginBorderVisibility, paddingMarginBorder, - body = document.getElementsByTagName("body")[0]; - - if ( !body ) { - // Return for frameset docs that don't have a body - return; - } - - conMarginTop = 1; - paddingMarginBorder = "padding:0;margin:0;border:"; - positionTopLeftWidthHeight = "position:absolute;top:0;left:0;width:1px;height:1px;"; - paddingMarginBorderVisibility = paddingMarginBorder + "0;visibility:hidden;"; - style = "style='" + positionTopLeftWidthHeight + paddingMarginBorder + "5px solid #000;"; - html = "
        " + - "" + - "
        "; - - container = document.createElement("div"); - container.style.cssText = paddingMarginBorderVisibility + "width:0;height:0;position:static;top:0;margin-top:" + conMarginTop + "px"; - body.insertBefore( container, body.firstChild ); - - // Construct the test element - div = document.createElement("div"); - container.appendChild( div ); - - // Check if table cells still have offsetWidth/Height when they are set - // to display:none and there are still other visible table cells in a - // table row; if so, offsetWidth/Height are not reliable for use when - // determining if an element has been hidden directly using - // display:none (it is still safe to use offsets if a parent element is - // hidden; don safety goggles and see bug #4512 for more information). - // (only IE 8 fails this test) - div.innerHTML = "
        t
        "; - tds = div.getElementsByTagName( "td" ); - isSupported = ( tds[ 0 ].offsetHeight === 0 ); - - tds[ 0 ].style.display = ""; - tds[ 1 ].style.display = "none"; - - // Check if empty table cells still have offsetWidth/Height - // (IE <= 8 fail this test) - support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 ); - - // Check if div with explicit width and no margin-right incorrectly - // gets computed margin-right based on width of container. For more - // info see bug #3333 - // Fails in WebKit before Feb 2011 nightlies - // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right - if ( window.getComputedStyle ) { - div.innerHTML = ""; - marginDiv = document.createElement( "div" ); - marginDiv.style.width = "0"; - marginDiv.style.marginRight = "0"; - div.style.width = "2px"; - div.appendChild( marginDiv ); - support.reliableMarginRight = - ( parseInt( ( window.getComputedStyle( marginDiv, null ) || { marginRight: 0 } ).marginRight, 10 ) || 0 ) === 0; - } - - if ( typeof div.style.zoom !== "undefined" ) { - // Check if natively block-level elements act like inline-block - // elements when setting their display to 'inline' and giving - // them layout - // (IE < 8 does this) - div.innerHTML = ""; - div.style.width = div.style.padding = "1px"; - div.style.border = 0; - div.style.overflow = "hidden"; - div.style.display = "inline"; - div.style.zoom = 1; - support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 ); - - // Check if elements with layout shrink-wrap their children - // (IE 6 does this) - div.style.display = "block"; - div.style.overflow = "visible"; - div.innerHTML = "
        "; - support.shrinkWrapBlocks = ( div.offsetWidth !== 3 ); - } - - div.style.cssText = positionTopLeftWidthHeight + paddingMarginBorderVisibility; - div.innerHTML = html; - - outer = div.firstChild; - inner = outer.firstChild; - td = outer.nextSibling.firstChild.firstChild; - - offsetSupport = { - doesNotAddBorder: ( inner.offsetTop !== 5 ), - doesAddBorderForTableAndCells: ( td.offsetTop === 5 ) - }; - - inner.style.position = "fixed"; - inner.style.top = "20px"; - - // safari subtracts parent border width here which is 5px - offsetSupport.fixedPosition = ( inner.offsetTop === 20 || inner.offsetTop === 15 ); - inner.style.position = inner.style.top = ""; - - outer.style.overflow = "hidden"; - outer.style.position = "relative"; - - offsetSupport.subtractsBorderForOverflowNotVisible = ( inner.offsetTop === -5 ); - offsetSupport.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== conMarginTop ); - - if ( window.getComputedStyle ) { - div.style.marginTop = "1%"; - support.pixelMargin = ( window.getComputedStyle( div, null ) || { marginTop: 0 } ).marginTop !== "1%"; - } - - if ( typeof container.style.zoom !== "undefined" ) { - container.style.zoom = 1; - } - - body.removeChild( container ); - marginDiv = div = container = null; - - jQuery.extend( support, offsetSupport ); - }); - - return support; -})(); - - - - -var rbrace = /^(?:\{.*\}|\[.*\])$/, - rmultiDash = /([A-Z])/g; - -jQuery.extend({ - cache: {}, - - // Please use with caution - uuid: 0, - - // Unique for each copy of jQuery on the page - // Non-digits removed to match rinlinejQuery - expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ), - - // The following elements throw uncatchable exceptions if you - // attempt to add expando properties to them. - noData: { - "embed": true, - // Ban all objects except for Flash (which handle expandos) - "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000", - "applet": true - }, - - hasData: function( elem ) { - elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ]; - return !!elem && !isEmptyDataObject( elem ); - }, - - data: function( elem, name, data, pvt /* Internal Use Only */ ) { - if ( !jQuery.acceptData( elem ) ) { - return; - } - - var privateCache, thisCache, ret, - internalKey = jQuery.expando, - getByName = typeof name === "string", - - // 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, - isEvents = name === "events"; - - // 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] || (!isEvents && !pvt && !cache[id].data)) && getByName && data === undefined ) { - 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 ) { - elem[ internalKey ] = id = ++jQuery.uuid; - } else { - id = internalKey; - } - } - - if ( !cache[ id ] ) { - cache[ id ] = {}; - - // Avoids exposing jQuery metadata on plain JS objects when the object - // is serialized using JSON.stringify - if ( !isNode ) { - cache[ id ].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 ); - } - } - - privateCache = 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; - } - - // Users should not attempt to inspect the internal events object using jQuery.data, - // it is undocumented and subject to change. But does anyone listen? No. - if ( isEvents && !thisCache[ name ] ) { - return privateCache.events; - } - - // Check for both converted-to-camel and non-converted data property names - // If a data property was specified - if ( getByName ) { - - // 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; - }, - - removeData: function( elem, name, pvt /* Internal Use Only */ ) { - if ( !jQuery.acceptData( elem ) ) { - return; - } - - var thisCache, i, l, - - // Reference to internal data cache key - internalKey = jQuery.expando, - - isNode = elem.nodeType, - - // See jQuery.data for more information - cache = isNode ? jQuery.cache : elem, - - // See jQuery.data for more information - id = isNode ? elem[ internalKey ] : internalKey; - - // 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( " " ); - } - } - } - - for ( i = 0, l = name.length; i < l; 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 : 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; - } - } - - // Browsers that fail expando deletion also refuse to delete expandos on - // the window, but it will allow it on all other JS objects; other browsers - // don't care - // Ensure that `cache` is not a window object #10080 - if ( jQuery.support.deleteExpando || !cache.setInterval ) { - delete cache[ id ]; - } else { - cache[ id ] = null; - } - - // We destroyed the cache and need to eliminate the expando on the node to avoid - // false lookups in the cache for entries that no longer exist - if ( isNode ) { - // IE does not allow us to delete expando properties from nodes, - // nor does it have a removeAttribute function on Document nodes; - // we must handle all of these cases - if ( jQuery.support.deleteExpando ) { - delete elem[ internalKey ]; - } else if ( elem.removeAttribute ) { - elem.removeAttribute( internalKey ); - } else { - elem[ internalKey ] = null; - } - } - }, - - // For internal use only. - _data: function( elem, name, data ) { - return jQuery.data( elem, name, data, true ); - }, - - // A method for determining if a DOM node can handle the data expando - acceptData: function( elem ) { - if ( elem.nodeName ) { - var match = jQuery.noData[ elem.nodeName.toLowerCase() ]; - - if ( match ) { - return !(match === true || elem.getAttribute("classid") !== match); - } - } - - return true; - } -}); - -jQuery.fn.extend({ - data: function( key, value ) { - var parts, part, attr, name, l, - elem = this[0], - i = 0, - data = null; - - // Gets all values - if ( key === undefined ) { - if ( this.length ) { - data = jQuery.data( elem ); - - if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) { - attr = elem.attributes; - for ( l = attr.length; i < l; i++ ) { - name = attr[i].name; - - if ( name.indexOf( "data-" ) === 0 ) { - name = jQuery.camelCase( name.substring(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 ); - }); - } - - parts = key.split( ".", 2 ); - parts[1] = parts[1] ? "." + parts[1] : ""; - part = parts[1] + "!"; - - return jQuery.access( this, function( value ) { - - if ( value === undefined ) { - data = this.triggerHandler( "getData" + part, [ parts[0] ] ); - - // Try to fetch any internally stored data first - if ( data === undefined && elem ) { - data = jQuery.data( elem, key ); - data = dataAttr( elem, key, data ); - } - - return data === undefined && parts[1] ? - this.data( parts[0] ) : - data; - } - - parts[1] = value; - this.each(function() { - var self = jQuery( this ); - - self.triggerHandler( "setData" + part, parts ); - jQuery.data( this, key, value ); - self.triggerHandler( "changeData" + part, parts ); - }); - }, null, value, arguments.length > 1, null, false ); - }, - - removeData: function( key ) { - return this.each(function() { - jQuery.removeData( this, key ); - }); - } -}); - -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 : - jQuery.isNumeric( 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 ) { - for ( var 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 handleQueueMarkDefer( elem, type, src ) { - var deferDataKey = type + "defer", - queueDataKey = type + "queue", - markDataKey = type + "mark", - defer = jQuery._data( elem, deferDataKey ); - if ( defer && - ( src === "queue" || !jQuery._data(elem, queueDataKey) ) && - ( src === "mark" || !jQuery._data(elem, markDataKey) ) ) { - // Give room for hard-coded callbacks to fire first - // and eventually mark/queue something else on the element - setTimeout( function() { - if ( !jQuery._data( elem, queueDataKey ) && - !jQuery._data( elem, markDataKey ) ) { - jQuery.removeData( elem, deferDataKey, true ); - defer.fire(); - } - }, 0 ); - } -} - -jQuery.extend({ - - _mark: function( elem, type ) { - if ( elem ) { - type = ( type || "fx" ) + "mark"; - jQuery._data( elem, type, (jQuery._data( elem, type ) || 0) + 1 ); - } - }, - - _unmark: function( force, elem, type ) { - if ( force !== true ) { - type = elem; - elem = force; - force = false; - } - if ( elem ) { - type = type || "fx"; - var key = type + "mark", - count = force ? 0 : ( (jQuery._data( elem, key ) || 1) - 1 ); - if ( count ) { - jQuery._data( elem, key, count ); - } else { - jQuery.removeData( elem, key, true ); - handleQueueMarkDefer( elem, type, "mark" ); - } - } - }, - - queue: function( elem, type, data ) { - var q; - if ( elem ) { - type = ( type || "fx" ) + "queue"; - q = jQuery._data( elem, type ); - - // Speed up dequeue by getting out quickly if this is just a lookup - if ( data ) { - if ( !q || jQuery.isArray(data) ) { - q = jQuery._data( elem, type, jQuery.makeArray(data) ); - } else { - q.push( data ); - } - } - return q || []; - } - }, - - dequeue: function( elem, type ) { - type = type || "fx"; - - var queue = jQuery.queue( elem, type ), - fn = queue.shift(), - hooks = {}; - - // If the fx queue is dequeued, always remove the progress sentinel - if ( fn === "inprogress" ) { - fn = queue.shift(); - } - - if ( fn ) { - // Add a progress sentinel to prevent the fx queue from being - // automatically dequeued - if ( type === "fx" ) { - queue.unshift( "inprogress" ); - } - - jQuery._data( elem, type + ".run", hooks ); - fn.call( elem, function() { - jQuery.dequeue( elem, type ); - }, hooks ); - } - - if ( !queue.length ) { - jQuery.removeData( elem, type + "queue " + type + ".run", true ); - handleQueueMarkDefer( elem, type, "queue" ); - } - } -}); - -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 ); - - if ( type === "fx" && queue[0] !== "inprogress" ) { - jQuery.dequeue( this, type ); - } - }); - }, - dequeue: function( type ) { - return this.each(function() { - jQuery.dequeue( this, type ); - }); - }, - // Based off of the plugin by Clint Helfers, with permission. - // http://blindsignals.com/index.php/2009/07/jquery-delay/ - delay: function( time, type ) { - time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; - type = type || "fx"; - - return this.queue( type, function( next, hooks ) { - var timeout = setTimeout( next, time ); - hooks.stop = function() { - clearTimeout( timeout ); - }; - }); - }, - 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, object ) { - if ( typeof type !== "string" ) { - object = type; - type = undefined; - } - type = type || "fx"; - var defer = jQuery.Deferred(), - elements = this, - i = elements.length, - count = 1, - deferDataKey = type + "defer", - queueDataKey = type + "queue", - markDataKey = type + "mark", - tmp; - function resolve() { - if ( !( --count ) ) { - defer.resolveWith( elements, [ elements ] ); - } - } - while( i-- ) { - if (( tmp = jQuery.data( elements[ i ], deferDataKey, undefined, true ) || - ( jQuery.data( elements[ i ], queueDataKey, undefined, true ) || - jQuery.data( elements[ i ], markDataKey, undefined, true ) ) && - jQuery.data( elements[ i ], deferDataKey, jQuery.Callbacks( "once memory" ), true ) )) { - count++; - tmp.add( resolve ); - } - } - resolve(); - return defer.promise( object ); - } -}); - - - - -var rclass = /[\n\t\r]/g, - rspace = /\s+/, - rreturn = /\r/g, - rtype = /^(?:button|input)$/i, - rfocusable = /^(?:button|input|object|select|textarea)$/i, - rclickable = /^a(?:rea)?$/i, - rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i, - getSetAttribute = jQuery.support.getSetAttribute, - nodeHook, boolHook, fixSpecified; - -jQuery.fn.extend({ - attr: function( name, value ) { - return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 ); - }, - - removeAttr: function( name ) { - return this.each(function() { - jQuery.removeAttr( this, name ); - }); - }, - - prop: function( name, value ) { - return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 ); - }, - - removeProp: function( name ) { - name = jQuery.propFix[ name ] || name; - return this.each(function() { - // try/catch handles cases where IE balks (such as removing a property on window) - try { - this[ name ] = undefined; - delete this[ name ]; - } catch( e ) {} - }); - }, - - addClass: function( value ) { - var classNames, i, l, elem, - setClass, c, cl; - - if ( jQuery.isFunction( value ) ) { - return this.each(function( j ) { - jQuery( this ).addClass( value.call(this, j, this.className) ); - }); - } - - if ( value && typeof value === "string" ) { - classNames = value.split( rspace ); - - for ( i = 0, l = this.length; i < l; i++ ) { - elem = this[ i ]; - - if ( elem.nodeType === 1 ) { - if ( !elem.className && classNames.length === 1 ) { - elem.className = value; - - } else { - setClass = " " + elem.className + " "; - - for ( c = 0, cl = classNames.length; c < cl; c++ ) { - if ( !~setClass.indexOf( " " + classNames[ c ] + " " ) ) { - setClass += classNames[ c ] + " "; - } - } - elem.className = jQuery.trim( setClass ); - } - } - } - } - - return this; - }, - - removeClass: function( value ) { - var classNames, i, l, elem, className, c, cl; - - if ( jQuery.isFunction( value ) ) { - return this.each(function( j ) { - jQuery( this ).removeClass( value.call(this, j, this.className) ); - }); - } - - if ( (value && typeof value === "string") || value === undefined ) { - classNames = ( value || "" ).split( rspace ); - - for ( i = 0, l = this.length; i < l; i++ ) { - elem = this[ i ]; - - if ( elem.nodeType === 1 && elem.className ) { - if ( value ) { - className = (" " + elem.className + " ").replace( rclass, " " ); - for ( c = 0, cl = classNames.length; c < cl; c++ ) { - className = className.replace(" " + classNames[ c ] + " ", " "); - } - elem.className = jQuery.trim( className ); - - } else { - elem.className = ""; - } - } - } - } - - return this; - }, - - toggleClass: function( value, stateVal ) { - var type = typeof value, - isBool = typeof stateVal === "boolean"; - - if ( jQuery.isFunction( value ) ) { - return this.each(function( i ) { - jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal ); - }); - } - - return this.each(function() { - if ( type === "string" ) { - // toggle individual class names - var className, - i = 0, - self = jQuery( this ), - state = stateVal, - classNames = value.split( rspace ); - - while ( (className = classNames[ i++ ]) ) { - // check each className given, space seperated list - state = isBool ? state : !self.hasClass( className ); - self[ state ? "addClass" : "removeClass" ]( className ); - } - - } else if ( type === "undefined" || type === "boolean" ) { - if ( this.className ) { - // store className if set - jQuery._data( this, "__className__", this.className ); - } - - // toggle whole className - this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || ""; - } - }); - }, - - hasClass: function( selector ) { - var className = " " + selector + " ", - i = 0, - l = this.length; - for ( ; i < l; i++ ) { - if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) { - return true; - } - } - - return false; - }, - - val: function( value ) { - var hooks, ret, isFunction, - elem = this[0]; - - if ( !arguments.length ) { - if ( elem ) { - hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ]; - - if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) { - return ret; - } - - ret = elem.value; - - return typeof ret === "string" ? - // handle most common string cases - ret.replace(rreturn, "") : - // handle cases where value is null/undef or number - ret == null ? "" : ret; - } - - return; - } - - isFunction = jQuery.isFunction( value ); - - return this.each(function( i ) { - var self = jQuery(this), val; - - if ( this.nodeType !== 1 ) { - return; - } - - if ( isFunction ) { - val = value.call( this, i, self.val() ); - } else { - val = value; - } - - // Treat null/undefined as ""; convert numbers to string - if ( val == null ) { - val = ""; - } else if ( typeof val === "number" ) { - val += ""; - } else if ( jQuery.isArray( val ) ) { - val = jQuery.map(val, function ( value ) { - return value == null ? "" : value + ""; - }); - } - - hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; - - // If set returns undefined, fall back to normal setting - if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) { - this.value = val; - } - }); - } -}); - -jQuery.extend({ - valHooks: { - option: { - get: function( elem ) { - // attributes.value is undefined in Blackberry 4.7 but - // uses .value. See #6932 - var val = elem.attributes.value; - return !val || val.specified ? elem.value : elem.text; - } - }, - select: { - get: function( elem ) { - var value, i, max, option, - index = elem.selectedIndex, - values = [], - options = elem.options, - one = elem.type === "select-one"; - - // Nothing was selected - if ( index < 0 ) { - return null; - } - - // Loop through all the selected options - i = one ? index : 0; - max = one ? index + 1 : options.length; - for ( ; i < max; i++ ) { - option = options[ i ]; - - // Don't return options that are disabled or in a disabled optgroup - if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) && - (!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) { - - // Get the specific value for the option - value = jQuery( option ).val(); - - // We don't need an array for one selects - if ( one ) { - return value; - } - - // Multi-Selects return an array - values.push( value ); - } - } - - // Fixes Bug #2551 -- select.val() broken in IE after form.reset() - if ( one && !values.length && options.length ) { - return jQuery( options[ index ] ).val(); - } - - return values; - }, - - set: function( elem, value ) { - var values = jQuery.makeArray( value ); - - jQuery(elem).find("option").each(function() { - this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0; - }); - - if ( !values.length ) { - elem.selectedIndex = -1; - } - return values; - } - } - }, - - attrFn: { - val: true, - css: true, - html: true, - text: true, - data: true, - width: true, - height: true, - offset: true - }, - - attr: function( elem, name, value, pass ) { - var ret, hooks, notxml, - nType = elem.nodeType; - - // don't get/set attributes on text, comment and attribute nodes - if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { - return; - } - - if ( pass && name in jQuery.attrFn ) { - return jQuery( elem )[ name ]( value ); - } - - // Fallback to prop when attributes are not supported - if ( typeof elem.getAttribute === "undefined" ) { - return jQuery.prop( elem, name, value ); - } - - notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); - - // All attributes are lowercase - // Grab necessary hook if one is defined - if ( notxml ) { - name = name.toLowerCase(); - hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook ); - } - - if ( value !== undefined ) { - - if ( value === null ) { - jQuery.removeAttr( elem, name ); - return; - - } else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) { - return ret; - - } else { - elem.setAttribute( name, "" + value ); - return value; - } - - } else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) { - return ret; - - } else { - - ret = elem.getAttribute( name ); - - // Non-existent attributes return null, we normalize to undefined - return ret === null ? - undefined : - ret; - } - }, - - removeAttr: function( elem, value ) { - var propName, attrNames, name, l, isBool, - i = 0; - - if ( value && elem.nodeType === 1 ) { - attrNames = value.toLowerCase().split( rspace ); - l = attrNames.length; - - for ( ; i < l; i++ ) { - name = attrNames[ i ]; - - if ( name ) { - propName = jQuery.propFix[ name ] || name; - isBool = rboolean.test( name ); - - // See #9699 for explanation of this approach (setting first, then removal) - // Do not do this for boolean attributes (see #10870) - if ( !isBool ) { - jQuery.attr( elem, name, "" ); - } - elem.removeAttribute( getSetAttribute ? name : propName ); - - // Set corresponding property to false for boolean attributes - if ( isBool && propName in elem ) { - elem[ propName ] = false; - } - } - } - } - }, - - attrHooks: { - type: { - set: function( elem, value ) { - // We can't allow the type property to be changed (since it causes problems in IE) - if ( rtype.test( elem.nodeName ) && elem.parentNode ) { - jQuery.error( "type property can't be changed" ); - } else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) { - // Setting the type on a radio button after the value resets the value in IE6-9 - // Reset value to it's default in case type is set after value - // This is for element creation - var val = elem.value; - elem.setAttribute( "type", value ); - if ( val ) { - elem.value = val; - } - return value; - } - } - }, - // Use the value property for back compat - // Use the nodeHook for button elements in IE6/7 (#1954) - value: { - get: function( elem, name ) { - if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { - return nodeHook.get( elem, name ); - } - return name in elem ? - elem.value : - null; - }, - set: function( elem, value, name ) { - if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { - return nodeHook.set( elem, value, name ); - } - // Does not return so that setAttribute is also used - elem.value = value; - } - } - }, - - propFix: { - tabindex: "tabIndex", - readonly: "readOnly", - "for": "htmlFor", - "class": "className", - maxlength: "maxLength", - cellspacing: "cellSpacing", - cellpadding: "cellPadding", - rowspan: "rowSpan", - colspan: "colSpan", - usemap: "useMap", - frameborder: "frameBorder", - contenteditable: "contentEditable" - }, - - prop: function( elem, name, value ) { - var ret, hooks, notxml, - nType = elem.nodeType; - - // don't get/set properties on text, comment and attribute nodes - if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { - return; - } - - notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); - - if ( notxml ) { - // Fix name and attach hooks - name = jQuery.propFix[ name ] || name; - hooks = jQuery.propHooks[ name ]; - } - - if ( value !== undefined ) { - if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) { - return ret; - - } else { - return ( elem[ name ] = value ); - } - - } else { - if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) { - return ret; - - } else { - return elem[ name ]; - } - } - }, - - propHooks: { - tabIndex: { - get: function( elem ) { - // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set - // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ - var attributeNode = elem.getAttributeNode("tabindex"); - - return attributeNode && attributeNode.specified ? - parseInt( attributeNode.value, 10 ) : - rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? - 0 : - undefined; - } - } - } -}); - -// Add the tabIndex propHook to attrHooks for back-compat (different case is intentional) -jQuery.attrHooks.tabindex = jQuery.propHooks.tabIndex; - -// Hook for boolean attributes -boolHook = { - get: function( elem, name ) { - // Align boolean attributes with corresponding properties - // Fall back to attribute presence where some booleans are not supported - var attrNode, - property = jQuery.prop( elem, name ); - return property === true || typeof property !== "boolean" && ( attrNode = elem.getAttributeNode(name) ) && attrNode.nodeValue !== false ? - name.toLowerCase() : - undefined; - }, - set: function( elem, value, name ) { - var propName; - if ( value === false ) { - // Remove boolean attributes when set to false - jQuery.removeAttr( elem, name ); - } else { - // value is true since we know at this point it's type boolean and not false - // Set boolean attributes to the same name and set the DOM property - propName = jQuery.propFix[ name ] || name; - if ( propName in elem ) { - // Only set the IDL specifically if it already exists on the element - elem[ propName ] = true; - } - - elem.setAttribute( name, name.toLowerCase() ); - } - return name; - } -}; - -// IE6/7 do not support getting/setting some attributes with get/setAttribute -if ( !getSetAttribute ) { - - fixSpecified = { - name: true, - id: true, - coords: true - }; - - // Use this for any attribute in IE6/7 - // This fixes almost every IE6/7 issue - nodeHook = jQuery.valHooks.button = { - get: function( elem, name ) { - var ret; - ret = elem.getAttributeNode( name ); - return ret && ( fixSpecified[ name ] ? ret.nodeValue !== "" : ret.specified ) ? - ret.nodeValue : - undefined; - }, - set: function( elem, value, name ) { - // Set the existing or create a new attribute node - var ret = elem.getAttributeNode( name ); - if ( !ret ) { - ret = document.createAttribute( name ); - elem.setAttributeNode( ret ); - } - return ( ret.nodeValue = value + "" ); - } - }; - - // Apply the nodeHook to tabindex - jQuery.attrHooks.tabindex.set = nodeHook.set; - - // Set width and height to auto instead of 0 on empty string( Bug #8150 ) - // This is for removals - jQuery.each([ "width", "height" ], function( i, name ) { - jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { - set: function( elem, value ) { - if ( value === "" ) { - elem.setAttribute( name, "auto" ); - return value; - } - } - }); - }); - - // Set contenteditable to false on removals(#10429) - // Setting to empty string throws an error as an invalid value - jQuery.attrHooks.contenteditable = { - get: nodeHook.get, - set: function( elem, value, name ) { - if ( value === "" ) { - value = "false"; - } - nodeHook.set( elem, value, name ); - } - }; -} - - -// Some attributes require a special call on IE -if ( !jQuery.support.hrefNormalized ) { - jQuery.each([ "href", "src", "width", "height" ], function( i, name ) { - jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { - get: function( elem ) { - var ret = elem.getAttribute( name, 2 ); - return ret === null ? undefined : ret; - } - }); - }); -} - -if ( !jQuery.support.style ) { - jQuery.attrHooks.style = { - get: function( elem ) { - // Return undefined in the case of empty string - // Normalize to lowercase since IE uppercases css property names - return elem.style.cssText.toLowerCase() || undefined; - }, - set: function( elem, value ) { - return ( elem.style.cssText = "" + value ); - } - }; -} - -// Safari mis-reports the default selected property of an option -// Accessing the parent's selectedIndex property fixes it -if ( !jQuery.support.optSelected ) { - jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, { - get: function( elem ) { - var parent = elem.parentNode; - - if ( parent ) { - parent.selectedIndex; - - // Make sure that it also works with optgroups, see #5701 - if ( parent.parentNode ) { - parent.parentNode.selectedIndex; - } - } - return null; - } - }); -} - -// IE6/7 call enctype encoding -if ( !jQuery.support.enctype ) { - jQuery.propFix.enctype = "encoding"; -} - -// Radios and checkboxes getter/setter -if ( !jQuery.support.checkOn ) { - jQuery.each([ "radio", "checkbox" ], function() { - jQuery.valHooks[ this ] = { - get: function( elem ) { - // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified - return elem.getAttribute("value") === null ? "on" : elem.value; - } - }; - }); -} -jQuery.each([ "radio", "checkbox" ], function() { - jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], { - set: function( elem, value ) { - if ( jQuery.isArray( value ) ) { - return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 ); - } - } - }); -}); - - - - -var rformElems = /^(?:textarea|input|select)$/i, - rtypenamespace = /^([^\.]*)?(?:\.(.+))?$/, - rhoverHack = /(?:^|\s)hover(\.\S+)?\b/, - rkeyEvent = /^key/, - rmouseEvent = /^(?:mouse|contextmenu)|click/, - rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, - rquickIs = /^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/, - quickParse = function( selector ) { - var quick = rquickIs.exec( selector ); - if ( quick ) { - // 0 1 2 3 - // [ _, tag, id, class ] - quick[1] = ( quick[1] || "" ).toLowerCase(); - quick[3] = quick[3] && new RegExp( "(?:^|\\s)" + quick[3] + "(?:\\s|$)" ); - } - return quick; - }, - quickIs = function( elem, m ) { - var attrs = elem.attributes || {}; - return ( - (!m[1] || elem.nodeName.toLowerCase() === m[1]) && - (!m[2] || (attrs.id || {}).value === m[2]) && - (!m[3] || m[3].test( (attrs[ "class" ] || {}).value )) - ); - }, - hoverHack = function( events ) { - return jQuery.event.special.hover ? events : events.replace( rhoverHack, "mouseenter$1 mouseleave$1" ); - }; - -/* - * Helper functions for managing events -- not part of the public interface. - * Props to Dean Edwards' addEvent library for many of the ideas. - */ -jQuery.event = { - - add: function( elem, types, handler, data, selector ) { - - var elemData, eventHandle, events, - t, tns, type, namespaces, handleObj, - handleObjIn, quick, handlers, special; - - // Don't attach events to noData or text/comment nodes (allow plain objects tho) - if ( elem.nodeType === 3 || elem.nodeType === 8 || !types || !handler || !(elemData = jQuery._data( elem )) ) { - 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 - events = elemData.events; - if ( !events ) { - elemData.events = events = {}; - } - eventHandle = elemData.handle; - if ( !eventHandle ) { - elemData.handle = eventHandle = 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 - // jQuery(...).bind("mouseover mouseout", fn); - types = jQuery.trim( hoverHack(types) ).split( " " ); - for ( t = 0; t < types.length; t++ ) { - - tns = rtypenamespace.exec( types[t] ) || []; - type = tns[1]; - namespaces = ( tns[2] || "" ).split( "." ).sort(); - - // 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: tns[1], - data: data, - handler: handler, - guid: handler.guid, - selector: selector, - quick: selector && quickParse( selector ), - namespace: namespaces.join(".") - }, handleObjIn ); - - // Init the event handler queue if we're the first - handlers = events[ type ]; - if ( !handlers ) { - 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; - }, - - global: {}, - - // Detach an event or set of events from an element - remove: function( elem, types, handler, selector, mappedTypes ) { - - var elemData = jQuery.hasData( elem ) && jQuery._data( elem ), - t, tns, type, origType, namespaces, origCount, - j, events, special, handle, eventType, handleObj; - - if ( !elemData || !(events = elemData.events) ) { - return; - } - - // Once for each type.namespace in types; type may be omitted - types = jQuery.trim( hoverHack( types || "" ) ).split(" "); - for ( t = 0; t < types.length; t++ ) { - tns = rtypenamespace.exec( types[t] ) || []; - type = origType = tns[1]; - namespaces = tns[2]; - - // 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; - eventType = events[ type ] || []; - origCount = eventType.length; - namespaces = namespaces ? new RegExp("(^|\\.)" + namespaces.split(".").sort().join("\\.(?:.*\\.)?") + "(\\.|$)") : null; - - // Remove matching events - for ( j = 0; j < eventType.length; j++ ) { - handleObj = eventType[ j ]; - - if ( ( mappedTypes || origType === handleObj.origType ) && - ( !handler || handler.guid === handleObj.guid ) && - ( !namespaces || namespaces.test( handleObj.namespace ) ) && - ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) { - eventType.splice( j--, 1 ); - - if ( handleObj.selector ) { - eventType.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 ( eventType.length === 0 && origCount !== eventType.length ) { - if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) { - jQuery.removeEvent( elem, type, elemData.handle ); - } - - delete events[ type ]; - } - } - - // Remove the expando if it's no longer used - if ( jQuery.isEmptyObject( events ) ) { - handle = elemData.handle; - if ( handle ) { - handle.elem = null; - } - - // removeData also checks for emptiness and clears the expando if empty - // so use it instead of delete - jQuery.removeData( elem, [ "events", "handle" ], true ); - } - }, - - // Events that are safe to short-circuit if no handlers are attached. - // Native DOM events should not be added, they may have inline handlers. - customEvent: { - "getData": true, - "setData": true, - "changeData": true - }, - - trigger: function( event, data, elem, onlyHandlers ) { - // Don't do events on text and comment nodes - if ( elem && (elem.nodeType === 3 || elem.nodeType === 8) ) { - return; - } - - // Event object or event type - var type = event.type || event, - namespaces = [], - cache, exclusive, i, cur, old, ontype, special, handle, eventPath, bubbleType; - - // 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( "!" ) >= 0 ) { - // Exclusive events trigger only for the exact event (no namespaces) - type = type.slice(0, -1); - exclusive = true; - } - - if ( type.indexOf( "." ) >= 0 ) { - // Namespaced trigger; create a regexp to match event type in handle() - namespaces = type.split("."); - type = namespaces.shift(); - namespaces.sort(); - } - - if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) { - // No jQuery handlers for this event type, and it can't have inline handlers - return; - } - - // Caller can pass in an Event, Object, or just an event type string - event = typeof event === "object" ? - // jQuery.Event object - event[ jQuery.expando ] ? event : - // Object literal - new jQuery.Event( type, event ) : - // Just the event type (string) - new jQuery.Event( type ); - - event.type = type; - event.isTrigger = true; - event.exclusive = exclusive; - event.namespace = namespaces.join( "." ); - event.namespace_re = event.namespace? new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.)?") + "(\\.|$)") : null; - ontype = type.indexOf( ":" ) < 0 ? "on" + type : ""; - - // Handle a global trigger - if ( !elem ) { - - // TODO: Stop taunting the data cache; remove global events and always attach to document - cache = jQuery.cache; - for ( i in cache ) { - if ( cache[ i ].events && cache[ i ].events[ type ] ) { - jQuery.event.trigger( event, data, cache[ i ].handle.elem, true ); - } - } - return; - } - - // 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 ? jQuery.makeArray( data ) : []; - data.unshift( event ); - - // Allow special events to draw outside the lines - special = jQuery.event.special[ type ] || {}; - if ( 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) - eventPath = [[ elem, special.bindType || type ]]; - if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { - - bubbleType = special.delegateType || type; - cur = rfocusMorph.test( bubbleType + type ) ? elem : elem.parentNode; - old = null; - for ( ; cur; cur = cur.parentNode ) { - eventPath.push([ cur, bubbleType ]); - old = cur; - } - - // Only add window if we got to document (e.g., not plain obj or detached DOM) - if ( old && old === elem.ownerDocument ) { - eventPath.push([ old.defaultView || old.parentWindow || window, bubbleType ]); - } - } - - // Fire handlers on the event path - for ( i = 0; i < eventPath.length && !event.isPropagationStopped(); i++ ) { - - cur = eventPath[i][0]; - event.type = eventPath[i][1]; - - handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" ); - if ( handle ) { - handle.apply( cur, data ); - } - // Note that this is a bare JS function and not a jQuery handler - handle = ontype && cur[ ontype ]; - if ( handle && jQuery.acceptData( cur ) && handle.apply( cur, data ) === 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( elem.ownerDocument, data ) === false) && - !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.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) - // IE<9 dies on focus/blur to hidden element (#1486) - if ( ontype && elem[ type ] && ((type !== "focus" && type !== "blur") || event.target.offsetWidth !== 0) && !jQuery.isWindow( elem ) ) { - - // Don't re-trigger an onFOO event when we call its FOO() method - old = elem[ ontype ]; - - if ( old ) { - elem[ ontype ] = null; - } - - // Prevent re-triggering of the same event, since we already bubbled it above - jQuery.event.triggered = type; - elem[ type ](); - jQuery.event.triggered = undefined; - - if ( old ) { - elem[ ontype ] = old; - } - } - } - } - - return event.result; - }, - - dispatch: function( event ) { - - // Make a writable jQuery.Event from the native event object - event = jQuery.event.fix( event || window.event ); - - var handlers = ( (jQuery._data( this, "events" ) || {} )[ event.type ] || []), - delegateCount = handlers.delegateCount, - args = [].slice.call( arguments, 0 ), - run_all = !event.exclusive && !event.namespace, - special = jQuery.event.special[ event.type ] || {}, - handlerQueue = [], - i, j, cur, jqcur, ret, selMatch, matched, matches, handleObj, sel, related; - - // 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 that should run if there are delegated events - // Avoid non-left-click bubbling in Firefox (#3861) - if ( delegateCount && !(event.button && event.type === "click") ) { - - // Pregenerate a single jQuery object for reuse with .is() - jqcur = jQuery(this); - jqcur.context = this.ownerDocument || this; - - for ( cur = event.target; cur != this; cur = cur.parentNode || this ) { - - // Don't process events on disabled elements (#6911, #8165) - if ( cur.disabled !== true ) { - selMatch = {}; - matches = []; - jqcur[0] = cur; - for ( i = 0; i < delegateCount; i++ ) { - handleObj = handlers[ i ]; - sel = handleObj.selector; - - if ( selMatch[ sel ] === undefined ) { - selMatch[ sel ] = ( - handleObj.quick ? quickIs( cur, handleObj.quick ) : jqcur.is( sel ) - ); - } - if ( selMatch[ sel ] ) { - matches.push( handleObj ); - } - } - if ( matches.length ) { - handlerQueue.push({ elem: cur, matches: matches }); - } - } - } - } - - // Add the remaining (directly-bound) handlers - if ( handlers.length > delegateCount ) { - handlerQueue.push({ elem: this, matches: handlers.slice( delegateCount ) }); - } - - // Run delegates first; they may want to stop propagation beneath us - for ( i = 0; i < handlerQueue.length && !event.isPropagationStopped(); i++ ) { - matched = handlerQueue[ i ]; - event.currentTarget = matched.elem; - - for ( j = 0; j < matched.matches.length && !event.isImmediatePropagationStopped(); j++ ) { - handleObj = matched.matches[ j ]; - - // Triggered event must either 1) be non-exclusive and have no namespace, or - // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace). - if ( run_all || (!event.namespace && !handleObj.namespace) || event.namespace_re && event.namespace_re.test( handleObj.namespace ) ) { - - event.data = handleObj.data; - event.handleObj = handleObj; - - ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler ) - .apply( matched.elem, args ); - - if ( ret !== undefined ) { - event.result = ret; - if ( 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; - }, - - // Includes some event props shared by KeyEvent and MouseEvent - // *** attrChange attrName relatedNode srcElement are not normalized, non-W3C, deprecated, will be removed in 1.8 *** - props: "attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget 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 eventDoc, doc, body, - 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; - } - }, - - fix: function( event ) { - if ( event[ jQuery.expando ] ) { - return event; - } - - // Create a writable copy of the event object and normalize some properties - var i, prop, - originalEvent = event, - fixHook = jQuery.event.fixHooks[ event.type ] || {}, - copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props; - - event = jQuery.Event( originalEvent ); - - for ( i = copy.length; i; ) { - prop = copy[ --i ]; - event[ prop ] = originalEvent[ prop ]; - } - - // Fix target property, if necessary (#1925, IE 6/7/8 & Safari2) - if ( !event.target ) { - event.target = originalEvent.srcElement || document; - } - - // Target should not be a text node (#504, Safari) - if ( event.target.nodeType === 3 ) { - event.target = event.target.parentNode; - } - - // For mouse/key events; add metaKey if it's not there (#3368, IE6/7/8) - if ( event.metaKey === undefined ) { - event.metaKey = event.ctrlKey; - } - - return fixHook.filter? fixHook.filter( event, originalEvent ) : event; - }, - - special: { - ready: { - // Make sure the ready event is setup - setup: jQuery.bindReady - }, - - load: { - // Prevent triggered image.load events from bubbling to window.load - noBubble: true - }, - - focus: { - delegateType: "focusin" - }, - blur: { - delegateType: "focusout" - }, - - beforeunload: { - setup: function( data, namespaces, eventHandle ) { - // We only want to do this special case on windows - if ( jQuery.isWindow( this ) ) { - this.onbeforeunload = eventHandle; - } - }, - - teardown: function( namespaces, eventHandle ) { - if ( this.onbeforeunload === eventHandle ) { - this.onbeforeunload = null; - } - } - } - }, - - simulate: function( type, elem, event, bubble ) { - // Piggyback on a donor event to simulate a different one. - // Fake originalEvent to avoid donor's stopPropagation, but if the - // simulated event prevents default then we do the same on the donor. - var e = jQuery.extend( - new jQuery.Event(), - event, - { type: type, - isSimulated: true, - originalEvent: {} - } - ); - if ( bubble ) { - jQuery.event.trigger( e, null, elem ); - } else { - jQuery.event.dispatch.call( elem, e ); - } - if ( e.isDefaultPrevented() ) { - event.preventDefault(); - } - } -}; - -// Some plugins are using, but it's undocumented/deprecated and will be removed. -// The 1.7 special event interface should provide all the hooks needed now. -jQuery.event.handle = jQuery.event.dispatch; - -jQuery.removeEvent = document.removeEventListener ? - function( elem, type, handle ) { - if ( elem.removeEventListener ) { - elem.removeEventListener( type, handle, false ); - } - } : - function( elem, type, handle ) { - if ( elem.detachEvent ) { - elem.detachEvent( "on" + type, 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.returnValue === false || - src.getPreventDefault && src.getPreventDefault() ) ? 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; -}; - -function returnFalse() { - return false; -} -function returnTrue() { - return 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 = { - preventDefault: function() { - this.isDefaultPrevented = returnTrue; - - var e = this.originalEvent; - if ( !e ) { - return; - } - - // if preventDefault exists run it on the original event - if ( e.preventDefault ) { - e.preventDefault(); - - // otherwise set the returnValue property of the original event to false (IE) - } else { - e.returnValue = false; - } - }, - stopPropagation: function() { - this.isPropagationStopped = returnTrue; - - var e = this.originalEvent; - if ( !e ) { - return; - } - // if stopPropagation exists run it on the original event - if ( e.stopPropagation ) { - e.stopPropagation(); - } - // otherwise set the cancelBubble property of the original event to true (IE) - e.cancelBubble = true; - }, - stopImmediatePropagation: function() { - this.isImmediatePropagationStopped = returnTrue; - this.stopPropagation(); - }, - isDefaultPrevented: returnFalse, - isPropagationStopped: returnFalse, - isImmediatePropagationStopped: returnFalse -}; - -// Create mouseenter/leave events using mouseover/out and event-time checks -jQuery.each({ - mouseenter: "mouseover", - mouseleave: "mouseout" -}, function( orig, fix ) { - jQuery.event.special[ orig ] = { - delegateType: fix, - bindType: fix, - - handle: function( event ) { - var target = this, - related = event.relatedTarget, - handleObj = event.handleObj, - selector = handleObj.selector, - ret; - - // For mousenter/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 ( !jQuery.support.submitBubbles ) { - - 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" ) ? elem.form : undefined; - if ( form && !form._submit_attached ) { - jQuery.event.add( form, "submit._submit", function( event ) { - event._submit_bubble = true; - }); - form._submit_attached = 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._submit_bubble ) { - delete event._submit_bubble; - if ( this.parentNode && !event.isTrigger ) { - jQuery.event.simulate( "submit", this.parentNode, event, true ); - } - } - }, - - 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 ( !jQuery.support.changeBubbles ) { - - 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._just_changed = true; - } - }); - jQuery.event.add( this, "click._change", function( event ) { - if ( this._just_changed && !event.isTrigger ) { - this._just_changed = false; - jQuery.event.simulate( "change", this, event, true ); - } - }); - } - 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 ) && !elem._change_attached ) { - jQuery.event.add( elem, "change._change", function( event ) { - if ( this.parentNode && !event.isSimulated && !event.isTrigger ) { - jQuery.event.simulate( "change", this.parentNode, event, true ); - } - }); - elem._change_attached = 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 ); - } - }; -} - -// Create "bubbling" focus and blur events -if ( !jQuery.support.focusinBubbles ) { - jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { - - // Attach a single capturing handler while someone wants focusin/focusout - var attaches = 0, - handler = function( event ) { - jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true ); - }; - - jQuery.event.special[ fix ] = { - setup: function() { - if ( attaches++ === 0 ) { - document.addEventListener( orig, handler, true ); - } - }, - teardown: function() { - if ( --attaches === 0 ) { - document.removeEventListener( orig, handler, true ); - } - } - }; - }); -} - -jQuery.fn.extend({ - - on: function( types, selector, data, fn, /*INTERNAL*/ one ) { - var origFn, type; - - // Types can be a map of types/handlers - if ( typeof types === "object" ) { - // ( types-Object, selector, data ) - if ( typeof selector !== "string" ) { // && selector != null - // ( types-Object, data ) - data = data || selector; - selector = undefined; - } - for ( type in types ) { - this.on( type, selector, data, types[ type ], one ); - } - return this; - } - - 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 this; - } - - 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 this.each( function() { - jQuery.event.add( this, types, fn, data, selector ); - }); - }, - one: function( types, selector, data, fn ) { - return this.on( types, selector, data, fn, 1 ); - }, - off: function( types, selector, fn ) { - if ( types && types.preventDefault && types.handleObj ) { - // ( event ) dispatched jQuery.Event - var 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 ( var 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 ); - }); - }, - - bind: function( types, data, fn ) { - return this.on( types, null, data, fn ); - }, - unbind: function( types, fn ) { - return this.off( types, null, fn ); - }, - - live: function( types, data, fn ) { - jQuery( this.context ).on( types, this.selector, data, fn ); - return this; - }, - die: function( types, fn ) { - jQuery( this.context ).off( types, this.selector || "**", fn ); - return this; - }, - - delegate: function( selector, types, data, fn ) { - return this.on( types, selector, data, fn ); - }, - undelegate: function( selector, types, fn ) { - // ( namespace ) or ( selector, types [, fn] ) - return arguments.length == 1? this.off( selector, "**" ) : this.off( types, selector, fn ); - }, - - trigger: function( type, data ) { - return this.each(function() { - jQuery.event.trigger( type, data, this ); - }); - }, - triggerHandler: function( type, data ) { - if ( this[0] ) { - return jQuery.event.trigger( type, data, this[0], true ); - } - }, - - toggle: function( fn ) { - // Save reference to arguments for access in closure - var args = arguments, - guid = fn.guid || jQuery.guid++, - i = 0, - toggler = function( event ) { - // Figure out which function to execute - var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i; - jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 ); - - // Make sure that clicks stop - event.preventDefault(); - - // and execute the function - return args[ lastToggle ].apply( this, arguments ) || false; - }; - - // link all the functions, so any of them can unbind this click handler - toggler.guid = guid; - while ( i < args.length ) { - args[ i++ ].guid = guid; - } - - return this.click( toggler ); - }, - - hover: function( fnOver, fnOut ) { - return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); - } -}); - -jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " + - "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + - "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) { - - // Handle event binding - jQuery.fn[ name ] = function( data, fn ) { - if ( fn == null ) { - fn = data; - data = null; - } - - return arguments.length > 0 ? - this.on( name, null, data, fn ) : - this.trigger( name ); - }; - - if ( jQuery.attrFn ) { - jQuery.attrFn[ name ] = true; - } - - if ( rkeyEvent.test( name ) ) { - jQuery.event.fixHooks[ name ] = jQuery.event.keyHooks; - } - - if ( rmouseEvent.test( name ) ) { - jQuery.event.fixHooks[ name ] = jQuery.event.mouseHooks; - } -}); - - - -/*! - * Sizzle CSS Selector Engine - * Copyright 2011, The Dojo Foundation - * Released under the MIT, BSD, and GPL Licenses. - * More information: http://sizzlejs.com/ - */ -(function(){ - -var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, - expando = "sizcache" + (Math.random() + '').replace('.', ''), - done = 0, - toString = Object.prototype.toString, - hasDuplicate = false, - baseHasDuplicate = true, - rBackslash = /\\/g, - rReturn = /\r\n/g, - rNonWord = /\W/; - -// Here we check if the JavaScript engine is using some sort of -// optimization where it does not always call our comparision -// function. If that is the case, discard the hasDuplicate value. -// Thus far that includes Google Chrome. -[0, 0].sort(function() { - baseHasDuplicate = false; - return 0; -}); - -var Sizzle = function( selector, context, results, seed ) { - results = results || []; - context = context || document; - - var origContext = context; - - if ( context.nodeType !== 1 && context.nodeType !== 9 ) { - return []; - } - - if ( !selector || typeof selector !== "string" ) { - return results; - } - - var m, set, checkSet, extra, ret, cur, pop, i, - prune = true, - contextXML = Sizzle.isXML( context ), - parts = [], - soFar = selector; - - // Reset the position of the chunker regexp (start from head) - do { - chunker.exec( "" ); - m = chunker.exec( soFar ); - - if ( m ) { - soFar = m[3]; - - parts.push( m[1] ); - - if ( m[2] ) { - extra = m[3]; - break; - } - } - } while ( m ); - - if ( parts.length > 1 && origPOS.exec( selector ) ) { - - if ( parts.length === 2 && Expr.relative[ parts[0] ] ) { - set = posProcess( parts[0] + parts[1], context, seed ); - - } else { - set = Expr.relative[ parts[0] ] ? - [ context ] : - Sizzle( parts.shift(), context ); - - while ( parts.length ) { - selector = parts.shift(); - - if ( Expr.relative[ selector ] ) { - selector += parts.shift(); - } - - set = posProcess( selector, set, seed ); - } - } - - } else { - // Take a shortcut and set the context if the root selector is an ID - // (but not if it'll be faster if the inner selector is an ID) - if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML && - Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) { - - ret = Sizzle.find( parts.shift(), context, contextXML ); - context = ret.expr ? - Sizzle.filter( ret.expr, ret.set )[0] : - ret.set[0]; - } - - if ( context ) { - ret = seed ? - { expr: parts.pop(), set: makeArray(seed) } : - Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML ); - - set = ret.expr ? - Sizzle.filter( ret.expr, ret.set ) : - ret.set; - - if ( parts.length > 0 ) { - checkSet = makeArray( set ); - - } else { - prune = false; - } - - while ( parts.length ) { - cur = parts.pop(); - pop = cur; - - if ( !Expr.relative[ cur ] ) { - cur = ""; - } else { - pop = parts.pop(); - } - - if ( pop == null ) { - pop = context; - } - - Expr.relative[ cur ]( checkSet, pop, contextXML ); - } - - } else { - checkSet = parts = []; - } - } - - if ( !checkSet ) { - checkSet = set; - } - - if ( !checkSet ) { - Sizzle.error( cur || selector ); - } - - if ( toString.call(checkSet) === "[object Array]" ) { - if ( !prune ) { - results.push.apply( results, checkSet ); - - } else if ( context && context.nodeType === 1 ) { - for ( i = 0; checkSet[i] != null; i++ ) { - if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && Sizzle.contains(context, checkSet[i])) ) { - results.push( set[i] ); - } - } - - } else { - for ( i = 0; checkSet[i] != null; i++ ) { - if ( checkSet[i] && checkSet[i].nodeType === 1 ) { - results.push( set[i] ); - } - } - } - - } else { - makeArray( checkSet, results ); - } - - if ( extra ) { - Sizzle( extra, origContext, results, seed ); - Sizzle.uniqueSort( results ); - } - - return results; -}; - -Sizzle.uniqueSort = function( results ) { - if ( sortOrder ) { - hasDuplicate = baseHasDuplicate; - results.sort( sortOrder ); - - if ( hasDuplicate ) { - for ( var i = 1; i < results.length; i++ ) { - if ( results[i] === results[ i - 1 ] ) { - results.splice( i--, 1 ); - } - } - } - } - - return results; -}; - -Sizzle.matches = function( expr, set ) { - return Sizzle( expr, null, null, set ); -}; - -Sizzle.matchesSelector = function( node, expr ) { - return Sizzle( expr, null, null, [node] ).length > 0; -}; - -Sizzle.find = function( expr, context, isXML ) { - var set, i, len, match, type, left; - - if ( !expr ) { - return []; - } - - for ( i = 0, len = Expr.order.length; i < len; i++ ) { - type = Expr.order[i]; - - if ( (match = Expr.leftMatch[ type ].exec( expr )) ) { - left = match[1]; - match.splice( 1, 1 ); - - if ( left.substr( left.length - 1 ) !== "\\" ) { - match[1] = (match[1] || "").replace( rBackslash, "" ); - set = Expr.find[ type ]( match, context, isXML ); - - if ( set != null ) { - expr = expr.replace( Expr.match[ type ], "" ); - break; - } - } - } - } - - if ( !set ) { - set = typeof context.getElementsByTagName !== "undefined" ? - context.getElementsByTagName( "*" ) : - []; - } - - return { set: set, expr: expr }; -}; - -Sizzle.filter = function( expr, set, inplace, not ) { - var match, anyFound, - type, found, item, filter, left, - i, pass, - old = expr, - result = [], - curLoop = set, - isXMLFilter = set && set[0] && Sizzle.isXML( set[0] ); - - while ( expr && set.length ) { - for ( type in Expr.filter ) { - if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) { - filter = Expr.filter[ type ]; - left = match[1]; - - anyFound = false; - - match.splice(1,1); - - if ( left.substr( left.length - 1 ) === "\\" ) { - continue; - } - - if ( curLoop === result ) { - result = []; - } - - if ( Expr.preFilter[ type ] ) { - match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter ); - - if ( !match ) { - anyFound = found = true; - - } else if ( match === true ) { - continue; - } - } - - if ( match ) { - for ( i = 0; (item = curLoop[i]) != null; i++ ) { - if ( item ) { - found = filter( item, match, i, curLoop ); - pass = not ^ found; - - if ( inplace && found != null ) { - if ( pass ) { - anyFound = true; - - } else { - curLoop[i] = false; - } - - } else if ( pass ) { - result.push( item ); - anyFound = true; - } - } - } - } - - if ( found !== undefined ) { - if ( !inplace ) { - curLoop = result; - } - - expr = expr.replace( Expr.match[ type ], "" ); - - if ( !anyFound ) { - return []; - } - - break; - } - } - } - - // Improper expression - if ( expr === old ) { - if ( anyFound == null ) { - Sizzle.error( expr ); - - } else { - break; - } - } - - old = expr; - } - - return curLoop; -}; - -Sizzle.error = function( msg ) { - throw new Error( "Syntax error, unrecognized expression: " + msg ); -}; - -/** - * Utility function for retreiving the text value of an array of DOM nodes - * @param {Array|Element} elem - */ -var getText = Sizzle.getText = function( elem ) { - var i, node, - nodeType = elem.nodeType, - ret = ""; - - if ( nodeType ) { - if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { - // Use textContent || innerText for elements - if ( typeof elem.textContent === 'string' ) { - return elem.textContent; - } else if ( typeof elem.innerText === 'string' ) { - // Replace IE's carriage returns - return elem.innerText.replace( rReturn, '' ); - } else { - // Traverse it's children - for ( elem = elem.firstChild; elem; elem = elem.nextSibling) { - ret += getText( elem ); - } - } - } else if ( nodeType === 3 || nodeType === 4 ) { - return elem.nodeValue; - } - } else { - - // If no nodeType, this is expected to be an array - for ( i = 0; (node = elem[i]); i++ ) { - // Do not traverse comment nodes - if ( node.nodeType !== 8 ) { - ret += getText( node ); - } - } - } - return ret; -}; - -var Expr = Sizzle.selectors = { - order: [ "ID", "NAME", "TAG" ], - - match: { - ID: /#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/, - CLASS: /\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/, - NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/, - ATTR: /\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/, - TAG: /^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/, - CHILD: /:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/, - POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/, - PSEUDO: /:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/ - }, - - leftMatch: {}, - - attrMap: { - "class": "className", - "for": "htmlFor" - }, - - attrHandle: { - href: function( elem ) { - return elem.getAttribute( "href" ); - }, - type: function( elem ) { - return elem.getAttribute( "type" ); - } - }, - - relative: { - "+": function(checkSet, part){ - var isPartStr = typeof part === "string", - isTag = isPartStr && !rNonWord.test( part ), - isPartStrNotTag = isPartStr && !isTag; - - if ( isTag ) { - part = part.toLowerCase(); - } - - for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) { - if ( (elem = checkSet[i]) ) { - while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {} - - checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ? - elem || false : - elem === part; - } - } - - if ( isPartStrNotTag ) { - Sizzle.filter( part, checkSet, true ); - } - }, - - ">": function( checkSet, part ) { - var elem, - isPartStr = typeof part === "string", - i = 0, - l = checkSet.length; - - if ( isPartStr && !rNonWord.test( part ) ) { - part = part.toLowerCase(); - - for ( ; i < l; i++ ) { - elem = checkSet[i]; - - if ( elem ) { - var parent = elem.parentNode; - checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false; - } - } - - } else { - for ( ; i < l; i++ ) { - elem = checkSet[i]; - - if ( elem ) { - checkSet[i] = isPartStr ? - elem.parentNode : - elem.parentNode === part; - } - } - - if ( isPartStr ) { - Sizzle.filter( part, checkSet, true ); - } - } - }, - - "": function(checkSet, part, isXML){ - var nodeCheck, - doneName = done++, - checkFn = dirCheck; - - if ( typeof part === "string" && !rNonWord.test( part ) ) { - part = part.toLowerCase(); - nodeCheck = part; - checkFn = dirNodeCheck; - } - - checkFn( "parentNode", part, doneName, checkSet, nodeCheck, isXML ); - }, - - "~": function( checkSet, part, isXML ) { - var nodeCheck, - doneName = done++, - checkFn = dirCheck; - - if ( typeof part === "string" && !rNonWord.test( part ) ) { - part = part.toLowerCase(); - nodeCheck = part; - checkFn = dirNodeCheck; - } - - checkFn( "previousSibling", part, doneName, checkSet, nodeCheck, isXML ); - } - }, - - find: { - ID: function( match, context, isXML ) { - if ( typeof context.getElementById !== "undefined" && !isXML ) { - var m = context.getElementById(match[1]); - // Check parentNode to catch when Blackberry 4.6 returns - // nodes that are no longer in the document #6963 - return m && m.parentNode ? [m] : []; - } - }, - - NAME: function( match, context ) { - if ( typeof context.getElementsByName !== "undefined" ) { - var ret = [], - results = context.getElementsByName( match[1] ); - - for ( var i = 0, l = results.length; i < l; i++ ) { - if ( results[i].getAttribute("name") === match[1] ) { - ret.push( results[i] ); - } - } - - return ret.length === 0 ? null : ret; - } - }, - - TAG: function( match, context ) { - if ( typeof context.getElementsByTagName !== "undefined" ) { - return context.getElementsByTagName( match[1] ); - } - } - }, - preFilter: { - CLASS: function( match, curLoop, inplace, result, not, isXML ) { - match = " " + match[1].replace( rBackslash, "" ) + " "; - - if ( isXML ) { - return match; - } - - for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) { - if ( elem ) { - if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n\r]/g, " ").indexOf(match) >= 0) ) { - if ( !inplace ) { - result.push( elem ); - } - - } else if ( inplace ) { - curLoop[i] = false; - } - } - } - - return false; - }, - - ID: function( match ) { - return match[1].replace( rBackslash, "" ); - }, - - TAG: function( match, curLoop ) { - return match[1].replace( rBackslash, "" ).toLowerCase(); - }, - - CHILD: function( match ) { - if ( match[1] === "nth" ) { - if ( !match[2] ) { - Sizzle.error( match[0] ); - } - - match[2] = match[2].replace(/^\+|\s*/g, ''); - - // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6' - var test = /(-?)(\d*)(?:n([+\-]?\d*))?/.exec( - match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" || - !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]); - - // calculate the numbers (first)n+(last) including if they are negative - match[2] = (test[1] + (test[2] || 1)) - 0; - match[3] = test[3] - 0; - } - else if ( match[2] ) { - Sizzle.error( match[0] ); - } - - // TODO: Move to normal caching system - match[0] = done++; - - return match; - }, - - ATTR: function( match, curLoop, inplace, result, not, isXML ) { - var name = match[1] = match[1].replace( rBackslash, "" ); - - if ( !isXML && Expr.attrMap[name] ) { - match[1] = Expr.attrMap[name]; - } - - // Handle if an un-quoted value was used - match[4] = ( match[4] || match[5] || "" ).replace( rBackslash, "" ); - - if ( match[2] === "~=" ) { - match[4] = " " + match[4] + " "; - } - - return match; - }, - - PSEUDO: function( match, curLoop, inplace, result, not ) { - if ( match[1] === "not" ) { - // If we're dealing with a complex expression, or a simple one - if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) { - match[3] = Sizzle(match[3], null, null, curLoop); - - } else { - var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not); - - if ( !inplace ) { - result.push.apply( result, ret ); - } - - return false; - } - - } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) { - return true; - } - - return match; - }, - - POS: function( match ) { - match.unshift( true ); - - return match; - } - }, - - filters: { - enabled: function( elem ) { - return elem.disabled === false && elem.type !== "hidden"; - }, - - disabled: function( elem ) { - return elem.disabled === true; - }, - - checked: function( elem ) { - return elem.checked === true; - }, - - 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; - }, - - parent: function( elem ) { - return !!elem.firstChild; - }, - - empty: function( elem ) { - return !elem.firstChild; - }, - - has: function( elem, i, match ) { - return !!Sizzle( match[3], elem ).length; - }, - - header: function( elem ) { - return (/h\d/i).test( elem.nodeName ); - }, - - text: function( elem ) { - var attr = elem.getAttribute( "type" ), type = elem.type; - // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) - // use getAttribute instead to test this case - return elem.nodeName.toLowerCase() === "input" && "text" === type && ( attr === type || attr === null ); - }, - - radio: function( elem ) { - return elem.nodeName.toLowerCase() === "input" && "radio" === elem.type; - }, - - checkbox: function( elem ) { - return elem.nodeName.toLowerCase() === "input" && "checkbox" === elem.type; - }, - - file: function( elem ) { - return elem.nodeName.toLowerCase() === "input" && "file" === elem.type; - }, - - password: function( elem ) { - return elem.nodeName.toLowerCase() === "input" && "password" === elem.type; - }, - - submit: function( elem ) { - var name = elem.nodeName.toLowerCase(); - return (name === "input" || name === "button") && "submit" === elem.type; - }, - - image: function( elem ) { - return elem.nodeName.toLowerCase() === "input" && "image" === elem.type; - }, - - reset: function( elem ) { - var name = elem.nodeName.toLowerCase(); - return (name === "input" || name === "button") && "reset" === elem.type; - }, - - button: function( elem ) { - var name = elem.nodeName.toLowerCase(); - return name === "input" && "button" === elem.type || name === "button"; - }, - - input: function( elem ) { - return (/input|select|textarea|button/i).test( elem.nodeName ); - }, - - focus: function( elem ) { - return elem === elem.ownerDocument.activeElement; - } - }, - setFilters: { - first: function( elem, i ) { - return i === 0; - }, - - last: function( elem, i, match, array ) { - return i === array.length - 1; - }, - - even: function( elem, i ) { - return i % 2 === 0; - }, - - odd: function( elem, i ) { - return i % 2 === 1; - }, - - lt: function( elem, i, match ) { - return i < match[3] - 0; - }, - - gt: function( elem, i, match ) { - return i > match[3] - 0; - }, - - nth: function( elem, i, match ) { - return match[3] - 0 === i; - }, - - eq: function( elem, i, match ) { - return match[3] - 0 === i; - } - }, - filter: { - PSEUDO: function( elem, match, i, array ) { - var name = match[1], - filter = Expr.filters[ name ]; - - if ( filter ) { - return filter( elem, i, match, array ); - - } else if ( name === "contains" ) { - return (elem.textContent || elem.innerText || getText([ elem ]) || "").indexOf(match[3]) >= 0; - - } else if ( name === "not" ) { - var not = match[3]; - - for ( var j = 0, l = not.length; j < l; j++ ) { - if ( not[j] === elem ) { - return false; - } - } - - return true; - - } else { - Sizzle.error( name ); - } - }, - - CHILD: function( elem, match ) { - var first, last, - doneName, parent, cache, - count, diff, - type = match[1], - node = elem; - - switch ( type ) { - case "only": - case "first": - while ( (node = node.previousSibling) ) { - if ( node.nodeType === 1 ) { - return false; - } - } - - if ( type === "first" ) { - return true; - } - - node = elem; - - /* falls through */ - case "last": - while ( (node = node.nextSibling) ) { - if ( node.nodeType === 1 ) { - return false; - } - } - - return true; - - case "nth": - first = match[2]; - last = match[3]; - - if ( first === 1 && last === 0 ) { - return true; - } - - doneName = match[0]; - parent = elem.parentNode; - - if ( parent && (parent[ expando ] !== doneName || !elem.nodeIndex) ) { - count = 0; - - for ( node = parent.firstChild; node; node = node.nextSibling ) { - if ( node.nodeType === 1 ) { - node.nodeIndex = ++count; - } - } - - parent[ expando ] = doneName; - } - - diff = elem.nodeIndex - last; - - if ( first === 0 ) { - return diff === 0; - - } else { - return ( diff % first === 0 && diff / first >= 0 ); - } - } - }, - - ID: function( elem, match ) { - return elem.nodeType === 1 && elem.getAttribute("id") === match; - }, - - TAG: function( elem, match ) { - return (match === "*" && elem.nodeType === 1) || !!elem.nodeName && elem.nodeName.toLowerCase() === match; - }, - - CLASS: function( elem, match ) { - return (" " + (elem.className || elem.getAttribute("class")) + " ") - .indexOf( match ) > -1; - }, - - ATTR: function( elem, match ) { - var name = match[1], - result = Sizzle.attr ? - Sizzle.attr( elem, name ) : - Expr.attrHandle[ name ] ? - Expr.attrHandle[ name ]( elem ) : - elem[ name ] != null ? - elem[ name ] : - elem.getAttribute( name ), - value = result + "", - type = match[2], - check = match[4]; - - return result == null ? - type === "!=" : - !type && Sizzle.attr ? - result != null : - type === "=" ? - value === check : - type === "*=" ? - value.indexOf(check) >= 0 : - type === "~=" ? - (" " + value + " ").indexOf(check) >= 0 : - !check ? - value && result !== false : - type === "!=" ? - value !== check : - type === "^=" ? - value.indexOf(check) === 0 : - type === "$=" ? - value.substr(value.length - check.length) === check : - type === "|=" ? - value === check || value.substr(0, check.length + 1) === check + "-" : - false; - }, - - POS: function( elem, match, i, array ) { - var name = match[2], - filter = Expr.setFilters[ name ]; - - if ( filter ) { - return filter( elem, i, match, array ); - } - } - } -}; - -var origPOS = Expr.match.POS, - fescape = function(all, num){ - return "\\" + (num - 0 + 1); - }; - -for ( var type in Expr.match ) { - Expr.match[ type ] = new RegExp( Expr.match[ type ].source + (/(?![^\[]*\])(?![^\(]*\))/.source) ); - Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, fescape) ); -} -// Expose origPOS -// "global" as in regardless of relation to brackets/parens -Expr.match.globalPOS = origPOS; - -var makeArray = function( array, results ) { - array = Array.prototype.slice.call( array, 0 ); - - if ( results ) { - results.push.apply( results, array ); - return results; - } - - return array; -}; - -// Perform a simple check to determine if the browser is capable of -// converting a NodeList to an array using builtin methods. -// Also verifies that the returned array holds DOM nodes -// (which is not the case in the Blackberry browser) -try { - Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType; - -// Provide a fallback method if it does not work -} catch( e ) { - makeArray = function( array, results ) { - var i = 0, - ret = results || []; - - if ( toString.call(array) === "[object Array]" ) { - Array.prototype.push.apply( ret, array ); - - } else { - if ( typeof array.length === "number" ) { - for ( var l = array.length; i < l; i++ ) { - ret.push( array[i] ); - } - - } else { - for ( ; array[i]; i++ ) { - ret.push( array[i] ); - } - } - } - - return ret; - }; -} - -var sortOrder, siblingCheck; - -if ( document.documentElement.compareDocumentPosition ) { - sortOrder = function( a, b ) { - if ( a === b ) { - hasDuplicate = true; - return 0; - } - - if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) { - return a.compareDocumentPosition ? -1 : 1; - } - - return a.compareDocumentPosition(b) & 4 ? -1 : 1; - }; - -} else { - sortOrder = function( a, b ) { - // The nodes are identical, we can exit early - if ( a === b ) { - hasDuplicate = true; - return 0; - - // Fallback to using sourceIndex (in IE) if it's available on both nodes - } else if ( a.sourceIndex && b.sourceIndex ) { - return a.sourceIndex - b.sourceIndex; - } - - var al, bl, - ap = [], - bp = [], - aup = a.parentNode, - bup = b.parentNode, - cur = aup; - - // If the nodes are siblings (or identical) we can do a quick check - if ( aup === bup ) { - return siblingCheck( a, b ); - - // If no parents were found then the nodes are disconnected - } else if ( !aup ) { - return -1; - - } else if ( !bup ) { - return 1; - } - - // Otherwise they're somewhere else in the tree so we need - // to build up a full list of the parentNodes for comparison - while ( cur ) { - ap.unshift( cur ); - cur = cur.parentNode; - } - - cur = bup; - - while ( cur ) { - bp.unshift( cur ); - cur = cur.parentNode; - } - - al = ap.length; - bl = bp.length; - - // Start walking down the tree looking for a discrepancy - for ( var i = 0; i < al && i < bl; i++ ) { - if ( ap[i] !== bp[i] ) { - return siblingCheck( ap[i], bp[i] ); - } - } - - // We ended someplace up the tree so do a sibling check - return i === al ? - siblingCheck( a, bp[i], -1 ) : - siblingCheck( ap[i], b, 1 ); - }; - - siblingCheck = function( a, b, ret ) { - if ( a === b ) { - return ret; - } - - var cur = a.nextSibling; - - while ( cur ) { - if ( cur === b ) { - return -1; - } - - cur = cur.nextSibling; - } - - return 1; - }; -} - -// Check to see if the browser returns elements by name when -// querying by getElementById (and provide a workaround) -(function(){ - // We're going to inject a fake input element with a specified name - var form = document.createElement("div"), - id = "script" + (new Date()).getTime(), - root = document.documentElement; - - form.innerHTML = ""; - - // Inject it into the root element, check its status, and remove it quickly - root.insertBefore( form, root.firstChild ); - - // The workaround has to do additional checks after a getElementById - // Which slows things down for other browsers (hence the branching) - if ( document.getElementById( id ) ) { - Expr.find.ID = function( match, context, isXML ) { - if ( typeof context.getElementById !== "undefined" && !isXML ) { - var m = context.getElementById(match[1]); - - return m ? - m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? - [m] : - undefined : - []; - } - }; - - Expr.filter.ID = function( elem, match ) { - var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id"); - - return elem.nodeType === 1 && node && node.nodeValue === match; - }; - } - - root.removeChild( form ); - - // release memory in IE - root = form = null; -})(); - -(function(){ - // Check to see if the browser returns only elements - // when doing getElementsByTagName("*") - - // Create a fake element - var div = document.createElement("div"); - div.appendChild( document.createComment("") ); - - // Make sure no comments are found - if ( div.getElementsByTagName("*").length > 0 ) { - Expr.find.TAG = function( match, context ) { - var results = context.getElementsByTagName( match[1] ); - - // Filter out possible comments - if ( match[1] === "*" ) { - var tmp = []; - - for ( var i = 0; results[i]; i++ ) { - if ( results[i].nodeType === 1 ) { - tmp.push( results[i] ); - } - } - - results = tmp; - } - - return results; - }; - } - - // Check to see if an attribute returns normalized href attributes - div.innerHTML = ""; - - if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" && - div.firstChild.getAttribute("href") !== "#" ) { - - Expr.attrHandle.href = function( elem ) { - return elem.getAttribute( "href", 2 ); - }; - } - - // release memory in IE - div = null; -})(); - -if ( document.querySelectorAll ) { - (function(){ - var oldSizzle = Sizzle, - div = document.createElement("div"), - id = "__sizzle__"; - - div.innerHTML = "

        "; - - // Safari can't handle uppercase or unicode characters when - // in quirks mode. - if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) { - return; - } - - Sizzle = function( query, context, extra, seed ) { - context = context || document; - - // Only use querySelectorAll on non-XML documents - // (ID selectors don't work in non-HTML documents) - if ( !seed && !Sizzle.isXML(context) ) { - // See if we find a selector to speed up - var match = /^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec( query ); - - if ( match && (context.nodeType === 1 || context.nodeType === 9) ) { - // Speed-up: Sizzle("TAG") - if ( match[1] ) { - return makeArray( context.getElementsByTagName( query ), extra ); - - // Speed-up: Sizzle(".CLASS") - } else if ( match[2] && Expr.find.CLASS && context.getElementsByClassName ) { - return makeArray( context.getElementsByClassName( match[2] ), extra ); - } - } - - if ( context.nodeType === 9 ) { - // Speed-up: Sizzle("body") - // The body element only exists once, optimize finding it - if ( query === "body" && context.body ) { - return makeArray( [ context.body ], extra ); - - // Speed-up: Sizzle("#ID") - } else if ( match && match[3] ) { - var elem = context.getElementById( match[3] ); - - // 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[3] ) { - return makeArray( [ elem ], extra ); - } - - } else { - return makeArray( [], extra ); - } - } - - try { - return makeArray( context.querySelectorAll(query), extra ); - } catch(qsaError) {} - - // qSA works strangely on Element-rooted queries - // We can work around this by specifying an extra ID on the root - // and working up from there (Thanks to Andrew Dupont for the technique) - // IE 8 doesn't work on object elements - } else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) { - var oldContext = context, - old = context.getAttribute( "id" ), - nid = old || id, - hasParent = context.parentNode, - relativeHierarchySelector = /^\s*[+~]/.test( query ); - - if ( !old ) { - context.setAttribute( "id", nid ); - } else { - nid = nid.replace( /'/g, "\\$&" ); - } - if ( relativeHierarchySelector && hasParent ) { - context = context.parentNode; - } - - try { - if ( !relativeHierarchySelector || hasParent ) { - return makeArray( context.querySelectorAll( "[id='" + nid + "'] " + query ), extra ); - } - - } catch(pseudoError) { - } finally { - if ( !old ) { - oldContext.removeAttribute( "id" ); - } - } - } - } - - return oldSizzle(query, context, extra, seed); - }; - - for ( var prop in oldSizzle ) { - Sizzle[ prop ] = oldSizzle[ prop ]; - } - - // release memory in IE - div = null; - })(); -} - -(function(){ - var html = document.documentElement, - matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector; - - if ( matches ) { - // Check to see if it's possible to do matchesSelector - // on a disconnected node (IE 9 fails this) - var disconnectedMatch = !matches.call( document.createElement( "div" ), "div" ), - pseudoWorks = false; - - try { - // This should fail with an exception - // Gecko does not error, returns false instead - matches.call( document.documentElement, "[test!='']:sizzle" ); - - } catch( pseudoError ) { - pseudoWorks = true; - } - - Sizzle.matchesSelector = function( node, expr ) { - // Make sure that attribute selectors are quoted - expr = expr.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']"); - - if ( !Sizzle.isXML( node ) ) { - try { - if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) { - var ret = matches.call( node, expr ); - - // IE 9's matchesSelector returns false on disconnected nodes - if ( ret || !disconnectedMatch || - // As well, disconnected nodes are said to be in a document - // fragment in IE 9, so check for that - node.document && node.document.nodeType !== 11 ) { - return ret; - } - } - } catch(e) {} - } - - return Sizzle(expr, null, null, [node]).length > 0; - }; - } -})(); - -(function(){ - var div = document.createElement("div"); - - div.innerHTML = "
        "; - - // Opera can't find a second classname (in 9.6) - // Also, make sure that getElementsByClassName actually exists - if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) { - return; - } - - // Safari caches class attributes, doesn't catch changes (in 3.2) - div.lastChild.className = "e"; - - if ( div.getElementsByClassName("e").length === 1 ) { - return; - } - - Expr.order.splice(1, 0, "CLASS"); - Expr.find.CLASS = function( match, context, isXML ) { - if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) { - return context.getElementsByClassName(match[1]); - } - }; - - // release memory in IE - div = null; -})(); - -function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { - for ( var i = 0, l = checkSet.length; i < l; i++ ) { - var elem = checkSet[i]; - - if ( elem ) { - var match = false; - - elem = elem[dir]; - - while ( elem ) { - if ( elem[ expando ] === doneName ) { - match = checkSet[elem.sizset]; - break; - } - - if ( elem.nodeType === 1 && !isXML ){ - elem[ expando ] = doneName; - elem.sizset = i; - } - - if ( elem.nodeName.toLowerCase() === cur ) { - match = elem; - break; - } - - elem = elem[dir]; - } - - checkSet[i] = match; - } - } -} - -function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { - for ( var i = 0, l = checkSet.length; i < l; i++ ) { - var elem = checkSet[i]; - - if ( elem ) { - var match = false; - - elem = elem[dir]; - - while ( elem ) { - if ( elem[ expando ] === doneName ) { - match = checkSet[elem.sizset]; - break; - } - - if ( elem.nodeType === 1 ) { - if ( !isXML ) { - elem[ expando ] = doneName; - elem.sizset = i; - } - - if ( typeof cur !== "string" ) { - if ( elem === cur ) { - match = true; - break; - } - - } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) { - match = elem; - break; - } - } - - elem = elem[dir]; - } - - checkSet[i] = match; - } - } -} - -if ( document.documentElement.contains ) { - Sizzle.contains = function( a, b ) { - return a !== b && (a.contains ? a.contains(b) : true); - }; - -} else if ( document.documentElement.compareDocumentPosition ) { - Sizzle.contains = function( a, b ) { - return !!(a.compareDocumentPosition(b) & 16); - }; - -} else { - Sizzle.contains = function() { - return false; - }; -} - -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 : 0).documentElement; - - return documentElement ? documentElement.nodeName !== "HTML" : false; -}; - -var posProcess = function( selector, context, seed ) { - var match, - tmpSet = [], - later = "", - root = context.nodeType ? [context] : context; - - // Position selectors must be done after the filter - // And so must :not(positional) so we move all PSEUDOs to the end - while ( (match = Expr.match.PSEUDO.exec( selector )) ) { - later += match[0]; - selector = selector.replace( Expr.match.PSEUDO, "" ); - } - - selector = Expr.relative[selector] ? selector + "*" : selector; - - for ( var i = 0, l = root.length; i < l; i++ ) { - Sizzle( selector, root[i], tmpSet, seed ); - } - - return Sizzle.filter( later, tmpSet ); -}; - -// EXPOSE -// Override sizzle attribute retrieval -Sizzle.attr = jQuery.attr; -Sizzle.selectors.attrMap = {}; -jQuery.find = Sizzle; -jQuery.expr = Sizzle.selectors; -jQuery.expr[":"] = jQuery.expr.filters; -jQuery.unique = Sizzle.uniqueSort; -jQuery.text = Sizzle.getText; -jQuery.isXMLDoc = Sizzle.isXML; -jQuery.contains = Sizzle.contains; - - -})(); - - -var runtil = /Until$/, - rparentsprev = /^(?:parents|prevUntil|prevAll)/, - // Note: This RegExp should be improved, or likely pulled from Sizzle - rmultiselector = /,/, - isSimple = /^.[^:#\[\.,]*$/, - slice = Array.prototype.slice, - POS = jQuery.expr.match.globalPOS, - // 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({ - find: function( selector ) { - var self = this, - i, l; - - if ( typeof selector !== "string" ) { - return jQuery( selector ).filter(function() { - for ( i = 0, l = self.length; i < l; i++ ) { - if ( jQuery.contains( self[ i ], this ) ) { - return true; - } - } - }); - } - - var ret = this.pushStack( "", "find", selector ), - length, n, r; - - for ( i = 0, l = this.length; i < l; i++ ) { - length = ret.length; - jQuery.find( selector, this[i], ret ); - - if ( i > 0 ) { - // Make sure that the results are unique - for ( n = length; n < ret.length; n++ ) { - for ( r = 0; r < length; r++ ) { - if ( ret[r] === ret[n] ) { - ret.splice(n--, 1); - break; - } - } - } - } - } - - return ret; - }, - - has: function( target ) { - var targets = jQuery( target ); - return this.filter(function() { - for ( var i = 0, l = targets.length; i < l; i++ ) { - if ( jQuery.contains( this, targets[i] ) ) { - return true; - } - } - }); - }, - - not: function( selector ) { - return this.pushStack( winnow(this, selector, false), "not", selector); - }, - - filter: function( selector ) { - return this.pushStack( winnow(this, selector, true), "filter", selector ); - }, - - is: function( selector ) { - return !!selector && ( - typeof selector === "string" ? - // If this is a positional selector, check membership in the returned set - // so $("p:first").is("p:last") won't return true for a doc with two "p". - POS.test( selector ) ? - jQuery( selector, this.context ).index( this[0] ) >= 0 : - jQuery.filter( selector, this ).length > 0 : - this.filter( selector ).length > 0 ); - }, - - closest: function( selectors, context ) { - var ret = [], i, l, cur = this[0]; - - // Array (deprecated as of jQuery 1.7) - if ( jQuery.isArray( selectors ) ) { - var level = 1; - - while ( cur && cur.ownerDocument && cur !== context ) { - for ( i = 0; i < selectors.length; i++ ) { - - if ( jQuery( cur ).is( selectors[ i ] ) ) { - ret.push({ selector: selectors[ i ], elem: cur, level: level }); - } - } - - cur = cur.parentNode; - level++; - } - - return ret; - } - - // String - var pos = POS.test( selectors ) || typeof selectors !== "string" ? - jQuery( selectors, context || this.context ) : - 0; - - for ( i = 0, l = this.length; i < l; i++ ) { - cur = this[i]; - - while ( cur ) { - if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) { - ret.push( cur ); - break; - - } else { - cur = cur.parentNode; - if ( !cur || !cur.ownerDocument || cur === context || cur.nodeType === 11 ) { - break; - } - } - } - } - - ret = ret.length > 1 ? jQuery.unique( ret ) : ret; - - return this.pushStack( ret, "closest", selectors ); - }, - - // 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.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 ) { - var set = typeof selector === "string" ? - jQuery( selector, context ) : - jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ), - all = jQuery.merge( this.get(), set ); - - return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ? - all : - jQuery.unique( all ) ); - }, - - andSelf: function() { - return this.add( this.prevObject ); - } -}); - -// A painfully simple check to see if an element is disconnected -// from a document (should be improved, where feasible). -function isDisconnected( node ) { - return !node || !node.parentNode || node.parentNode.nodeType === 11; -} - -jQuery.each({ - parent: function( elem ) { - var parent = elem.parentNode; - return parent && parent.nodeType !== 11 ? parent : null; - }, - parents: function( elem ) { - return jQuery.dir( elem, "parentNode" ); - }, - parentsUntil: function( elem, i, until ) { - return jQuery.dir( elem, "parentNode", until ); - }, - next: function( elem ) { - return jQuery.nth( elem, 2, "nextSibling" ); - }, - prev: function( elem ) { - return jQuery.nth( elem, 2, "previousSibling" ); - }, - nextAll: function( elem ) { - return jQuery.dir( elem, "nextSibling" ); - }, - prevAll: function( elem ) { - return jQuery.dir( elem, "previousSibling" ); - }, - nextUntil: function( elem, i, until ) { - return jQuery.dir( elem, "nextSibling", until ); - }, - prevUntil: function( elem, i, until ) { - return jQuery.dir( elem, "previousSibling", until ); - }, - siblings: function( elem ) { - return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem ); - }, - children: function( elem ) { - return jQuery.sibling( elem.firstChild ); - }, - contents: function( elem ) { - return jQuery.nodeName( elem, "iframe" ) ? - elem.contentDocument || elem.contentWindow.document : - jQuery.makeArray( elem.childNodes ); - } -}, function( name, fn ) { - jQuery.fn[ name ] = function( until, selector ) { - var ret = jQuery.map( this, fn, until ); - - if ( !runtil.test( name ) ) { - selector = until; - } - - if ( selector && typeof selector === "string" ) { - ret = jQuery.filter( selector, ret ); - } - - ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret; - - if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) { - ret = ret.reverse(); - } - - return this.pushStack( ret, name, slice.call( arguments ).join(",") ); - }; -}); - -jQuery.extend({ - filter: function( expr, elems, not ) { - if ( not ) { - expr = ":not(" + expr + ")"; - } - - return elems.length === 1 ? - jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] : - jQuery.find.matches(expr, elems); - }, - - dir: function( elem, dir, until ) { - var matched = [], - cur = elem[ dir ]; - - while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { - if ( cur.nodeType === 1 ) { - matched.push( cur ); - } - cur = cur[dir]; - } - return matched; - }, - - nth: function( cur, result, dir, elem ) { - result = result || 1; - var num = 0; - - for ( ; cur; cur = cur[dir] ) { - if ( cur.nodeType === 1 && ++num === result ) { - break; - } - } - - return cur; - }, - - sibling: function( n, elem ) { - var r = []; - - for ( ; n; n = n.nextSibling ) { - if ( n.nodeType === 1 && n !== elem ) { - r.push( n ); - } - } - - return r; - } -}); - -// Implement the identical functionality for filter and not -function winnow( elements, qualifier, keep ) { - - // Can't pass null or undefined to indexOf in Firefox 4 - // Set to 0 to skip string check - qualifier = qualifier || 0; - - if ( jQuery.isFunction( qualifier ) ) { - return jQuery.grep(elements, function( elem, i ) { - var retVal = !!qualifier.call( elem, i, elem ); - return retVal === keep; - }); - - } else if ( qualifier.nodeType ) { - return jQuery.grep(elements, function( elem, i ) { - return ( elem === qualifier ) === keep; - }); - - } else if ( typeof qualifier === "string" ) { - var filtered = jQuery.grep(elements, function( elem ) { - return elem.nodeType === 1; - }); - - if ( isSimple.test( qualifier ) ) { - return jQuery.filter(qualifier, filtered, !keep); - } else { - qualifier = jQuery.filter( qualifier, filtered ); - } - } - - return jQuery.grep(elements, function( elem, i ) { - return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep; - }); -} - - - - -function createSafeFragment( document ) { - var list = nodeNames.split( "|" ), - safeFrag = document.createDocumentFragment(); - - if ( safeFrag.createElement ) { - while ( list.length ) { - safeFrag.createElement( - list.pop() - ); - } - } - return safeFrag; -} - -var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" + - "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video", - rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g, - rleadingWhitespace = /^\s+/, - rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig, - rtagName = /<([\w:]+)/, - rtbody = /
        ", "
        " ], - tr: [ 2, "", "
        " ], - td: [ 3, "", "
        " ], - col: [ 2, "", "
        " ], - area: [ 1, "", "" ], - _default: [ 0, "", "" ] - }, - safeFragment = createSafeFragment( document ); - -wrapMap.optgroup = wrapMap.option; -wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; -wrapMap.th = wrapMap.td; - -// IE can't serialize and - - - - - diff --git a/GRID/jquery.gridder.html b/GRID/jquery.gridder.html deleted file mode 100644 index a2b41d3..0000000 --- a/GRID/jquery.gridder.html +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - -
        -
          -
          - - - - - - - diff --git a/GRID/jquery.gridder_test.js b/GRID/jquery.gridder_test.js deleted file mode 100644 index 2df25e7..0000000 --- a/GRID/jquery.gridder_test.js +++ /dev/null @@ -1,38 +0,0 @@ -/*global QUnit:false, module:false, test:false, asyncTest:false, expect:false*/ -/*global start:false, stop:false ok:false, equal:false, notEqual:false, deepEqual:false*/ -/*global notDeepEqual:false, strictEqual:false, notStrictEqual:false, raises:false*/ -(function($) { - - /* - ======== A Handy Little QUnit Reference ======== - http://docs.jquery.com/QUnit - - Test methods: - expect(numAssertions) - stop(increment) - start(decrement) - Test assertions: - ok(value, [message]) - equal(actual, expected, [message]) - notEqual(actual, expected, [message]) - deepEqual(actual, expected, [message]) - notDeepEqual(actual, expected, [message]) - strictEqual(actual, expected, [message]) - notStrictEqual(actual, expected, [message]) - raises(block, [expected], [message]) - */ - - module('jQuery#gridster', { - setup: function() { - - this.el = $('#qunit-fixture').find(".wrapper ul"); - - } - }); - - // test('is chainable', 1, function() { - // // Not a bad test to run on collection methods. - // strictEqual(this.el, this.el.gridster(), 'should be chaninable'); - // }); - -}(jQuery)); diff --git a/GRID/package.json b/GRID/package.json deleted file mode 100644 index 23354b5..0000000 --- a/GRID/package.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "name": "gridster", - "title": "gridster.js", - "description": "a drag-and-drop multi-column jQuery grid plugin", - "version": "0.5.6", - "homepage": "http://gridster.net/", - "author": { - "name": "ducksboard", - "email": "hackers@ducksboard.com" - }, - "repository": { - "type": "git", - "url": "git://github.com/ducksboard/gridster.js.git" - }, - "bugs": { - "url": "https://github.com/ducksboard/gridster.js/issues" - }, - "licenses": [ - { - "type": "MIT", - "url": "https://github.com/ducksboard/gridster.js/blob/master/LICENSE" - } - ], - "keywords": [], - "dependencies": { - "jquery": "git+https://github.com/jquery/jquery.git#2.0.3" - }, - "devDependencies": { - "grunt": "~0.4.1", - "grunt-contrib-uglify": "~0.2.0", - "grunt-contrib-jshint": "~0.3.0", - "grunt-contrib-concat": "~0.1.3", - "grunt-contrib-watch": "~0.3.1", - "grunt-contrib-cssmin": "~0.5.0", - "grunt-contrib-yuidoc": "~0.4.0", - "bower": "~0.9.2", - "qunitjs": "~1.11.0", - "grunt-bump": "0.0.11", - "grunt-conventional-changelog": "~1.0.0" - } -} diff --git a/GRID/src/jquery.collision.js b/GRID/src/jquery.collision.js deleted file mode 100644 index 4a15e8e..0000000 --- a/GRID/src/jquery.collision.js +++ /dev/null @@ -1,242 +0,0 @@ -/* - * jquery.collision - * https://github.com/ducksboard/gridster.js - * - * Copyright (c) 2012 ducksboard - * Licensed under the MIT licenses. - */ - -;(function(root, factory) { - - if (typeof define === 'function' && define.amd) { - define('gridster-collision', ['jquery', 'gridster-coords'], factory); - } else { - root.GridsterCollision = factory(root.$ || root.jQuery, - root.GridsterCoords); - } - -}(this, function($, Coords) { - - var defaults = { - colliders_context: document.body, - overlapping_region: 'C' - // ,on_overlap: function(collider_data){}, - // on_overlap_start : function(collider_data){}, - // on_overlap_stop : function(collider_data){} - }; - - - /** - * Detects collisions between a DOM element against other DOM elements or - * Coords objects. - * - * @class Collision - * @uses Coords - * @param {HTMLElement} el The jQuery wrapped HTMLElement. - * @param {HTMLElement|Array} colliders Can be a jQuery collection - * of HTMLElements or an Array of Coords instances. - * @param {Object} [options] An Object with all options you want to - * overwrite: - * @param {String} [options.overlapping_region] Determines when collision - * is valid, depending on the overlapped area. Values can be: 'N', 'S', - * 'W', 'E', 'C' or 'all'. Default is 'C'. - * @param {Function} [options.on_overlap_start] Executes a function the first - * time each `collider ` is overlapped. - * @param {Function} [options.on_overlap_stop] Executes a function when a - * `collider` is no longer collided. - * @param {Function} [options.on_overlap] Executes a function when the - * mouse is moved during the collision. - * @return {Object} Collision instance. - * @constructor - */ - function Collision(el, colliders, options) { - this.options = $.extend(defaults, options); - this.$element = el; - this.last_colliders = []; - this.last_colliders_coords = []; - this.set_colliders(colliders); - - this.init(); - } - - Collision.defaults = defaults; - - var fn = Collision.prototype; - - - fn.init = function() { - this.find_collisions(); - }; - - - fn.overlaps = function(a, b) { - var x = false; - var y = false; - - if ((b.x1 >= a.x1 && b.x1 <= a.x2) || - (b.x2 >= a.x1 && b.x2 <= a.x2) || - (a.x1 >= b.x1 && a.x2 <= b.x2) - ) { x = true; } - - if ((b.y1 >= a.y1 && b.y1 <= a.y2) || - (b.y2 >= a.y1 && b.y2 <= a.y2) || - (a.y1 >= b.y1 && a.y2 <= b.y2) - ) { y = true; } - - return (x && y); - }; - - - fn.detect_overlapping_region = function(a, b){ - var regionX = ''; - var regionY = ''; - - if (a.y1 > b.cy && a.y1 < b.y2) { regionX = 'N'; } - if (a.y2 > b.y1 && a.y2 < b.cy) { regionX = 'S'; } - if (a.x1 > b.cx && a.x1 < b.x2) { regionY = 'W'; } - if (a.x2 > b.x1 && a.x2 < b.cx) { regionY = 'E'; } - - return (regionX + regionY) || 'C'; - }; - - - fn.calculate_overlapped_area_coords = function(a, b){ - var x1 = Math.max(a.x1, b.x1); - var y1 = Math.max(a.y1, b.y1); - var x2 = Math.min(a.x2, b.x2); - var y2 = Math.min(a.y2, b.y2); - - return $({ - left: x1, - top: y1, - width : (x2 - x1), - height: (y2 - y1) - }).coords().get(); - }; - - - fn.calculate_overlapped_area = function(coords){ - return (coords.width * coords.height); - }; - - - fn.manage_colliders_start_stop = function(new_colliders_coords, start_callback, stop_callback){ - var last = this.last_colliders_coords; - - for (var i = 0, il = last.length; i < il; i++) { - if ($.inArray(last[i], new_colliders_coords) === -1) { - start_callback.call(this, last[i]); - } - } - - for (var j = 0, jl = new_colliders_coords.length; j < jl; j++) { - if ($.inArray(new_colliders_coords[j], last) === -1) { - stop_callback.call(this, new_colliders_coords[j]); - } - - } - }; - - - fn.find_collisions = function(player_data_coords){ - var self = this; - var overlapping_region = this.options.overlapping_region; - var colliders_coords = []; - var colliders_data = []; - var $colliders = (this.colliders || this.$colliders); - var count = $colliders.length; - var player_coords = self.$element.coords() - .update(player_data_coords || false).get(); - - while(count--){ - var $collider = self.$colliders ? - $($colliders[count]) : $colliders[count]; - var $collider_coords_ins = ($collider.isCoords) ? - $collider : $collider.coords(); - var collider_coords = $collider_coords_ins.get(); - var overlaps = self.overlaps(player_coords, collider_coords); - - if (!overlaps) { - continue; - } - - var region = self.detect_overlapping_region( - player_coords, collider_coords); - - //todo: make this an option - if (region === overlapping_region || overlapping_region === 'all') { - - var area_coords = self.calculate_overlapped_area_coords( - player_coords, collider_coords); - var area = self.calculate_overlapped_area(area_coords); - var collider_data = { - area: area, - area_coords : area_coords, - region: region, - coords: collider_coords, - player_coords: player_coords, - el: $collider - }; - - if (self.options.on_overlap) { - self.options.on_overlap.call(this, collider_data); - } - colliders_coords.push($collider_coords_ins); - colliders_data.push(collider_data); - } - } - - if (self.options.on_overlap_stop || self.options.on_overlap_start) { - this.manage_colliders_start_stop(colliders_coords, - self.options.on_overlap_start, self.options.on_overlap_stop); - } - - this.last_colliders_coords = colliders_coords; - - return colliders_data; - }; - - - fn.get_closest_colliders = function(player_data_coords){ - var colliders = this.find_collisions(player_data_coords); - - colliders.sort(function(a, b) { - /* if colliders are being overlapped by the "C" (center) region, - * we have to set a lower index in the array to which they are placed - * above in the grid. */ - if (a.region === 'C' && b.region === 'C') { - if (a.coords.y1 < b.coords.y1 || a.coords.x1 < b.coords.x1) { - return - 1; - }else{ - return 1; - } - } - - if (a.area < b.area) { - return 1; - } - - return 1; - }); - return colliders; - }; - - - fn.set_colliders = function(colliders) { - if (typeof colliders === 'string' || colliders instanceof $) { - this.$colliders = $(colliders, - this.options.colliders_context).not(this.$element); - }else{ - this.colliders = $(colliders); - } - }; - - - //jQuery adapter - $.fn.collision = function(collider, options) { - return new Collision( this, collider, options ); - }; - - return Collision; - -})); diff --git a/GRID/src/jquery.coords.js b/GRID/src/jquery.coords.js deleted file mode 100644 index 821b67c..0000000 --- a/GRID/src/jquery.coords.js +++ /dev/null @@ -1,125 +0,0 @@ -/* - * jquery.coords - * https://github.com/ducksboard/gridster.js - * - * Copyright (c) 2012 ducksboard - * Licensed under the MIT licenses. - */ - -;(function(root, factory) { - - if (typeof define === 'function' && define.amd) { - define('gridster-coords', ['jquery'], factory); - } else { - root.GridsterCoords = factory(root.$ || root.jQuery); - } - -}(this, function($) { - /** - * Creates objects with coordinates (x1, y1, x2, y2, cx, cy, width, height) - * to simulate DOM elements on the screen. - * Coords is used by Gridster to create a faux grid with any DOM element can - * collide. - * - * @class Coords - * @param {HTMLElement|Object} obj The jQuery HTMLElement or a object with: left, - * top, width and height properties. - * @return {Object} Coords instance. - * @constructor - */ - function Coords(obj) { - if (obj[0] && $.isPlainObject(obj[0])) { - this.data = obj[0]; - }else { - this.el = obj; - } - - this.isCoords = true; - this.coords = {}; - this.init(); - return this; - } - - - var fn = Coords.prototype; - - - fn.init = function(){ - this.set(); - this.original_coords = this.get(); - }; - - - fn.set = function(update, not_update_offsets) { - var el = this.el; - - if (el && !update) { - this.data = el.offset(); - this.data.width = el.width(); - this.data.height = el.height(); - } - - if (el && update && !not_update_offsets) { - var offset = el.offset(); - this.data.top = offset.top; - this.data.left = offset.left; - } - - var d = this.data; - - typeof d.left === 'undefined' && (d.left = d.x1); - typeof d.top === 'undefined' && (d.top = d.y1); - - this.coords.x1 = d.left; - this.coords.y1 = d.top; - this.coords.x2 = d.left + d.width; - this.coords.y2 = d.top + d.height; - this.coords.cx = d.left + (d.width / 2); - this.coords.cy = d.top + (d.height / 2); - this.coords.width = d.width; - this.coords.height = d.height; - this.coords.el = el || false ; - - return this; - }; - - - fn.update = function(data){ - if (!data && !this.el) { - return this; - } - - if (data) { - var new_data = $.extend({}, this.data, data); - this.data = new_data; - return this.set(true, true); - } - - this.set(true); - return this; - }; - - - fn.get = function(){ - return this.coords; - }; - - fn.destroy = function() { - this.el.removeData('coords'); - delete this.el; - }; - - //jQuery adapter - $.fn.coords = function() { - if (this.data('coords') ) { - return this.data('coords'); - } - - var ins = new Coords(this, arguments[0]); - this.data('coords', ins); - return ins; - }; - - return Coords; - -})); diff --git a/GRID/src/jquery.draggable.js b/GRID/src/jquery.draggable.js deleted file mode 100644 index d9b5d98..0000000 --- a/GRID/src/jquery.draggable.js +++ /dev/null @@ -1,432 +0,0 @@ -/* - * jquery.draggable - * https://github.com/ducksboard/gridster.js - * - * Copyright (c) 2012 ducksboard - * Licensed under the MIT licenses. - */ - -;(function(root, factory) { - - if (typeof define === 'function' && define.amd) { - define('gridster-draggable', ['jquery'], factory); - } else { - root.GridsterDraggable = factory(root.$ || root.jQuery); - } - -}(this, function($) { - - var defaults = { - items: 'li', - distance: 1, - limit: true, - offset_left: 0, - autoscroll: true, - ignore_dragging: ['INPUT', 'TEXTAREA', 'SELECT', 'BUTTON'], // or function - handle: null, - container_width: 0, // 0 == auto - move_element: true, - helper: false, // or 'clone' - remove_helper: true - // drag: function(e) {}, - // start : function(e, ui) {}, - // stop : function(e) {} - }; - - var $window = $(window); - var dir_map = { x : 'left', y : 'top' }; - var isTouch = !!('ontouchstart' in window); - - var capitalize = function(str) { - return str.charAt(0).toUpperCase() + str.slice(1); - }; - - var idCounter = 0; - var uniqId = function() { - return ++idCounter + ''; - } - - /** - * Basic drag implementation for DOM elements inside a container. - * Provide start/stop/drag callbacks. - * - * @class Draggable - * @param {HTMLElement} el The HTMLelement that contains all the widgets - * to be dragged. - * @param {Object} [options] An Object with all options you want to - * overwrite: - * @param {HTMLElement|String} [options.items] Define who will - * be the draggable items. Can be a CSS Selector String or a - * collection of HTMLElements. - * @param {Number} [options.distance] Distance in pixels after mousedown - * the mouse must move before dragging should start. - * @param {Boolean} [options.limit] Constrains dragging to the width of - * the container - * @param {Object|Function} [options.ignore_dragging] Array of node names - * that sould not trigger dragging, by default is `['INPUT', 'TEXTAREA', - * 'SELECT', 'BUTTON']`. If a function is used return true to ignore dragging. - * @param {offset_left} [options.offset_left] Offset added to the item - * that is being dragged. - * @param {Number} [options.drag] Executes a callback when the mouse is - * moved during the dragging. - * @param {Number} [options.start] Executes a callback when the drag - * starts. - * @param {Number} [options.stop] Executes a callback when the drag stops. - * @return {Object} Returns `el`. - * @constructor - */ - function Draggable(el, options) { - this.options = $.extend({}, defaults, options); - this.$document = $(document); - this.$container = $(el); - this.$dragitems = $(this.options.items, this.$container); - this.is_dragging = false; - this.player_min_left = 0 + this.options.offset_left; - this.id = uniqId(); - this.ns = '.gridster-draggable-' + this.id; - this.init(); - } - - Draggable.defaults = defaults; - - var fn = Draggable.prototype; - - fn.init = function() { - var pos = this.$container.css('position'); - this.calculate_dimensions(); - this.$container.css('position', pos === 'static' ? 'relative' : pos); - this.disabled = false; - this.events(); - - $(window).bind(this.nsEvent('resize'), - throttle($.proxy(this.calculate_dimensions, this), 200)); - }; - - fn.nsEvent = function(ev) { - return (ev || '') + this.ns; - }; - - fn.events = function() { - this.pointer_events = { - start: this.nsEvent('touchstart') + ' ' + this.nsEvent('mousedown'), - move: this.nsEvent('touchmove') + ' ' + this.nsEvent('mousemove'), - end: this.nsEvent('touchend') + ' ' + this.nsEvent('mouseup'), - }; - - this.$container.on(this.nsEvent('selectstart'), - $.proxy(this.on_select_start, this)); - - this.$container.on(this.pointer_events.start, this.options.items, - $.proxy(this.drag_handler, this)); - - this.$document.on(this.pointer_events.end, $.proxy(function(e) { - this.is_dragging = false; - if (this.disabled) { return; } - this.$document.off(this.pointer_events.move); - if (this.drag_start) { - this.on_dragstop(e); - } - }, this)); - }; - - fn.get_actual_pos = function($el) { - var pos = $el.position(); - return pos; - }; - - - fn.get_mouse_pos = function(e) { - if (e.originalEvent && e.originalEvent.touches) { - var oe = e.originalEvent; - e = oe.touches.length ? oe.touches[0] : oe.changedTouches[0]; - } - - return { - left: e.clientX, - top: e.clientY - }; - }; - - - fn.get_offset = function(e) { - e.preventDefault(); - var mouse_actual_pos = this.get_mouse_pos(e); - var diff_x = Math.round( - mouse_actual_pos.left - this.mouse_init_pos.left); - var diff_y = Math.round(mouse_actual_pos.top - this.mouse_init_pos.top); - - var left = Math.round(this.el_init_offset.left + - diff_x - this.baseX + $(window).scrollLeft() - this.win_offset_x); - var top = Math.round(this.el_init_offset.top + - diff_y - this.baseY + $(window).scrollTop() - this.win_offset_y); - - if (this.options.limit) { - if (left > this.player_max_left) { - left = this.player_max_left; - } else if(left < this.player_min_left) { - left = this.player_min_left; - } - } - - return { - position: { - left: left, - top: top - }, - pointer: { - left: mouse_actual_pos.left, - top: mouse_actual_pos.top, - diff_left: diff_x + ($(window).scrollLeft() - this.win_offset_x), - diff_top: diff_y + ($(window).scrollTop() - this.win_offset_y) - } - }; - }; - - - fn.get_drag_data = function(e) { - var offset = this.get_offset(e); - offset.$player = this.$player; - offset.$helper = this.helper ? this.$helper : this.$player; - - return offset; - }; - - - fn.set_limits = function(container_width) { - container_width || (container_width = this.$container.width()); - this.player_max_left = (container_width - this.player_width + - - this.options.offset_left); - - this.options.container_width = container_width; - - return this; - }; - - - fn.scroll_in = function(axis, data) { - var dir_prop = dir_map[axis]; - - var area_size = 50; - var scroll_inc = 30; - - var is_x = axis === 'x'; - var window_size = is_x ? this.window_width : this.window_height; - var doc_size = is_x ? $(document).width() : $(document).height(); - var player_size = is_x ? this.$player.width() : this.$player.height(); - - var next_scroll; - var scroll_offset = $window['scroll' + capitalize(dir_prop)](); - var min_window_pos = scroll_offset; - var max_window_pos = min_window_pos + window_size; - - var mouse_next_zone = max_window_pos - area_size; // down/right - var mouse_prev_zone = min_window_pos + area_size; // up/left - - var abs_mouse_pos = min_window_pos + data.pointer[dir_prop]; - - var max_player_pos = (doc_size - window_size + player_size); - - if (abs_mouse_pos >= mouse_next_zone) { - next_scroll = scroll_offset + scroll_inc; - if (next_scroll < max_player_pos) { - $window['scroll' + capitalize(dir_prop)](next_scroll); - this['scroll_offset_' + axis] += scroll_inc; - } - } - - if (abs_mouse_pos <= mouse_prev_zone) { - next_scroll = scroll_offset - scroll_inc; - if (next_scroll > 0) { - $window['scroll' + capitalize(dir_prop)](next_scroll); - this['scroll_offset_' + axis] -= scroll_inc; - } - } - - return this; - }; - - - fn.manage_scroll = function(data) { - this.scroll_in('x', data); - this.scroll_in('y', data); - }; - - - fn.calculate_dimensions = function(e) { - this.window_height = $window.height(); - this.window_width = $window.width(); - }; - - - fn.drag_handler = function(e) { - var node = e.target.nodeName; - // skip if drag is disabled, or click was not done with the mouse primary button - if (this.disabled || e.which !== 1 && !isTouch) { - return; - } - - if (this.ignore_drag(e)) { - return; - } - - var self = this; - var first = true; - this.$player = $(e.currentTarget); - - this.el_init_pos = this.get_actual_pos(this.$player); - this.mouse_init_pos = this.get_mouse_pos(e); - this.offsetY = this.mouse_init_pos.top - this.el_init_pos.top; - - this.$document.on(this.pointer_events.move, function(mme) { - var mouse_actual_pos = self.get_mouse_pos(mme); - var diff_x = Math.abs( - mouse_actual_pos.left - self.mouse_init_pos.left); - var diff_y = Math.abs( - mouse_actual_pos.top - self.mouse_init_pos.top); - if (!(diff_x > self.options.distance || - diff_y > self.options.distance) - ) { - return false; - } - - if (first) { - first = false; - self.on_dragstart.call(self, mme); - return false; - } - - if (self.is_dragging === true) { - self.on_dragmove.call(self, mme); - } - - return false; - }); - - if (!isTouch) { return false; } - }; - - - fn.on_dragstart = function(e) { - e.preventDefault(); - - if (this.is_dragging) { return this; } - - this.drag_start = this.is_dragging = true; - var offset = this.$container.offset(); - this.baseX = Math.round(offset.left); - this.baseY = Math.round(offset.top); - this.initial_container_width = this.options.container_width || this.$container.width(); - - if (this.options.helper === 'clone') { - this.$helper = this.$player.clone() - .appendTo(this.$container).addClass('helper'); - this.helper = true; - } else { - this.helper = false; - } - - this.win_offset_y = $(window).scrollTop(); - this.win_offset_x = $(window).scrollLeft(); - this.scroll_offset_y = 0; - this.scroll_offset_x = 0; - this.el_init_offset = this.$player.offset(); - this.player_width = this.$player.width(); - this.player_height = this.$player.height(); - - this.set_limits(this.options.container_width); - - if (this.options.start) { - this.options.start.call(this.$player, e, this.get_drag_data(e)); - } - return false; - }; - - - fn.on_dragmove = function(e) { - var data = this.get_drag_data(e); - - this.options.autoscroll && this.manage_scroll(data); - - if (this.options.move_element) { - (this.helper ? this.$helper : this.$player).css({ - 'position': 'absolute', - 'left' : data.position.left, - 'top' : data.position.top - }); - } - - var last_position = this.last_position || data.position; - data.prev_position = last_position; - - if (this.options.drag) { - this.options.drag.call(this.$player, e, data); - } - - this.last_position = data.position; - return false; - }; - - - fn.on_dragstop = function(e) { - var data = this.get_drag_data(e); - this.drag_start = false; - - if (this.options.stop) { - this.options.stop.call(this.$player, e, data); - } - - if (this.helper && this.options.remove_helper) { - this.$helper.remove(); - } - - return false; - }; - - fn.on_select_start = function(e) { - if (this.disabled) { return; } - - if (this.ignore_drag(e)) { - return; - } - - return false; - }; - - fn.enable = function() { - this.disabled = false; - }; - - fn.disable = function() { - this.disabled = true; - }; - - fn.destroy = function() { - this.disable(); - - this.$container.off(this.ns); - this.$document.off(this.ns); - $(window).off(this.ns); - - $.removeData(this.$container, 'drag'); - }; - - fn.ignore_drag = function(event) { - if (this.options.handle) { - return !$(event.target).is(this.options.handle); - } - - if ($.isFunction(this.options.ignore_dragging)) { - return this.options.ignore_dragging(event); - } - - return $(event.target).is(this.options.ignore_dragging.join(', ')); - }; - - //jQuery adapter - $.fn.drag = function ( options ) { - return new Draggable(this, options); - }; - - return Draggable; - -})); diff --git a/GRID/src/jquery.gridster.css b/GRID/src/jquery.gridster.css deleted file mode 100644 index 52feaab..0000000 --- a/GRID/src/jquery.gridster.css +++ /dev/null @@ -1,117 +0,0 @@ -.gridster { - position:relative; -} - -.gridster > * { - margin: 0 auto; - -webkit-transition: height .4s, width .4s; - -moz-transition: height .4s, width .4s; - -o-transition: height .4s, width .4s; - -ms-transition: height .4s, width .4s; - transition: height .4s, width .4s; -} - -.gridster .gs-w { - z-index: 2; - position: absolute; -} - -.ready .gs-w:not(.preview-holder) { - -webkit-transition: opacity .3s, left .3s, top .3s; - -moz-transition: opacity .3s, left .3s, top .3s; - -o-transition: opacity .3s, left .3s, top .3s; - transition: opacity .3s, left .3s, top .3s; -} - -.ready .gs-w:not(.preview-holder), -.ready .resize-preview-holder { - -webkit-transition: opacity .3s, left .3s, top .3s, width .3s, height .3s; - -moz-transition: opacity .3s, left .3s, top .3s, width .3s, height .3s; - -o-transition: opacity .3s, left .3s, top .3s, width .3s, height .3s; - transition: opacity .3s, left .3s, top .3s, width .3s, height .3s; -} - -.gridster .preview-holder { - z-index: 1; - position: absolute; - background-color: #fff; - border-color: #fff; - opacity: 0.3; -} - -.gridster .player-revert { - z-index: 10!important; - -webkit-transition: left .3s, top .3s!important; - -moz-transition: left .3s, top .3s!important; - -o-transition: left .3s, top .3s!important; - transition: left .3s, top .3s!important; -} - -.gridster .dragging, -.gridster .resizing { - z-index: 10!important; - -webkit-transition: all 0s !important; - -moz-transition: all 0s !important; - -o-transition: all 0s !important; - transition: all 0s !important; -} - - -.gs-resize-handle { - position: absolute; - z-index: 1; -} - -.gs-resize-handle-both { - width: 20px; - height: 20px; - bottom: -8px; - right: -8px; - background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/Pg08IS0tIEdlbmVyYXRvcjogQWRvYmUgRmlyZXdvcmtzIENTNiwgRXhwb3J0IFNWRyBFeHRlbnNpb24gYnkgQWFyb24gQmVhbGwgKGh0dHA6Ly9maXJld29ya3MuYWJlYWxsLmNvbSkgLiBWZXJzaW9uOiAwLjYuMSAgLS0+DTwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+DTxzdmcgaWQ9IlVudGl0bGVkLVBhZ2UlMjAxIiB2aWV3Qm94PSIwIDAgNiA2IiBzdHlsZT0iYmFja2dyb3VuZC1jb2xvcjojZmZmZmZmMDAiIHZlcnNpb249IjEuMSINCXhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHhtbDpzcGFjZT0icHJlc2VydmUiDQl4PSIwcHgiIHk9IjBweCIgd2lkdGg9IjZweCIgaGVpZ2h0PSI2cHgiDT4NCTxnIG9wYWNpdHk9IjAuMzAyIj4NCQk8cGF0aCBkPSJNIDYgNiBMIDAgNiBMIDAgNC4yIEwgNCA0LjIgTCA0LjIgNC4yIEwgNC4yIDAgTCA2IDAgTCA2IDYgTCA2IDYgWiIgZmlsbD0iIzAwMDAwMCIvPg0JPC9nPg08L3N2Zz4='); - background-position: top left; - background-repeat: no-repeat; - cursor: se-resize; - z-index: 20; -} - -.gs-resize-handle-x { - top: 0; - bottom: 13px; - right: -5px; - width: 10px; - cursor: e-resize; -} - -.gs-resize-handle-y { - left: 0; - right: 13px; - bottom: -5px; - height: 10px; - cursor: s-resize; -} - -.gs-w:hover .gs-resize-handle, -.resizing .gs-resize-handle { - opacity: 1; -} - -.gs-resize-handle, -.gs-w.dragging .gs-resize-handle { - opacity: 0; -} - -.gs-resize-disabled .gs-resize-handle { - display: none!important; -} - -[data-max-sizex="1"] .gs-resize-handle-x, -[data-max-sizey="1"] .gs-resize-handle-y, -[data-max-sizey="1"][data-max-sizex="1"] .gs-resize-handle { - display: none !important; -} - -/* Uncomment this if you set helper : "clone" in draggable options */ -/*.gridster .player { - opacity:0; -} -*/ \ No newline at end of file diff --git a/GRID/src/jquery.gridster.extras.js b/GRID/src/jquery.gridster.extras.js deleted file mode 100644 index e7ea59f..0000000 --- a/GRID/src/jquery.gridster.extras.js +++ /dev/null @@ -1,175 +0,0 @@ -;(function(root, factory) { - - if (typeof define === 'function' && define.amd) { - define(['jquery', 'gridster'], factory); - } else { - root.Gridster = factory(root.$ || root.jQuery, root.Gridster); - } - -}(this, function($, Gridster) { - - var fn = Gridster.prototype; - - fn.widgets_in_col = function(col) { - if (!this.gridmap[col]) { - return false; - } - - for (var i = this.gridmap[col].length - 1; i >= 0; i--) { - if (this.is_widget(col, i) !== false) { - return true; - } - } - - return false; - }; - - fn.widgets_in_row = function(row) { - for (var i = this.gridmap.length; i >= 1; i--) { - if (this.is_widget(i, row) !== false) { - return true; - } - } - - return false; - }; - - - fn.widgets_in_range = function(col1, row1, col2, row2) { - var valid_cols = []; - var valid_rows = []; - var $widgets = $([]); - var c, r, $w, wgd; - - for (c = col2; c >= col1; c--) { - for (r = row2; r >= row1; r--) { - $w = this.is_widget(c, r); - - if ($w !== false) { - wgd = $w.data('coords').grid; - if (wgd.col >= col1 && wgd.col <= col2 && - wgd.row >= row1 && wgd.row <= row2 - ) { - $widgets = $widgets.add($w); - } - } - } - } - - return $widgets; - }; - - - fn.get_bottom_most_occupied_cell = function() { - var row = 0; - var col = 0; - this.for_each_cell(function($el, c, r) { - if ($el && r > row) { - row = r; - col = c; - } - }); - - return {col: col, row: row}; - }; - - - fn.get_right_most_occupied_cell = function() { - var row = 0; - var col = 0; - this.for_each_cell(function($el, c, r) { - if ($el) { - row = r; - col = c; - return false; - } - }); - - return {col: col, row: row}; - }; - - - fn.for_each_cell = function(callback, gridmap) { - gridmap || (gridmap = this.gridmap); - var cols = gridmap.length; - var rows = gridmap[1].length; - - cols_iter: - for (var c = cols - 1; c >= 1; c--) { - for (var r = rows - 1; r >= 1; r--) { - var $el = gridmap[c] && gridmap[c][r]; - if (callback) { - if (callback.call(this, $el, c, r) === false) { - break cols_iter; - } else { continue; } - } - } - } - }; - - - fn.next_position_in_range = function(size_x, size_y, max_rows) { - size_x || (size_x = 1); - size_y || (size_y = 1); - var ga = this.gridmap; - var cols_l = ga.length; - var valid_pos = []; - var rows_l; - - for (var c = 1; c < cols_l; c++) { - rows_l = max_rows || ga[c].length; - for (var r = 1; r <= rows_l; r++) { - var can_move_to = this.can_move_to({ - size_x: size_x, - size_y: size_y - }, c, r, max_rows); - - if (can_move_to) { - valid_pos.push({ - col: c, - row: r, - size_y: size_y, - size_x: size_x - }); - } - } - } - - if (valid_pos.length >= 1) { - return Gridster.sort_by_col_asc(valid_pos)[0]; - } - - return false; - }; - - - fn.closest_to_right = function(col, row) { - if (!this.gridmap[col]) { return false; } - var cols_l = this.gridmap.length - 1; - - for (var c = col; c <= cols_l; c++) { - if (this.gridmap[c][row]) { - return { col: c, row: row }; - } - } - - return false; - }; - - - fn.closest_to_left = function(col, row) { - var cols_l = this.gridmap.length - 1; - if (!this.gridmap[col]) { return false; } - - for (var c = col; c >= 1; c--) { - if (this.gridmap[c][row]) { - return { col: c, row: row }; - } - } - - return false; - }; - - return Gridster; - -})); diff --git a/GRID/src/jquery.gridster.js b/GRID/src/jquery.gridster.js deleted file mode 100644 index 7bac911..0000000 --- a/GRID/src/jquery.gridster.js +++ /dev/null @@ -1,3140 +0,0 @@ -/* - * jquery.gridster - * https://github.com/ducksboard/gridster.js - * - * Copyright (c) 2012 ducksboard - * Licensed under the MIT licenses. - */ - -;(function(root, factory) { - - if (typeof define === 'function' && define.amd) { - define(['jquery', 'gridster-draggable', 'gridster-collision'], factory); - } else { - root.Gridster = factory(root.$ || root.jQuery, root.GridsterDraggable, - root.GridsterCollision); - } - - }(this, function($, Draggable, Collision) { - - var defaults = { - namespace: '', - widget_selector: 'li', - widget_margins: [10, 10], - widget_base_dimensions: [400, 225], - extra_rows: 0, - extra_cols: 0, - min_cols: 1, - max_cols: Infinity, - min_rows: 15, - max_size_x: false, - autogrow_cols: false, - autogenerate_stylesheet: true, - avoid_overlapped_widgets: true, - auto_init: true, - serialize_params: function($w, wgd) { - return { - col: wgd.col, - row: wgd.row, - size_x: wgd.size_x, - size_y: wgd.size_y - }; - }, - collision: {}, - draggable: { - items: '.gs-w', - distance: 4, - ignore_dragging: Draggable.defaults.ignore_dragging.slice(0) - }, - resize: { - enabled: false, - axes: ['both'], - handle_append_to: '', - handle_class: 'gs-resize-handle', - max_size: [Infinity, Infinity], - min_size: [1, 1] - } - }; - - /** - * @class Gridster - * @uses Draggable - * @uses Collision - * @param {HTMLElement} el The HTMLelement that contains all the widgets. - * @param {Object} [options] An Object with all options you want to - * overwrite: - * @param {HTMLElement|String} [options.widget_selector] Define who will - * be the draggable widgets. Can be a CSS Selector String or a - * collection of HTMLElements - * @param {Array} [options.widget_margins] Margin between widgets. - * The first index for the horizontal margin (left, right) and - * the second for the vertical margin (top, bottom). - * @param {Array} [options.widget_base_dimensions] Base widget dimensions - * in pixels. The first index for the width and the second for the - * height. - * @param {Number} [options.extra_cols] Add more columns in addition to - * those that have been calculated. - * @param {Number} [options.extra_rows] Add more rows in addition to - * those that have been calculated. - * @param {Number} [options.min_cols] The minimum required columns. - * @param {Number} [options.max_cols] The maximum columns possible (set to null - * for no maximum). - * @param {Number} [options.min_rows] The minimum required rows. - * @param {Number} [options.max_size_x] The maximum number of columns - * that a widget can span. - * @param {Boolean} [options.autogenerate_stylesheet] If true, all the - * CSS required to position all widgets in their respective columns - * and rows will be generated automatically and injected to the - * `` of the document. You can set this to false, and write - * your own CSS targeting rows and cols via data-attributes like so: - * `[data-col="1"] { left: 10px; }` - * @param {Boolean} [options.avoid_overlapped_widgets] Avoid that widgets loaded - * from the DOM can be overlapped. It is helpful if the positions were - * bad stored in the database or if there was any conflict. - * @param {Boolean} [options.auto_init] Automatically call gridster init - * method or not when the plugin is instantiated. - * @param {Function} [options.serialize_params] Return the data you want - * for each widget in the serialization. Two arguments are passed: - * `$w`: the jQuery wrapped HTMLElement, and `wgd`: the grid - * coords object (`col`, `row`, `size_x`, `size_y`). - * @param {Object} [options.collision] An Object with all options for - * Collision class you want to overwrite. See Collision docs for - * more info. - * @param {Object} [options.draggable] An Object with all options for - * Draggable class you want to overwrite. See Draggable docs for more - * info. - * @param {Object|Function} [options.draggable.ignore_dragging] Note that - * if you use a Function, and resize is enabled, you should ignore the - * resize handlers manually (options.resize.handle_class). - * @param {Object} [options.resize] An Object with resize config options. - * @param {Boolean} [options.resize.enabled] Set to true to enable - * resizing. - * @param {Array} [options.resize.axes] Axes in which widgets can be - * resized. Possible values: ['x', 'y', 'both']. - * @param {String} [options.resize.handle_append_to] Set a valid CSS - * selector to append resize handles to. - * @param {String} [options.resize.handle_class] CSS class name used - * by resize handles. - * @param {Array} [options.resize.max_size] Limit widget dimensions - * when resizing. Array values should be integers: - * `[max_cols_occupied, max_rows_occupied]` - * @param {Array} [options.resize.min_size] Limit widget dimensions - * when resizing. Array values should be integers: - * `[min_cols_occupied, min_rows_occupied]` - * @param {Function} [options.resize.start] Function executed - * when resizing starts. - * @param {Function} [otions.resize.resize] Function executed - * during the resizing. - * @param {Function} [options.resize.stop] Function executed - * when resizing stops. - * - * @constructor - */ - function Gridster(el, options) { - this.options = $.extend(true, {}, defaults, options); - this.$el = $(el); - this.$wrapper = this.$el.parent(); - this.$widgets = this.$el.children( - this.options.widget_selector).addClass('gs-w'); - this.widgets = []; - this.$changed = $([]); - this.wrapper_width = this.$wrapper.width(); - this.min_widget_width = (this.options.widget_margins[0] * 2) + - this.options.widget_base_dimensions[0]; - this.min_widget_height = (this.options.widget_margins[1] * 2) + - this.options.widget_base_dimensions[1]; - - this.generated_stylesheets = []; - this.$style_tags = $([]); - - this.options.auto_init && this.init(); - } - - Gridster.defaults = defaults; - Gridster.generated_stylesheets = []; - - - /** - * Sorts an Array of grid coords objects (representing the grid coords of - * each widget) in ascending way. - * - * @method sort_by_row_asc - * @param {Array} widgets Array of grid coords objects - * @return {Array} Returns the array sorted. - */ - Gridster.sort_by_row_asc = function(widgets) { - widgets = widgets.sort(function(a, b) { - if (!a.row) { - a = $(a).coords().grid; - b = $(b).coords().grid; - } - - if (a.row > b.row) { - return 1; - } - return -1; - }); - - return widgets; - }; - - - /** - * Sorts an Array of grid coords objects (representing the grid coords of - * each widget) placing first the empty cells upper left. - * - * @method sort_by_row_and_col_asc - * @param {Array} widgets Array of grid coords objects - * @return {Array} Returns the array sorted. - */ - Gridster.sort_by_row_and_col_asc = function(widgets) { - widgets = widgets.sort(function(a, b) { - if (a.row > b.row || a.row === b.row && a.col > b.col) { - return 1; - } - return -1; - }); - - return widgets; - }; - - - /** - * Sorts an Array of grid coords objects by column (representing the grid - * coords of each widget) in ascending way. - * - * @method sort_by_col_asc - * @param {Array} widgets Array of grid coords objects - * @return {Array} Returns the array sorted. - */ - Gridster.sort_by_col_asc = function(widgets) { - widgets = widgets.sort(function(a, b) { - if (a.col > b.col) { - return 1; - } - return -1; - }); - - return widgets; - }; - - - /** - * Sorts an Array of grid coords objects (representing the grid coords of - * each widget) in descending way. - * - * @method sort_by_row_desc - * @param {Array} widgets Array of grid coords objects - * @return {Array} Returns the array sorted. - */ - Gridster.sort_by_row_desc = function(widgets) { - widgets = widgets.sort(function(a, b) { - if (a.row + a.size_y < b.row + b.size_y) { - return 1; - } - return -1; - }); - return widgets; - }; - - - - /** Instance Methods **/ - - var fn = Gridster.prototype; - - fn.init = function() { - this.options.resize.enabled && this.setup_resize(); - this.generate_grid_and_stylesheet(); - this.get_widgets_from_DOM(); - this.set_dom_grid_height(); - this.set_dom_grid_width(); - this.$wrapper.addClass('ready'); - this.draggable(); - this.options.resize.enabled && this.resizable(); - - $(window).bind('resize.gridster', throttle( - $.proxy(this.recalculate_faux_grid, this), 200)); - }; - - - /** - * Disables dragging. - * - * @method disable - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.disable = function() { - this.$wrapper.find('.player-revert').removeClass('player-revert'); - this.drag_api.disable(); - return this; - }; - - - /** - * Enables dragging. - * - * @method enable - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.enable = function() { - this.drag_api.enable(); - return this; - }; - - - - /** - * Disables drag-and-drop widget resizing. - * - * @method disable - * @return {Class} Returns instance of gridster Class. - */ - fn.disable_resize = function() { - this.$el.addClass('gs-resize-disabled'); - this.resize_api.disable(); - return this; - }; - - - /** - * Enables drag-and-drop widget resizing. - * - * @method enable - * @return {Class} Returns instance of gridster Class. - */ - fn.enable_resize = function() { - this.$el.removeClass('gs-resize-disabled'); - this.resize_api.enable(); - return this; - }; - - - /** - * Add a new widget to the grid. - * - * @method add_widget - * @param {String|HTMLElement} html The string representing the HTML of the widget - * or the HTMLElement. - * @param {Number} [size_x] The nº of rows the widget occupies horizontally. - * @param {Number} [size_y] The nº of columns the widget occupies vertically. - * @param {Number} [col] The column the widget should start in. - * @param {Number} [row] The row the widget should start in. - * @param {Array} [max_size] max_size Maximun size (in units) for width and height. - * @param {Array} [min_size] min_size Minimum size (in units) for width and height. - * @return {HTMLElement} Returns the jQuery wrapped HTMLElement representing. - * the widget that was just created. - */ - fn.add_widget = function(html, size_x, size_y, col, row, max_size, min_size) { - var pos; - size_x || (size_x = 1); - size_y || (size_y = 1); - - if (!col & !row) { - pos = this.next_position(size_x, size_y); - } else { - pos = { - col: col, - row: row, - size_x: size_x, - size_y: size_y - }; - - this.empty_cells(col, row, size_x, size_y); - } - - var $w = $(html).attr({ - 'data-col': pos.col, - 'data-row': pos.row, - 'data-sizex' : size_x, - 'data-sizey' : size_y - }).addClass('gs-w').appendTo(this.$el).hide(); - - this.$widgets = this.$widgets.add($w); - - this.register_widget($w); - - this.add_faux_rows(pos.size_y); - //this.add_faux_cols(pos.size_x); - - if (max_size) { - this.set_widget_max_size($w, max_size); - } - - if (min_size) { - this.set_widget_min_size($w, min_size); - } - - this.set_dom_grid_width(); - this.set_dom_grid_height(); - - this.drag_api.set_limits(this.cols * this.min_widget_width); - - return $w.fadeIn(); - }; - - - /** - * Change widget size limits. - * - * @method set_widget_min_size - * @param {HTMLElement|Number} $widget The jQuery wrapped HTMLElement - * representing the widget or an index representing the desired widget. - * @param {Array} min_size Minimum size (in units) for width and height. - * @return {HTMLElement} Returns instance of gridster Class. - */ - fn.set_widget_min_size = function($widget, min_size) { - $widget = typeof $widget === 'number' ? - this.$widgets.eq($widget) : $widget; - - if (!$widget.length) { return this; } - - var wgd = $widget.data('coords').grid; - wgd.min_size_x = min_size[0]; - wgd.min_size_y = min_size[1]; - - return this; - }; - - - /** - * Change widget size limits. - * - * @method set_widget_max_size - * @param {HTMLElement|Number} $widget The jQuery wrapped HTMLElement - * representing the widget or an index representing the desired widget. - * @param {Array} max_size Maximun size (in units) for width and height. - * @return {HTMLElement} Returns instance of gridster Class. - */ - fn.set_widget_max_size = function($widget, max_size) { - $widget = typeof $widget === 'number' ? - this.$widgets.eq($widget) : $widget; - - if (!$widget.length) { return this; } - - var wgd = $widget.data('coords').grid; - wgd.max_size_x = max_size[0]; - wgd.max_size_y = max_size[1]; - - return this; - }; - - - /** - * Append the resize handle into a widget. - * - * @method add_resize_handle - * @param {HTMLElement} $widget The jQuery wrapped HTMLElement - * representing the widget. - * @return {HTMLElement} Returns instance of gridster Class. - */ - fn.add_resize_handle = function($w) { - var append_to = this.options.resize.handle_append_to; - $(this.resize_handle_tpl).appendTo( append_to ? $(append_to, $w) : $w); - - return this; - }; - - - /** - * Change the size of a widget. Width is limited to the current grid width. - * - * @method resize_widget - * @param {HTMLElement} $widget The jQuery wrapped HTMLElement - * representing the widget. - * @param {Number} size_x The number of columns that will occupy the widget. - * By default size_x is limited to the space available from - * the column where the widget begins, until the last column to the right. - * @param {Number} size_y The number of rows that will occupy the widget. - * @param {Function} [callback] Function executed when the widget is removed. - * @return {HTMLElement} Returns $widget. - */ - fn.resize_widget = function($widget, size_x, size_y, callback) { - var wgd = $widget.coords().grid; - var col = wgd.col; - var max_cols = this.options.max_cols; - var old_size_y = wgd.size_y; - var old_col = wgd.col; - var new_col = old_col; - - size_x || (size_x = wgd.size_x); - size_y || (size_y = wgd.size_y); - - if (max_cols !== Infinity) { - size_x = Math.min(size_x, max_cols - col + 1); - } - - if (size_y > old_size_y) { - this.add_faux_rows(Math.max(size_y - old_size_y, 0)); - } - - var player_rcol = (col + size_x - 1); - if (player_rcol > this.cols) { - this.add_faux_cols(player_rcol - this.cols); - } - - var new_grid_data = { - col: new_col, - row: wgd.row, - size_x: size_x, - size_y: size_y - }; - - this.mutate_widget_in_gridmap($widget, wgd, new_grid_data); - - this.set_dom_grid_height(); - this.set_dom_grid_width(); - - if (callback) { - callback.call(this, new_grid_data.size_x, new_grid_data.size_y); - } - - return $widget; - }; - - - /** - * Mutate widget dimensions and position in the grid map. - * - * @method mutate_widget_in_gridmap - * @param {HTMLElement} $widget The jQuery wrapped HTMLElement - * representing the widget to mutate. - * @param {Object} wgd Current widget grid data (col, row, size_x, size_y). - * @param {Object} new_wgd New widget grid data. - * @return {HTMLElement} Returns instance of gridster Class. - */ - fn.mutate_widget_in_gridmap = function($widget, wgd, new_wgd) { - var old_size_x = wgd.size_x; - var old_size_y = wgd.size_y; - - var old_cells_occupied = this.get_cells_occupied(wgd); - var new_cells_occupied = this.get_cells_occupied(new_wgd); - - var empty_cols = []; - $.each(old_cells_occupied.cols, function(i, col) { - if ($.inArray(col, new_cells_occupied.cols) === -1) { - empty_cols.push(col); - } - }); - - var occupied_cols = []; - $.each(new_cells_occupied.cols, function(i, col) { - if ($.inArray(col, old_cells_occupied.cols) === -1) { - occupied_cols.push(col); - } - }); - - var empty_rows = []; - $.each(old_cells_occupied.rows, function(i, row) { - if ($.inArray(row, new_cells_occupied.rows) === -1) { - empty_rows.push(row); - } - }); - - var occupied_rows = []; - $.each(new_cells_occupied.rows, function(i, row) { - if ($.inArray(row, old_cells_occupied.rows) === -1) { - occupied_rows.push(row); - } - }); - - this.remove_from_gridmap(wgd); - - if (occupied_cols.length) { - var cols_to_empty = [ - new_wgd.col, new_wgd.row, new_wgd.size_x, Math.min(old_size_y, new_wgd.size_y), $widget - ]; - this.empty_cells.apply(this, cols_to_empty); - } - - if (occupied_rows.length) { - var rows_to_empty = [new_wgd.col, new_wgd.row, new_wgd.size_x, new_wgd.size_y, $widget]; - this.empty_cells.apply(this, rows_to_empty); - } - - // not the same that wgd = new_wgd; - wgd.col = new_wgd.col; - wgd.row = new_wgd.row; - wgd.size_x = new_wgd.size_x; - wgd.size_y = new_wgd.size_y; - - this.add_to_gridmap(new_wgd, $widget); - - $widget.removeClass('player-revert'); - - //update coords instance attributes - $widget.data('coords').update({ - width: (new_wgd.size_x * this.options.widget_base_dimensions[0] + - ((new_wgd.size_x - 1) * this.options.widget_margins[0]) * 2), - height: (new_wgd.size_y * this.options.widget_base_dimensions[1] + - ((new_wgd.size_y - 1) * this.options.widget_margins[1]) * 2) - }); - - $widget.attr({ - 'data-col': new_wgd.col, - 'data-row': new_wgd.row, - 'data-sizex': new_wgd.size_x, - 'data-sizey': new_wgd.size_y - }); - - if (empty_cols.length) { - var cols_to_remove_holes = [ - empty_cols[0], new_wgd.row, - empty_cols.length, - Math.min(old_size_y, new_wgd.size_y), - $widget - ]; - - this.remove_empty_cells.apply(this, cols_to_remove_holes); - } - - if (empty_rows.length) { - var rows_to_remove_holes = [ - new_wgd.col, new_wgd.row, new_wgd.size_x, new_wgd.size_y, $widget - ]; - this.remove_empty_cells.apply(this, rows_to_remove_holes); - } - - this.move_widget_up($widget); - - return this; - }; - - - /** - * Move down widgets in cells represented by the arguments col, row, size_x, - * size_y - * - * @method empty_cells - * @param {Number} col The column where the group of cells begin. - * @param {Number} row The row where the group of cells begin. - * @param {Number} size_x The number of columns that the group of cells - * occupy. - * @param {Number} size_y The number of rows that the group of cells - * occupy. - * @param {HTMLElement} $exclude Exclude widgets from being moved. - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.empty_cells = function(col, row, size_x, size_y, $exclude) { - var $nexts = this.widgets_below({ - col: col, - row: row - size_y, - size_x: size_x, - size_y: size_y - }); - - $nexts.not($exclude).each($.proxy(function(i, w) { - var wgd = $(w).coords().grid; - if ( !(wgd.row <= (row + size_y - 1))) { return; } - var diff = (row + size_y) - wgd.row; - this.move_widget_down($(w), diff); - }, this)); - - this.set_dom_grid_height(); - - return this; - }; - - - /** - * Move up widgets below cells represented by the arguments col, row, size_x, - * size_y. - * - * @method remove_empty_cells - * @param {Number} col The column where the group of cells begin. - * @param {Number} row The row where the group of cells begin. - * @param {Number} size_x The number of columns that the group of cells - * occupy. - * @param {Number} size_y The number of rows that the group of cells - * occupy. - * @param {HTMLElement} exclude Exclude widgets from being moved. - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.remove_empty_cells = function(col, row, size_x, size_y, exclude) { - var $nexts = this.widgets_below({ - col: col, - row: row, - size_x: size_x, - size_y: size_y - }); - - $nexts.not(exclude).each($.proxy(function(i, widget) { - this.move_widget_up( $(widget), size_y ); - }, this)); - - this.set_dom_grid_height(); - - return this; - }; - - - /** - * Get the most left column below to add a new widget. - * - * @method next_position - * @param {Number} size_x The nº of rows the widget occupies horizontally. - * @param {Number} size_y The nº of columns the widget occupies vertically. - * @return {Object} Returns a grid coords object representing the future - * widget coords. - */ - fn.next_position = function(size_x, size_y) { - size_x || (size_x = 1); - size_y || (size_y = 1); - var ga = this.gridmap; - var cols_l = ga.length; - var valid_pos = []; - var rows_l; - - for (var c = 1; c < cols_l; c++) { - rows_l = ga[c].length; - for (var r = 1; r <= rows_l; r++) { - var can_move_to = this.can_move_to({ - size_x: size_x, - size_y: size_y - }, c, r); - - if (can_move_to) { - valid_pos.push({ - col: c, - row: r, - size_y: size_y, - size_x: size_x - }); - } - } - } - - if (valid_pos.length) { - return Gridster.sort_by_row_and_col_asc(valid_pos)[0]; - } - return false; - }; - - - /** - * Remove a widget from the grid. - * - * @method remove_widget - * @param {HTMLElement} el The jQuery wrapped HTMLElement you want to remove. - * @param {Boolean|Function} silent If true, widgets below the removed one - * will not move up. If a Function is passed it will be used as callback. - * @param {Function} callback Function executed when the widget is removed. - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.remove_widget = function(el, silent, callback) { - var $el = el instanceof $ ? el : $(el); - var wgd = $el.coords().grid; - - // if silent is a function assume it's a callback - if ($.isFunction(silent)) { - callback = silent; - silent = false; - } - - this.cells_occupied_by_placeholder = {}; - this.$widgets = this.$widgets.not($el); - - var $nexts = this.widgets_below($el); - - this.remove_from_gridmap(wgd); - - $el.fadeOut($.proxy(function() { - $el.remove(); - - if (!silent) { - $nexts.each($.proxy(function(i, widget) { - this.move_widget_up( $(widget), wgd.size_y ); - }, this)); - } - - this.set_dom_grid_height(); - - if (callback) { - callback.call(this, el); - } - }, this)); - - return this; - }; - - - /** - * Remove all widgets from the grid. - * - * @method remove_all_widgets - * @param {Function} callback Function executed for each widget removed. - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.remove_all_widgets = function(callback) { - this.$widgets.each($.proxy(function(i, el){ - this.remove_widget(el, true, callback); - }, this)); - - return this; - }; - - - /** - * Returns a serialized array of the widgets in the grid. - * - * @method serialize - * @param {HTMLElement} [$widgets] The collection of jQuery wrapped - * HTMLElements you want to serialize. If no argument is passed all widgets - * will be serialized. - * @return {Array} Returns an Array of Objects with the data specified in - * the serialize_params option. - */ - fn.serialize = function($widgets) { - $widgets || ($widgets = this.$widgets); - - return $widgets.map($.proxy(function(i, widget) { - var $w = $(widget); - return this.options.serialize_params($w, $w.coords().grid); - }, this)).get(); - }; - - - /** - * Returns a serialized array of the widgets that have changed their - * position. - * - * @method serialize_changed - * @return {Array} Returns an Array of Objects with the data specified in - * the serialize_params option. - */ - fn.serialize_changed = function() { - return this.serialize(this.$changed); - }; - - - /** - * Convert widgets from DOM elements to "widget grid data" Objects. - * - * @method dom_to_coords - * @param {HTMLElement} $widget The widget to be converted. - */ - fn.dom_to_coords = function($widget) { - return { - 'col': parseInt($widget.attr('data-col'), 10), - 'row': parseInt($widget.attr('data-row'), 10), - 'size_x': parseInt($widget.attr('data-sizex'), 10) || 1, - 'size_y': parseInt($widget.attr('data-sizey'), 10) || 1, - 'max_size_x': parseInt($widget.attr('data-max-sizex'), 10) || false, - 'max_size_y': parseInt($widget.attr('data-max-sizey'), 10) || false, - 'min_size_x': parseInt($widget.attr('data-min-sizex'), 10) || false, - 'min_size_y': parseInt($widget.attr('data-min-sizey'), 10) || false, - 'el': $widget - }; - }; - - - /** - * Creates the grid coords object representing the widget an add it to the - * mapped array of positions. - * - * @method register_widget - * @param {HTMLElement|Object} $el jQuery wrapped HTMLElement representing - * the widget, or an "widget grid data" Object with (col, row, el ...). - * @return {Boolean} Returns true if the widget final position is different - * than the original. - */ - fn.register_widget = function($el) { - var isDOM = $el instanceof jQuery; - var wgd = isDOM ? this.dom_to_coords($el) : $el; - var posChanged = false; - isDOM || ($el = wgd.el); - - var empty_upper_row = this.can_go_widget_up(wgd); - if (empty_upper_row) { - wgd.row = empty_upper_row; - $el.attr('data-row', empty_upper_row); - this.$el.trigger('gridster:positionchanged', [wgd]); - posChanged = true; - } - - if (this.options.avoid_overlapped_widgets && - !this.can_move_to( - {size_x: wgd.size_x, size_y: wgd.size_y}, wgd.col, wgd.row) - ) { - $.extend(wgd, this.next_position(wgd.size_x, wgd.size_y)); - $el.attr({ - 'data-col': wgd.col, - 'data-row': wgd.row, - 'data-sizex': wgd.size_x, - 'data-sizey': wgd.size_y - }); - posChanged = true; - } - - // attach Coord object to player data-coord attribute - $el.data('coords', $el.coords()); - // Extend Coord object with grid position info - $el.data('coords').grid = wgd; - - this.add_to_gridmap(wgd, $el); - - this.options.resize.enabled && this.add_resize_handle($el); - - return posChanged; - }; - - - /** - * Update in the mapped array of positions the value of cells represented by - * the grid coords object passed in the `grid_data` param. - * - * @param {Object} grid_data The grid coords object representing the cells - * to update in the mapped array. - * @param {HTMLElement|Boolean} value Pass `false` or the jQuery wrapped - * HTMLElement, depends if you want to delete an existing position or add - * a new one. - * @method update_widget_position - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.update_widget_position = function(grid_data, value) { - this.for_each_cell_occupied(grid_data, function(col, row) { - if (!this.gridmap[col]) { return this; } - this.gridmap[col][row] = value; - }); - return this; - }; - - - /** - * Remove a widget from the mapped array of positions. - * - * @method remove_from_gridmap - * @param {Object} grid_data The grid coords object representing the cells - * to update in the mapped array. - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.remove_from_gridmap = function(grid_data) { - return this.update_widget_position(grid_data, false); - }; - - - /** - * Add a widget to the mapped array of positions. - * - * @method add_to_gridmap - * @param {Object} grid_data The grid coords object representing the cells - * to update in the mapped array. - * @param {HTMLElement|Boolean} value The value to set in the specified - * position . - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.add_to_gridmap = function(grid_data, value) { - this.update_widget_position(grid_data, value || grid_data.el); - - if (grid_data.el) { - var $widgets = this.widgets_below(grid_data.el); - $widgets.each($.proxy(function(i, widget) { - this.move_widget_up( $(widget)); - }, this)); - } - }; - - - /** - * Make widgets draggable. - * - * @uses Draggable - * @method draggable - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.draggable = function() { - var self = this; - var draggable_options = $.extend(true, {}, this.options.draggable, { - offset_left: this.options.widget_margins[0], - offset_top: this.options.widget_margins[1], - container_width: this.cols * this.min_widget_width, - limit: true, - start: function(event, ui) { - self.$widgets.filter('.player-revert') - .removeClass('player-revert'); - - self.$player = $(this); - self.$helper = $(ui.$helper); - - self.helper = !self.$helper.is(self.$player); - - self.on_start_drag.call(self, event, ui); - self.$el.trigger('gridster:dragstart'); - }, - stop: function(event, ui) { - self.on_stop_drag.call(self, event, ui); - self.$el.trigger('gridster:dragstop'); - }, - drag: throttle(function(event, ui) { - self.on_drag.call(self, event, ui); - self.$el.trigger('gridster:drag'); - }, 60) - }); - - this.drag_api = this.$el.drag(draggable_options); - return this; - }; - - - /** - * Bind resize events to get resize working. - * - * @method resizable - * @return {Class} Returns instance of gridster Class. - */ - fn.resizable = function() { - this.resize_api = this.$el.drag({ - items: '.' + this.options.resize.handle_class, - offset_left: this.options.widget_margins[0], - container_width: this.container_width, - move_element: false, - resize: true, - limit: this.options.autogrow_cols ? false : true, - start: $.proxy(this.on_start_resize, this), - stop: $.proxy(function(event, ui) { - delay($.proxy(function() { - this.on_stop_resize(event, ui); - }, this), 120); - }, this), - drag: throttle($.proxy(this.on_resize, this), 60) - }); - - return this; - }; - - - /** - * Setup things required for resizing. Like build templates for drag handles. - * - * @method setup_resize - * @return {Class} Returns instance of gridster Class. - */ - fn.setup_resize = function() { - this.resize_handle_class = this.options.resize.handle_class; - var axes = this.options.resize.axes; - var handle_tpl = ''; - - this.resize_handle_tpl = $.map(axes, function(type) { - return handle_tpl.replace('{type}', type); - }).join(''); - - if ($.isArray(this.options.draggable.ignore_dragging)) { - this.options.draggable.ignore_dragging.push( - '.' + this.resize_handle_class); - } - - return this; - }; - - - /** - * This function is executed when the player begins to be dragged. - * - * @method on_start_drag - * @param {Event} event The original browser event - * @param {Object} ui A prepared ui object with useful drag-related data - */ - fn.on_start_drag = function(event, ui) { - this.$helper.add(this.$player).add(this.$wrapper).addClass('dragging'); - - this.highest_col = this.get_highest_occupied_cell().col; - - this.$player.addClass('player'); - this.player_grid_data = this.$player.coords().grid; - this.placeholder_grid_data = $.extend({}, this.player_grid_data); - - this.set_dom_grid_height(this.$el.height() + - (this.player_grid_data.size_y * this.min_widget_height)); - - this.set_dom_grid_width(this.cols); - - var pgd_sizex = this.player_grid_data.size_x; - var cols_diff = this.cols - this.highest_col; - - if (this.options.autogrow_cols && cols_diff <= pgd_sizex) { - this.add_faux_cols(Math.min(pgd_sizex - cols_diff, 1)); - } - - var colliders = this.faux_grid; - var coords = this.$player.data('coords').coords; - - this.cells_occupied_by_player = this.get_cells_occupied( - this.player_grid_data); - this.cells_occupied_by_placeholder = this.get_cells_occupied( - this.placeholder_grid_data); - - this.last_cols = []; - this.last_rows = []; - - // see jquery.collision.js - this.collision_api = this.$helper.collision( - colliders, this.options.collision); - - this.$preview_holder = $('<' + this.$player.get(0).tagName + ' />', { - 'class': 'preview-holder', - 'data-row': this.$player.attr('data-row'), - 'data-col': this.$player.attr('data-col'), - css: { - width: coords.width, - height: coords.height - } - }).appendTo(this.$el); - - if (this.options.draggable.start) { - this.options.draggable.start.call(this, event, ui); - } - }; - - - /** - * This function is executed when the player is being dragged. - * - * @method on_drag - * @param {Event} event The original browser event - * @param {Object} ui A prepared ui object with useful drag-related data - */ - fn.on_drag = function(event, ui) { - //break if dragstop has been fired - if (this.$player === null) { - return false; - } - - var abs_offset = { - left: ui.position.left + this.baseX, - top: ui.position.top + this.baseY - }; - - // auto grow cols - if (this.options.autogrow_cols) { - var prcol = this.placeholder_grid_data.col + - this.placeholder_grid_data.size_x - 1; - - // "- 1" due to adding at least 1 column in on_start_drag - if (prcol >= this.cols - 1 && this.options.max_cols >= this.cols + 1) { - this.add_faux_cols(1); - this.set_dom_grid_width(this.cols + 1); - this.drag_api.set_limits(this.container_width); - } - - this.collision_api.set_colliders(this.faux_grid); - } - - this.colliders_data = this.collision_api.get_closest_colliders( - abs_offset); - - this.on_overlapped_column_change( - this.on_start_overlapping_column, this.on_stop_overlapping_column); - - this.on_overlapped_row_change( - this.on_start_overlapping_row, this.on_stop_overlapping_row); - - - if (this.helper && this.$player) { - this.$player.css({ - 'left': ui.position.left, - 'top': ui.position.top - }); - } - - if (this.options.draggable.drag) { - this.options.draggable.drag.call(this, event, ui); - } - }; - - - /** - * This function is executed when the player stops being dragged. - * - * @method on_stop_drag - * @param {Event} event The original browser event - * @param {Object} ui A prepared ui object with useful drag-related data - */ - fn.on_stop_drag = function(event, ui) { - this.$helper.add(this.$player).add(this.$wrapper) - .removeClass('dragging'); - - ui.position.left = ui.position.left + this.baseX; - ui.position.top = ui.position.top + this.baseY; - this.colliders_data = this.collision_api.get_closest_colliders( - ui.position); - - this.on_overlapped_column_change( - this.on_start_overlapping_column, - this.on_stop_overlapping_column - ); - - this.on_overlapped_row_change( - this.on_start_overlapping_row, - this.on_stop_overlapping_row - ); - - this.$player.addClass('player-revert').removeClass('player') - .attr({ - 'data-col': this.placeholder_grid_data.col, - 'data-row': this.placeholder_grid_data.row - }).css({ - 'left': '', - 'top': '' - }); - - this.$changed = this.$changed.add(this.$player); - - this.cells_occupied_by_player = this.get_cells_occupied( - this.placeholder_grid_data); - this.set_cells_player_occupies( - this.placeholder_grid_data.col, this.placeholder_grid_data.row); - - this.$player.coords().grid.row = this.placeholder_grid_data.row; - this.$player.coords().grid.col = this.placeholder_grid_data.col; - - if (this.options.draggable.stop) { - this.options.draggable.stop.call(this, event, ui); - } - - this.$preview_holder.remove(); - - this.$player = null; - this.$helper = null; - this.placeholder_grid_data = {}; - this.player_grid_data = {}; - this.cells_occupied_by_placeholder = {}; - this.cells_occupied_by_player = {}; - - this.set_dom_grid_height(); - this.set_dom_grid_width(); - - if (this.options.autogrow_cols) { - this.drag_api.set_limits(this.cols * this.min_widget_width); - } - }; - - - /** - * This function is executed every time a widget starts to be resized. - * - * @method on_start_resize - * @param {Event} event The original browser event - * @param {Object} ui A prepared ui object with useful drag-related data - */ - fn.on_start_resize = function(event, ui) { - this.$resized_widget = ui.$player.closest('.gs-w'); - this.resize_coords = this.$resized_widget.coords(); - this.resize_wgd = this.resize_coords.grid; - this.resize_initial_width = this.resize_coords.coords.width; - this.resize_initial_height = this.resize_coords.coords.height; - this.resize_initial_sizex = this.resize_coords.grid.size_x; - this.resize_initial_sizey = this.resize_coords.grid.size_y; - this.resize_initial_col = this.resize_coords.grid.col; - this.resize_last_sizex = this.resize_initial_sizex; - this.resize_last_sizey = this.resize_initial_sizey; - - this.resize_max_size_x = Math.min(this.resize_wgd.max_size_x || - this.options.resize.max_size[0], - this.options.max_cols - this.resize_initial_col + 1); - this.resize_max_size_y = this.resize_wgd.max_size_y || - this.options.resize.max_size[1]; - - this.resize_min_size_x = (this.resize_wgd.min_size_x || - this.options.resize.min_size[0] || 1); - this.resize_min_size_y = (this.resize_wgd.min_size_y || - this.options.resize.min_size[1] || 1); - - this.resize_initial_last_col = this.get_highest_occupied_cell().col; - - this.set_dom_grid_width(this.cols); - - this.resize_dir = { - right: ui.$player.is('.' + this.resize_handle_class + '-x'), - bottom: ui.$player.is('.' + this.resize_handle_class + '-y') - }; - - this.$resized_widget.css({ - 'min-width': this.options.widget_base_dimensions[0], - 'min-height': this.options.widget_base_dimensions[1] - }); - - var nodeName = this.$resized_widget.get(0).tagName; - this.$resize_preview_holder = $('<' + nodeName + ' />', { - 'class': 'preview-holder resize-preview-holder', - 'data-row': this.$resized_widget.attr('data-row'), - 'data-col': this.$resized_widget.attr('data-col'), - 'css': { - 'width': this.resize_initial_width, - 'height': this.resize_initial_height - } - }).appendTo(this.$el); - - this.$resized_widget.addClass('resizing'); - - if (this.options.resize.start) { - this.options.resize.start.call(this, event, ui, this.$resized_widget); - } - - this.$el.trigger('gridster:resizestart'); - }; - - - /** - * This function is executed every time a widget stops being resized. - * - * @method on_stop_resize - * @param {Event} event The original browser event - * @param {Object} ui A prepared ui object with useful drag-related data - */ - fn.on_stop_resize = function(event, ui) { - this.$resized_widget - .removeClass('resizing') - .css({ - 'width': '', - 'height': '' - }); - - delay($.proxy(function() { - this.$resize_preview_holder - .remove() - .css({ - 'min-width': '', - 'min-height': '' - }); - - if (this.options.resize.stop) { - this.options.resize.stop.call(this, event, ui, this.$resized_widget); - } - - this.$el.trigger('gridster:resizestop'); - }, this), 300); - - this.set_dom_grid_width(); - - if (this.options.autogrow_cols) { - this.drag_api.set_limits(this.cols * this.min_widget_width); - } - }; - - - /** - * This function is executed when a widget is being resized. - * - * @method on_resize - * @param {Event} event The original browser event - * @param {Object} ui A prepared ui object with useful drag-related data - */ - fn.on_resize = function(event, ui) { - var rel_x = (ui.pointer.diff_left); - var rel_y = (ui.pointer.diff_top); - var wbd_x = this.options.widget_base_dimensions[0]; - var wbd_y = this.options.widget_base_dimensions[1]; - var margin_x = this.options.widget_margins[0]; - var margin_y = this.options.widget_margins[1]; - var max_size_x = this.resize_max_size_x; - var min_size_x = this.resize_min_size_x; - var max_size_y = this.resize_max_size_y; - var min_size_y = this.resize_min_size_y; - var autogrow = this.options.autogrow_cols; - var width; - var max_width = Infinity; - var max_height = Infinity; - - var inc_units_x = Math.ceil((rel_x / (wbd_x + margin_x * 2)) - 0.2); - var inc_units_y = Math.ceil((rel_y / (wbd_y + margin_y * 2)) - 0.2); - - var size_x = Math.max(1, this.resize_initial_sizex + inc_units_x); - var size_y = Math.max(1, this.resize_initial_sizey + inc_units_y); - - var max_cols = (this.container_width / this.min_widget_width) - - this.resize_initial_col + 1; - var limit_width = ((max_cols * this.min_widget_width) - margin_x * 2); - - size_x = Math.max(Math.min(size_x, max_size_x), min_size_x); - size_x = Math.min(max_cols, size_x); - width = (max_size_x * wbd_x) + ((size_x - 1) * margin_x * 2); - max_width = Math.min(width, limit_width); - min_width = (min_size_x * wbd_x) + ((size_x - 1) * margin_x * 2); - - size_y = Math.max(Math.min(size_y, max_size_y), min_size_y); - max_height = (max_size_y * wbd_y) + ((size_y - 1) * margin_y * 2); - min_height = (min_size_y * wbd_y) + ((size_y - 1) * margin_y * 2); - - if (this.resize_dir.right) { - size_y = this.resize_initial_sizey; - } else if (this.resize_dir.bottom) { - size_x = this.resize_initial_sizex; - } - - if (autogrow) { - var last_widget_col = this.resize_initial_col + size_x - 1; - if (autogrow && this.resize_initial_last_col <= last_widget_col) { - this.set_dom_grid_width(Math.max(last_widget_col + 1, this.cols)); - - if (this.cols < last_widget_col) { - this.add_faux_cols(last_widget_col - this.cols); - } - } - } - - var css_props = {}; - !this.resize_dir.bottom && (css_props.width = Math.max(Math.min( - this.resize_initial_width + rel_x, max_width), min_width)); - !this.resize_dir.right && (css_props.height = Math.max(Math.min( - this.resize_initial_height + rel_y, max_height), min_height)); - - this.$resized_widget.css(css_props); - - if (size_x !== this.resize_last_sizex || - size_y !== this.resize_last_sizey) { - - this.resize_widget(this.$resized_widget, size_x, size_y); - this.set_dom_grid_width(this.cols); - - this.$resize_preview_holder.css({ - 'width': '', - 'height': '' - }).attr({ - 'data-row': this.$resized_widget.attr('data-row'), - 'data-sizex': size_x, - 'data-sizey': size_y - }); - } - - if (this.options.resize.resize) { - this.options.resize.resize.call(this, event, ui, this.$resized_widget); - } - - this.$el.trigger('gridster:resize'); - - this.resize_last_sizex = size_x; - this.resize_last_sizey = size_y; - }; - - - /** - * Executes the callbacks passed as arguments when a column begins to be - * overlapped or stops being overlapped. - * - * @param {Function} start_callback Function executed when a new column - * begins to be overlapped. The column is passed as first argument. - * @param {Function} stop_callback Function executed when a column stops - * being overlapped. The column is passed as first argument. - * @method on_overlapped_column_change - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.on_overlapped_column_change = function(start_callback, stop_callback) { - if (!this.colliders_data.length) { - return this; - } - var cols = this.get_targeted_columns( - this.colliders_data[0].el.data.col); - - var last_n_cols = this.last_cols.length; - var n_cols = cols.length; - var i; - - for (i = 0; i < n_cols; i++) { - if ($.inArray(cols[i], this.last_cols) === -1) { - (start_callback || $.noop).call(this, cols[i]); - } - } - - for (i = 0; i< last_n_cols; i++) { - if ($.inArray(this.last_cols[i], cols) === -1) { - (stop_callback || $.noop).call(this, this.last_cols[i]); - } - } - - this.last_cols = cols; - - return this; - }; - - - /** - * Executes the callbacks passed as arguments when a row starts to be - * overlapped or stops being overlapped. - * - * @param {Function} start_callback Function executed when a new row begins - * to be overlapped. The row is passed as first argument. - * @param {Function} end_callback Function executed when a row stops being - * overlapped. The row is passed as first argument. - * @method on_overlapped_row_change - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.on_overlapped_row_change = function(start_callback, end_callback) { - if (!this.colliders_data.length) { - return this; - } - var rows = this.get_targeted_rows(this.colliders_data[0].el.data.row); - var last_n_rows = this.last_rows.length; - var n_rows = rows.length; - var i; - - for (i = 0; i < n_rows; i++) { - if ($.inArray(rows[i], this.last_rows) === -1) { - (start_callback || $.noop).call(this, rows[i]); - } - } - - for (i = 0; i < last_n_rows; i++) { - if ($.inArray(this.last_rows[i], rows) === -1) { - (end_callback || $.noop).call(this, this.last_rows[i]); - } - } - - this.last_rows = rows; - }; - - - /** - * Sets the current position of the player - * - * @param {Number} col - * @param {Number} row - * @param {Boolean} no_player - * @method set_player - * @return {object} - */ - fn.set_player = function(col, row, no_player) { - var self = this; - if (!no_player) { - this.empty_cells_player_occupies(); - } - var cell = !no_player ? self.colliders_data[0].el.data : {col: col}; - var to_col = cell.col; - var to_row = row || cell.row; - - this.player_grid_data = { - col: to_col, - row: to_row, - size_y : this.player_grid_data.size_y, - size_x : this.player_grid_data.size_x - }; - - this.cells_occupied_by_player = this.get_cells_occupied( - this.player_grid_data); - - var $overlapped_widgets = this.get_widgets_overlapped( - this.player_grid_data); - - var constraints = this.widgets_constraints($overlapped_widgets); - - this.manage_movements(constraints.can_go_up, to_col, to_row); - this.manage_movements(constraints.can_not_go_up, to_col, to_row); - - /* if there is not widgets overlapping in the new player position, - * update the new placeholder position. */ - if (!$overlapped_widgets.length) { - var pp = this.can_go_player_up(this.player_grid_data); - if (pp !== false) { - to_row = pp; - } - this.set_placeholder(to_col, to_row); - } - - return { - col: to_col, - row: to_row - }; - }; - - - /** - * See which of the widgets in the $widgets param collection can go to - * a upper row and which not. - * - * @method widgets_contraints - * @param {jQuery} $widgets A jQuery wrapped collection of - * HTMLElements. - * @return {object} Returns a literal Object with two keys: `can_go_up` & - * `can_not_go_up`. Each contains a set of HTMLElements. - */ - fn.widgets_constraints = function($widgets) { - var $widgets_can_go_up = $([]); - var $widgets_can_not_go_up; - var wgd_can_go_up = []; - var wgd_can_not_go_up = []; - - $widgets.each($.proxy(function(i, w) { - var $w = $(w); - var wgd = $w.coords().grid; - if (this.can_go_widget_up(wgd)) { - $widgets_can_go_up = $widgets_can_go_up.add($w); - wgd_can_go_up.push(wgd); - } else { - wgd_can_not_go_up.push(wgd); - } - }, this)); - - $widgets_can_not_go_up = $widgets.not($widgets_can_go_up); - - return { - can_go_up: Gridster.sort_by_row_asc(wgd_can_go_up), - can_not_go_up: Gridster.sort_by_row_desc(wgd_can_not_go_up) - }; - }; - - - /** - * Sorts an Array of grid coords objects (representing the grid coords of - * each widget) in descending way. - * - * @method manage_movements - * @param {jQuery} $widgets A jQuery collection of HTMLElements - * representing the widgets you want to move. - * @param {Number} to_col The column to which we want to move the widgets. - * @param {Number} to_row The row to which we want to move the widgets. - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.manage_movements = function($widgets, to_col, to_row) { - $.each($widgets, $.proxy(function(i, w) { - var wgd = w; - var $w = wgd.el; - - var can_go_widget_up = this.can_go_widget_up(wgd); - - if (can_go_widget_up) { - //target CAN go up - //so move widget up - this.move_widget_to($w, can_go_widget_up); - this.set_placeholder(to_col, can_go_widget_up + wgd.size_y); - - } else { - //target can't go up - var can_go_player_up = this.can_go_player_up( - this.player_grid_data); - - if (!can_go_player_up) { - // target can't go up - // player cant't go up - // so we need to move widget down to a position that dont - // overlaps player - var y = (to_row + this.player_grid_data.size_y) - wgd.row; - - this.move_widget_down($w, y); - this.set_placeholder(to_col, to_row); - } - } - }, this)); - - return this; - }; - - /** - * Determines if there is a widget in the row and col given. Or if the - * HTMLElement passed as first argument is the player. - * - * @method is_player - * @param {Number|HTMLElement} col_or_el A jQuery wrapped collection of - * HTMLElements. - * @param {Number} [row] The column to which we want to move the widgets. - * @return {Boolean} Returns true or false. - */ - fn.is_player = function(col_or_el, row) { - if (row && !this.gridmap[col_or_el]) { return false; } - var $w = row ? this.gridmap[col_or_el][row] : col_or_el; - return $w && ($w.is(this.$player) || $w.is(this.$helper)); - }; - - - /** - * Determines if the widget that is being dragged is currently over the row - * and col given. - * - * @method is_player_in - * @param {Number} col The column to check. - * @param {Number} row The row to check. - * @return {Boolean} Returns true or false. - */ - fn.is_player_in = function(col, row) { - var c = this.cells_occupied_by_player || {}; - return $.inArray(col, c.cols) >= 0 && $.inArray(row, c.rows) >= 0; - }; - - - /** - * Determines if the placeholder is currently over the row and col given. - * - * @method is_placeholder_in - * @param {Number} col The column to check. - * @param {Number} row The row to check. - * @return {Boolean} Returns true or false. - */ - fn.is_placeholder_in = function(col, row) { - var c = this.cells_occupied_by_placeholder || {}; - return this.is_placeholder_in_col(col) && $.inArray(row, c.rows) >= 0; - }; - - - /** - * Determines if the placeholder is currently over the column given. - * - * @method is_placeholder_in_col - * @param {Number} col The column to check. - * @return {Boolean} Returns true or false. - */ - fn.is_placeholder_in_col = function(col) { - var c = this.cells_occupied_by_placeholder || []; - return $.inArray(col, c.cols) >= 0; - }; - - - /** - * Determines if the cell represented by col and row params is empty. - * - * @method is_empty - * @param {Number} col The column to check. - * @param {Number} row The row to check. - * @return {Boolean} Returns true or false. - */ - fn.is_empty = function(col, row) { - if (typeof this.gridmap[col] !== 'undefined') { - if(typeof this.gridmap[col][row] !== 'undefined' && - this.gridmap[col][row] === false - ) { - return true; - } - return false; - } - return true; - }; - - - /** - * Determines if the cell represented by col and row params is occupied. - * - * @method is_occupied - * @param {Number} col The column to check. - * @param {Number} row The row to check. - * @return {Boolean} Returns true or false. - */ - fn.is_occupied = function(col, row) { - if (!this.gridmap[col]) { - return false; - } - - if (this.gridmap[col][row]) { - return true; - } - return false; - }; - - - /** - * Determines if there is a widget in the cell represented by col/row params. - * - * @method is_widget - * @param {Number} col The column to check. - * @param {Number} row The row to check. - * @return {Boolean|HTMLElement} Returns false if there is no widget, - * else returns the jQuery HTMLElement - */ - fn.is_widget = function(col, row) { - var cell = this.gridmap[col]; - if (!cell) { - return false; - } - - cell = cell[row]; - - if (cell) { - return cell; - } - - return false; - }; - - - /** - * Determines if there is a widget in the cell represented by col/row - * params and if this is under the widget that is being dragged. - * - * @method is_widget_under_player - * @param {Number} col The column to check. - * @param {Number} row The row to check. - * @return {Boolean} Returns true or false. - */ - fn.is_widget_under_player = function(col, row) { - if (this.is_widget(col, row)) { - return this.is_player_in(col, row); - } - return false; - }; - - - /** - * Get widgets overlapping with the player or with the object passed - * representing the grid cells. - * - * @method get_widgets_under_player - * @return {HTMLElement} Returns a jQuery collection of HTMLElements - */ - fn.get_widgets_under_player = function(cells) { - cells || (cells = this.cells_occupied_by_player || {cols: [], rows: []}); - var $widgets = $([]); - - $.each(cells.cols, $.proxy(function(i, col) { - $.each(cells.rows, $.proxy(function(i, row) { - if(this.is_widget(col, row)) { - $widgets = $widgets.add(this.gridmap[col][row]); - } - }, this)); - }, this)); - - return $widgets; - }; - - - /** - * Put placeholder at the row and column specified. - * - * @method set_placeholder - * @param {Number} col The column to which we want to move the - * placeholder. - * @param {Number} row The row to which we want to move the - * placeholder. - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.set_placeholder = function(col, row) { - var phgd = $.extend({}, this.placeholder_grid_data); - var $nexts = this.widgets_below({ - col: phgd.col, - row: phgd.row, - size_y: phgd.size_y, - size_x: phgd.size_x - }); - - // Prevents widgets go out of the grid - var right_col = (col + phgd.size_x - 1); - if (right_col > this.cols) { - col = col - (right_col - col); - } - - var moved_down = this.placeholder_grid_data.row < row; - var changed_column = this.placeholder_grid_data.col !== col; - - this.placeholder_grid_data.col = col; - this.placeholder_grid_data.row = row; - - this.cells_occupied_by_placeholder = this.get_cells_occupied( - this.placeholder_grid_data); - - this.$preview_holder.attr({ - 'data-row' : row, - 'data-col' : col - }); - - if (moved_down || changed_column) { - $nexts.each($.proxy(function(i, widget) { - this.move_widget_up( - $(widget), this.placeholder_grid_data.col - col + phgd.size_y); - }, this)); - } - - var $widgets_under_ph = this.get_widgets_under_player( - this.cells_occupied_by_placeholder); - - if ($widgets_under_ph.length) { - $widgets_under_ph.each($.proxy(function(i, widget) { - var $w = $(widget); - this.move_widget_down( - $w, row + phgd.size_y - $w.data('coords').grid.row); - }, this)); - } - - }; - - - /** - * Determines whether the player can move to a position above. - * - * @method can_go_player_up - * @param {Object} widget_grid_data The actual grid coords object of the - * player. - * @return {Number|Boolean} If the player can be moved to an upper row - * returns the row number, else returns false. - */ - fn.can_go_player_up = function(widget_grid_data) { - var p_bottom_row = widget_grid_data.row + widget_grid_data.size_y - 1; - var result = true; - var upper_rows = []; - var min_row = 10000; - var $widgets_under_player = this.get_widgets_under_player(); - - /* generate an array with columns as index and array with upper rows - * empty as value */ - this.for_each_column_occupied(widget_grid_data, function(tcol) { - var grid_col = this.gridmap[tcol]; - var r = p_bottom_row + 1; - upper_rows[tcol] = []; - - while (--r > 0) { - if (this.is_empty(tcol, r) || this.is_player(tcol, r) || - this.is_widget(tcol, r) && - grid_col[r].is($widgets_under_player) - ) { - upper_rows[tcol].push(r); - min_row = r < min_row ? r : min_row; - } else { - break; - } - } - - if (upper_rows[tcol].length === 0) { - result = false; - return true; //break - } - - upper_rows[tcol].sort(function(a, b) { - return a - b; - }); - }); - - if (!result) { return false; } - - return this.get_valid_rows(widget_grid_data, upper_rows, min_row); - }; - - - /** - * Determines whether a widget can move to a position above. - * - * @method can_go_widget_up - * @param {Object} widget_grid_data The actual grid coords object of the - * widget we want to check. - * @return {Number|Boolean} If the widget can be moved to an upper row - * returns the row number, else returns false. - */ - fn.can_go_widget_up = function(widget_grid_data) { - var p_bottom_row = widget_grid_data.row + widget_grid_data.size_y - 1; - var result = true; - var upper_rows = []; - var min_row = 10000; - - /* generate an array with columns as index and array with topmost rows - * empty as value */ - this.for_each_column_occupied(widget_grid_data, function(tcol) { - var grid_col = this.gridmap[tcol]; - upper_rows[tcol] = []; - - var r = p_bottom_row + 1; - // iterate over each row - while (--r > 0) { - if (this.is_widget(tcol, r) && !this.is_player_in(tcol, r)) { - if (!grid_col[r].is(widget_grid_data.el)) { - break; - } - } - - if (!this.is_player(tcol, r) && - !this.is_placeholder_in(tcol, r) && - !this.is_player_in(tcol, r)) { - upper_rows[tcol].push(r); - } - - if (r < min_row) { - min_row = r; - } - } - - if (upper_rows[tcol].length === 0) { - result = false; - return true; //break - } - - upper_rows[tcol].sort(function(a, b) { - return a - b; - }); - }); - - if (!result) { return false; } - - return this.get_valid_rows(widget_grid_data, upper_rows, min_row); - }; - - - /** - * Search a valid row for the widget represented by `widget_grid_data' in - * the `upper_rows` array. Iteration starts from row specified in `min_row`. - * - * @method get_valid_rows - * @param {Object} widget_grid_data The actual grid coords object of the - * player. - * @param {Array} upper_rows An array with columns as index and arrays - * of valid rows as values. - * @param {Number} min_row The upper row from which the iteration will start. - * @return {Number|Boolean} Returns the upper row valid from the `upper_rows` - * for the widget in question. - */ - fn.get_valid_rows = function(widget_grid_data, upper_rows, min_row) { - var p_top_row = widget_grid_data.row; - var p_bottom_row = widget_grid_data.row + widget_grid_data.size_y - 1; - var size_y = widget_grid_data.size_y; - var r = min_row - 1; - var valid_rows = []; - - while (++r <= p_bottom_row ) { - var common = true; - $.each(upper_rows, function(col, rows) { - if ($.isArray(rows) && $.inArray(r, rows) === -1) { - common = false; - } - }); - - if (common === true) { - valid_rows.push(r); - if (valid_rows.length === size_y) { - break; - } - } - } - - var new_row = false; - if (size_y === 1) { - if (valid_rows[0] !== p_top_row) { - new_row = valid_rows[0] || false; - } - } else { - if (valid_rows[0] !== p_top_row) { - new_row = this.get_consecutive_numbers_index( - valid_rows, size_y); - } - } - - return new_row; - }; - - - fn.get_consecutive_numbers_index = function(arr, size_y) { - var max = arr.length; - var result = []; - var first = true; - var prev = -1; // or null? - - for (var i=0; i < max; i++) { - if (first || arr[i] === prev + 1) { - result.push(i); - if (result.length === size_y) { - break; - } - first = false; - } else { - result = []; - first = true; - } - - prev = arr[i]; - } - - return result.length >= size_y ? arr[result[0]] : false; - }; - - - /** - * Get widgets overlapping with the player. - * - * @method get_widgets_overlapped - * @return {jQuery} Returns a jQuery collection of HTMLElements. - */ - fn.get_widgets_overlapped = function() { - var $w; - var $widgets = $([]); - var used = []; - var rows_from_bottom = this.cells_occupied_by_player.rows.slice(0); - rows_from_bottom.reverse(); - - $.each(this.cells_occupied_by_player.cols, $.proxy(function(i, col) { - $.each(rows_from_bottom, $.proxy(function(i, row) { - // if there is a widget in the player position - if (!this.gridmap[col]) { return true; } //next iteration - var $w = this.gridmap[col][row]; - if (this.is_occupied(col, row) && !this.is_player($w) && - $.inArray($w, used) === -1 - ) { - $widgets = $widgets.add($w); - used.push($w); - } - - }, this)); - }, this)); - - return $widgets; - }; - - - /** - * This callback is executed when the player begins to collide with a column. - * - * @method on_start_overlapping_column - * @param {Number} col The collided column. - * @return {jQuery} Returns a jQuery collection of HTMLElements. - */ - fn.on_start_overlapping_column = function(col) { - this.set_player(col, false); - }; - - - /** - * A callback executed when the player begins to collide with a row. - * - * @method on_start_overlapping_row - * @param {Number} row The collided row. - * @return {jQuery} Returns a jQuery collection of HTMLElements. - */ - fn.on_start_overlapping_row = function(row) { - this.set_player(false, row); - }; - - - /** - * A callback executed when the the player ends to collide with a column. - * - * @method on_stop_overlapping_column - * @param {Number} col The collided row. - * @return {jQuery} Returns a jQuery collection of HTMLElements. - */ - fn.on_stop_overlapping_column = function(col) { - this.set_player(col, false); - - var self = this; - this.for_each_widget_below(col, this.cells_occupied_by_player.rows[0], - function(tcol, trow) { - self.move_widget_up(this, self.player_grid_data.size_y); - }); - }; - - - /** - * This callback is executed when the player ends to collide with a row. - * - * @method on_stop_overlapping_row - * @param {Number} row The collided row. - * @return {jQuery} Returns a jQuery collection of HTMLElements. - */ - fn.on_stop_overlapping_row = function(row) { - this.set_player(false, row); - - var self = this; - var cols = this.cells_occupied_by_player.cols; - for (var c = 0, cl = cols.length; c < cl; c++) { - this.for_each_widget_below(cols[c], row, function(tcol, trow) { - self.move_widget_up(this, self.player_grid_data.size_y); - }); - } - }; - - - /** - * Move a widget to a specific row. The cell or cells must be empty. - * If the widget has widgets below, all of these widgets will be moved also - * if they can. - * - * @method move_widget_to - * @param {HTMLElement} $widget The jQuery wrapped HTMLElement of the - * widget is going to be moved. - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.move_widget_to = function($widget, row) { - var self = this; - var widget_grid_data = $widget.coords().grid; - var diff = row - widget_grid_data.row; - var $next_widgets = this.widgets_below($widget); - - var can_move_to_new_cell = this.can_move_to( - widget_grid_data, widget_grid_data.col, row, $widget); - - if (can_move_to_new_cell === false) { - return false; - } - - this.remove_from_gridmap(widget_grid_data); - widget_grid_data.row = row; - this.add_to_gridmap(widget_grid_data); - $widget.attr('data-row', row); - this.$changed = this.$changed.add($widget); - - - $next_widgets.each(function(i, widget) { - var $w = $(widget); - var wgd = $w.coords().grid; - var can_go_up = self.can_go_widget_up(wgd); - if (can_go_up && can_go_up !== wgd.row) { - self.move_widget_to($w, can_go_up); - } - }); - - return this; - }; - - - /** - * Move up the specified widget and all below it. - * - * @method move_widget_up - * @param {HTMLElement} $widget The widget you want to move. - * @param {Number} [y_units] The number of cells that the widget has to move. - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.move_widget_up = function($widget, y_units) { - var el_grid_data = $widget.coords().grid; - var actual_row = el_grid_data.row; - var moved = []; - var can_go_up = true; - y_units || (y_units = 1); - - if (!this.can_go_up($widget)) { return false; } //break; - - this.for_each_column_occupied(el_grid_data, function(col) { - // can_go_up - if ($.inArray($widget, moved) === -1) { - var widget_grid_data = $widget.coords().grid; - var next_row = actual_row - y_units; - next_row = this.can_go_up_to_row( - widget_grid_data, col, next_row); - - if (!next_row) { - return true; - } - - var $next_widgets = this.widgets_below($widget); - - this.remove_from_gridmap(widget_grid_data); - widget_grid_data.row = next_row; - this.add_to_gridmap(widget_grid_data); - $widget.attr('data-row', widget_grid_data.row); - this.$changed = this.$changed.add($widget); - - moved.push($widget); - - $next_widgets.each($.proxy(function(i, widget) { - this.move_widget_up($(widget), y_units); - }, this)); - } - }); - - }; - - - /** - * Move down the specified widget and all below it. - * - * @method move_widget_down - * @param {jQuery} $widget The jQuery object representing the widget - * you want to move. - * @param {Number} y_units The number of cells that the widget has to move. - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.move_widget_down = function($widget, y_units) { - var el_grid_data, actual_row, moved, y_diff; - - if (y_units <= 0) { return false; } - - el_grid_data = $widget.coords().grid; - actual_row = el_grid_data.row; - moved = []; - y_diff = y_units; - - if (!$widget) { return false; } - - if ($.inArray($widget, moved) === -1) { - - var widget_grid_data = $widget.coords().grid; - var next_row = actual_row + y_units; - var $next_widgets = this.widgets_below($widget); - - this.remove_from_gridmap(widget_grid_data); - - $next_widgets.each($.proxy(function(i, widget) { - var $w = $(widget); - var wd = $w.coords().grid; - var tmp_y = this.displacement_diff( - wd, widget_grid_data, y_diff); - - if (tmp_y > 0) { - this.move_widget_down($w, tmp_y); - } - }, this)); - - widget_grid_data.row = next_row; - this.update_widget_position(widget_grid_data, $widget); - $widget.attr('data-row', widget_grid_data.row); - this.$changed = this.$changed.add($widget); - - moved.push($widget); - } - }; - - - /** - * Check if the widget can move to the specified row, else returns the - * upper row possible. - * - * @method can_go_up_to_row - * @param {Number} widget_grid_data The current grid coords object of the - * widget. - * @param {Number} col The target column. - * @param {Number} row The target row. - * @return {Boolean|Number} Returns the row number if the widget can move - * to the target position, else returns false. - */ - fn.can_go_up_to_row = function(widget_grid_data, col, row) { - var ga = this.gridmap; - var result = true; - var urc = []; // upper_rows_in_columns - var actual_row = widget_grid_data.row; - var r; - - /* generate an array with columns as index and array with - * upper rows empty in the column */ - this.for_each_column_occupied(widget_grid_data, function(tcol) { - var grid_col = ga[tcol]; - urc[tcol] = []; - - r = actual_row; - while (r--) { - if (this.is_empty(tcol, r) && - !this.is_placeholder_in(tcol, r) - ) { - urc[tcol].push(r); - } else { - break; - } - } - - if (!urc[tcol].length) { - result = false; - return true; - } - - }); - - if (!result) { return false; } - - /* get common rows starting from upper position in all the columns - * that widget occupies */ - r = row; - for (r = 1; r < actual_row; r++) { - var common = true; - - for (var uc = 0, ucl = urc.length; uc < ucl; uc++) { - if (urc[uc] && $.inArray(r, urc[uc]) === -1) { - common = false; - } - } - - if (common === true) { - result = r; - break; - } - } - - return result; - }; - - - fn.displacement_diff = function(widget_grid_data, parent_bgd, y_units) { - var actual_row = widget_grid_data.row; - var diffs = []; - var parent_max_y = parent_bgd.row + parent_bgd.size_y; - - this.for_each_column_occupied(widget_grid_data, function(col) { - var temp_y_units = 0; - - for (var r = parent_max_y; r < actual_row; r++) { - if (this.is_empty(col, r)) { - temp_y_units = temp_y_units + 1; - } - } - - diffs.push(temp_y_units); - }); - - var max_diff = Math.max.apply(Math, diffs); - y_units = (y_units - max_diff); - - return y_units > 0 ? y_units : 0; - }; - - - /** - * Get widgets below a widget. - * - * @method widgets_below - * @param {HTMLElement} $el The jQuery wrapped HTMLElement. - * @return {jQuery} A jQuery collection of HTMLElements. - */ - fn.widgets_below = function($el) { - var el_grid_data = $.isPlainObject($el) ? $el : $el.coords().grid; - var self = this; - var ga = this.gridmap; - var next_row = el_grid_data.row + el_grid_data.size_y - 1; - var $nexts = $([]); - - this.for_each_column_occupied(el_grid_data, function(col) { - self.for_each_widget_below(col, next_row, function(tcol, trow) { - if (!self.is_player(this) && $.inArray(this, $nexts) === -1) { - $nexts = $nexts.add(this); - return true; // break - } - }); - }); - - return Gridster.sort_by_row_asc($nexts); - }; - - - /** - * Update the array of mapped positions with the new player position. - * - * @method set_cells_player_occupies - * @param {Number} col The new player col. - * @param {Number} col The new player row. - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.set_cells_player_occupies = function(col, row) { - this.remove_from_gridmap(this.placeholder_grid_data); - this.placeholder_grid_data.col = col; - this.placeholder_grid_data.row = row; - this.add_to_gridmap(this.placeholder_grid_data, this.$player); - return this; - }; - - - /** - * Remove from the array of mapped positions the reference to the player. - * - * @method empty_cells_player_occupies - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.empty_cells_player_occupies = function() { - this.remove_from_gridmap(this.placeholder_grid_data); - return this; - }; - - - fn.can_go_up = function($el) { - var el_grid_data = $el.coords().grid; - var initial_row = el_grid_data.row; - var prev_row = initial_row - 1; - var ga = this.gridmap; - var upper_rows_by_column = []; - - var result = true; - if (initial_row === 1) { return false; } - - this.for_each_column_occupied(el_grid_data, function(col) { - var $w = this.is_widget(col, prev_row); - - if (this.is_occupied(col, prev_row) || - this.is_player(col, prev_row) || - this.is_placeholder_in(col, prev_row) || - this.is_player_in(col, prev_row) - ) { - result = false; - return true; //break - } - }); - - return result; - }; - - - /** - * Check if it's possible to move a widget to a specific col/row. It takes - * into account the dimensions (`size_y` and `size_x` attrs. of the grid - * coords object) the widget occupies. - * - * @method can_move_to - * @param {Object} widget_grid_data The grid coords object that represents - * the widget. - * @param {Object} col The col to check. - * @param {Object} row The row to check. - * @param {Number} [max_row] The max row allowed. - * @return {Boolean} Returns true if all cells are empty, else return false. - */ - fn.can_move_to = function(widget_grid_data, col, row, max_row) { - var ga = this.gridmap; - var $w = widget_grid_data.el; - var future_wd = { - size_y: widget_grid_data.size_y, - size_x: widget_grid_data.size_x, - col: col, - row: row - }; - var result = true; - - //Prevents widgets go out of the grid - var right_col = col + widget_grid_data.size_x - 1; - if (right_col > this.cols) { - return false; - } - - if (max_row && max_row < row + widget_grid_data.size_y - 1) { - return false; - } - - this.for_each_cell_occupied(future_wd, function(tcol, trow) { - var $tw = this.is_widget(tcol, trow); - if ($tw && (!widget_grid_data.el || $tw.is($w))) { - result = false; - } - }); - - return result; - }; - - - /** - * Given the leftmost column returns all columns that are overlapping - * with the player. - * - * @method get_targeted_columns - * @param {Number} [from_col] The leftmost column. - * @return {Array} Returns an array with column numbers. - */ - fn.get_targeted_columns = function(from_col) { - var max = (from_col || this.player_grid_data.col) + - (this.player_grid_data.size_x - 1); - var cols = []; - for (var col = from_col; col <= max; col++) { - cols.push(col); - } - return cols; - }; - - - /** - * Given the upper row returns all rows that are overlapping with the player. - * - * @method get_targeted_rows - * @param {Number} [from_row] The upper row. - * @return {Array} Returns an array with row numbers. - */ - fn.get_targeted_rows = function(from_row) { - var max = (from_row || this.player_grid_data.row) + - (this.player_grid_data.size_y - 1); - var rows = []; - for (var row = from_row; row <= max; row++) { - rows.push(row); - } - return rows; - }; - - /** - * Get all columns and rows that a widget occupies. - * - * @method get_cells_occupied - * @param {Object} el_grid_data The grid coords object of the widget. - * @return {Object} Returns an object like `{ cols: [], rows: []}`. - */ - fn.get_cells_occupied = function(el_grid_data) { - var cells = { cols: [], rows: []}; - var i; - if (arguments[1] instanceof $) { - el_grid_data = arguments[1].coords().grid; - } - - for (i = 0; i < el_grid_data.size_x; i++) { - var col = el_grid_data.col + i; - cells.cols.push(col); - } - - for (i = 0; i < el_grid_data.size_y; i++) { - var row = el_grid_data.row + i; - cells.rows.push(row); - } - - return cells; - }; - - - /** - * Iterate over the cells occupied by a widget executing a function for - * each one. - * - * @method for_each_cell_occupied - * @param {Object} el_grid_data The grid coords object that represents the - * widget. - * @param {Function} callback The function to execute on each column - * iteration. Column and row are passed as arguments. - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.for_each_cell_occupied = function(grid_data, callback) { - this.for_each_column_occupied(grid_data, function(col) { - this.for_each_row_occupied(grid_data, function(row) { - callback.call(this, col, row); - }); - }); - return this; - }; - - - /** - * Iterate over the columns occupied by a widget executing a function for - * each one. - * - * @method for_each_column_occupied - * @param {Object} el_grid_data The grid coords object that represents - * the widget. - * @param {Function} callback The function to execute on each column - * iteration. The column number is passed as first argument. - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.for_each_column_occupied = function(el_grid_data, callback) { - for (var i = 0; i < el_grid_data.size_x; i++) { - var col = el_grid_data.col + i; - callback.call(this, col, el_grid_data); - } - }; - - - /** - * Iterate over the rows occupied by a widget executing a function for - * each one. - * - * @method for_each_row_occupied - * @param {Object} el_grid_data The grid coords object that represents - * the widget. - * @param {Function} callback The function to execute on each column - * iteration. The row number is passed as first argument. - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.for_each_row_occupied = function(el_grid_data, callback) { - for (var i = 0; i < el_grid_data.size_y; i++) { - var row = el_grid_data.row + i; - callback.call(this, row, el_grid_data); - } - }; - - - - fn._traversing_widgets = function(type, direction, col, row, callback) { - var ga = this.gridmap; - if (!ga[col]) { return; } - - var cr, max; - var action = type + '/' + direction; - if (arguments[2] instanceof $) { - var el_grid_data = arguments[2].coords().grid; - col = el_grid_data.col; - row = el_grid_data.row; - callback = arguments[3]; - } - var matched = []; - var trow = row; - - - var methods = { - 'for_each/above': function() { - while (trow--) { - if (trow > 0 && this.is_widget(col, trow) && - $.inArray(ga[col][trow], matched) === -1 - ) { - cr = callback.call(ga[col][trow], col, trow); - matched.push(ga[col][trow]); - if (cr) { break; } - } - } - }, - 'for_each/below': function() { - for (trow = row + 1, max = ga[col].length; trow < max; trow++) { - if (this.is_widget(col, trow) && - $.inArray(ga[col][trow], matched) === -1 - ) { - cr = callback.call(ga[col][trow], col, trow); - matched.push(ga[col][trow]); - if (cr) { break; } - } - } - } - }; - - if (methods[action]) { - methods[action].call(this); - } - }; - - - /** - * Iterate over each widget above the column and row specified. - * - * @method for_each_widget_above - * @param {Number} col The column to start iterating. - * @param {Number} row The row to start iterating. - * @param {Function} callback The function to execute on each widget - * iteration. The value of `this` inside the function is the jQuery - * wrapped HTMLElement. - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.for_each_widget_above = function(col, row, callback) { - this._traversing_widgets('for_each', 'above', col, row, callback); - return this; - }; - - - /** - * Iterate over each widget below the column and row specified. - * - * @method for_each_widget_below - * @param {Number} col The column to start iterating. - * @param {Number} row The row to start iterating. - * @param {Function} callback The function to execute on each widget - * iteration. The value of `this` inside the function is the jQuery wrapped - * HTMLElement. - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.for_each_widget_below = function(col, row, callback) { - this._traversing_widgets('for_each', 'below', col, row, callback); - return this; - }; - - - /** - * Returns the highest occupied cell in the grid. - * - * @method get_highest_occupied_cell - * @return {Object} Returns an object with `col` and `row` numbers. - */ - fn.get_highest_occupied_cell = function() { - var r; - var gm = this.gridmap; - var rl = gm[1].length; - var rows = [], cols = []; - var row_in_col = []; - for (var c = gm.length - 1; c >= 1; c--) { - for (r = rl - 1; r >= 1; r--) { - if (this.is_widget(c, r)) { - rows.push(r); - cols.push(c); - break; - } - } - } - - return { - col: Math.max.apply(Math, cols), - row: Math.max.apply(Math, rows) - }; - }; - - - fn.get_widgets_from = function(col, row) { - var ga = this.gridmap; - var $widgets = $(); - - if (col) { - $widgets = $widgets.add( - this.$widgets.filter(function() { - var tcol = $(this).attr('data-col'); - return (tcol === col || tcol > col); - }) - ); - } - - if (row) { - $widgets = $widgets.add( - this.$widgets.filter(function() { - var trow = $(this).attr('data-row'); - return (trow === row || trow > row); - }) - ); - } - - return $widgets; - }; - - - /** - * Set the current height of the parent grid. - * - * @method set_dom_grid_height - * @return {Object} Returns the instance of the Gridster class. - */ - fn.set_dom_grid_height = function(height) { - if (typeof height === 'undefined') { - var r = this.get_highest_occupied_cell().row; - height = r * this.min_widget_height; - } - - this.container_height = height; - this.$el.css('height', this.container_height); - return this; - }; - - /** - * Set the current width of the parent grid. - * - * @method set_dom_grid_width - * @return {Object} Returns the instance of the Gridster class. - */ - fn.set_dom_grid_width = function(cols) { - if (typeof cols === 'undefined') { - cols = this.get_highest_occupied_cell().col; - } - - var max_cols = (this.options.autogrow_cols ? this.options.max_cols : - this.cols); - - cols = Math.min(max_cols, Math.max(cols, this.options.min_cols)); - this.container_width = cols * this.min_widget_width; - this.$el.css('width', this.container_width); - return this; - }; - - - /** - * It generates the neccessary styles to position the widgets. - * - * @method generate_stylesheet - * @param {Number} rows Number of columns. - * @param {Number} cols Number of rows. - * @return {Object} Returns the instance of the Gridster class. - */ - fn.generate_stylesheet = function(opts) { - var styles = ''; - var max_size_x = this.options.max_size_x || this.cols; - var max_rows = 0; - var max_cols = 0; - var i; - var rules; - - opts || (opts = {}); - opts.cols || (opts.cols = this.cols); - opts.rows || (opts.rows = this.rows); - opts.namespace || (opts.namespace = this.options.namespace); - opts.widget_base_dimensions || - (opts.widget_base_dimensions = this.options.widget_base_dimensions); - opts.widget_margins || - (opts.widget_margins = this.options.widget_margins); - opts.min_widget_width = (opts.widget_margins[0] * 2) + - opts.widget_base_dimensions[0]; - opts.min_widget_height = (opts.widget_margins[1] * 2) + - opts.widget_base_dimensions[1]; - - // don't duplicate stylesheets for the same configuration - var serialized_opts = $.param(opts); - if ($.inArray(serialized_opts, Gridster.generated_stylesheets) >= 0) { - return false; - } - - this.generated_stylesheets.push(serialized_opts); - Gridster.generated_stylesheets.push(serialized_opts); - - /* generate CSS styles for cols */ - for (i = opts.cols; i >= 0; i--) { - styles += (opts.namespace + ' [data-col="'+ (i + 1) + '"] { left:' + - ((i * opts.widget_base_dimensions[0]) + - (i * opts.widget_margins[0]) + - ((i + 1) * opts.widget_margins[0])) + 'px; }\n'); - } - - /* generate CSS styles for rows */ - for (i = opts.rows; i >= 0; i--) { - styles += (opts.namespace + ' [data-row="' + (i + 1) + '"] { top:' + - ((i * opts.widget_base_dimensions[1]) + - (i * opts.widget_margins[1]) + - ((i + 1) * opts.widget_margins[1]) ) + 'px; }\n'); - } - - for (var y = 1; y <= opts.rows; y++) { - styles += (opts.namespace + ' [data-sizey="' + y + '"] { height:' + - (y * opts.widget_base_dimensions[1] + - (y - 1) * (opts.widget_margins[1] * 2)) + 'px; }\n'); - } - - for (var x = 1; x <= max_size_x; x++) { - styles += (opts.namespace + ' [data-sizex="' + x + '"] { width:' + - (x * opts.widget_base_dimensions[0] + - (x - 1) * (opts.widget_margins[0] * 2)) + 'px; }\n'); - } - - this.remove_style_tags(); - - return this.add_style_tag(styles); - }; - - - /** - * Injects the given CSS as string to the head of the document. - * - * @method add_style_tag - * @param {String} css The styles to apply. - * @return {Object} Returns the instance of the Gridster class. - */ - fn.add_style_tag = function(css) { - var d = document; - var tag = d.createElement('style'); - - d.getElementsByTagName('head')[0].appendChild(tag); - tag.setAttribute('type', 'text/css'); - - if (tag.styleSheet) { - tag.styleSheet.cssText = css; - } else { - tag.appendChild(document.createTextNode(css)); - } - - this.$style_tags = this.$style_tags.add(tag); - - return this; - }; - - - /** - * Remove the style tag with the associated id from the head of the document - * - * @method remove_style_tag - * @return {Object} Returns the instance of the Gridster class. - */ - fn.remove_style_tags = function() { - var all_styles = Gridster.generated_stylesheets; - var ins_styles = this.generated_stylesheets; - - this.$style_tags.remove(); - - Gridster.generated_stylesheets = $.map(all_styles, function(s) { - if ($.inArray(s, ins_styles) === -1) { return s; } - }); - }; - - - /** - * Generates a faux grid to collide with it when a widget is dragged and - * detect row or column that we want to go. - * - * @method generate_faux_grid - * @param {Number} rows Number of columns. - * @param {Number} cols Number of rows. - * @return {Object} Returns the instance of the Gridster class. - */ - fn.generate_faux_grid = function(rows, cols) { - this.faux_grid = []; - this.gridmap = []; - var col; - var row; - for (col = cols; col > 0; col--) { - this.gridmap[col] = []; - for (row = rows; row > 0; row--) { - this.add_faux_cell(row, col); - } - } - return this; - }; - - - /** - * Add cell to the faux grid. - * - * @method add_faux_cell - * @param {Number} row The row for the new faux cell. - * @param {Number} col The col for the new faux cell. - * @return {Object} Returns the instance of the Gridster class. - */ - fn.add_faux_cell = function(row, col) { - var coords = $({ - left: this.baseX + ((col - 1) * this.min_widget_width), - top: this.baseY + (row -1) * this.min_widget_height, - width: this.min_widget_width, - height: this.min_widget_height, - col: col, - row: row, - original_col: col, - original_row: row - }).coords(); - - if (!$.isArray(this.gridmap[col])) { - this.gridmap[col] = []; - } - - this.gridmap[col][row] = false; - this.faux_grid.push(coords); - - return this; - }; - - - /** - * Add rows to the faux grid. - * - * @method add_faux_rows - * @param {Number} rows The number of rows you want to add to the faux grid. - * @return {Object} Returns the instance of the Gridster class. - */ - fn.add_faux_rows = function(rows) { - var actual_rows = this.rows; - var max_rows = actual_rows + (rows || 1); - - for (var r = max_rows; r > actual_rows; r--) { - for (var c = this.cols; c >= 1; c--) { - this.add_faux_cell(r, c); - } - } - - this.rows = max_rows; - - if (this.options.autogenerate_stylesheet) { - this.generate_stylesheet(); - } - - return this; - }; - - /** - * Add cols to the faux grid. - * - * @method add_faux_cols - * @param {Number} cols The number of cols you want to add to the faux grid. - * @return {Object} Returns the instance of the Gridster class. - */ - fn.add_faux_cols = function(cols) { - var actual_cols = this.cols; - var max_cols = actual_cols + (cols || 1); - max_cols = Math.min(max_cols, this.options.max_cols); - - for (var c = actual_cols + 1; c <= max_cols; c++) { - for (var r = this.rows; r >= 1; r--) { - this.add_faux_cell(r, c); - } - } - - this.cols = max_cols; - - if (this.options.autogenerate_stylesheet) { - this.generate_stylesheet(); - } - - return this; - }; - - - /** - * Recalculates the offsets for the faux grid. You need to use it when - * the browser is resized. - * - * @method recalculate_faux_grid - * @return {Object} Returns the instance of the Gridster class. - */ - fn.recalculate_faux_grid = function() { - var aw = this.$wrapper.width(); - this.baseX = ($(window).width() - aw) / 2; - this.baseY = this.$wrapper.offset().top; - - $.each(this.faux_grid, $.proxy(function(i, coords) { - this.faux_grid[i] = coords.update({ - left: this.baseX + (coords.data.col -1) * this.min_widget_width, - top: this.baseY + (coords.data.row -1) * this.min_widget_height - }); - }, this)); - - return this; - }; - - - /** - * Get all widgets in the DOM and register them. - * - * @method get_widgets_from_DOM - * @return {Object} Returns the instance of the Gridster class. - */ - fn.get_widgets_from_DOM = function() { - var widgets_coords = this.$widgets.map($.proxy(function(i, widget) { - var $w = $(widget); - return this.dom_to_coords($w); - }, this)); - - widgets_coords = Gridster.sort_by_row_and_col_asc(widgets_coords); - - var changes = $(widgets_coords).map($.proxy(function(i, wgd) { - return this.register_widget(wgd) || null; - }, this)); - - if (changes.length) { - this.$el.trigger('gridster:positionschanged'); - } - - return this; - }; - - - /** - * Calculate columns and rows to be set based on the configuration - * parameters, grid dimensions, etc ... - * - * @method generate_grid_and_stylesheet - * @return {Object} Returns the instance of the Gridster class. - */ - fn.generate_grid_and_stylesheet = function() { - var aw = this.$wrapper.width(); - var max_cols = this.options.max_cols; - - var cols = Math.floor(aw / this.min_widget_width) + - this.options.extra_cols; - - var actual_cols = this.$widgets.map(function() { - return $(this).attr('data-col'); - }).get(); - - //needed to pass tests with phantomjs - actual_cols.length || (actual_cols = [0]); - - var min_cols = Math.max.apply(Math, actual_cols); - - this.cols = Math.max(min_cols, cols, this.options.min_cols); - - if (max_cols !== Infinity && max_cols >= min_cols && max_cols < this.cols) { - this.cols = max_cols; - } - - // get all rows that could be occupied by the current widgets - var max_rows = this.options.extra_rows; - this.$widgets.each(function(i, w) { - max_rows += (+$(w).attr('data-sizey')); - }); - - this.rows = Math.max(max_rows, this.options.min_rows); - - this.baseX = ($(window).width() - aw) / 2; - this.baseY = this.$wrapper.offset().top; - - if (this.options.autogenerate_stylesheet) { - this.generate_stylesheet(); - } - - return this.generate_faux_grid(this.rows, this.cols); - }; - - /** - * Destroy this gridster by removing any sign of its presence, making it easy to avoid memory leaks - * - * @method destroy - * @param {Boolean} remove If true, remove gridster from DOM. - * @return {Object} Returns the instance of the Gridster class. - */ - fn.destroy = function(remove) { - this.$el.removeData('gridster'); - - // remove bound callback on window resize - $(window).unbind('.gridster'); - - if (this.drag_api) { - this.drag_api.destroy(); - } - - this.remove_style_tags(); - - remove && this.$el.remove(); - - return this; - }; - - - //jQuery adapter - $.fn.gridster = function(options) { - return this.each(function() { - if (! $(this).data('gridster')) { - $(this).data('gridster', new Gridster( this, options )); - } - }); - }; - - return Gridster; - -})); diff --git a/GRID/src/utils.js b/GRID/src/utils.js deleted file mode 100644 index f66910d..0000000 --- a/GRID/src/utils.js +++ /dev/null @@ -1,72 +0,0 @@ -;(function(window, undefined) { - - /* Delay, debounce and throttle functions taken from underscore.js - * - * Copyright (c) 2009-2013 Jeremy Ashkenas, DocumentCloud and - * Investigative Reporters & Editors - * - * 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. - */ - - window.delay = function(func, wait) { - var args = Array.prototype.slice.call(arguments, 2); - return setTimeout(function(){ return func.apply(null, args); }, wait); - }; - - window.debounce = function(func, wait, immediate) { - var timeout; - return function() { - var context = this, args = arguments; - var later = function() { - timeout = null; - if (!immediate) func.apply(context, args); - }; - if (immediate && !timeout) func.apply(context, args); - clearTimeout(timeout); - timeout = setTimeout(later, wait); - }; - }; - - window.throttle = function(func, wait) { - var context, args, timeout, throttling, more, result; - var whenDone = debounce( - function(){ more = throttling = false; }, wait); - return function() { - context = this; args = arguments; - var later = function() { - timeout = null; - if (more) func.apply(context, args); - whenDone(); - }; - if (!timeout) timeout = setTimeout(later, wait); - if (throttling) { - more = true; - } else { - result = func.apply(context, args); - } - whenDone(); - throttling = true; - return result; - }; - }; - -})(window); diff --git a/Pic/Upload/couch.png b/Pic/Upload/couch.png new file mode 100644 index 0000000000000000000000000000000000000000..dfd3e6025788a61f329c08bd37372abe9d77f572 GIT binary patch literal 18162 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 ul").gridster({ widget_margins: [3, 3], widget_base_dimensions: [140, 140], - draggable: {ignore_dragging: true}, - max_cols: [4], - max_rows: [4], + max_cols: [2], + max_rows: [2], // serialize_params: function($w, wgd) { return { id: $($w).attr('id'),col: wgd.col, row: wgd.row,size_x: wgd.size_x,size_y: wgd.size_y } // A function to return serialized data for each each widget, used when calling the serialize method. Two arguments are passed: diff --git a/config/TEST.php b/config/TEST.php new file mode 100644 index 0000000..2ecc44b --- /dev/null +++ b/config/TEST.php @@ -0,0 +1,15 @@ + \ No newline at end of file diff --git a/config/set1.php b/config/set1.php index 0290e77..94abbd0 100644 --- a/config/set1.php +++ b/config/set1.php @@ -1,6 +1,12 @@ + @@ -25,6 +31,8 @@
          Show Version : "0") echo "checked=checked; "; ?> />

          + Reset Widgets :
          +
          diff --git a/config/set2.php b/config/set2.php index e8a66f4..1719dfc 100644 --- a/config/set2.php +++ b/config/set2.php @@ -4,7 +4,23 @@ SAB Enabled: "0") echo "checked=checked; "; ?> />
          SAB Port:
          SAB Name:
          - SAB Pic:
          + SAB Pic:

          Sick Enabled: "0") echo "checked=checked; "; ?> />
          Sick Type : >SickBeard / "1") echo "checked=checked; "; ?>>SickRage
          diff --git a/config/write2.php b/config/write2.php index 3bfd049..640803c 100644 --- a/config/write2.php +++ b/config/write2.php @@ -2,7 +2,7 @@ $sabvis1 = $_POST['sabvisible']; $sabport1 = $_POST['sabport']; $sabname1 = $_POST['sabname']; -$sabpicname1 = $_POST['sabpicname']; +$sabpicname1 = $_POST['sabpic']; $sickvis1 = $_POST['sickvisible']; $sicktype1 = $_POST['sicktype']; $sickname1 = $_POST['sickname']; diff --git a/grid.php b/grid.php deleted file mode 100644 index a362f10..0000000 --- a/grid.php +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - - - -
          -
            -
            - - - - - - - - - - - diff --git a/links/cpdual.php b/links/cpdual.php index 5bb5aa9..cb2838c 100644 --- a/links/cpdual.php +++ b/links/cpdual.php @@ -1,9 +1,10 @@ "; + echo "
          • "; } else { - echo ""; + echo "
          • "; } -?> \ No newline at end of file +?> + diff --git a/links/cpsingle.php b/links/cpsingle.php index eb5ec88..b483394 100644 --- a/links/cpsingle.php +++ b/links/cpsingle.php @@ -1,9 +1,10 @@ "; + echo "
          • "; } else { - echo ""; + echo "
          • "; } -?> \ No newline at end of file +?> + diff --git a/links/ftp.php b/links/ftp.php index 3e92539..f6dc4cf 100644 --- a/links/ftp.php +++ b/links/ftp.php @@ -1,9 +1,10 @@ "; + echo "
          • "; } else { - echo ""; + echo "
          • "; } -?> \ No newline at end of file +?> + diff --git a/links/headphones.php b/links/headphones.php new file mode 100644 index 0000000..6fa1eef --- /dev/null +++ b/links/headphones.php @@ -0,0 +1,10 @@ + +
          • "; +} +else { + echo "
          • "; +} +?> + diff --git a/links/jdownloader.php b/links/jdownloader.php index 30c117e..0817914 100644 --- a/links/jdownloader.php +++ b/links/jdownloader.php @@ -1,10 +1,10 @@ "; + echo "
          • "; } else { -echo "
          • "; +echo "
          • "; } ?> diff --git a/links/kodi.php b/links/kodi.php index 74b018f..204287b 100644 --- a/links/kodi.php +++ b/links/kodi.php @@ -1,9 +1,9 @@ "; + echo "
          • "; } else { - echo ""; + echo "
          • "; } ?> \ No newline at end of file diff --git a/links/madsonic.php b/links/madsonic.php index 91c41de..5ca21b9 100644 --- a/links/madsonic.php +++ b/links/madsonic.php @@ -1,9 +1,10 @@ "; + echo "
          • "; } else { - echo ""; + echo "
          • "; } -?> \ No newline at end of file +?> + diff --git a/links/plex.php b/links/plex.php index 87c3794..8527703 100644 --- a/links/plex.php +++ b/links/plex.php @@ -1,9 +1,11 @@ "; + echo "
          • "; } else { - echo ""; + echo "
          • "; } -?> \ No newline at end of file +?> + + \ No newline at end of file diff --git a/links/sab.php b/links/sab.php index 39e8c38..0bcdefe 100644 --- a/links/sab.php +++ b/links/sab.php @@ -1,9 +1,10 @@ "; + echo "
          • "; } else { - echo ""; + echo "
          • "; } -?> \ No newline at end of file +?> + diff --git a/links/sickbeard.php b/links/sickbeard.php index 79d1f1f..24c8369 100644 --- a/links/sickbeard.php +++ b/links/sickbeard.php @@ -1,9 +1,10 @@ "; + echo "
          • "; } else { - echo ""; + echo "
          • "; } -?> \ No newline at end of file +?> + diff --git a/links/sickrage.php b/links/sickrage.php index 1a9598b..551060c 100644 --- a/links/sickrage.php +++ b/links/sickrage.php @@ -1,9 +1,10 @@ "; + echo "
          • "; } else { - echo ""; + echo "
          • "; } -?> \ No newline at end of file +?> + diff --git a/links/squeeze.php b/links/squeeze.php index 4b15d8e..d3f934d 100644 --- a/links/squeeze.php +++ b/links/squeeze.php @@ -1,9 +1,11 @@ "; + echo "
          • "; } else { - echo ""; + echo "
          • "; } -?> \ No newline at end of file +?> + + \ No newline at end of file diff --git a/links/transmission.php b/links/transmission.php index 151c3e5..05ecd5f 100644 --- a/links/transmission.php +++ b/links/transmission.php @@ -1,6 +1,6 @@ "; + echo "
          • "; } ?> diff --git a/links/utorrent.php b/links/utorrent.php index c2691bf..25e29e6 100644 --- a/links/utorrent.php +++ b/links/utorrent.php @@ -1,10 +1,10 @@ "; + echo "
          • "; } else { - echo "
          • "; + echo "
          • "; } ?> diff --git a/main.php b/main.php index eea0105..adf0b14 100644 --- a/main.php +++ b/main.php @@ -29,9 +29,23 @@ indicateSelected(formref.switchcontrol) + + + + + - - + + + + + - - - "0") { - require "konvoschat.php"; - } -?> - + + + + \ No newline at end of file diff --git a/newtest.php b/main.phpold similarity index 77% rename from newtest.php rename to main.phpold index 561826d..eea0105 100644 --- a/newtest.php +++ b/main.phpold @@ -29,23 +29,9 @@ indicateSelected(formref.switchcontrol) - - - - - - - - - - - - - - - + + + "0") { + require "konvoschat.php"; + } +?> + \ No newline at end of file From 4bca8874471a8350ca963137321fcf02ec4613e2 Mon Sep 17 00:00:00 2001 From: Karl Hudgell Date: Sat, 30 Jan 2016 12:19:12 +0000 Subject: [PATCH 3/5] fix styling --- assets/css/jquery.gridster.css | 4 - assets/css/jquery.gridster.min.css | 4 +- assets/css/styles.css | 6 +- assets/gridster_new.js | 4 +- assets/jquery.gridster.js | 489 ++++++++++++++++++++++++++--- 5 files changed, 445 insertions(+), 62 deletions(-) diff --git a/assets/css/jquery.gridster.css b/assets/css/jquery.gridster.css index c36d418..e07b7e0 100644 --- a/assets/css/jquery.gridster.css +++ b/assets/css/jquery.gridster.css @@ -1,7 +1,3 @@ -/*! gridster.js - v0.1.0 - 2012-10-20 -* http://gridster.net/ -* Copyright (c) 2012 ducksboard; Licensed MIT */ - .gridster { position:relative; } diff --git a/assets/css/jquery.gridster.min.css b/assets/css/jquery.gridster.min.css index f11001c..10ff0fa 100644 --- a/assets/css/jquery.gridster.min.css +++ b/assets/css/jquery.gridster.min.css @@ -1,3 +1 @@ -/*! gridster.js - v0.1.0 - 2012-10-20 -* http://gridster.net/ -* Copyright (c) 2012 ducksboard; Licensed MIT */.gridster{position:relative}.gridster>*{margin:0 auto;-webkit-transition:height .4s;-moz-transition:height .4s;-o-transition:height .4s;-ms-transition:height .4s;transition:height .4s}.gridster .gs_w{z-index:2;position:absolute}.ready .gs_w:not(.preview-holder){-webkit-transition:opacity .3s,left .3s,top .3s;-moz-transition:opacity .3s,left .3s,top .3s;-o-transition:opacity .3s,left .3s,top .3s;transition:opacity .3s,left .3s,top .3s}.ready .gs_w:not(.preview-holder){-webkit-transition:opacity .3s,left .3s,top .3s,width .3s,height .3s;-moz-transition:opacity .3s,left .3s,top .3s,width .3s,height .3s;-o-transition:opacity .3s,left .3s,top .3s,width .3s,height .3s;transition:opacity .3s,left .3s,top .3s,width .3s,height .3s}.gridster .preview-holder{z-index:1;position:absolute;background-color:#fff;border-color:#fff;opacity:.3}.gridster .player-revert{z-index:10!important;-webkit-transition:left .3s,top .3s!important;-moz-transition:left .3s,top .3s!important;-o-transition:left .3s,top .3s!important;transition:left .3s,top .3s!important}.gridster .dragging{z-index:10!important;-webkit-transition:all 0s!important;-moz-transition:all 0s!important;-o-transition:all 0s!important;transition:all 0s!important} \ No newline at end of file +.gridster{position:relative}.gridster>*{margin:0 auto;-webkit-transition:height .4s;-moz-transition:height .4s;-o-transition:height .4s;-ms-transition:height .4s;transition:height .4s}.gridster .gs_w{z-index:2;position:absolute}.ready .gs_w:not(.preview-holder){-webkit-transition:opacity .3s,left .3s,top .3s;-moz-transition:opacity .3s,left .3s,top .3s;-o-transition:opacity .3s,left .3s,top .3s;transition:opacity .3s,left .3s,top .3s}.ready .gs_w:not(.preview-holder){-webkit-transition:opacity .3s,left .3s,top .3s,width .3s,height .3s;-moz-transition:opacity .3s,left .3s,top .3s,width .3s,height .3s;-o-transition:opacity .3s,left .3s,top .3s,width .3s,height .3s;transition:opacity .3s,left .3s,top .3s,width .3s,height .3s}.gridster .preview-holder{z-index:1;position:absolute;background-color:#fff;border-color:#fff;opacity:.3}.gridster .player-revert{z-index:10!important;-webkit-transition:left .3s,top .3s!important;-moz-transition:left .3s,top .3s!important;-o-transition:left .3s,top .3s!important;transition:left .3s,top .3s!important}.gridster .dragging{z-index:10!important;-webkit-transition:all 0s!important;-moz-transition:all 0s!important;-o-transition:all 0s!important;transition:all 0s!important} \ No newline at end of file diff --git a/assets/css/styles.css b/assets/css/styles.css index ec0ce7f..970099b 100644 --- a/assets/css/styles.css +++ b/assets/css/styles.css @@ -32,7 +32,7 @@ h3 { .demo { margin: 3em 0; padding: 7.5em 0 5.5em; - /* background: #004756; */ + background: #004756; } .demo:hover .gridster { @@ -53,8 +53,8 @@ h3 { } .gridster .gs_w { - /* background: #FFF; */ + background: #FFF; cursor: pointer; -webkit-box-shadow: 0 0 5px rgba(0,0,0,0.3); - /* box-shadow: 0 0 5px rgba(0,0,0,0.3); */ + box-shadow: 0 0 5px rgba(0,0,0,0.3); } \ No newline at end of file diff --git a/assets/gridster_new.js b/assets/gridster_new.js index 5eb6628..cbed2d2 100644 --- a/assets/gridster_new.js +++ b/assets/gridster_new.js @@ -34,8 +34,8 @@ var grid_canvas = $(".gridster > ul").gridster({ widget_margins: [3, 3], widget_base_dimensions: [140, 140], - max_cols: [2], - max_rows: [2], + max_cols: [5], + max_rows: [4], // serialize_params: function($w, wgd) { return { id: $($w).attr('id'),col: wgd.col, row: wgd.row,size_x: wgd.size_x,size_y: wgd.size_y } // A function to return serialized data for each each widget, used when calling the serialize method. Two arguments are passed: diff --git a/assets/jquery.gridster.js b/assets/jquery.gridster.js index 947f4bb..5c65ca4 100644 --- a/assets/jquery.gridster.js +++ b/assets/jquery.gridster.js @@ -1,6 +1,10 @@ -/*! gridster.js - v0.1.0 - 2012-10-20 -* http://gridster.net/ -* Copyright (c) 2012 ducksboard; Licensed MIT */ +/* + * jquery.coords + * https://github.com/ducksboard/gridster.js + * + * Copyright (c) 2012 ducksboard + * Licensed under the MIT licenses. + */ ;(function($, window, document, undefined){ /** @@ -103,6 +107,14 @@ }(jQuery, window, document)); +/* + * jquery.collision + * https://github.com/ducksboard/gridster.js + * + * Copyright (c) 2012 ducksboard + * Licensed under the MIT licenses. + */ + ;(function($, window, document, undefined){ var defaults = { @@ -274,7 +286,7 @@ if (self.options.on_overlap_stop || self.options.on_overlap_start) { this.manage_colliders_start_stop(colliders_coords, - self.options.on_overlap_stop, self.options.on_overlap_start); + self.options.on_overlap_start, self.options.on_overlap_stop); } this.last_colliders_coords = colliders_coords; @@ -358,6 +370,14 @@ })(window); +/* + * jquery.draggable + * https://github.com/ducksboard/gridster.js + * + * Copyright (c) 2012 ducksboard + * Licensed under the MIT licenses. + */ + ;(function($, window, document, undefined){ var defaults = { @@ -368,7 +388,7 @@ autoscroll: true, ignore_dragging: ['INPUT', 'TEXTAREA', 'SELECT', 'BUTTON'], handle: null - // ,drag: function(e){}, + // drag: function(e){}, // start : function(e, ui){}, // stop : function(e){} }; @@ -425,24 +445,26 @@ this.disabled = false; this.events(); - $(window).bind('resize', - throttle($.proxy(this.calculate_positions, this), 200)); + this.on_window_resize = throttle($.proxy(this.calculate_positions, this), 200); + $(window).bind('resize', this.on_window_resize); }; fn.events = function() { - this.$container.on('selectstart', $.proxy(this.on_select_start, this)); + this.proxied_on_select_start = $.proxy(this.on_select_start, this); + this.$container.on('selectstart', this.proxied_on_select_start); - this.$container.on(pointer_events.start, this.options.items, $.proxy( - this.drag_handler, this)); + this.proxied_drag_handler = $.proxy(this.drag_handler, this); + this.$container.on(pointer_events.start, this.options.items, this.proxied_drag_handler); - this.$body.on(pointer_events.end, $.proxy(function(e) { + this.proxied_pointer_events_end = $.proxy(function(e) { this.is_dragging = false; if (this.disabled) { return; } this.$body.off(pointer_events.move); if (this.drag_start) { this.on_dragstop(e); } - }, this)); + }, this); + this.$body.on(pointer_events.end, this.proxied_pointer_events_end); }; fn.get_actual_pos = function($el) { @@ -549,7 +571,7 @@ this.mouse_init_pos = this.get_mouse_pos(e); this.offsetY = this.mouse_init_pos.top - this.el_init_pos.top; - this.$body.on(pointer_events.move, function(mme){ + this.on_pointer_events_move = function(mme){ var mouse_actual_pos = self.get_mouse_pos(mme); var diff_x = Math.abs( mouse_actual_pos.left - self.mouse_init_pos.left); @@ -557,7 +579,7 @@ mouse_actual_pos.top - self.mouse_init_pos.top); if (!(diff_x > self.options.distance || diff_y > self.options.distance) - ) { + ) { return false; } @@ -572,7 +594,9 @@ } return false; - }); + }; + + this.$body.on(pointer_events.move, this.on_pointer_events_move); return false; }; @@ -678,6 +702,13 @@ fn.destroy = function(){ this.disable(); + + this.$container.off('selectstart', this.proxied_on_select_start); + this.$container.off(pointer_events.start, this.proxied_drag_handler); + this.$body.off(pointer_events.end, this.proxied_pointer_events_end); + this.$body.off(pointer_events.move, this.on_pointer_events_move); + $(window).unbind('resize', this.on_window_resize); + $.removeData(this.$container, 'drag'); }; @@ -690,7 +721,7 @@ }; //jQuery adapter - $.fn.drag = function ( options ) { + $.fn.dragg = function ( options ) { return this.each(function () { if (!$.data(this, 'drag')) { $.data(this, 'drag', new Draggable( this, options )); @@ -701,20 +732,32 @@ }(jQuery, window, document)); +/* + * jquery.gridster + * https://github.com/ducksboard/gridster.js + * + * Copyright (c) 2012 ducksboard + * Licensed under the MIT licenses. + */ ;(function($, window, document, undefined) { + //ToDo Max_cols and Max_size_x conflict.. need to unify var defaults = { namespace: '', widget_selector: 'li', + static_class: 'static', widget_margins: [10, 10], widget_base_dimensions: [400, 225], extra_rows: 0, extra_cols: 0, min_cols: 1, + max_cols: 60, min_rows: 15, + max_rows: 15, max_size_x: 6, autogenerate_stylesheet: true, avoid_overlapped_widgets: true, + shift_larger_widgets_down: true, serialize_params: function($w, wgd) { return { col: wgd.col, @@ -725,7 +768,8 @@ }, collision: {}, draggable: { - distance: 4 + distance: 4, + items: ".gs_w:not(.static)" } }; @@ -783,6 +827,7 @@ this.$widgets = this.$el.children(this.options.widget_selector).addClass('gs_w'); this.widgets = []; this.$changed = $([]); + this.w_queue = {}; this.wrapper_width = this.$wrapper.width(); this.min_widget_width = (this.options.widget_margins[0] * 2) + this.options.widget_base_dimensions[0]; @@ -869,6 +914,7 @@ }).addClass('gs_w').appendTo(this.$el).hide(); this.$widgets = this.$widgets.add($w); + this.$changed = this.$changed.add($w); this.register_widget($w); @@ -1071,9 +1117,12 @@ size_y: size_y }); + /* $nexts.not(exclude).each($.proxy(function(i, widget) { + console.log("from_remove") this.move_widget_up( $(widget), size_y ); }, this)); + */ this.set_dom_grid_height(); @@ -1123,6 +1172,13 @@ return false; }; + fn.remove_by_grid = function(col, row){ + var $w = this.is_widget(col, row); + if($w){ + this.remove_widget($w); + } + } + /** * Remove a widget from the grid. @@ -1199,14 +1255,15 @@ $widgets || ($widgets = this.$widgets); var result = []; $widgets.each($.proxy(function(i, widget) { - result.push(this.options.serialize_params( + if(typeof($(widget).coords().grid) != "undefined"){ + result.push(this.options.serialize_params( $(widget), $(widget).coords().grid ) ); + } }, this)); return result; }; - /** * Returns a serialized array of the widgets that have changed their * position. @@ -1241,6 +1298,10 @@ !this.can_move_to( {size_x: wgd.size_x, size_y: wgd.size_y}, wgd.col, wgd.row) ) { + /*if(!$el.hasClass('.disp_ad')){ + $el.remove(); + return false; + }*/ wgd = this.next_position(wgd.size_x, wgd.size_y); wgd.el = $el; $el.attr({ @@ -1309,13 +1370,13 @@ */ fn.add_to_gridmap = function(grid_data, value) { this.update_widget_position(grid_data, value || grid_data.el); - - if (grid_data.el) { + /*if (grid_data.el) { var $widgets = this.widgets_below(grid_data.el); $widgets.each($.proxy(function(i, widget) { + console.log("from_add_to_gridmap"); this.move_widget_up( $(widget)); }, this)); - } + } */ }; @@ -1352,7 +1413,7 @@ }, 60) }); - this.drag_api = this.$el.drag(draggable_options).data('drag'); + this.drag_api = this.$el.dragg(draggable_options).data('drag'); return this; }; @@ -1507,6 +1568,7 @@ this.player_grid_data = {}; this.cells_occupied_by_placeholder = {}; this.cells_occupied_by_player = {}; + this.w_queue = {}; this.set_dom_grid_height(); }; @@ -1600,12 +1662,13 @@ */ fn.set_player = function(col, row, no_player) { var self = this; + var swap = false; if (!no_player) { this.empty_cells_player_occupies(); } var cell = !no_player ? self.colliders_data[0].el.data : {col: col}; var to_col = cell.col; - var to_row = row || cell.row; + var to_row = cell.row || row; this.player_grid_data = { col: to_col, @@ -1617,13 +1680,102 @@ this.cells_occupied_by_player = this.get_cells_occupied( this.player_grid_data); + //Added placeholder for more advanced movement. + this.cells_occupied_by_placeholder = this.get_cells_occupied( + this.placeholder_grid_data); + var $overlapped_widgets = this.get_widgets_overlapped( this.player_grid_data); - var constraints = this.widgets_constraints($overlapped_widgets); + var player_size_y = this.player_grid_data.size_y; + var player_size_x = this.player_grid_data.size_x; + var placeholder_cells = this.cells_occupied_by_placeholder; + var $gr = this; - this.manage_movements(constraints.can_go_up, to_col, to_row); - this.manage_movements(constraints.can_not_go_up, to_col, to_row); + + //Queue Swaps + $overlapped_widgets.each($.proxy(function(i, w){ + var $w = $(w); + var wgd = $w.coords().grid; + + // Ensure all values are in integer format + wgd.col = parseInt(wgd.col); + wgd.row = parseInt(wgd.row); + wgd.size_x = parseInt(wgd.size_x); + wgd.size_y = parseInt(wgd.size_y); + player_size_x = parseInt(player_size_x); + player_size_y = parseInt(player_size_y); + + var outside_col = placeholder_cells.cols[0]+player_size_x-1; + var outside_row = placeholder_cells.rows[0]+player_size_y-1; + if ($w.hasClass($gr.options.static_class)){ + //next iteration + return true; + } + if(wgd.size_x <= player_size_x && wgd.size_y <= player_size_y){ + if(!$gr.is_swap_occupied(placeholder_cells.cols[0], wgd.row, wgd.size_x, wgd.size_y) && !$gr.is_player_in(placeholder_cells.cols[0], wgd.row) && !$gr.is_in_queue(placeholder_cells.cols[0], wgd.row, $w)){ + swap = $gr.queue_widget(placeholder_cells.cols[0], wgd.row, $w); + } + else if(!$gr.is_swap_occupied(outside_col, wgd.row, wgd.size_x, wgd.size_y) && !$gr.is_player_in(outside_col, wgd.row) && !$gr.is_in_queue(outside_col, wgd.row, $w)){ + swap = $gr.queue_widget(outside_col, wgd.row, $w); + } + else if(!$gr.is_swap_occupied(wgd.col, placeholder_cells.rows[0], wgd.size_x, wgd.size_y) && !$gr.is_player_in(wgd.col, placeholder_cells.rows[0]) && !$gr.is_in_queue(wgd.col, placeholder_cells.rows[0], $w)){ + swap = $gr.queue_widget(wgd.col, placeholder_cells.rows[0], $w); + } + else if(!$gr.is_swap_occupied(wgd.col, outside_row, wgd.size_x, wgd.size_y) && !$gr.is_player_in(wgd.col, outside_row) && !$gr.is_in_queue(wgd.col, outside_row, $w)){ + swap = $gr.queue_widget(wgd.col, outside_row, $w); + } + else if(!$gr.is_swap_occupied(placeholder_cells.cols[0],placeholder_cells.rows[0], wgd.size_x, wgd.size_y) && !$gr.is_player_in(placeholder_cells.cols[0],placeholder_cells.rows[0]) && !$gr.is_in_queue(placeholder_cells.cols[0],placeholder_cells.rows[0], $w)){ + swap = $gr.queue_widget(placeholder_cells.cols[0], placeholder_cells.rows[0], $w); + } else { + //in one last attempt we check for any other empty spaces + for (var c = 0; c < player_size_x; c++){ + for (var r = 0; r < player_size_y; r++){ + var colc = placeholder_cells.cols[0]+c; + var rowc = placeholder_cells.rows[0]+r; + if (!$gr.is_swap_occupied(colc,rowc, wgd.size_x, wgd.size_y) && !$gr.is_player_in(colc,rowc) && !$gr.is_in_queue(colc, rowc, $w)){ + swap = $gr.queue_widget(colc, rowc, $w); + c = player_size_x; + break; + } + } + } + + } + } else if ($gr.options.shift_larger_widgets_down && !swap) { + $overlapped_widgets.each($.proxy(function(i, w){ + var $w = $(w); + var wgd = $w.coords().grid; + + if($gr.can_go_down($w)){ + $gr.move_widget_down($w, $gr.player_grid_data.size_y); + $gr.set_placeholder(to_col, to_row); + } + })); + } + + $gr.clean_up_changed(); + })); + + + /* To show queued items in console + for(var key in this.w_queue){ + console.log("key " +key); + console.log(this.w_queue[key]); + } + */ + + //Move queued widgets + if(swap && this.can_placeholder_be_set(to_col, to_row, player_size_x, player_size_y)){ + for(var key in this.w_queue){ + var col = parseInt(key.split("_")[0]); + var row = parseInt(key.split("_")[1]); + if (this.w_queue[key] != "full"){ + this.new_move_widget_to(this.w_queue[key], col, row); + } + } + this.set_placeholder(to_col, to_row); + } /* if there is not widgets overlapping in the new player position, * update the new placeholder position. */ @@ -1632,9 +1784,13 @@ if (pp !== false) { to_row = pp; } - this.set_placeholder(to_col, to_row); + if(this.can_placeholder_be_set(to_col, to_row, player_size_x, player_size_y)){ + this.set_placeholder(to_col, to_row); + } } + this.w_queue = {}; + return { col: to_col, row: to_row @@ -1642,6 +1798,151 @@ }; + fn.is_swap_occupied = function(col, row, w_size_x, w_size_y) { + var occupied = false; + for (var c = 0; c < w_size_x; c++){ + for (var r = 0; r < w_size_y; r++){ + var colc = col + c; + var rowc = row + r; + var key = colc+"_"+rowc; + if(this.is_occupied(colc,rowc)){ + occupied = true; + } else if(key in this.w_queue){ + if(this.w_queue[key] == "full"){ + occupied = true; + continue; + } + $tw = this.w_queue[key]; + tgd = $tw.coords().grid; + //remove queued items if no longer under player. + if(!this.is_widget_under_player(tgd.col,tgd.row)){ + delete this.w_queue[key]; + } + } + if(rowc > parseInt(this.options.max_rows)){ + occupied = true; + } + if(colc > parseInt(this.options.max_cols)){ + occupied = true; + } + if (this.is_player_in(colc,rowc)){ + occupied = true; + } + } + } + + return occupied; + } + + fn.can_placeholder_be_set = function(col, row, player_size_x, player_size_y){ + var can_set = true; + for (var c = 0; c < player_size_x; c++){ + for (var r = 0; r < player_size_y; r++){ + var colc = col + c; + var rowc = row + r; + var key = colc+"_"+rowc; + var $tw = this.is_widget(colc, rowc); + //if this space is occupied and not queued for move. + if(rowc > parseInt(this.options.max_rows)){ + can_set = false; + } + if(colc > parseInt(this.options.max_cols)){ + can_set = false; + } + if(this.is_occupied(colc,rowc) && !this.is_widget_queued_and_can_move($tw)){ + can_set = false; + } + } + } + return can_set; + } + + fn.queue_widget = function(col, row, $widget){ + var $w = $widget + var wgd = $w.coords().grid; + var primary_key = col+"_"+row; + if (primary_key in this.w_queue){ + return false; + } + + this.w_queue[primary_key] = $w; + + for (var c = 0; c < wgd.size_x; c++){ + for (var r = 0; r < wgd.size_y; r++){ + var colc = col + c; + var rowc = row + r; + var key = colc+"_"+rowc; + if (key == primary_key){ + continue; + } + this.w_queue[key] = "full"; + } + } + + return true; + } + + fn.is_widget_queued_and_can_move = function($widget){ + var queued = false; + if ($widget === false){ + return false; + } + + for(var key in this.w_queue){ + if(this.w_queue[key] == "full"){ + continue; + } + if(this.w_queue[key].attr("data-col") == $widget.attr("data-col") && this.w_queue[key].attr("data-row") == $widget.attr("data-row")){ + queued = true; + //test whole space + var $w = this.w_queue[key]; + var dcol = parseInt(key.split("_")[0]); + var drow = parseInt(key.split("_")[1]); + var wgd = $w.coords().grid; + + for (var c = 0; c < wgd.size_x; c++){ + for (var r = 0; r < wgd.size_y; r++){ + var colc = dcol + c; + var rowc = drow + r; + if (this.is_player_in(colc,rowc)){ + queued = false; + } + + } + } + + } + } + + return queued + } + + fn.is_in_queue = function(col,row, $widget){ + var queued = false; + var key = col+"_"+row; + + if ((key in this.w_queue)){ + if (this.w_queue[key] == "full"){ + queued = true; + } else { + $tw = this.w_queue[key]; + tgd = $tw.coords().grid; + if(!this.is_widget_under_player(tgd.col,tgd.row)){ + delete this.w_queue[key] + queued = false; + } else if(this.w_queue[key].attr("data-col") == $widget.attr("data-col") && this.w_queue[key].attr("data-row") == $widget.attr("data-row")) { + delete this.w_queue[key] + queued = false; + } else { + queued = true; + } + } + } + + return queued; + } + + /** * See which of the widgets in the $widgets param collection can go to * a upper row and which not. @@ -1765,6 +2066,8 @@ /** * Sorts an Array of grid coords objects (representing the grid coords of * each widget) in descending way. + + * Depreciated. * * @method manage_movements * @param {HTMLElements} $widgets A jQuery collection of HTMLElements @@ -1797,9 +2100,11 @@ // so we need to move widget down to a position that dont // overlaps player var y = (to_row + this.player_grid_data.size_y) - wgd.row; - - this.move_widget_down($w, y); - this.set_placeholder(to_col, to_row); + if (this.can_go_down($w)){ + console.log("In Move Down!") + this.move_widget_down($w, y); + this.set_placeholder(to_col, to_row); + } } } }, this)); @@ -1929,6 +2234,32 @@ return false; }; + /** + * Determines if widget is supposed to be static. + * @method is_static + * @param {Number} col The column to check. + * @param {Number} row The row to check. + * @return {Boolean} Returns true if widget exists and has static class, + * else returns false + */ + + fn.is_static = function(col, row) { + var cell = this.gridmap[col]; + if (!cell) { + return false; + } + + cell = cell[row]; + + if (cell) { + if(cell.hasClass(this.options.static_class)){ + return true; + } + } + + return false; + }; + /** * Determines if there is a widget in the cell represented by col/row @@ -1990,7 +2321,7 @@ }); // Prevents widgets go out of the grid - var right_col = (col + phgd.size_x - 1); + var right_col = (col + parseInt(phgd.size_x) - 1); if (right_col > this.cols) { col = col - (right_col - col); } @@ -2011,8 +2342,16 @@ if (moved_down || changed_column) { $nexts.each($.proxy(function(i, widget) { - this.move_widget_up( - $(widget), this.placeholder_grid_data.col - col + phgd.size_y); + //Make sure widget is at it's topmost position + $w = $(widget); + wgd = $w.coords().grid; + + var can_go_widget_up = this.can_go_widget_up(wgd); + + if (can_go_widget_up) { + this.move_widget_to($w, can_go_widget_up); + } + }, this)); } @@ -2274,13 +2613,14 @@ * @return {HTMLElements} Returns a jQuery collection of HTMLElements. */ fn.on_stop_overlapping_column = function(col) { - this.set_player(col, false); - + //this.set_player(col, false); var self = this; - this.for_each_widget_below(col, this.cells_occupied_by_player.rows[0], - function(tcol, trow) { - self.move_widget_up(this, self.player_grid_data.size_y); - }); + if(this.options.shift_larger_widgets_down){ + this.for_each_widget_below(col, this.cells_occupied_by_player.rows[0], + function(tcol, trow) { + self.move_widget_up(this, self.player_grid_data.size_y); + }); + } }; @@ -2292,17 +2632,37 @@ * @return {HTMLElements} Returns a jQuery collection of HTMLElements. */ fn.on_stop_overlapping_row = function(row) { - this.set_player(false, row); - + //this.set_player(false, row); var self = this; var cols = this.cells_occupied_by_player.cols; - for (var c = 0, cl = cols.length; c < cl; c++) { - this.for_each_widget_below(cols[c], row, function(tcol, trow) { - self.move_widget_up(this, self.player_grid_data.size_y); - }); + if(this.options.shift_larger_widgets_down){ + for (var c = 0, cl = cols.length; c < cl; c++) { + this.for_each_widget_below(cols[c], row, function(tcol, trow) { + console.log("from_on_stop_overlapping_row"); + self.move_widget_up(this, self.player_grid_data.size_y); + }); + } } }; + //Not yet part of api - DM. + fn.new_move_widget_to = function($widget, col, row){ + var self = this; + var widget_grid_data = $widget.coords().grid; + + this.remove_from_gridmap(widget_grid_data); + widget_grid_data.row = row; + widget_grid_data.col = col; + + this.add_to_gridmap(widget_grid_data); + $widget.attr('data-row', row); + $widget.attr('data-col', col); + this.update_widget_position(widget_grid_data, $widget); + this.$changed = this.$changed.add($widget); + + return this; + } + /** * Move a widget to a specific row. The cell or cells must be empty. @@ -2386,9 +2746,10 @@ moved.push($widget); - $next_widgets.each($.proxy(function(i, widget) { + /* $next_widgets.each($.proxy(function(i, widget) { + console.log("from_within_move_widget_up"); this.move_widget_up($(widget), y_units); - }, this)); + }, this)); */ } }); @@ -2587,6 +2948,23 @@ return this; }; + fn.can_go_down = function($el) { + var can_go_down = true; + var $gr = this; + + if ($el.hasClass(this.options.static_class)){ + can_go_down = false; + } + + this.widgets_below($el).each(function(){ + if ($(this).hasClass($gr.options.static_class)){ + can_go_down = false; + } + }) + + return can_go_down; + } + fn.can_go_up = function($el) { var el_grid_data = $el.coords().grid; @@ -2783,6 +3161,15 @@ } }; + fn.clean_up_changed = function(){ + $gr = this; + $gr.$changed.each(function(){ + if($gr.options.shift_larger_widgets_down){ + $gr.move_widget_up($(this)); + } + }); + } + fn._traversing_widgets = function(type, direction, col, row, callback) { @@ -2820,7 +3207,8 @@ ) { cr = callback.call(ga[col][trow], col, trow); matched.push(ga[col][trow]); - if (cr) { break; } + //break was causing problems, leaving for testing. + //if (cr) { break; } } } } @@ -3205,7 +3593,8 @@ }); this.cols = Math.max(min_cols, cols, this.options.min_cols); - this.rows = Math.max(max_rows, this.options.min_rows); + //this.rows = Math.max(max_rows, this.options.min_rows); + this.rows = this.options.max_rows; this.baseX = ($(window).width() - aw) / 2; this.baseY = this.$wrapper.offset().top; From fa2bb58e90d88b22efc45d7070667146e077d4ce Mon Sep 17 00:00:00 2001 From: Karl Hudgell Date: Fri, 5 Feb 2016 13:46:30 +0000 Subject: [PATCH 4/5] centered girds --- assets/css/jquery.gridster.css | 56 ++++++++++++++++++++++++++++++++-- assets/css/styles.css | 28 ----------------- configs_services.php | 4 +++ css/custom.php | 9 ------ main.php | 32 ++++++++++++------- 5 files changed, 79 insertions(+), 50 deletions(-) diff --git a/assets/css/jquery.gridster.css b/assets/css/jquery.gridster.css index e07b7e0..cc19584 100644 --- a/assets/css/jquery.gridster.css +++ b/assets/css/jquery.gridster.css @@ -1,7 +1,16 @@ .gridster { - position:relative; + width: 730px; + background: #004756; + margin-left:auto; + margin-right:auto; + opacity: .8; + -webkit-transition: opacity .6s; + -moz-transition: opacity .6s; + -o-transition: opacity .6s; + -ms-transition: opacity .6s; + transition: opacity .6s; + text-align: center; } - .gridster > * { margin: 0 auto; -webkit-transition: height .4s; @@ -14,6 +23,10 @@ .gridster .gs_w{ z-index: 2; position: absolute; + background: #FFF; + cursor: pointer; + -webkit-box-shadow: 0 0 5px rgba(0,0,0,0.3); + box-shadow: 0 0 5px rgba(0,0,0,0.3); } .ready .gs_w:not(.preview-holder) { @@ -54,6 +67,45 @@ transition: all 0s !important; } +.gridWrapper { + width: 100%; + + overflow-x: hidden; + overflow-y: hidden; +} + +body { + background-color: #EEEEEE; + font-family: 'Helvetica Neue', Arial, sans-serif; + -webkit-font-smoothing: antialiased; + font-size: x-small; + color: #666666; + text-align: center; + vertical-align: middle; +} + +ul, ol { + list-style: none; + margin:0 auto; + text-align: center; + vertical-align: middle; + + +} + +h1 { + margin-bottom: 12px; + text-align: center; + font-size: 30px; + font-weight: 400; +} + +h3 { + font-size: 25px; + font-weight: 600; + color: white; +} + /* Uncomment this if you set helper : "clone" in draggable options */ /*.gridster .player { opacity:0; diff --git a/assets/css/styles.css b/assets/css/styles.css index 970099b..9954a48 100644 --- a/assets/css/styles.css +++ b/assets/css/styles.css @@ -29,32 +29,4 @@ h3 { } /* Gridster styles */ -.demo { - margin: 3em 0; - padding: 7.5em 0 5.5em; - background: #004756; -} -.demo:hover .gridster { - opacity: 1; -} - -.gridster { - width: 940px; - margin: 0 auto; - - opacity: .8; - - -webkit-transition: opacity .6s; - -moz-transition: opacity .6s; - -o-transition: opacity .6s; - -ms-transition: opacity .6s; - transition: opacity .6s; -} - -.gridster .gs_w { - background: #FFF; - cursor: pointer; - -webkit-box-shadow: 0 0 5px rgba(0,0,0,0.3); - box-shadow: 0 0 5px rgba(0,0,0,0.3); -} \ No newline at end of file diff --git a/configs_services.php b/configs_services.php index 09c1388..31bdc51 100644 --- a/configs_services.php +++ b/configs_services.php @@ -44,6 +44,10 @@ if ($cpkidsvisible > "0") { $configs['services']["$cpkidsname"] = $cpkids; } +if ($headvisible > "0") { + $configs['services']["$headname"] = $headport; + } + if ($ftpvisible > "0") { $configs['services']["$ftpname"] = $ftpport; } diff --git a/css/custom.php b/css/custom.php index 0727df3..aae8626 100644 --- a/css/custom.php +++ b/css/custom.php @@ -8,11 +8,6 @@ } #style{ -position: absolute; -top: 0; -left: 0; -width: 100%; /*Width of left frame div*/ -height: 100%; overflow: hidden; /*Disable scrollbars. Set to "scroll" to enable*/ background-color: ; color: white; #000000; @@ -28,10 +23,6 @@ overflow: auto; background: } -.innertube{ -margin: 15px; /*Margins for inner DIV inside each DIV (to provide padding)*/ -color: black; -} * html body{ /*IE6 hack*/ padding: 120px 150px 0 200px; /*Set value to (HeightOfTopFrameDiv WidthOfRightFrameDiv 0 WidthOfLeftFrameDiv)*/ diff --git a/main.php b/main.php index adf0b14..4b5b6e4 100644 --- a/main.php +++ b/main.php @@ -31,7 +31,6 @@ indicateSelected(formref.switchcontrol) - @@ -90,8 +89,7 @@ $('.window').hide(); }); -
            -
            +
            @@ -103,10 +101,10 @@ $('.window').hide();

            "; ?>

            -
            - -
            -
              +
              + +
              +
                "0") { @@ -175,9 +173,17 @@ if ($headvisible > "0") { } ?>
              -
              - -
            + + +
            +
            +
            + "0") { + echo "

            Version - $localversion

            "; + } +?> +

            @@ -201,7 +207,11 @@ if ($headvisible > "0") {

            - + "0") { + require "konvoschat.php"; + } +?> From 02c2cb2552f10009b9dd8784f761ccadf5052cfb Mon Sep 17 00:00:00 2001 From: Karl Hudgell Date: Sat, 6 Feb 2016 11:00:38 +0000 Subject: [PATCH 5/5] fixed image select and added headphones --- Pic/Upload/KWorld.png | Bin 0 -> 20461 bytes Pic/Upload/Konvos.png | Bin 0 -> 21392 bytes Pic/Upload/ftp.png | Bin 0 -> 37592 bytes Pic/Upload/headphones.png | Bin 0 -> 20516 bytes Pic/Upload/madsonic.png | Bin 0 -> 220135 bytes Pic/Upload/sick.png | Bin 0 -> 42335 bytes Pic/Upload/test.jpg | Bin 0 -> 3801 bytes assets/css/jquery.gridster.css | 8 +- config/set2.php | 119 ++++++++++++++++++---- config/set3.php | 177 ++++++++++++++++++++++++++++++--- config/upload.php | 2 +- config/write2.php | 6 +- config/write3.php | 16 +++ links/sab.php | 2 +- 14 files changed, 285 insertions(+), 45 deletions(-) create mode 100644 Pic/Upload/KWorld.png create mode 100644 Pic/Upload/Konvos.png create mode 100644 Pic/Upload/ftp.png create mode 100644 Pic/Upload/headphones.png create mode 100644 Pic/Upload/madsonic.png create mode 100644 Pic/Upload/sick.png create mode 100644 Pic/Upload/test.jpg diff --git a/Pic/Upload/KWorld.png b/Pic/Upload/KWorld.png new file mode 100644 index 0000000000000000000000000000000000000000..677d4711a6f2e7df115d0c26825c7cec5110405a GIT binary patch literal 20461 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 I^ueS51rsbI{Qv*} literal 0 HcmV?d00001 diff --git a/Pic/Upload/Konvos.png b/Pic/Upload/Konvos.png new file mode 100644 index 0000000000000000000000000000000000000000..a04e00aa936dd40441d26753e010a288dcefe90d GIT binary patch literal 21392 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 literal 0 HcmV?d00001 diff --git a/Pic/Upload/ftp.png b/Pic/Upload/ftp.png new file mode 100644 index 0000000000000000000000000000000000000000..eaf6215fb76e61e617c8e60e121793ab284e3845 GIT binary patch literal 37592 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

            0q#Z|`g~%M>=Nq8++YTV=2^-U=(9 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 literal 0 HcmV?d00001 diff --git a/Pic/Upload/headphones.png b/Pic/Upload/headphones.png new file mode 100644 index 0000000000000000000000000000000000000000..3110160942176cca75263cd43e5c6c161cd9ce48 GIT binary patch literal 20516 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 P|3GFYmd0g9H=_On^ZTuN literal 0 HcmV?d00001 diff --git a/Pic/Upload/madsonic.png b/Pic/Upload/madsonic.png new file mode 100644 index 0000000000000000000000000000000000000000..f9dc55e5deaed25754cac5b48e71278e72cacedd GIT binary patch literal 220135 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 z

            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%0DSa1_t=sFEQ>2B-3q46U@-tN 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
            BOfbdI<6B5F-O(#TOh-?j`|`7J0V+Sm|*qdQC*0 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

            Mq;J9&a~?iGXI2}rT)CBYT2PkFB85O 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 IM6N<$f{=b$f&c&j literal 0 HcmV?d00001 diff --git a/Pic/Upload/test.jpg b/Pic/Upload/test.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7fb175b34202dc68f6b76e87f22e0a7faa453dcd GIT binary patch literal 3801 zcmbtX2{hDe8~=|nW=67Q4Kz547Qn}2IPtT_#U=8oR*Z}|QxtYs$R<2C}d4g!<(i;UAl=mp&_;g^+OA8Idr_u5r+z1}Lqb7OI^u@Vu=1Y#FlIa<0G`EcgX zio*)r=9`BDBu>k|E?d?W#cHa&><~TkbYWa%)IDZg*H#YW9zQrE}FXPF$(qn!5GY-nQ1edclohb#P zR`*Eaj8X63Ts1a(G)Nu3(MQ+HtH=`2ABx=oLsVzXiQYJLk9u!AOEot^tzS@@F^*Iw@V{w?XhZ~m5Y7VbZp z{tqwVe}M-6TWD5$UaVjcl#?9_h5W_-`<2V%q7uQQ=75tJ?0XJ_o=%0+Z_vrUJ2I&DzAQOFJzZE?3f{d`I(OnyoyyPDeVndBICqa8j^LZ^TPr(D zlWk{{jnKc!3cVujj%08Xg8C)Qq#fNdrpXXagru1)l0+S_tOH4-C7U5W^5}>~^SvuccV52|9eT%UV4A`4%Ab3uuf7h}?M~zwB;sJP6b%=6ShK zbl*yYf=R=X5QC_Y5Wm6nFZdX8@M6GSNUiIDrs*IhX8d7;zawd?b(i6&U+*B2<}<;r zyYg0ifglTwBC3@xm|4juDlJcllX3)j+$+a(ifs}<3cfjF1W_>B%(7M(cqinu!brEG z2=>h&Ap~`|={SUqb{qFqj=+eGrs6J*z@nn^sKHG$}3c<*9bZC zHwTDVNf69nQY&hiV9WQ;k6ZN1A;IHz~;PMB>? zqetV1IJ4s zU}Qpls1F&#q7x5S5tPttX1;*i|j`)Mbm*>9d0^0<=cd11Xx<>MQqb{RI>SkR0U;Vd7lmaU@j zL_C0=@kA&h0tU?nlJlxV*WtGjwGQ(a5W>6Jts6?Z;STQq+j{;bo>dSpkG-E-2$Pa&K+ZH=Jx(OPH2{CPCCwWV&XI>EJs>@&mBZ0w zQX{z#m_US=b~6DN0Z$uvp8(?iUI%x!X^0~T%2{U{+tJRzRliWvISdoj7*X54%hZdw zYQ{4nHYv;)d|CIr*c(`Z7Zl|*WjtAS38^ZdV~GQebH$i`RI?4@D7Lp!J=VSj*S?8Y z#?UrXc1*t16*{|Ax_tV;Ij-QV9Gm=gZK)qMPu<);dToMEpLw*MQsO)@@BHjc)5}+( zm4o`a85Y+qUr!0HMlyl3N#9sJqGE$msteIcHRh>sb#%ZO>JHCRWPeYpuOCs8(pHF$ zi56c0^C^z=ShpS>9*w=#cECwPC|2SrrXHuTm{x#KtGKA&NJ5U;i!1(BDS7?3QfjKI z?AR3#$M|o+73-y=gR6+w)05`q-j`aqC#L!)<$Wk%CykZ5V$snW zbW)}J+HjYtW@jR?`i}nUiw7~>nKsD9Oku)>3cKkdoa}6hop)820^`58kCiohQ$n(s z)TmWa^Fn3fppz?I_WN1+qo=~IY>%sq%;GFNu_XYzRHzW`CsED+j2~ZvAt>S^jFVdk zSvEq1*;0!$fFoyNpSwKM&S)JHE>@MBm26a}oe%vb*uApzX$G16f=+MBPYk{0d^u@G zISF#{TCR7!1egQ`8uvdPL1JRK?-kM@ylgCa&mm;chTF8^vlpkldt?k;X#}-6Ar2UK zbb_Y=AI_MfO%`p@ih`v!l8jv2imKbYKXA90&8v2Z(lXM-SVB8JDECwDQBsnrmM}7$ zLPCV`QgXQ-3D8x3YqRgAQDBe+II2;PUByqQ4HAHV6qh}GLGGt9g$L+YgkmW;qFGl98F hzbbQ{e_if=i1~;gIv=zriPf0EUzqG&41bsm{{t54N2>q; literal 0 HcmV?d00001 diff --git a/assets/css/jquery.gridster.css b/assets/css/jquery.gridster.css index cc19584..46f467f 100644 --- a/assets/css/jquery.gridster.css +++ b/assets/css/jquery.gridster.css @@ -1,6 +1,5 @@ .gridster { width: 730px; - background: #004756; margin-left:auto; margin-right:auto; opacity: .8; @@ -104,9 +103,4 @@ h3 { font-size: 25px; font-weight: 600; color: white; -} - -/* Uncomment this if you set helper : "clone" in draggable options */ -/*.gridster .player { - opacity:0; -}*/ +} \ No newline at end of file diff --git a/config/set2.php b/config/set2.php index 1719dfc..0667346 100644 --- a/config/set2.php +++ b/config/set2.php @@ -4,38 +4,115 @@ SAB Enabled: "0") echo "checked=checked; "; ?> />
            SAB Port:
            SAB Name:
            - SAB Pic:
            -
            +$folder = '../Pic/Upload'; + +echo ''."\n".'

            '; + +function image_filenames($dir) +{ + $handle = @opendir($dir) + or die("I cannot open the directory '$dir' for reading."); + $images = array(); + while (false !== ($file = readdir($handle))) + { + if (eregi('\.(jpg|gif|png)$', $file)) + { + $images[] = $file; + } + } + closedir($handle); + return $images; +} + +function dropdown($options_array, $selected = null) +{ +global $sabpicname; + $return = null; + foreach($options_array as $option) + { + $return .= ''."\n"; + } + return $return; +} + +?> Sick Enabled: "0") echo "checked=checked; "; ?> />
            Sick Type : >SickBeard / "1") echo "checked=checked; "; ?>>SickRage
            Sick Port:
            Sick Name:
            - Sick Pic:
            -
            + Sick Pic:'."\n". + dropdown_sick(image_filenames($folder), @$_POST['image2']). + ''."\n".'

            '; + +function dropdown_sick($options_array, $selected = null) +{ +global $sickpicname; + $return = null; + foreach($options_array as $option) + { + $return .= ''."\n"; + } + return $return; +} + +?> + Couch Enabled: "0") echo "checked=checked; "; ?> />
            Couch Adults : "0") echo "checked=checked; "; ?>>Enabled / >Disabled
            Couch Adults Port:
            Couch Adults Name:
            - Couch Adults Pic:
            + Couch Adults Pic: '."\n". + dropdown_cpa(image_filenames($folder), @$_POST['image2']). + ''."\n".'

            '; + +function dropdown_cpa($options_array, $selected = null) +{ +global $cpadultspicname; + $return = null; + foreach($options_array as $option) + { + $return .= ''."\n"; + } + return $return; +} + +?> Couch Kids : "0") echo "checked=checked; "; ?>>Enabled / >Disabled
            Couch Kids Port:
            Couch Kids Name:
            - Couch Kids Pic:
            + Couch Kids Pic: '."\n". + dropdown_cpk(image_filenames($folder), @$_POST['image2']). + ''."\n".'

            '; + +function dropdown_cpk($options_array, $selected = null) +{ +global $cpkidspicname; + $return = null; + foreach($options_array as $option) + { + $return .= ''."\n"; + } + return $return; +} + +?> \ No newline at end of file diff --git a/config/set3.php b/config/set3.php index caddcf1..6a0948c 100644 --- a/config/set3.php +++ b/config/set3.php @@ -1,4 +1,24 @@ +$dir
            ' for reading."); + $images = array(); + while (false !== ($file = readdir($handle))) + { + if (eregi('\.(jpg|gif|png)$', $file)) + { + $images[] = $file; + } + } + closedir($handle); + return $images; +} +?>

            @@ -6,18 +26,73 @@ FTP Enabled: "0") echo "checked=checked; "; ?> />
            FTP Port:
            FTP Name:
            - FTP Pic:
            -
            + FTP Pic: '."\n". + dropdown_ftp(image_filenames($folder), @$_POST['image2']). + ''."\n".'

            '; + +function dropdown_ftp($options_array, $selected = null) +{ +global $ftppicname; + $return = null; + foreach($options_array as $option) + { + $return .= ''."\n"; + } + return $return; +} + +?> Torrent Enabled: "0") echo "checked=checked; "; ?> />
            Torrent Type : >uTorrent / "1") echo "checked=checked; "; ?>>Transmission
            Torrent Port:
            Torrent Name:
            - Torrent Pic:
            -
            + Torrent Pic: '."\n". + dropdown_torrent(image_filenames($folder), @$_POST['image2']). + ''."\n".'

            '; + +function dropdown_torrent($options_array, $selected = null) +{ +global $torrentpicname; + $return = null; + foreach($options_array as $option) + { + $return .= ''."\n"; + } + return $return; +} + +?> Madsonic Enabled: "0") echo "checked=checked; "; ?> />
            Madsonic Port:
            Madsonic Name:
            - Madsonic Pic:
            + Madsonic Pic: '."\n". + dropdown_mad(image_filenames($folder), @$_POST['image2']). + ''."\n".'

            '; + +function dropdown_mad($options_array, $selected = null) +{ +global $madsonicpicname; + $return = null; + foreach($options_array as $option) + { + $return .= ''."\n"; + } + return $return; +} + +?>
            @@ -25,16 +100,94 @@ Plex Enabled: "0") echo "checked=checked; "; ?> />
            Plex Port:
            Plex Name:
            - Plex Pic:
            -
            - Squeezebox Enabled: "0") echo "checked=checked; "; ?> />
            + Plex Pic: '."\n". + dropdown_plex(image_filenames($folder), @$_POST['image2']). + ''."\n".'

            '; + +function dropdown_plex($options_array, $selected = null) +{ +global $plexpicname; + $return = null; + foreach($options_array as $option) + { + $return .= ''."\n"; + } + return $return; +} + +?> + Squeezebox Enabled: "0") echo "checked=checked; "; ?> />
            Squeezebox Port:
            Squeezebox Name:
            - Squeezebox Pic:
            -
            - Jdownloader Enabled: "0") echo "checked=checked; "; ?> />
            + Squeezebox Pic: '."\n". + dropdown_squeeze(image_filenames($folder), @$_POST['image2']). + ''."\n".'

            '; + +function dropdown_squeeze($options_array, $selected = null) +{ +global $squeezepicname; + $return = null; + foreach($options_array as $option) + { + $return .= ''."\n"; + } + return $return; +} + +?> + Jdownloader Enabled: "0") echo "checked=checked; "; ?> />
            Jdownloader Name:
            - Jdownloader Pic:
            + Jdownloader Pic: '."\n". + dropdown_jd(image_filenames($folder), @$_POST['image2']). + ''."\n".'

            '; + +function dropdown_jd($options_array, $selected = null) +{ +global $jdownloaderpicname; + $return = null; + foreach($options_array as $option) + { + $return .= ''."\n"; + } + return $return; +} + +?> +HeadPhones Enabled: "0") echo "checked=checked; "; ?> />
            +HeadPhones Port:
            + HeadPhones Name:
            + HeadPhones Pic: '."\n". + dropdown_head(image_filenames($folder), @$_POST['image2']). + ''."\n".'

            '; + +function dropdown_head($options_array, $selected = null) +{ +global $headphonespicname; + $return = null; + foreach($options_array as $option) + { + $return .= ''."\n"; + } + return $return; +} + +?>
            diff --git a/config/upload.php b/config/upload.php index d9aa551..6598bbd 100644 --- a/config/upload.php +++ b/config/upload.php @@ -1,5 +1,5 @@ */ $tmp =fopen($fl, "w"); fwrite($tmp, $content); fclose($tmp); diff --git a/links/sab.php b/links/sab.php index 0bcdefe..8f69c3b 100644 --- a/links/sab.php +++ b/links/sab.php @@ -4,7 +4,7 @@ if (empty($sabpicname)) { echo "
          • "; } else { - echo "
          • "; + echo "
          • "; } ?>